## Comm-JDBC 使用指引 ### 1. 说明 a.本框架基于springboot jdbcTemplate二次封装,支持事务,分页,批量、函数、存储过程操作等,支持MySQL、PostgreSQL等多方言关系数据的读写操作。 b.数据核心pojo类一一对应数据库表,使用自定义的注解解析器动态生成SQL,相较于mybatis支持pojo类配置封装类型如List、Set、Map、自定义类的持久化和序列化反序列化操作,无须配置类型处理器,无须配置mapper.xml。 c.除了pojo类注解方式,也兼容自定义SQL读写操作,此时封装类需自行处理(适用于复杂SQL)。 d.代码生成类 /wash/car-wash-admin/src/main/java/com/kym/admin/utils/CommJdbcCodeGenerator.java ### 2. 基类 DbHandler:所有DAO类继承该类,提供基础CRUD操作,支持事务,分页,批量操作等。 BasicQuery:查询封装基类(第一种,适用于暴露前端接口参数定义,默认分页30),预封装查询参数,动态生成关联查询条件、排序SQL语句。 OBuilder:查询封装类(第二种,适用于后端业务查询),按需查询,类似mybatisplus语法。 ### 3. 使用 以知识库t_org_doc表为例,介绍如何使用本框架进行CRUD操作。 #### 3.1 定义实体类(OrgDoc) ```java package com.png.entity.po.org; import com.png.entity.bo.AccessStrategy; import com.png.entity.po.user.User; import com.png.entity.vo.SimpleVo; import com.png.entity.vo.SimpleVo.SimpleAttachVo; import com.png.jdbc.BasicQuery; import com.png.jdbc.annotations.DBF; import com.png.jdbc.annotations.Entity; import com.png.jdbc.annotations.FK; import com.png.jdbc.annotations.OP; import com.png.jdbc.annotations.One; import com.png.jdbc.annotations.QE; import com.png.jdbc.annotations.QF; import jakarta.validation.constraints.NotEmpty; import lombok.Data; import lombok.EqualsAndHashCode; import java.io.Serializable; import java.util.Date; import java.util.List; /** * 知识库 * * @author yaop * @date 2024-02-03T10:44:52.780 */ @Data @EqualsAndHashCode(callSuper = false) @Entity(clz = OrgDoc.class, comment = "知识库") public class OrgDoc implements Serializable { public static final int STATUS_拟稿中= 1; public static final int STATUS_已发布= 2; @DBF(comment = "ID") private long id; @DBF(comment = "组织") private long oid; @DBF(comment = "应用") private long appletId; @NotEmpty(message = "名称不能为空") @DBF(comment = "名称", max = 128) private String name; @DBF(comment = "摘要", max = 512) private String digest; @DBF(comment = "文章目录") private List outlineList; @DBF(comment = "是否目录") private boolean directory; @DBF(comment = "父级目录") private long pid; @DBF(comment = "所在目录结构") private List pathList; @DBF(comment = "状态") private int status; @DBF(comment = "排序权重") private int weight; @DBF(comment = "附件清单") private List attachIdList; @DBF(comment = "附件清单") private List attachList; @DBF(comment = "是否删除") private boolean deleted; @DBF(comment = "是否开启访问控制") private boolean accessAvailable; @DBF(comment = "访问策略") private AccessStrategy accessStrategy; @DBF(comment = "创建时间") private Date createAt; @FK(clz = User.class) @DBF(comment = "创建人") private long createBy; @DBF(comment = "更新时间") private Date updateAt; @FK(clz = User.class) @DBF(comment = "更新人") private long updateBy; @DBF(comment = "源文章") private long sid; @DBF(comment = "是否最新版本") private boolean latest; @DBF(comment = "版本号") private int version; //region 版本相关 //endregion @Data @EqualsAndHashCode(callSuper = true) public static class OrgDocInfo extends OrgDoc { @One(mkf = "createBy", tf = "name", comment = "创建人") private String createName; //扩展类字段,查询Info扩展类时自动生成SQL @One(mkf = "updateBy", tf = "name", comment = "更新人") private String updateName; //扩展类字段,无注解不会持久化 private String content; } /** * 富文本目录结构 */ @Data public static class OrgDocOutline { private String id; /** * 目录名称(或内容) */ private String text; /** * level: 目录级别,值是 1 ~ 6,对应的 html 标签是 h1 ~ h6 */ private int level; /** * 目录节点所在文档位置 */ private int pos; /** * 目录节点的内容大小 */ private int size; } /** *查询实体类,字段为封装类型,框架根据非空值生成SQL */ @Data @EqualsAndHashCode(callSuper = true) @QE(clz = OrgDocInfo.class) public static class OrgDocBasicQuery extends BasicQuery { private Long id; private Long orgId; private Long appletId; private String name; private String digest; private Long pid; private Integer status; private String attachIdList; private String attachList; private String userIdList; private String userList; private String roleList; private String roleIdList; private Long createBy; private Long updateBy; private Long sid; private Boolean latest; private Integer version; //region date query @QF(op = OP.GTE, tf = "createAt") private Date createAtStart; @QF(op = OP.LTE, tf = "createAt") private Date createAtEnd; @QF(op = OP.GTE, tf = "updateAt") private Date updateAtStart; @QF(op = OP.LTE, tf = "updateAt") private Date updateAtEnd; //endregion //json数组查询(第一种,自定义sql片段) @QF(sql="json_contains(l.attach_id_list,?) ") private Long attachId; //json数据查询(第二种) @QF(op = OP.JIN, tf = "attachIdList") private Long attachId; //关联查询 @QF(tf = "name",pkf = "createBy") private String createName; //region sort query 1-升序 2-降序 private Integer idSort; private Integer orgIdSort; private Integer appletIdSort; private Integer pidSort; private Integer statusSort; private Integer createAtSort; private Integer createBySort; private Integer updateAtSort; private Integer updateBySort; //endregion } } ``` #### 3.2 定义持久类(OrgDocDAO) ```java package com.png.dao.org; import com.png.JacksonUtil; import com.png.dao.DbHandler; import org.springframework.stereotype.Component; import java.util.List; @Component("orgDocDAO") public class OrgDocDAO extends DbHandler { /** * 更新旧版本标识 * @param sid * @param latest */ public void updateVersionLatest(long sid, boolean latest) { update("update t_org_doc set latest = ? where sid = ?", latest, sid); } /** * 更新旧版本的文档路径 * @param sid * @param pathList */ public void updateOldVersionPath(long sid, List pathList) { update("update t_org_doc set path_list=? where sid =?", JacksonUtil.toJSONString(pathList),sid); } } ``` #### 3.3 编写业务类(OrgDocService) ```java package com.png.service.org; /** * 知识库业务类 * * @author yaop * @date 2024-02-03T10:44:52.780 */ @Service("orgDocService") public class OrgDocService extends IService { @Resource private OrgDocDAO orgDocDAO; } ``` ##### 3.3.1 插入-insert ```java OrgDoc orgDoc = new OrgDoc(); orgDoc.setSid(orgDoc.getId()); orgDoc.setLatest(true); orgDoc.setVersion(1); if (orgDoc.getPid() == 0) { orgDoc.setPathList(List.of("/")); } else { OrgDoc parent = orgDocDAO.selectOneExist(OrgDoc.class, orgDoc.getPid()); parent.getPathList().add(parent.getName()); //封装类型字段,除业务处理外不做其他操作 orgDoc.setPathList(parent.getPathList()); } //插入数据库,有ID返回 long id = orgDocDAO.insert(orgDoc); //插入数据库,无ID返回 orgDocDAO.insertOnly(orgDoc); //插入数据库,有ID返回,跳过status、digest字段 orgDocDAO.insertSelective(orgDoc,"status","digest"); //插入数据库,无ID返回,跳过status、digest字段 orgDocDAO.insertSelectiveOnly(orgDoc,"status","digest"); //批量插入 orgDocDAO.insertBatch(orgDocs); //批量插入 ,仅插入id name字段 orgDocDAO.insertBatch(List.of("name","id"),orgDocs); //批量插入,自定义sql方式 orgDocDAO.insertBatch("insert into t_org_doc (id,name) values (?,?)",orgDocs); ``` ##### 3.3.2 删除-delete ```java //删除ID为1的知识库记录 orgDocDAO.delete(OrgDoc.class,1); //删除状态有效且创建时间大于‘2024-09-01’的知识库记录,builder方式条件构造 orgDocDAO. delete(User.class,OBuilder.build().eq(OrgDoc::getStatus,Consts.STATUS_有效).gt(OrgDoc::getCreateAt,date)); ``` ##### 3.3.3 修改-update ```java //更新ID为1的知识库记录的名称为wiki1111 OrgDoc orgDoc = new OrgDoc(); orgDoc.setId(1); orgDoc.setName("wiki11111"); orgDocDAO.update(orgDoc); //更新ID为1的知识库记录 orgDocDAO. update(orgDoc,OBuilder.build().eq(OrgDoc::getID,1)); //更新ID为1的知识库记录 orgDocDAO. update("UPDATE t_org_doc set name = ? where id =? ","wiki111",1)); //批量更新,默认where条件为id orgDocDAO. updateBatch(List.of("name"),orgDocs); //批量更新,sql方式 orgDocDAO. updateBatch("UPDATE t_org_doc set name = ? where id =? and status =? ",orgDocs); ``` ##### 3.3.4 查询-select ```java //查询ID为1的知识库记录,无关联扩展字段 OrgDoc orgDoc = orgDocDAO.selectOne(OrgDoc.class, OBuilder.build().eq(OrgDoc::getID, 1)); //查询ID为1的知识库记录,自动关联外键字段 OrgDocInfo orgDoc = orgDocDAO.selectOne(OrgDocInfo.class, OBuilder.build().eq(OrgDoc::getID, 1)); //查询ID为1的知识库记录,自动关联外键字段并校验记录是否存在,不存在时抛出异常IllegalArgumentException OrgDocInfo orgDoc = orgDocDAO.selectOneExist(OrgDocInfo.class, OBuilder.build().eq(OrgDoc::getID, 1)); //查询ID为1的知识库记录, 无关联外键字段并校验记录是否存在,不存在时抛出异常IllegalArgumentException OrgDoc orgDoc = orgDocDAO.selectOneExist(OrgDoc.class, 1); //查询ID为1的知识库记录,自动关联外键字段,且仅查询id name attachList字段(封装类自动处理) OrgDocInfo orgDoc = orgDocDAO.selectOne(OrgDocInfo.class, OBuilder.build().eq(OrgDoc::getID, 1), List.of("id","name","attachList")); //查询ID为1的知识库记录,自动关联外键字段,且查询i排除d name attachList字段 OrgDocQuery query = new OrgDocQuery(); query.setId(1); OrgDocInfo orgDoc = orgDocDAO.selectOneExclude(query, List.of("id","name","attachList")); //查询I状态有效的的知识库记录列表,自动关联外键字段(第一种,builder构造查询条件) List orgDocs = orgDocDAO.selectList(OrgDocInfo.class, OBuilder.build().eq(OrgDoc::getStatus, Consts.STATUS_有效)); //查询I状态有效的的知识库记录列表,自动关联外键字段且查询i排除d name attachList字段(第二种,query实体类查询) OrgDocQuery query = new OrgDocQuery(); query.setStatus(Consts.STATUS_有效); OrgDocInfo orgDoc = orgDocDAO.selectListExclude(query, List.of("id","name","attachList")); //查询I状态有效的的知识库记录列表 (第三种,自定义sql语句) List orgDocs = orgDocDAO.selectList("select id,name from t_org_doc",data->{ OrgDocInfo info = new OrgDocInfo(); info.setId(data.get("id")); return info; }, Consts.STATUS_有效)); ```