# spring-boot-demo-orm-jdbctemplate > 本 demo 主要演示了Spring Boot如何使用 JdbcTemplate 操作数据库,并且简易地封装了一个通用的 Dao 层,包括增删改查。 ## pom.xml ```xml 4.0.0 spring-boot-demo-orm-jdbctemplate 1.0.0-SNAPSHOT jar spring-boot-demo-orm-jdbctemplate Demo project for Spring Boot com.xkcoding spring-boot-demo 1.0.0-SNAPSHOT UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter-jdbc org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test mysql mysql-connector-java cn.hutool hutool-all org.projectlombok lombok true spring-boot-demo-orm-jdbctemplate org.springframework.boot spring-boot-maven-plugin ``` ## BaseDao.java ```java /** *

* Dao基类 *

* * @author yangkai.shen * @date Created in 2018-10-15 11:28 */ @Slf4j public class BaseDao { private JdbcTemplate jdbcTemplate; private Class clazz; @SuppressWarnings(value = "unchecked") public BaseDao(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; clazz = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; } /** * 通用插入,自增列需要添加 {@link Pk} 注解 * * @param t 对象 * @param ignoreNull 是否忽略 null 值 * @return 操作的行数 */ protected Integer insert(T t, Boolean ignoreNull) { String table = getTableName(t); List filterField = getField(t, ignoreNull); List columnList = getColumns(filterField); String columns = StrUtil.join(Const.SEPARATOR_COMMA, columnList); // 构造占位符 String params = StrUtil.repeatAndJoin("?", columnList.size(), Const.SEPARATOR_COMMA); // 构造值 Object[] values = filterField.stream().map(field -> ReflectUtil.getFieldValue(t, field)).toArray(); String sql = StrUtil.format("INSERT INTO {table} ({columns}) VALUES ({params})", Dict.create().set("table", table).set("columns", columns).set("params", params)); log.debug("【执行SQL】SQL:{}", sql); log.debug("【执行SQL】参数:{}", JSONUtil.toJsonStr(values)); return jdbcTemplate.update(sql, values); } /** * 通用根据主键删除 * * @param pk 主键 * @return 影响行数 */ protected Integer deleteById(P pk) { String tableName = getTableName(); String sql = StrUtil.format("DELETE FROM {table} where id = ?", Dict.create().set("table", tableName)); log.debug("【执行SQL】SQL:{}", sql); log.debug("【执行SQL】参数:{}", JSONUtil.toJsonStr(pk)); return jdbcTemplate.update(sql, pk); } /** * 通用根据主键更新,自增列需要添加 {@link Pk} 注解 * * @param t 对象 * @param pk 主键 * @param ignoreNull 是否忽略 null 值 * @return 操作的行数 */ protected Integer updateById(T t, P pk, Boolean ignoreNull) { String tableName = getTableName(t); List filterField = getField(t, ignoreNull); List columnList = getColumns(filterField); List columns = columnList.stream().map(s -> StrUtil.appendIfMissing(s, " = ?")).collect(Collectors.toList()); String params = StrUtil.join(Const.SEPARATOR_COMMA, columns); // 构造值 List valueList = filterField.stream().map(field -> ReflectUtil.getFieldValue(t, field)).collect(Collectors.toList()); valueList.add(pk); Object[] values = ArrayUtil.toArray(valueList, Object.class); String sql = StrUtil.format("UPDATE {table} SET {params} where id = ?", Dict.create().set("table", tableName).set("params", params)); log.debug("【执行SQL】SQL:{}", sql); log.debug("【执行SQL】参数:{}", JSONUtil.toJsonStr(values)); return jdbcTemplate.update(sql, values); } /** * 通用根据主键查询单条记录 * * @param pk 主键 * @return 单条记录 */ public T findOneById(P pk) { String tableName = getTableName(); String sql = StrUtil.format("SELECT * FROM {table} where id = ?", Dict.create().set("table", tableName)); RowMapper rowMapper = new BeanPropertyRowMapper<>(clazz); log.debug("【执行SQL】SQL:{}", sql); log.debug("【执行SQL】参数:{}", JSONUtil.toJsonStr(pk)); return jdbcTemplate.queryForObject(sql, new Object[]{pk}, rowMapper); } /** * 根据对象查询 * * @param t 查询条件 * @return 对象列表 */ public List findByExample(T t) { String tableName = getTableName(t); List filterField = getField(t, true); List columnList = getColumns(filterField); List columns = columnList.stream().map(s -> " and " + s + " = ? ").collect(Collectors.toList()); String where = StrUtil.join(" ", columns); // 构造值 Object[] values = filterField.stream().map(field -> ReflectUtil.getFieldValue(t, field)).toArray(); String sql = StrUtil.format("SELECT * FROM {table} where 1=1 {where}", Dict.create().set("table", tableName).set("where", StrUtil.isBlank(where) ? "" : where)); log.debug("【执行SQL】SQL:{}", sql); log.debug("【执行SQL】参数:{}", JSONUtil.toJsonStr(values)); List> maps = jdbcTemplate.queryForList(sql, values); List ret = CollUtil.newArrayList(); maps.forEach(map -> ret.add(BeanUtil.fillBeanWithMap(map, ReflectUtil.newInstance(clazz), true, false))); return ret; } /** * 获取表名 * * @param t 对象 * @return 表名 */ private String getTableName(T t) { Table tableAnnotation = t.getClass().getAnnotation(Table.class); if (ObjectUtil.isNotNull(tableAnnotation)) { return StrUtil.format("`{}`", tableAnnotation.name()); } else { return StrUtil.format("`{}`", t.getClass().getName().toLowerCase()); } } /** * 获取表名 * * @return 表名 */ private String getTableName() { Table tableAnnotation = clazz.getAnnotation(Table.class); if (ObjectUtil.isNotNull(tableAnnotation)) { return StrUtil.format("`{}`", tableAnnotation.name()); } else { return StrUtil.format("`{}`", clazz.getName().toLowerCase()); } } /** * 获取列 * * @param fieldList 字段列表 * @return 列信息列表 */ private List getColumns(List fieldList) { // 构造列 List columnList = CollUtil.newArrayList(); for (Field field : fieldList) { Column columnAnnotation = field.getAnnotation(Column.class); String columnName; if (ObjectUtil.isNotNull(columnAnnotation)) { columnName = columnAnnotation.name(); } else { columnName = field.getName(); } columnList.add(StrUtil.format("`{}`", columnName)); } return columnList; } /** * 获取字段列表 {@code 过滤数据库中不存在的字段,以及自增列} * * @param t 对象 * @param ignoreNull 是否忽略空值 * @return 字段列表 */ private List getField(T t, Boolean ignoreNull) { // 获取所有字段,包含父类中的字段 Field[] fields = ReflectUtil.getFields(t.getClass()); // 过滤数据库中不存在的字段,以及自增列 List filterField; Stream fieldStream = CollUtil.toList(fields).stream().filter(field -> ObjectUtil.isNull(field.getAnnotation(Ignore.class)) || ObjectUtil.isNull(field.getAnnotation(Pk.class))); // 是否过滤字段值为null的字段 if (ignoreNull) { filterField = fieldStream.filter(field -> ObjectUtil.isNotNull(ReflectUtil.getFieldValue(t, field))).collect(Collectors.toList()); } else { filterField = fieldStream.collect(Collectors.toList()); } return filterField; } } ``` ## application.yml ```yaml server: port: 8080 servlet: context-path: /demo spring: datasource: 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 username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver type: com.zaxxer.hikari.HikariDataSource initialization-mode: always continue-on-error: true schema: - "classpath:db/schema.sql" data: - "classpath:db/data.sql" hikari: minimum-idle: 5 connection-test-query: SELECT 1 FROM DUAL maximum-pool-size: 20 auto-commit: true idle-timeout: 30000 pool-name: SpringBootDemoHikariCP max-lifetime: 60000 connection-timeout: 30000 logging: level: com.xkcoding: debug ``` ## 备注 其余详细代码参见 demo