表單是由多個表單元素組合而成的,而表單元素又分很多種類型,文本類的表單元素是使用頻率最高的,但是文本類的表單元素不單是有文本類,還有密碼框,數字框、電話號碼框等,而這些表單元素各有自己的作用。
標
表單是用于搜集用戶輸入的信息。而表單是由表單元素組合而成。而根據表單元素的類型,又分為文本類表單元素、選擇類表單元素、單選類表單元素、多選類表單元素和時間類表單元素等。
注冊表單
<input />
在項目開發過程中,有很多業務模塊的代碼是具有一定規律性的,例如controller控制器、service接口、service實現類、mapper接口、model實體類等等,這部分代碼可以使用代碼生成器生成,我們就可以將更多的時間放在業務邏輯上。
傳統的開發步驟:
創建數據庫和表 根據表設計實體類 ? 編寫mapper接口 ? 編寫service接口和實現類 ? 編寫controller控制器 ? 編寫前端頁面 ? 前后端聯調
基于代碼生成器開發步驟:
創建數據庫和表 ? 使用代碼生成器生成實體類、mapper、service、controller、前端頁面 ? 將生成好的代碼拷貝到項目中并做調整 ? 前后端聯調
我們只需要知道數據庫和表相關信息,就可以結合模版生成各個模塊的代碼,減少了很多重復工作,也減少出錯概率,提高效率。
(1)需要對數據庫表解析獲取到元數據,包含表字段名稱、字段類型等等
(2)將通用的代碼編寫成模版文件,部分數據需使用占位符替換
(3)將元數據和模版文件結合,使用一些模版引擎工具(例如freemarker)即可生成源代碼文件
FreeMarker 是一款 模板引擎: 即一種基于模板和要改變的數據, 并用來生成輸出文本(HTML網頁,電子郵件,配置文件,源代碼等)的通用工具。 它不是面向最終用戶的,而是一個Java類庫,是一款程序員可以嵌入他們所開發產品的組件。
模板編寫為FreeMarker Template Language (FTL)。它是簡單的,專用的語言, 在模板中,你可以專注于如何展現數據, 而在模板之外可以專注于要展示什么數據。
(1)動態頁面
freemarker可以作為springmvc一種視圖格式,像jsp一樣被瀏覽器訪問。
(2)頁面靜態化
對于一些內容比較多,更新頻率很小,訪問又很頻繁的頁面,可以使用freemarker靜態化,減少DB的壓力,提高頁面打開速度。
(3)代碼生成器
根據配置生成頁面和代碼,減少重復工作,提高開發效率。
(1)創建freemarker-demo模塊,并導入相關依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itheima</groupId>
<artifactId>freemarker-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
</parent>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- freemarker -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
(2)application.yml相關配置
server:
port: 8881 #服務端口
spring:
application:
name: freemarker-demo #指定服務名
freemarker:
cache: false #關閉模板緩存,方便測試
settings:
template_update_delay: 0 #檢查模板更新延遲時間,設置為0表示立即檢查,如果時間大于0會有緩存不方便進行模板測試
suffix: .ftl #指定Freemarker模板文件的后綴名
(3)創建啟動類
package com.heima.freemarker;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class FreemarkerDemotApplication {
public static void main(String[] args) {
SpringApplication.run(FreemarkerDemotApplication.class,args);
}
}
(4)創建Student模型類
package com.itheima.freemarker.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
private Integer id;
private String name;//姓名
private Integer age;//年齡
private Date birthday;//生日
private Float money;//錢包
}
(5)創建StudentController
package com.itheima.freemarker.controller;
import com.itheima.freemarker.entity.Student;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Date;
@Controller
@RequestMapping("student")
public class StudentController {
@GetMapping("index")
public String index(Model model){
//1.純文本形式的參數
model.addAttribute("name", "Freemarker");
//2.實體類相關的參數
Student student=new Student();
student.setName("黑馬");
student.setAge(18);
model.addAttribute("stu", student);
return "01-index";
}
}
(6)在resources/templates下創建01-index.ftl模版文件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>首頁</title>
</head>
<body>
<b>普通文本 String 展示:</b><br/>
Hello ${name} <br>
<hr>
<b>對象Student中的數據展示:</b><br/>
姓名:${stu.name}<br/>
年齡:${stu.age}
<hr>
</body>
</html>
(7)測試
瀏覽器訪問 http://localhost:8881/student/index
效果如下
(1)注釋,即<#-- -->,介于其之間的內容會被freemarker忽略
<#--我是一個freemarker注釋-->
(2)插值(Interpolation):即 ${..} 部分,freemarker會用真實的值代替${..}
Hello ${name}
(3)FTL指令:和HTML標記類似,名字前加#予以區分,Freemarker會解析標簽中的表達式或邏輯。
<# >FTL指令</#>
(4)文本,僅文本信息,這些不是freemarker的注釋、插值、FTL指令的內容會被freemarker忽略解析,直接輸出內容。
<#--freemarker中的普通文本-->
我是一個普通的文本
if 指令即判斷指令,是常用的FTL指令,freemarker在解析時遇到if會進行判斷,條件為真則輸出if中間的內容,否則跳過內容不再輸出。
格式如下
<#if condition>
....
<#elseif condition2>
...
<#elseif condition3>
...
<#else>
...
</#if>
需求:根據年齡輸出所處的年齡段
童年:0歲—6歲(周歲,下同) 少年:7歲—17歲 青年:18歲—40歲 中年:41—65歲 老年:66歲以后
實例代碼:
(1)在01-index.ftl添加如下代碼
<#if stu.age <=6>
童年
<#elseif stu.age <=17>
少年
<#elseif stu.age <=40>
青年
<#elseif stu.age <=65>
中年
<#else>
老年
</#if>
(2)測試
瀏覽器訪問http://localhost:8881/student/index
效果如下
list指令時一個迭代輸出指令,用于迭代輸出數據模型中的集合
格式如下
<#list items as item>
${item_index + 1}------${item}-----<#if item_has_next>,</#if>
</#list>
迭代集合對象時,包括兩個特殊的循環變量: (1)item_index:當前變量的索引值。 (2)item_has_next:是否存在下一個對象
item_index 和 item_has_nex 中的item為<#list items as item> 中as后面的臨時變量
需求:遍歷學生集合,輸出序號,學生id,姓名,所處的年齡段,是否最后一條數據
(1)在StudentController中增加方法
@GetMapping("list")
public String list(Model model) throws ParseException {
List<Student> list=new ArrayList<>();
list.add(new Student(1001,"張飛",15, null, 1000.11F));
list.add(new Student(1002,"劉備",28, null, 5000.3F));
list.add(new Student(1003,"關羽",45, null, 9000.63F));
list.add(new Student(1004,"諸葛亮",62, null, 10000.99F));
list.add(new Student(1005,"成吉思汗",75, null, 16000.66F));
model.addAttribute("stus",list);
return "02-list";
}
(2)在resources/templates目錄下創建02-list.ftl模版
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>列表頁面</title>
<style>
table{
border-spacing: 0;/*把單元格間隙設置為0*/
border-collapse: collapse;/*設置單元格的邊框合并為1*/
}
td{
border:1px solid #ACBED1;
text-align: center;
}
</style>
</head>
<body>
<table>
<tr>
<td>序號</td>
<td>id</td>
<td>姓名</td>
<td>所處的年齡段</td>
<td>生日</td>
<td>錢包</td>
<td>是否最后一條數據</td>
</tr>
<#list stus as stu >
<tr>
<td>${stu_index + 1}</td>
<td>${stu.id}</td>
<td>${stu.name}</td>
<td>
<#if stu.age <=6>
童年
<#elseif stu.age <=17>
少年
<#elseif stu.age <=40>
青年
<#elseif stu.age <=65>
中年
<#else>
老年
</#if>
</td>
<td></td>
<td>${stu.money}</td>
<td>
<#if stu_has_next>
否
<#else>
是
</#if>
</td>
</tr>
</#list>
</table>
<hr>
</body>
</html>
(2)測試
瀏覽器訪問http://localhost:8881/student/list
效果如下
include指令的作用類似于JSP的包含指令,用于包含指定頁,include指令的語法格式如下
<#include filename [options]></#include>
(1)filename:該參數指定被包含的模板文件 (2)options:該參數可以省略,指定包含時的選項,包含encoding和parse兩個選項,encoding 指定包含頁面時所使用的解碼集,而parse指定被包含是否作為FTL文件來解析。如果省略了parse選項值,則該選項值默認是true
需求:"早上好,尊敬的 某某 用戶!" 這句話在很多頁面都有用到,請合理設計!
(1)在resources/templates目錄下創建00-head.ftl模版,內容如下
早上好,尊敬的 ${name} 用戶!
(2)在resources/templates目錄下創建03-include.ftl模版,使用include引入00-head.ftl模版,內容如下
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>詳情頁</title>
</head>
<body>
<#include "00-head.ftl" />
<br>
歡迎來到黑馬程序員。
</body>
</html>
(3)在StudentController中增加方法
@GetMapping("include")
public String include(Model model) throws ParseException {
model.addAttribute("name", "黑馬");
return "03-include";
}
(4)測試
瀏覽器訪問http://localhost:8881/student/include
效果如下
它用于為該模板頁面創建或替換一個頂層變量
<#assign name="zhangsan" />
(1)算數運算符
FreeMarker表達式中完全支持算術運算,FreeMarker支持的算術運算符包括:
(2)比較運算符
比較運算符注意
(3)邏輯運算符
邏輯運算符只能作用于布爾值,否則將產生錯誤 。
(1)缺失變量默認值使用 “!”
(2)判斷某變量是否存在使用 “??”
用法為:variable??,如果該變量存在,返回true,否則返回false
例:為防止stus為空報錯可以加上判斷如下:
<#if stus??>
<#list stus as stu>
......
</#list>
</#if>
內建函數語法格式: 變量+?+函數名稱
(1)求集合的大小
${集合名?size}
(2)日期格式化
顯示年月日: ${today?date} 顯示時分秒:${today?time} 顯示日期+時間:${today?datetime} 自定義格式化: ${today?string("yyyy年MM月")}
(3)內建函數c
model.addAttribute("point", 102920122);
point是數字型,使用${point}會顯示這個數字的值,每三位使用逗號分隔。
如果不想顯示為每三位分隔的數字,可以使用c函數將數字型轉成字符串輸出
${point?c}
(4)將json字符串轉成對象
一個例子:
其中用到了 assign標簽,assign的作用是定義一個變量。
<#assign text="{'bank':'工商銀行','account':'10101920201920212'}" />
<#assign data=text?eval />
開戶行:${data.bank} 賬號:${data.account}
(5)常見內建函數匯總
?html:html字符轉義
?cap_first: 字符串的第一個字母變為大寫形式
?lower_case :字符串的小寫形式
?upper_case :字符串的大寫形式
?trim:去掉字符串首尾的空格
?substring(from,to):截字符串 from是第一個字符的開始索引,to最后一個字符之后的位置索引,當to為空時,默認的是字符串的長度
?lenth: 取長度
?size: 序列中元素的個數
?int: 數字的整數部分(比如 -1.9?int 就是 -1)
?replace(param1,param2):字符串替換 param1是匹配的字符串 param2是將匹配的字符替換成指定字符
內建函數測試demo1
(1)在StudentController新增方法:
@GetMapping("innerFunc")
public String testInnerFunc(Model model) {
//1.1 小強對象模型數據
Student stu1=new Student();
stu1.setName("小強");
stu1.setAge(18);
stu1.setMoney(1000.86f);
stu1.setBirthday(new Date());
//1.2 小紅對象模型數據
Student stu2=new Student();
stu2.setName("小紅");
stu2.setMoney(200.1f);
stu2.setAge(19);
//1.3 將兩個對象模型數據存放到List集合中
List<Student> stus=new ArrayList<>();
stus.add(stu1);
stus.add(stu2);
model.addAttribute("stus", stus);
// 2.1 添加日期
Date date=new Date();
model.addAttribute("today", date);
// 3.1 添加數值
model.addAttribute("point", 102920122);
return "04-innerFunc";
}
(2)在resources/templates目錄下創建04-innerFunc.ftl模版頁面:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>inner Function</title>
</head>
<body>
<b>獲得集合大小</b><br>
集合大小:${stus?size}
<hr>
<b>獲得日期</b><br>
顯示年月日: ${today?date} <br>
顯示時分秒:${today?time}<br>
顯示日期+時間:${today?datetime}<br>
自定義格式化: ${today?string("yyyy年MM月")}<br>
<hr>
<b>內建函數C</b><br>
沒有C函數顯示的數值:${point} <br>
有C函數顯示的數值:${point?c}
<hr>
<b>聲明變量assign</b><br>
<#assign text="{'bank':'工商銀行','account':'10101920201920212'}" />
<#assign data=text?eval />
開戶行:${data.bank} 賬號:${data.account}
<hr>
</body>
</html>
(3)測試
瀏覽器訪問http://localhost:8881/student/innerFunc
效果如下
內建函數測試demo2
需求:遍歷學生集合,顯示集合總條數,id不要逗號隔開,顯示學生的生日(只顯示年月日),錢包顯示整數并顯示單位元,用戶姓名做脫敏處理(如果是兩個字第二個字顯示為星號,例如張三顯示為張*,如果大于兩個字,中間字顯示為星號,例如成吉思汗顯示為成*汗,諸葛亮顯示為諸*亮)
(1)修改StudentController中的list方法,
@GetMapping("list")
public String list(Model model) throws ParseException {
DateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
List<Student> list=new ArrayList<>();
list.add(new Student(1001,"張三",15, dateFormat.parse("2007-10-01 10:00:00"), 1000.11F));
list.add(new Student(1002,"李四",28, dateFormat.parse("1994-10-01 10:00:00"), 5000.3F));
list.add(new Student(1003,"王五",45, dateFormat.parse("1977-10-01 10:00:00"), 9000.63F));
list.add(new Student(1004,"趙六",62, dateFormat.parse("1960-10-01 10:00:00"), 10000.99F));
list.add(new Student(1005,"孫七",75, dateFormat.parse("1947-10-01 10:00:00"), 16000.66F));
model.addAttribute("stus",list);
return "02-list";
}
(2)修改02-list.ftl模版
共${stus?size}條數據:輸出總條數
stu.id后面加?c:id不需要逗號分割
stu.birthday后面加?date:生日只輸出年月日
stu.money后面加?int:金額取整
姓名需要使用replace和substring函數處理
完整內容如下
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>列表頁面</title>
<style>
table{
border-spacing: 0;/*把單元格間隙設置為0*/
border-collapse: collapse;/*設置單元格的邊框合并為1*/
}
td{
border:1px solid #ACBED1;
text-align: center;
}
</style>
</head>
<body>
共${stus?size}條數據
<table>
<tr>
<td>序號</td>
<td>id</td>
<td>姓名</td>
<td>所處的年齡段</td>
<td>生日</td>
<td>錢包</td>
<td>是否最后一條數據</td>
</tr>
<#list stus as stu >
<tr>
<td>${stu_index + 1}</td>
<td>${stu.id?c}</td>
<td>
<#if stu.name?length=2>
${stu.name?replace(stu.name?substring(1), "*")}
<#else>
${stu.name?replace(stu.name?substring(1, stu.name?length-1), "*")}
</#if>
</td>
<td>
<#if stu.age <=6>
童年
<#elseif stu.age <=17>
少年
<#elseif stu.age <=40>
青年
<#elseif stu.age <=65>
中年
<#else>
老年
</#if>
</td>
<td>${stu.birthday?date}</td>
<td>${stu.money?int}元</td>
<td>
<#if stu_has_next>
否
<#else>
是
</#if>
</td>
</tr>
</#list>
</table>
<hr>
</body>
</html>
(3)測試
瀏覽器訪問http://localhost:8881/student/list
效果如下
(1)springboot整合freemarker靜態化文件用法
編寫springboot測試用例
package com.itheima.test;
import com.itheima.freemarker.FreemarkerDemoApplication;
import com.itheima.freemarker.entity.Student;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
@SpringBootTest(classes=FreemarkerDemoApplication.class)
@RunWith(SpringRunner.class)
public class FreemarkerTest {
//注入freemarker配置類
@Autowired
private Configuration configuration;
@Test
public void test() throws IOException, TemplateException {
Template template=configuration.getTemplate("04-innerFunc.ftl");
/**
* 靜態化并輸出到文件中 參數1:數據模型 參數2:文件輸出流
*/
template.process(getData(), new FileWriter("d:/list.html"));
/**
* 靜態化并輸出到字節輸出流中
*/
//StringWriter out=new StringWriter();
//template.process(getData(), out);
//System.out.println(out.toString());
}
private Map getData(){
Map<String,Object> map=new HashMap<>();
Student stu1=new Student();
stu1.setName("小強");
stu1.setAge(18);
stu1.setMoney(1000.86f);
stu1.setBirthday(new Date());
//小紅對象模型數據
Student stu2=new Student();
stu2.setName("小紅");
stu2.setMoney(200.1f);
stu2.setAge(19);
//將兩個對象模型數據存放到List集合中
List<Student> stus=new ArrayList<>();
stus.add(stu1);
stus.add(stu2);
//向model中存放List集合數據
map.put("stus",stus);
//map數據
Map<String,Student> stuMap=new HashMap<>();
stuMap.put("stu1",stu1);
stuMap.put("stu2",stu2);
map.put("stuMap",stuMap);
//日期
map.put("today",new Date());
//長數值
map.put("point",38473897438743L);
return map;
}
}
(2)freemarker原生靜態化用法
package com.itheima.freemarker.test;
import com.itheima.freemarker.entity.Student;
import freemarker.cache.FileTemplateLoader;
import freemarker.cache.NullCacheStorage;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
public class FreemarkerTest {
public static void main(String[] args) throws IOException, TemplateException {
//創建配置類
Configuration CONFIGURATION=new Configuration(Configuration.VERSION_2_3_22);
//設置模版加載路徑
//ClassTemplateLoader方式:需要將模版放在FreemarkerTest類所在的包,加載模版時會從該包下加載
//CONFIGURATION.setTemplateLoader(new ClassTemplateLoader(FreemarkerTest.class,""));
String path=java.net.URLDecoder.decode(FreemarkerTest.class.getClassLoader().getResource("").getPath(),"utf-8");
//FileTemplateLoader方式:需要將模版放置在classpath目錄下 目錄有中文也可以
CONFIGURATION.setTemplateLoader(new FileTemplateLoader(new File(path)));
//設置編碼
CONFIGURATION.setDefaultEncoding("UTF-8");
//設置異常處理器
CONFIGURATION.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
//設置緩存方式
CONFIGURATION.setCacheStorage(NullCacheStorage.INSTANCE);
//加載模版
Template template=CONFIGURATION.getTemplate("templates/04-innerFunc.ftl");
/**
* 靜態化并輸出到文件中 參數1:數據模型 參數2:文件輸出流
*/
template.process(getModel(), new FileWriter("d:/list.html"));
/**
* 靜態化并輸出到字節輸出流中
*/
//StringWriter out=new StringWriter();
//template.process(getData(), out);
//System.out.println(out.toString());
}
public static Map getModel(){
Map map=new HashMap();
//1.1 小強對象模型數據
Student stu1=new Student();
stu1.setName("小強");
stu1.setAge(18);
stu1.setMoney(1000.86f);
stu1.setBirthday(new Date());
//1.2 小紅對象模型數據
Student stu2=new Student();
stu2.setName("小紅");
stu2.setMoney(200.1f);
stu2.setAge(19);
//1.3 將兩個對象模型數據存放到List集合中
List<Student> stus=new ArrayList<>();
stus.add(stu1);
stus.add(stu2);
map.put("stus", stus);
// 2.1 添加日期
Date date=new Date();
map.put("today", date);
// 3.1 添加數值
map.put("point", 102920122);
return map;
}
}
元數據(Metadata)是描述數據的數據。
數據庫元數據(DatabaseMetaData)就是指定義數據庫各類對象結構的數據。
在mysql中可以通過show關鍵字獲取相關的元數據
show status; 獲取數據庫的狀態
show databases; 列出所有數據庫
show tables; 列出所有表
show create database [數據庫名]; 獲取數據庫的定義
show create table [數據表名]; 獲取數據表的定義
show columns from <table_name>; 顯示表的結構
show index from <table_name>; 顯示表中有關索引和索引列的信息
show character set; 顯示可用的字符集以及其默認整理
show collation; 顯示每個字符集的整理
show variables; 列出數據庫中的參數定義值
也可以從 information_schema庫中獲取元數據,information_schema數據庫是MySQL自帶的信息數據庫,它提供了訪問數據庫元數據的方式。存著其他數據庫的信息。
select schema_name from information_schema.schemata; 列出所有的庫
select table_name FROM information_schema.tables; 列出所有的表
在代碼中可以由JDBC的Connection對象通過getMetaData方法獲取而來,主要封裝了是對數據庫本身的一些整體綜合信息,例如數據庫的產品名稱,數據庫的版本號,數據庫的URL,是否支持事務等等。
DatabaseMetaData的常用方法:
getDatabaseProductName:獲取數據庫的產品名稱
getDatabaseProductName:獲取數據庫的版本號
getUserName:獲取數據庫的用戶名
getURL:獲取數據庫連接的URL
getDriverName:獲取數據庫的驅動名稱
driverVersion:獲取數據庫的驅動版本號
isReadOnly:查看數據庫是否只允許讀操作
supportsTransactions:查看數據庫是否支持事務
(1)導入mysql依賴
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
(2)創建測試用例
package com.itheima.test;
import org.junit.Before;
import org.junit.Test;
import java.sql.*;
import java.util.Properties;
public class DataBaseMetaDataTest {
private Connection conn;
@Before
public void init() throws Exception {
Properties pro=new Properties();
pro.setProperty("user", "root");
pro.setProperty("password", "123456");
pro.put("useInformationSchema", "true");//獲取mysql表注釋
//pro.setProperty("remarksReporting","true");//獲取oracle表注釋
conn=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/?useUnicode=true&characterEncoding=UTF8", pro);
}
}
(1)獲取數據庫元信息綜合信息
@Test
public void testDatabaseMetaData() throws SQLException {
//獲取數據庫元數據
DatabaseMetaData dbMetaData=conn.getMetaData();
//獲取數據庫產品名稱
String productName=dbMetaData.getDatabaseProductName();
System.out.println(productName);
//獲取數據庫版本號
String productVersion=dbMetaData.getDatabaseProductVersion();
System.out.println(productVersion);
//獲取數據庫用戶名
String userName=dbMetaData.getUserName();
System.out.println(userName);
//獲取數據庫連接URL
String userUrl=dbMetaData.getURL();
System.out.println(userUrl);
//獲取數據庫驅動
String driverName=dbMetaData.getDriverName();
System.out.println(driverName);
//獲取數據庫驅動版本號
String driverVersion=dbMetaData.getDriverVersion();
System.out.println(driverVersion);
//查看數據庫是否允許讀操作
boolean isReadOnly=dbMetaData.isReadOnly();
System.out.println(isReadOnly);
//查看數據庫是否支持事務操作
boolean supportsTransactions=dbMetaData.supportsTransactions();
System.out.println(supportsTransactions);
}
(2)獲取數據庫列表
@Test
public void testFindAllCatalogs() throws Exception {
//獲取元數據
DatabaseMetaData metaData=conn.getMetaData();
//獲取數據庫列表
ResultSet rs=metaData.getCatalogs();
//遍歷獲取所有數據庫表
while (rs.next()) {
//打印數據庫名稱
System.out.println(rs.getString(1));
}
//釋放資源
rs.close();
conn.close();
}
(3)獲取某數據庫中的所有表信息
@Test
public void testFindAllTable() throws Exception {
//獲取元數據
DatabaseMetaData metaData=conn.getMetaData();
//獲取所有的數據庫表信息
ResultSet rs=metaData.getTables("庫名", "%", "%", new String[]{"TABLE"});
//拼裝table
while (rs.next()) {
//所屬數據庫
System.out.println(rs.getString(1));
//所屬schema
System.out.println(rs.getString(2));
//表名
System.out.println(rs.getString(3));
//數據庫表類型
System.out.println(rs.getString(4));
//數據庫表備注
System.out.println(rs.getString(5));
System.out.println("--------------");
}
}
(4)獲取某張表所有的列信息
@Test
public void testFindAllColumns() throws Exception {
//獲取元數據
DatabaseMetaData metaData=conn.getMetaData();
//獲取所有的數據庫某張表所有列信息
ResultSet rs=metaData.getColumns("庫名", "%", "表名","%");
while(rs.next()) {
//表名
System.out.println(rs.getString("TABLE_NAME"));
//列名
System.out.println(rs.getString("COLUMN_NAME"));
//類型碼值
System.out.println(rs.getString("DATA_TYPE"));
//類型名稱
System.out.println(rs.getString("TYPE_NAME"));
//列的大小
System.out.println(rs.getString("COLUMN_SIZE"));
//小數部分位數,不適用的類型會返回null
System.out.println(rs.getString("DECIMAL_DIGITS"));
//是否允許使用null
System.out.println(rs.getString("NULLABLE"));
//列的注釋信息
System.out.println(rs.getString("REMARKS"));
//默認值
System.out.println(rs.getString("COLUMN_DEF"));
//是否自增
System.out.println(rs.getString("IS_AUTOINCREMENT"));
//表中的列的索引(從 1 開始
System.out.println(rs.getString("ORDINAL_POSITION"));
System.out.println("--------------");
}
}
參數元數據(ParameterMetaData):是由PreparedStatement對象通過getParameterMetaData方法獲取而 來,主要是針對PreparedStatement對象和其預編譯的SQL命令語句提供一些信息,ParameterMetaData能提供占位符參數的個數,獲取指定位置占位符的SQL類型等等 以下有一些關于ParameterMetaData的常用方法:
getParameterCount:獲取預編譯SQL語句中占位符參數的個數
@Test
public void testParameterMetaData() throws Exception {
String sql="select * from health.t_checkgroup where id=? and code=?";
PreparedStatement pstmt=conn.prepareStatement(sql);
pstmt.setString(1, "7");
pstmt.setString(2, "0003");
//獲取ParameterMetaData對象
ParameterMetaData paramMetaData=pstmt.getParameterMetaData();
//獲取參數個數
int paramCount=paramMetaData.getParameterCount();
System.out.println(paramCount);
}
結果集元數據(ResultSetMetaData):是由ResultSet對象通過getMetaData方法獲取而來,主要是針對由數據庫執行的SQL腳本命令獲取的結果集對象ResultSet中提供的一些信息,比如結果集中的列數、指定列的名稱、指 定列的SQL類型等等,可以說這個是對于框架來說非常重要的一個對象。 以下有一些關于ResultSetMetaData的常用方法:
getColumnCount:獲取結果集中列項目的個數
getColumnType:獲取指定列的SQL類型對應于Java中Types類的字段
getColumnTypeName:獲取指定列的SQL類型
getClassName:獲取指定列SQL類型對應于Java中的類型(包名加類名
@Test
public void testResultSetMetaData() throws Exception {
String sql="select * from health.t_checkgroup where id=?";
PreparedStatement pstmt=conn.prepareStatement(sql);
pstmt.setString(1, "7");
//執行sql語句
ResultSet rs=pstmt.executeQuery();
//獲取ResultSetMetaData對象
ResultSetMetaData metaData=rs.getMetaData();
//獲取查詢字段數量
int columnCount=metaData.getColumnCount();
System.out.println("字段總數量:"+ columnCount);
for (int i=1; i <=columnCount; i++) {
//獲取表名稱
System.out.println(metaData.getColumnName(i));
//獲取java類型
System.out.println(metaData.getColumnClassName(i));
//獲取sql類型
System.out.println(metaData.getColumnTypeName(i));
System.out.println("----------");
}
}
創建maven工程并導入以下依賴
<properties>
<java.version>11</java.version>
<!-- 項目源碼及編譯輸出的編碼 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- 項目編譯JDK版本 -->
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.23</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.10</version>
</dependency>
</dependencies>
目錄結構如下
譯局是36氪旗下編譯團隊,關注科技、商業、職場、生活等領域,重點介紹國外的新技術、新觀點、新風向。
編者按:Marc Andreessen十年前說的“軟件蠶食世界”不僅完全正確,而且似乎不僅如此:軟件正在重塑世界。人類世界的運轉已經無法離開軟件。在浩如煙海的軟件代碼當中,哪些對我們起到了關鍵作用呢?Slate網站邀請了各方人士對那些改變了一切的代碼進行評選,這里篩選出36個代碼片段。如果你有更好的選項,不妨在評論區留下你的意見。原文作者是Future Tense,標題是:The Lines of Code That Changed Everything。鑒于篇幅太長,我們將分三部分刊出,此為第二部分。
人類歷史上最重要的36個代碼片段(一)
年代:1988
在網上閑逛的起源
/join #cats
Internet Relay Chat(一般簡稱IRC)的歷史很早,甚至在大部分人不能告訴你互聯網是什么的時候就有了。這是第一種流行的在群組頻道內跟他人實時聊天的手段。早期用戶會登錄上去分享消息,比方說1991年蘇聯發生一起政變期間曾進行了媒體管制。聊天本身也需要輸入一些代碼:比方說,要加入頻道,你得輸入“/ join #[ 頻道名稱]。”(對于今天玩Slack上癮的人來說會很熟悉。)如果你想表達一些關于自己的信息,可以輸入“/ me太累了”,它就會顯示你的名字加上星號加上“太累了。”功能很基礎,但是對于很多人來說,這是他們用計算機命令畫出的第一筆,并且是加入談話的門票。——April Glaser, Slate
年代:1988
讓人意識到互聯網已經變得有多龐大的一盆冷水
checkother /* 0x57d0 */
{
int s, l8, l12, l16, optval;
struct sockaddr_in sin; /* 16 bytes */
optval=1;
if ((random % 7)==3)
return; /* 612 */
s=socket(AF_INET, SOCK_STREAM, 0);
if (s return;
這是莫里斯蠕蟲代碼關鍵功能的摘錄。Robert Morris,計算機歷史博物館和Arialdo Martini提供
當時23歲的康奈爾大學研究生莫里斯Morris釋放莫里斯蠕蟲(Morris Worm),發動了所謂的“互聯網的首次重大攻擊”時,羅伯特·莫里斯和互聯網本身都還很年輕。當時接入互聯網的6萬臺機器里面,大概有10%遭到了破壞,造成數百萬美元的損失,并導致《紐約時報》首次刊出“互聯網”這一詞。即使是精通技術的人,對于這個蠕蟲的影響范圍如此之廣也感到瞠目結舌。莫里斯說,他本意并不想造成如此大的傷害,他也因此成為根據《計算機欺詐和濫用法》被起訴的第一人。在被判處三年緩刑之后,他成為了著名的創業孵化器Y Combinator 的共同創始人以及麻省理工學院的計算機科學助理教授。——Elena Botella
年代:大約1990年代
一行代碼的威力,以及計算機總讓人驚訝的脆弱性
:{:| :&}; :
不要在家里跑這行代碼。提供者:Chris Noessel
你在上面看到的是一種稱為“叉路炸彈(fork bomb)”的病毒——只有一行代碼。當然它的發作需要滿足一些特定的條件(包括Unix 操作系統版本要舊一點,易感染的那種)。在條件滿足的情況下,如果你在Bash里面輸入這條命令,它就會一遍又一遍地復制自身,直到把計算機中的所有可用內存耗盡,導致計算機崩潰。
這段代碼的美麗之處不在于代碼之小與危害之大的對比,而在于它用冒號作為函數名。大多數函數(可重復使用的代碼行)的命名都是描述性的,比方說“Print”或“isThisEmailValid”,但是這并不是嚴格要求的規矩。大多數計算語言都不能用冒號作為函數名稱,但是Bash就可以。
我最早見到這行代碼要追溯到2002年,當時德國法蘭克福的一家藝術博物館Angewandte Kunst 博物館正在展覽。博物館展覽代碼可是很罕見的的——Chris Noessel
年代:1990
讓我們把所有東西連接上任何東西(甚至是難以想象的東西)的工具
https://www.slate.com">Slate
蒂姆·伯納斯·李(Tim Berners-Lee)引入超鏈接,世界從此改變了。超鏈接是一段讓人人皆可遨游WWW的代碼。將信息鏈接起來的概念并不算特別新穎,但超鏈接的新鮮之處在于,它把各種計算機系統約定的標點符號拼湊到了一起,統一成URL冒號雙斜杠的格式,從而對任何現有的條目進行命名。盡管伯納斯·李擔心向后兼容性的問題,但超鏈接任何東西的概念令該想法永不過時。伯納斯·李的超鏈接可以隨意變成“馬上購買”按鈕,點贊拇指、轉發推特等等。這些令人意想不到的用例應該能夠提醒我們,當我們站在技術革命的風口浪尖時,最難預料到的就是接下來會發生的事情。——R Street技術和創新總監Charles Duan
年代:1992
永遠改變了我們與攝影的關系
double *NaiveDct_transform(double vector[], size_t len) {
if (SIZE_MAX / sizeof(double) return NULL;
double *result=malloc(len * sizeof(double));
if (result==NULL)
return NULL;
double factor=M_PI / len;
for (size_t i=0; i double sum=0;
for (size_t j=0; j sum +=vector[j] * cos((j + 0.5) * i * factor);
result[i]=sum;
}
return result;
}
上述代碼片段是離散余弦變換算法,JPEG背后的基石。
Nayuki項目
我們現在已經把相機裝滿照片視為理所當然。但是過去表示圖像需要大量的數據。1992年,聯合圖像專家組(Joint Photographic Experts Group)發布了JPEG的標準規范,從而讓圖像文件變得更小。盡管當時也可以用其他的壓縮格式,但JPEG之所以能成為世界標準,部分原因是它不用交版稅。JPEG采用了有損壓縮,在壓縮過程當中可以消除圖像里面人眼無法檢測到的部分,比方說顏色的細微變化。有損壓縮對于1992年引入的另一項發明MP3也至關重要.類似地,這種音頻文件格式通過丟棄人耳無法檢測到的數據而變得緊湊。——Aaron Mak, Slate
年代:1993
現代web的誕生
MakeImage(dsp, data, width, height, depth, img_info, clip)
Display *dsp;
unsigned char *data;
int width, height;
int depth;
ImageInfo *img_info;
int clip;
{
int linepad, shiftnum;
int shiftstart, shiftstop, shiftinc;
int bytesperline,bpp;
int temp;
int w, h;
XImage *newimage;
unsigned char *bit_data, *bitp, *datap;
Visual *theVisual;
int bmap_order;
unsigned long c;
int rshift, gshift, bshift;
#ifdef NEW
switch(bpp=bits_per_pixel(dsp,depth))
#else
switch(depth)
以上是2.7版代碼的一部分。
美國國家超級計算機應用中心軟件開發小組,用于X Windows系統的NCSA Mosaic
以前的瀏覽器渲染處理得很笨拙,雖然文本呈現的效果很好,但是瀏覽圖像卻一定要單獨打開窗口。Marc Andreessen領導的Mosaic黑客希望做出一個能讓文字和圖像一起呈現的瀏覽器。是他們讓web變得我們熟悉的樣子,就好像在看一本很酷的數字雜志或報紙一樣。隨著世界各地的網站管理員開始要求更多的標簽來讓網站看起來更酷,這也促使HTML標準的發展走上了快車道。(那時候框架似乎是個超酷的主意。)——Clive Thompson
年代:1993
Facebook的PageView 跟蹤像素。
Facebook's PageView Tracking Pixel.
這些小小的HTML片段看起來并沒有多少,但它們卻是數字廣告的基石,讓它們成為了許多當代問題(監視,媒體整合甚至虛假信息)的核心。
早在1990年代的時候,web設計師就開始用透明的單像素圖像來調整頁面布局。但是,計算機必須下載網頁上的每一張圖像,甚至大家察覺不到的像素也得下載。1993年,公司開始利用這一個漏洞:通過跟蹤像素下載,他們就可以了解了你是誰在哪里,還觸發一個cookie下載到你的瀏覽器。這個cookie使得Cookie使廣告主可以跨多個網站跟蹤你。
像素跟蹤的成功直接導致了Facebook的“贊”按鈕的誕生,這個按鈕可在嵌入它的每個網站上跟蹤你。這種大規模的數據收集實現了超級的定向,讓Facebook廣告變得無比成功,其結果是媒體公司數十億美元的收入被轉移到Facebook。隨著新聞業的沉淪,定向性的虛假信息大行其道,而基于監視的商業模式開始激增。——Sara Wachter -Boettcher,《技術錯誤:性別歧視app,帶偏見的算法以及其他的有毒技術》作者
年代:1994
一個對搜索等應用具有重大影響的微型工具
User-agent: Mediapartners-Google
Disallow:
User-agent: TruliaBot
Disallow: /
User-agent: *
Disallow: /search.html
User-agent: *
Disallow: /comments/*
User-agent: Mediapartners-Google*
Disallow:
Slate自己的robot.txt
如果你執行過Google搜索的話,你可能會遇到過這樣的結果:“由于該網站的robots.txt,該搜索結果的描述不可用。”并不是每個人都希望自己的網站被搜索引擎索引到,這就是robots.txt文件添加到網站的原因之一,讓給網站建檔的bot(有時也叫做蜘蛛或爬蟲)走開而不是訪問該站點。robots.txt在訪問網站內容方面起到的非比尋常的調停作用使得robots.txt成為了法庭上控辯雙方斗爭得最激烈的代碼段之一,其中涉及到了十幾個涉及版權、黑客、入侵,侵權行為的案件,甚至2009年的一樁司法不端行為調查還牽涉到了前第九巡回法院首席法官Alex Kozinski。——喬治敦大學法學院知識產權與信息政策研究室主任Amanda Levendowski
年代:1994
為維基百科鋪平了道路
sub AsLink {
local($num)=(@_);
local($ref)=$old{"r$num"};
defined $ref
? ($ref=~ /\.(?:gif|jpg|jpeg|png)$/i
? "
"
: "[$num]")
: "[$num]";
}
WikiWikiWeb的WikiBase ,最后編輯于2000年6月13日
Ward Cunningham通過自己的網站WikiWikiWeb率先發明了Wiki ,他認為這是分享信息最簡單的方法。他用了一種基本的標記語言,里面使用方括號將單詞不留空格串在一起,并在文本周圍用省略號標記,讓編輯者更新和組織跨頁面鏈接的信息,這套系統至今在各類Wiki網站上仍被廣泛使用,其中就包括2001年推出的Wikipedia(維基百科)。便利的格式使得Wiki成為了某些最重要的活躍在線協作形式(安全漏洞跟蹤、記筆記等)的工具。但是,跟任何可以在網上進行編輯的內容一樣,Wiki也很容易受到故意破壞,以及圍繞著應該發布什么不應該發布什么展開的激烈爭吵,所以Wikipedia才會引入討論頁面和規則來管控編輯添加新信息的方式。——April Glaser
年代:90年代中期
互聯網的災禍
window.open ('https://www.slate.com/')
在新窗口打開特定URL的基本代碼。
20多年前,我寫過一小段JavaScript代碼,它會在打開你請求的頁面的同時打開另一個小的Web瀏覽器窗口。這個新窗口里面有一個廣告——可怕的彈出式廣告。在接下來的幾年中,我震驚地看著彈出廣告在網絡上泛濫,被web上最糟糕、最具侵擾性的廣告主濫用。
我當時做彈出廣告的目的是這個:我的公司Tripod提供免費主頁,讓大家把自己想放的任何內容放到上面。為了給這項服務提供補貼,我們得賣廣告。但是廣告主并不總是喜歡他們刊登廣告的頁面的內容,因此我們決定將廣告與用戶的內容分開。所以就有了彈出廣告。
我實現彈出式廣告的時候就知道這并不是個很好的解決方案。看著它在web上傳播就像用膠帶來固定你的汽車,然后看著路上的其他人扯掉幾條銀色的袋子一起湊熱鬧一樣。
自從我向全世界釋放了這頭邪惡的野獸之后,我出過書,創辦過公司,在大學教過人,但別人總會把我跟彈出窗口聯系到一起。當本文發表時,我預計仍會收到仇恨的郵件——麻省理工學院公民媒體中心主任Ethan Zuckerman
年代:大約1995年
語言:Perl
以代碼表現激進主義的最早例子之一
#!/bin/perl -s-- -export-a-crypto-system-sig -RSA-3-lines-PERL
$m=unpack(H.$w,$m.">$m=unpack(H.$w,$m."\0"x$w),$_=`echo "16do$w 2+4Oi0$d*-^1[d2%Sa <"x$w),$_=`echo "16do$w 2+4Oi0$d*-^1[d2%Sa
2/d0pack('H*',$_)while read(STDIN,$m,($w=2*$d-1+length($n)&~1)/2)
Munitions T-Shirt主頁
那件T恤上的文字是這樣寫的:“警告:這件T恤被歸類為軍需品,不得從美國出口或展示給外國人。”曾經有一段時間美國政府把強加密看作是地對空導彈:一旦落入美國敵人手中就會變得無比危險。當加密是在笨重、昂貴的設備內進行時,這種想法還說得過去,但是1990年代,當美國國務院想要阻止密碼學研究人員把代碼發布到互聯網上時,這種想法就不大說得過去了。可是他們沒想到RSA加密算法(現代加密技術的基本建構塊之一)實在是太優雅了,以至于僅用四行寫得密密麻麻的Perl代碼就能表示出來……緊湊到可以印到T恤上面。原先的那件T恤現在已成收藏家的藏品。出口管制雖然還沒有完全取消,但已大大減少。——康奈爾理工學院、康奈爾法學院法學教授James Grimmelmann
年代:1996
革新了我們知識的組織方式
import numpy as np
def pagerank(M, num_iterations=100, d=0.85):
N=M.shape[1]
v=np.random.rand(N, 1)
v=v / np.linalg.norm(v, 1)
iteration=0
while iteration iteration +=1
v=d * np.matmul(M, v) + (1 - d) / N
return v
Google創建的算法,上述實現由Wikipedia提供
在PageRank之前,搜索引擎是通過尋找我們的查詢關鍵字是否跟文檔里面的單詞匹配來查找信息的。但Larry PageSergey Brin提出了一個絕妙的主意:知識是社會化的,搜索也應如此。為此,他們創建了一種算法,PageRank,這個算法會根據網上有多少其他頁面鏈接到某個網頁來對該網頁的突出程度進行排名。Google今天之所以如此強大,就因為這一個洞察。——Clive Thompson
人類歷史上最重要的36個代碼片段(三)
譯者:boxi。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。