|
|
@@ -0,0 +1,366 @@
|
|
|
+## 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<OrgDocOutline> outlineList;
|
|
|
+ @DBF(comment = "是否目录")
|
|
|
+ private boolean directory;
|
|
|
+ @DBF(comment = "父级目录")
|
|
|
+ private long pid;
|
|
|
+ @DBF(comment = "所在目录结构")
|
|
|
+ private List<String> pathList;
|
|
|
+ @DBF(comment = "状态")
|
|
|
+ private int status;
|
|
|
+ @DBF(comment = "排序权重")
|
|
|
+ private int weight;
|
|
|
+
|
|
|
+ @DBF(comment = "附件清单")
|
|
|
+ private List<Long> attachIdList;
|
|
|
+ @DBF(comment = "附件清单")
|
|
|
+ private List<SimpleAttachVo> 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<String> 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<OrgDocInfo> 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<OrgDocInfo> orgDocs = orgDocDAO.selectList("select id,name from t_org_doc",data->{
|
|
|
+ OrgDocInfo info = new OrgDocInfo();
|
|
|
+ info.setId(data.get("id"));
|
|
|
+ return info;
|
|
|
+}, Consts.STATUS_有效));
|
|
|
+
|
|
|
+```
|