You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

README.md 11 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. # spring-boot-demo-orm-jdbctemplate
  2. > 本 demo 主要演示了Spring Boot如何使用 JdbcTemplate 操作数据库,并且简易地封装了一个通用的 Dao 层,包括增删改查。
  3. ## pom.xml
  4. ```xml
  5. <?xml version="1.0" encoding="UTF-8"?>
  6. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  7. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  8. <modelVersion>4.0.0</modelVersion>
  9. <artifactId>spring-boot-demo-orm-jdbctemplate</artifactId>
  10. <version>1.0.0-SNAPSHOT</version>
  11. <packaging>jar</packaging>
  12. <name>spring-boot-demo-orm-jdbctemplate</name>
  13. <description>Demo project for Spring Boot</description>
  14. <parent>
  15. <groupId>com.xkcoding</groupId>
  16. <artifactId>spring-boot-demo</artifactId>
  17. <version>1.0.0-SNAPSHOT</version>
  18. </parent>
  19. <properties>
  20. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  21. <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  22. <java.version>1.8</java.version>
  23. </properties>
  24. <dependencies>
  25. <dependency>
  26. <groupId>org.springframework.boot</groupId>
  27. <artifactId>spring-boot-starter-jdbc</artifactId>
  28. </dependency>
  29. <dependency>
  30. <groupId>org.springframework.boot</groupId>
  31. <artifactId>spring-boot-starter-web</artifactId>
  32. </dependency>
  33. <dependency>
  34. <groupId>org.springframework.boot</groupId>
  35. <artifactId>spring-boot-starter-test</artifactId>
  36. <scope>test</scope>
  37. </dependency>
  38. <dependency>
  39. <groupId>mysql</groupId>
  40. <artifactId>mysql-connector-java</artifactId>
  41. </dependency>
  42. <dependency>
  43. <groupId>cn.hutool</groupId>
  44. <artifactId>hutool-all</artifactId>
  45. </dependency>
  46. <dependency>
  47. <groupId>org.projectlombok</groupId>
  48. <artifactId>lombok</artifactId>
  49. <optional>true</optional>
  50. </dependency>
  51. </dependencies>
  52. <build>
  53. <finalName>spring-boot-demo-orm-jdbctemplate</finalName>
  54. <plugins>
  55. <plugin>
  56. <groupId>org.springframework.boot</groupId>
  57. <artifactId>spring-boot-maven-plugin</artifactId>
  58. </plugin>
  59. </plugins>
  60. </build>
  61. </project>
  62. ```
  63. ## BaseDao.java
  64. ```java
  65. /**
  66. * <p>
  67. * Dao基类
  68. * </p>
  69. *
  70. * @package: com.xkcoding.orm.jdbctemplate.dao.base
  71. * @description: Dao基类
  72. * @author: yangkai.shen
  73. * @date: Created in 2018/10/15 11:28 AM
  74. * @copyright: Copyright (c) 2018
  75. * @version: V1.0
  76. * @modified: yangkai.shen
  77. */
  78. @Slf4j
  79. public class BaseDao<T, P> {
  80. private JdbcTemplate jdbcTemplate;
  81. private Class<T> clazz;
  82. @SuppressWarnings(value = "unchecked")
  83. public BaseDao(JdbcTemplate jdbcTemplate) {
  84. this.jdbcTemplate = jdbcTemplate;
  85. clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
  86. }
  87. /**
  88. * 通用插入,自增列需要添加 {@link Pk} 注解
  89. *
  90. * @param t 对象
  91. * @param ignoreNull 是否忽略 null 值
  92. * @return 操作的行数
  93. */
  94. protected Integer insert(T t, Boolean ignoreNull) {
  95. String table = getTableName(t);
  96. List<Field> filterField = getField(t, ignoreNull);
  97. List<String> columnList = getColumns(filterField);
  98. String columns = StrUtil.join(Const.SEPARATOR_COMMA, columnList);
  99. // 构造占位符
  100. String params = StrUtil.repeatAndJoin("?", columnList.size(), Const.SEPARATOR_COMMA);
  101. // 构造值
  102. Object[] values = filterField.stream().map(field -> ReflectUtil.getFieldValue(t, field)).toArray();
  103. String sql = StrUtil.format("INSERT INTO {table} ({columns}) VALUES ({params})", Dict.create().set("table", table).set("columns", columns).set("params", params));
  104. log.debug("【执行SQL】SQL:{}", sql);
  105. log.debug("【执行SQL】参数:{}", JSONUtil.toJsonStr(values));
  106. return jdbcTemplate.update(sql, values);
  107. }
  108. /**
  109. * 通用根据主键删除
  110. *
  111. * @param pk 主键
  112. * @return 影响行数
  113. */
  114. protected Integer deleteById(P pk) {
  115. String tableName = getTableName();
  116. String sql = StrUtil.format("DELETE FROM {table} where id = ?", Dict.create().set("table", tableName));
  117. log.debug("【执行SQL】SQL:{}", sql);
  118. log.debug("【执行SQL】参数:{}", JSONUtil.toJsonStr(pk));
  119. return jdbcTemplate.update(sql, pk);
  120. }
  121. /**
  122. * 通用根据主键更新,自增列需要添加 {@link Pk} 注解
  123. *
  124. * @param t 对象
  125. * @param pk 主键
  126. * @param ignoreNull 是否忽略 null 值
  127. * @return 操作的行数
  128. */
  129. protected Integer updateById(T t, P pk, Boolean ignoreNull) {
  130. String tableName = getTableName(t);
  131. List<Field> filterField = getField(t, ignoreNull);
  132. List<String> columnList = getColumns(filterField);
  133. List<String> columns = columnList.stream().map(s -> StrUtil.appendIfMissing(s, " = ?")).collect(Collectors.toList());
  134. String params = StrUtil.join(Const.SEPARATOR_COMMA, columns);
  135. // 构造值
  136. List<Object> valueList = filterField.stream().map(field -> ReflectUtil.getFieldValue(t, field)).collect(Collectors.toList());
  137. valueList.add(pk);
  138. Object[] values = ArrayUtil.toArray(valueList, Object.class);
  139. String sql = StrUtil.format("UPDATE {table} SET {params} where id = ?", Dict.create().set("table", tableName).set("params", params));
  140. log.debug("【执行SQL】SQL:{}", sql);
  141. log.debug("【执行SQL】参数:{}", JSONUtil.toJsonStr(values));
  142. return jdbcTemplate.update(sql, values);
  143. }
  144. /**
  145. * 通用根据主键查询单条记录
  146. *
  147. * @param pk 主键
  148. * @return 单条记录
  149. */
  150. public T findOneById(P pk) {
  151. String tableName = getTableName();
  152. String sql = StrUtil.format("SELECT * FROM {table} where id = ?", Dict.create().set("table", tableName));
  153. RowMapper<T> rowMapper = new BeanPropertyRowMapper<>(clazz);
  154. log.debug("【执行SQL】SQL:{}", sql);
  155. log.debug("【执行SQL】参数:{}", JSONUtil.toJsonStr(pk));
  156. return jdbcTemplate.queryForObject(sql, new Object[]{pk}, rowMapper);
  157. }
  158. /**
  159. * 根据对象查询
  160. *
  161. * @param t 查询条件
  162. * @return 对象列表
  163. */
  164. public List<T> findByExample(T t) {
  165. String tableName = getTableName(t);
  166. List<Field> filterField = getField(t, true);
  167. List<String> columnList = getColumns(filterField);
  168. List<String> columns = columnList.stream().map(s -> " and " + s + " = ? ").collect(Collectors.toList());
  169. String where = StrUtil.join(" ", columns);
  170. // 构造值
  171. Object[] values = filterField.stream().map(field -> ReflectUtil.getFieldValue(t, field)).toArray();
  172. String sql = StrUtil.format("SELECT * FROM {table} where 1=1 {where}", Dict.create().set("table", tableName).set("where", StrUtil.isBlank(where) ? "" : where));
  173. log.debug("【执行SQL】SQL:{}", sql);
  174. log.debug("【执行SQL】参数:{}", JSONUtil.toJsonStr(values));
  175. List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql, values);
  176. List<T> ret = CollUtil.newArrayList();
  177. maps.forEach(map -> ret.add(BeanUtil.fillBeanWithMap(map, ReflectUtil.newInstance(clazz), true, false)));
  178. return ret;
  179. }
  180. /**
  181. * 获取表名
  182. *
  183. * @param t 对象
  184. * @return 表名
  185. */
  186. private String getTableName(T t) {
  187. Table tableAnnotation = t.getClass().getAnnotation(Table.class);
  188. if (ObjectUtil.isNotNull(tableAnnotation)) {
  189. return StrUtil.format("`{}`", tableAnnotation.name());
  190. } else {
  191. return StrUtil.format("`{}`", t.getClass().getName().toLowerCase());
  192. }
  193. }
  194. /**
  195. * 获取表名
  196. *
  197. * @return 表名
  198. */
  199. private String getTableName() {
  200. Table tableAnnotation = clazz.getAnnotation(Table.class);
  201. if (ObjectUtil.isNotNull(tableAnnotation)) {
  202. return StrUtil.format("`{}`", tableAnnotation.name());
  203. } else {
  204. return StrUtil.format("`{}`", clazz.getName().toLowerCase());
  205. }
  206. }
  207. /**
  208. * 获取列
  209. *
  210. * @param fieldList 字段列表
  211. * @return 列信息列表
  212. */
  213. private List<String> getColumns(List<Field> fieldList) {
  214. // 构造列
  215. List<String> columnList = CollUtil.newArrayList();
  216. for (Field field : fieldList) {
  217. Column columnAnnotation = field.getAnnotation(Column.class);
  218. String columnName;
  219. if (ObjectUtil.isNotNull(columnAnnotation)) {
  220. columnName = columnAnnotation.name();
  221. } else {
  222. columnName = field.getName();
  223. }
  224. columnList.add(StrUtil.format("`{}`", columnName));
  225. }
  226. return columnList;
  227. }
  228. /**
  229. * 获取字段列表 {@code 过滤数据库中不存在的字段,以及自增列}
  230. *
  231. * @param t 对象
  232. * @param ignoreNull 是否忽略空值
  233. * @return 字段列表
  234. */
  235. private List<Field> getField(T t, Boolean ignoreNull) {
  236. // 获取所有字段,包含父类中的字段
  237. Field[] fields = ReflectUtil.getFields(t.getClass());
  238. // 过滤数据库中不存在的字段,以及自增列
  239. List<Field> filterField;
  240. Stream<Field> fieldStream = CollUtil.toList(fields).stream().filter(field -> ObjectUtil.isNull(field.getAnnotation(Ignore.class)) || ObjectUtil.isNull(field.getAnnotation(Pk.class)));
  241. // 是否过滤字段值为null的字段
  242. if (ignoreNull) {
  243. filterField = fieldStream.filter(field -> ObjectUtil.isNotNull(ReflectUtil.getFieldValue(t, field))).collect(Collectors.toList());
  244. } else {
  245. filterField = fieldStream.collect(Collectors.toList());
  246. }
  247. return filterField;
  248. }
  249. }
  250. ```
  251. ## application.yml
  252. ```yaml
  253. server:
  254. port: 8080
  255. servlet:
  256. context-path: /demo
  257. spring:
  258. datasource:
  259. url: jdbc:mysql://127.0.0.1:3306/spring-boot-demo?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
  260. username: root
  261. password: root
  262. driver-class-name: com.mysql.cj.jdbc.Driver
  263. type: com.zaxxer.hikari.HikariDataSource
  264. initialization-mode: always
  265. continue-on-error: true
  266. schema:
  267. - "classpath:db/schema.sql"
  268. data:
  269. - "classpath:db/data.sql"
  270. hikari:
  271. minimum-idle: 5
  272. connection-test-query: SELECT 1 FROM DUAL
  273. maximum-pool-size: 20
  274. auto-commit: true
  275. idle-timeout: 30000
  276. pool-name: SpringBootDemoHikariCP
  277. max-lifetime: 60000
  278. connection-timeout: 30000
  279. logging:
  280. level:
  281. com.xkcoding: debug
  282. ```
  283. ## 备注
  284. 其余详细代码参见 demo

一个用来深度学习并实战 spring boot 的项目,目前总共包含 66 个集成demo,已经完成 55 个。

Contributors (1)