【设计模式活用】之代码重构之DAO扮演多个职责的重构案例

2023-12-03 12:58

本文主要是介绍【设计模式活用】之代码重构之DAO扮演多个职责的重构案例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在本次关于GPS优化需求项目时,发现相关功能菜单查询页面共同一个DAO接口实现类,紧接着我看了一下listAll,pre,next,countAll方法业务代码高度相似,此已说明该DAO扮演着非单一原则,其承担着 系统多个功能菜单的查询功能。

文章目录

  • 1.背景介绍
    • 1.1 业务分析
    • 1.2 思路分析
  • 2、相关类图
    • 2.1、executor类图
    • 2.2、context类图
  • 3、相关源码
    • 3.1、AbstractWhereExecutor
    • 3.2、InstalledGpsQueryExecutor
    • 3.3、TobeUploadGpsQueryExecutor
    • 3.4、UnInstalledGpsQueryExecutor
    • 3.5、UploadedGpsQueryExecutor
    • 3.6、调用方
  • 4、归纳总结

1.背景介绍

  • 共同之处,就是查询共同表 ca_app_info,或者操作共同Hibernate对象VCaAppInfo。

  • 不同之处体现如下方面:1、包含HQL和SQL查询 。2、where条件不同(为了过滤数据以及根据页面表单条件动态判断拼加成一个StringBuffer对象(即SQL/HQL))。

1.1 业务分析

涉及查询的四个方法中(listAll,pre,next,countAll方法业务代码高度相似),代码冗余,不利于维护。

因此,借此机遇,对涉及本期需求GPS查询 四个页面进行重构,提炼出四个单据的实现类,统一继承抽象类,内部维护相关SQL或者HQL查询逻辑,调用方只需构造上线文,

产生不同的实现类即可,提高可扩展,可维护性。重构前代码,点击链接,查看方法:listAll,pre,next,countAll,你就晓得了。

源代码片段

@Overridepublic List<VCaAppInfo> pre(VCaAppInfoId ci, int pn, int defaultPageSize) {// TODO Auto-generated method stubStringBuffer sb = new StringBuffer();sb.append("from VCaAppInfo v where 1=1");List<Object> listParams = new ArrayList<Object>();AbstractWhereExecutor<VCaAppInfoId> whereExecutor;WhereContext whereContext = new WhereContext(ci,sb,listParams,WhereContext.Strategy.HQL);String status = ci.getStatus();if (StringUtil.checkStatus(status)) {sb.append(" and v.id.status in (?)");listParams.add(status);sb.append(" and v.AUserId=? ");listParams.add(ci.getUser().getUserId());/** if("23".equals(status)){ //根据REFUSE_STATUS拒绝状态查询* sb.append(" and v.refuseStatus in (?)");* listParams.add(ci.getRefusestatus()); }else* if("24".equals(status)){ sb.append(" and v.refuseStatus <> 3"); }*/if ("23".equals(status)) { // 根据REFUSE_STATUS拒绝状态查询sb.append(" and v.refuseStatus in (?)");listParams.add(ci.getRefusestatus());} else if ("24".equals(status) && !"3".equals(ci.getRefusestatus())) { // refusestatus// =// 0// 1// 终审sb.append(" and v.refuseStatus <> 3");} else if ("3".equals(ci.getRefusestatus())) { // 3 复核拒绝sb.append(" and v.refuseStatus = 3");}} else if ("80".equals(ci.getStatus())) { // 复审审批页面 显示自己审批的和信贷经理退回审批的// 150123sb.append(" and v.id.status in('23','30')");sb.append(" and v.AUserId=? ");listParams.add(ci.getUser().getUserId());} else if ("-27".equals(status)) { // 经销商上传GPS安装单 150302sb.append(" and (v.isGps ='0' or v.isGps ='2') and v.gpsFee<>0 and v.gpsFee !='' and v.gpsFee is not null and v.manageApprovalTime is not null and v.id.status not in('11','12') ");// 经销商用户只能查看该门店单子 其他用户查看所有Set<SyUserDealer> ds = ci.getUser().getSyUserDealers();if (ds.size() != 0) {sb.append(" and v.id.dealerCode in(");Iterator<SyUserDealer> it = ci.getUser().getSyUserDealers().iterator();while (it.hasNext()) {SyUserDealer d = it.next();int dealerCode = d.getId().getDealerCode();sb.append(dealerCode + " ,");}String allhql = sb.substring(0, sb.length() - 1);allhql += ") ";sb.setLength(0);// 清空 后加上sb.append(allhql);}} else if ("-28".equals(status)) { // GPS维护 已上传GPS安装whereExecutor = new InstalledGpsQueryExecutor(whereContext);whereExecutor.execute();} else if ("-29".equals(status)) { // GPS维护whereExecutor = new UnInstallGpsQueryExecutor(whereContext);whereExecutor.execute();} else if ("-30".equals(status)) { // 贷后资料维护sb.append(" and (v.ALOANARRIVE is null or v.ALOANARRIVE!='1') and v.id.status='32' ");if (ci.getIsOld() != null) {sb.append(" and v.isOld=? ");listParams.add(ci.getIsOld());}if (ci.getPostLoanStatus() != null) {// 新车贷后资料上传状态(包括花乡的二手车 即先放款后抵押)if ("0".equals(ci.getPostLoanStatus())) {// 未上传sb.append(" and (v.postLoanStatus is null or v.postLoanStatus='0' ) ");} else if ("1".equals(ci.getPostLoanStatus())) {// 已上传sb.append(" and v.postLoanStatus='1' ");} else if ("2".equals(ci.getPostLoanStatus())) {// 审批退回sb.append(" and v.postLoanStatus='2' ");} else if ("3".equals(ci.getPostLoanStatus())) {// 审批通过sb.append(" and v.postLoanStatus='3' ");}}} else if ("-31".equals(status)) { // 贷后资料维护回退sb.append(" and v.ALOANARRIVE='1' and v.id.status='32' ");} else if ("-32".equals(status)) { // 新车等待上传贷后资料sb.append(" and v.id.status='32' and ifnull(v.ALOANARRIVE,'')!='1' ");if (ci.getIsOld() != null) {sb.append(" and v.isOld=? ");listParams.add(ci.getIsOld());}if (ci.getPostLoanStatus() != null) {if ("0".equals(ci.getPostLoanStatus())) {// 未上传sb.append(" and (v.postLoanStatus is null or v.postLoanStatus='0') ");} else if ("1".equals(ci.getPostLoanStatus())) {// 已上传sb.append(" and v.postLoanStatus='1' ");} else if ("2".equals(ci.getPostLoanStatus())) {// 审批退回sb.append(" and v.postLoanStatus='2' ");} else if ("3".equals(ci.getPostLoanStatus())) {// 审批通过sb.append(" and v.postLoanStatus='3' ");}} else {sb.append(" and ifnull(v.postLoanStatus,'')!='1' and ifnull(v.postLoanStatus,'')!='3' ");// 所有,不显示已上传的申请单和审批通过的}// 经销商用户只能查看该门店单子 其他用户查看所有Set<SyUserDealer> ds = ci.getUser().getSyUserDealers();if (ds.size() != 0) {sb.append(" and v.id.dealerCode in(");Iterator<SyUserDealer> it = ci.getUser().getSyUserDealers().iterator();while (it.hasNext()) {SyUserDealer d = it.next();int dealerCode = d.getId().getDealerCode();sb.append(dealerCode + " ,");}String allhql = sb.substring(0, sb.length() - 1);allhql += ") ";sb.setLength(0);// 清空 后加上sb.append(allhql);}} else if ("-33".equals(status)) {// 经销商GPS安装列表,TODO zhaozhaoxin// 20170411 addsb.append(" and v.gpsFee<>0 and v.gpsFee !='' and v.gpsFee is not null and v.manageApprovalTime is not null and status in('15','16','17','18','19','25','26','27','28','29','32') ");// 经销商用户只能查看该门店单子 其他用户查看所有Set<SyUserDealer> ds = ci.getUser().getSyUserDealers();if (ds.size() != 0) {sb.append(" and v.id.dealerCode in(");Iterator<SyUserDealer> it = ci.getUser().getSyUserDealers().iterator();while (it.hasNext()) {SyUserDealer d = it.next();int dealerCode = d.getId().getDealerCode();sb.append(dealerCode + " ,");}String allhql = sb.substring(0, sb.length() - 1);allhql += ") ";sb.setLength(0);// 清空 后加上sb.append(allhql);}} else {sb.append(" and v.id.status in (?)");listParams.add(status);// TODO zhaozhaoxin 20170308 add 进行分组查询if (isRoleQueryData(ci.getUser())) {getUserGroupIds(sb, ci.getUser(), status, true);} else {return null;}}if (ci.getFlowSeq() != null) {sb.append(" and v.flowSeq= ?");listParams.add(ci.getFlowSeq());}if (ci.getDealerName() != null) {sb.append(" and v.id.dealerName like ?");listParams.add("%" + ci.getDealerName() + "%");}if (ci.getAppCode() != null) {sb.append(" and v.id.appCode = ?");listParams.add(ci.getAppCode());}if (ci.getProppserName() != null) {sb.append(" and v.id.proppserName like ?");listParams.add("%" + ci.getProppserName() + "%");}if (ci.getIsLcv() != null) {sb.append(" and v.isLcv = ?");listParams.add(ci.getIsLcv());}if (ci.getAppTime() != null) {sb.append(" and date_format(v.id.appTime,'%Y%m%d') >= ?");listParams.add(DateUtil.getDateFormatE(ci.getAppTime()));}if (ci.getAppTime2() != null) {sb.append(" and date_format(v.id.appTime,'%Y%m%d') <= ?");listParams.add(DateUtil.getDateFormatE(ci.getAppTime2()));}if (ci.getUpdateTime1() != null) {sb.append(" and date_format(v.updateTime,'%Y%m%d') >= ?");listParams.add(DateUtil.getDateFormatE(ci.getUpdateTime1()));}if (ci.getUpdateTime2() != null) {sb.append(" and date_format(v.updateTime,'%Y%m%d') <= ?");listParams.add(DateUtil.getDateFormatE(ci.getUpdateTime2()));}if (ci.getLoanDate1() != null) {sb.append(" and date_format(v.loanTime,'%Y%m%d') >= ?");listParams.add(DateUtil.getDateFormatE(ci.getLoanDate1()));}if (ci.getLoanDate2() != null) {sb.append(" and date_format(v.loanTime,'%Y%m%d') <= ?");listParams.add(DateUtil.getDateFormatE(ci.getLoanDate2()));}sb.append(" order by v.updateTime asc");// 从小到大排序 先提交的在前面List<VCaAppInfo> result = queryByHql(sb.toString(), pn,defaultPageSize, listParams.toArray());return result;}

1.2 思路分析

涉及四个功能菜单

  • 1、待上传GPS安装单
  • 2、GPS安装单列表
  • 3、GPS安装单未上传
  • 4、GPS安装单已上传

思路:分析如上四个菜单的查询特征,通过把相同和差异的抽象出来,即提取一个抽象类,通过模板方法,差异部分为抽象类子类,实现差异部分业务逻辑。

2、相关类图

2.1、executor类图

类图概览

2.2、context类图

context类图

3、相关源码

3.1、AbstractWhereExecutor

public abstract class AbstractWhereExecutor<T> implements Predicate<WhereContext> {/*** 上线文*/protected WhereContext<T> context;/*** 参数DTO*/protected T dto;/*** 查询条件*/protected StringBuffer queryWhere;/*** 构造函数* @param context 上线文对象*/public AbstractWhereExecutor(WhereContext<T> context) {this.context = context;}/*** 处理接口*/public void execute() {this.execute((e)->{});}/*** 处理接口* @param after*/public void execute(Consumer<WhereContext> after) {// 初始化this.prepare();// 检查参数this.check(context);// 执行鉴定if(this.test(context)){switch (context.getStrategy()){case SQL:sql();break;case HQL:hql();break;default:break;}}// 后置处理after.accept(context);}/*** 参数检查* @param context*/protected void check(WhereContext context){Assert.notNull(context.getDto(),"DTO对象为空");Assert.notNull(context.getStrategy(),"strategy为空");}/*** 初始化参数*/protected void prepare(){this.dto = this.context.getDto();this.queryWhere = this.context.getQueryWhere();}/*** 由子类实现具体处理SQL条件*/protected abstract void sql();/*** 由子类实现具体处理HQL条件*/protected abstract void hql();
}

3.2、InstalledGpsQueryExecutor

public class InstalledGpsQueryExecutor extends AbstractWhereExecutor<VCaAppInfoId> {/*** 标示*/protected String gpsFlow;/*** 审批人*/protected Integer approvalUserId;/*** 构造函数** @param context 上线文对象*/public InstalledGpsQueryExecutor(WhereContext context) {super(context);}@Overrideprotected void check(WhereContext context) {super.check(context);SyUser sessionUser = dto.getUser();Assert.notNull(sessionUser,"sessionUser为空");}@Overrideprotected void prepare() {super.prepare();this.gpsFlow = dto.getGpsFlow();this.approvalUserId = dto.getUser().getUserId();}@Overrideprotected void sql() {VCaAppInfoId dto = super.dto;StringBuffer where = super.queryWhere;if(this.isMine()){where.append(" and exists(select 1 from ca_gps_flow f where f.app_code = v.app_code and f.flow_step = 0 and f.approval_user_id = "+this.approvalUserId+") ");}where.append(" and v.status not in (11,13) and v.is_Gps ='2' and v.gps_Fee<>0 and v.gps_Fee !='' and v.gps_Fee is not null  and v.manage_Approval_Time is not null");if(!StringUtil.isBlank(dto.getProvince())){where.append(" and exists(select 1 from Sy_Dealer dr where dr.province = '"+dto.getProvince()+"' and dr.dealer_Code =  v.dealer_Code) ");}if (!StringUtil.isBlank(dto.getPostLoanStatus())) {//由于manual_audit_code多个时以";"分割,所以需要使用FIND_IN_SET函数处理 add by 石冬冬 on 2017/9/21where.append(" and v.app_code IN (SELECT app_code FROM Ca_Car_Gps WHERE del_status=1 and FIND_IN_SET ("+dto.getPostLoanStatus()+",replace(manual_audit_code,';',','))>0 ");where.append(" GROUP BY app_code) ");}}@Overrideprotected void hql() {VCaAppInfoId dto = super.dto;StringBuffer where = super.queryWhere;if(this.isMine()){where.append(" and exists(select 1 from CaGpsFlow f where f.appCode = v.id.appCode and f.flowStep = 0 and f.approvalUserId = " + this.approvalUserId+")");}where.append(" and v.id.status not in (11,13) and v.isGps ='2' and v.gpsFee<>0 and v.gpsFee !='' and v.gpsFee is not null and v.manageApprovalTime is not null");if(!StringUtil.isBlank(dto.getProvince())){where.append(" and exists(select 1 from SyDealer dr where dr.province = '"+dto.getProvince()+"' and dr.dealerCode =  v.id.dealerCode) ");}if (!StringUtil.isBlank(dto.getPostLoanStatus())) {//由于manual_audit_code多个时以";"分割,所以需要使用FIND_IN_SET函数处理 add by 石冬冬 on 2017/9/21where.append(" and v.id.appCode IN (SELECT appCode FROM CaCarGps WHERE delStatus=1 and find_in_set("+dto.getPostLoanStatus()+",replace(manualAuditCode,';',','))>0 ");where.append(" GROUP BY appCode) ");}}@Overridepublic boolean test(WhereContext context) {VCaAppInfoId dto = (VCaAppInfoId)context.getDto();return "-28".equals(dto.getStatus());}private boolean isMine(){return "mine".equals(gpsFlow);}
}

3.3、TobeUploadGpsQueryExecutor

public class TobeUploadGpsQueryExecutor extends AbstractWhereExecutor<VCaAppInfoId> {/*** 构造函数** @param context 上线文对象*/public TobeUploadGpsQueryExecutor(WhereContext context) {super(context);}@Overrideprotected void check(WhereContext context) {super.check(context);SyUser sessionUser = dto.getUser();Assert.notNull(sessionUser,"sessionUser为空");}@Overrideprotected void sql() {StringBuffer where = super.queryWhere;SyUser sessionUser = dto.getUser();where.append(" and (v.is_Gps ='0' or v.is_Gps ='2') and v.gps_Fee<>0 and v.gps_Fee !='' and v.gps_Fee is not null  and v.manage_Approval_Time is not null and v.status not in('11','12') ");GpsUtil.appendDealerCodes(sessionUser,(list) -> {String condition = MessageFormat.format(" and v.dealer_Code in({0})", StringUtils.join(list,","));where.append(condition);});}@Overrideprotected void hql() {StringBuffer where = super.queryWhere;SyUser sessionUser = dto.getUser();where.append(" and (v.isGps ='0' or v.isGps ='2') and v.gpsFee<>0 and v.gpsFee !='' and v.gpsFee is not null and v.manageApprovalTime is not null and v.id.status not in('11','12') ");GpsUtil.appendDealerCodes(sessionUser,(list) -> {String condition = MessageFormat.format(" and v.id.dealerCode in({0})", StringUtils.join(list,","));where.append(condition);});}@Overridepublic boolean test(WhereContext context) {VCaAppInfoId dto = (VCaAppInfoId)context.getDto();return "-27".equals(dto.getStatus());}
}

3.4、UnInstalledGpsQueryExecutor

/*** @description: 车贷审批管理》GPS安装单未上传* @Date : 上午10:17 2017/11/17* @Author : 石冬冬-Heil Hitler(dongdong.shi@mljr.com)*/
public class UnInstalledGpsQueryExecutor extends AbstractWhereExecutor<VCaAppInfoId> {/*** 标示*/protected String gpsFlow;/*** 审批人*/protected Integer approvalUserId;/*** 构造函数** @param context 上线文对象*/public UnInstalledGpsQueryExecutor(WhereContext context) {super(context);}@Overrideprotected void check(WhereContext context) {super.check(context);SyUser sessionUser = dto.getUser();Assert.notNull(sessionUser,"sessionUser为空");}@Overrideprotected void prepare() {super.prepare();this.gpsFlow = dto.getGpsFlow();this.approvalUserId = dto.getUser().getUserId();}@Overrideprotected void sql() {StringBuffer where = super.queryWhere;if(this.isMine()){where.append(" and exists(select 1 from ca_gps_flow f where f.app_code = v.app_code and f.flow_step = 0 and f.approval_user_id = "+this.approvalUserId+")");}where.append(" and v.status not in (11,13) and v.is_Gps ='0' and v.gps_Fee<>0 and v.gps_Fee !='' and v.gps_Fee is not null  and v.manage_Approval_Time is not null");if(!StringUtil.isBlank(dto.getProvince())){where.append(" and exists(select 1 from Sy_Dealer dr where dr.province = '"+dto.getProvince()+"' and dr.dealer_Code =  v.dealer_Code) ");}}@Overrideprotected void hql() {VCaAppInfoId dto = super.dto;StringBuffer where = super.queryWhere;if(this.isMine()){where.append(" and exists(select 1 from CaGpsFlow f where f.appCode = v.id.appCode and f.flowStep = 0 and f.approvalUserId = "+this.approvalUserId+")");}where.append(" and v.id.status not in (11,13) and v.isGps ='0' and v.gpsFee<>0 and v.gpsFee !='' and v.gpsFee is not null and v.manageApprovalTime is not null");if(!StringUtil.isBlank(dto.getProvince())){where.append(" and exists(select 1 from SyDealer dr where dr.province = '"+dto.getProvince()+"' and dr.dealerCode =  v.id.dealerCode) ");}}@Overridepublic boolean test(WhereContext context) {VCaAppInfoId dto = (VCaAppInfoId)context.getDto();return "-29".equals(dto.getStatus());}private boolean isMine(){return "mine".equals(gpsFlow);}
}

3.5、UploadedGpsQueryExecutor

public class UploadedGpsQueryExecutor extends AbstractWhereExecutor<VCaAppInfoId> {private final String STATUS_SCOPE = "'15','16','17','18','19','25','26','27','28','29','32'";/*** 构造函数** @param context 上线文对象*/public UploadedGpsQueryExecutor(WhereContext context) {super(context);}@Overrideprotected void check(WhereContext context) {super.check(context);SyUser sessionUser = dto.getUser();Assert.notNull(sessionUser,"sessionUser为空");}@Overrideprotected void sql() {VCaAppInfoId dto = super.dto;StringBuffer where = super.queryWhere;SyUser sessionUser = dto.getUser();where.append(" and v.gps_Fee<>0 and v.gps_Fee !='' and v.gps_Fee is not null  and v.manage_Approval_Time is not null and status in("+STATUS_SCOPE+") ");GpsUtil.appendDealerCodes(sessionUser,(list) -> {String condition = MessageFormat.format(" and v.dealer_Code in({0})", StringUtils.join(list,","));where.append(condition);});}@Overrideprotected void hql() {VCaAppInfoId dto = super.dto;StringBuffer where = super.queryWhere;SyUser sessionUser = dto.getUser();where.append(" and v.gpsFee<>0 and v.gpsFee !='' and v.gpsFee is not null and v.manageApprovalTime is not null and status in("+STATUS_SCOPE+") ");GpsUtil.appendDealerCodes(sessionUser,(list) -> {String condition = MessageFormat.format(" and v.id.dealerCode in({0})", StringUtils.join(list,","));where.append(condition);});}@Overridepublic boolean test(WhereContext context) {VCaAppInfoId dto = (VCaAppInfoId)context.getDto();return "-33".equals(dto.getStatus());}
}

3.6、调用方

入口

4、归纳总结

如上,即使用了模板方法这个设计模式,模板方法也是最通常使用的,即把相同的逻辑骨架抽象处理,由子类实现各自的差异部门。

下面的是我的公众号二维码图片,欢迎关注,或公众号搜索【秋夜无霜】。
秋夜无霜

这篇关于【设计模式活用】之代码重构之DAO扮演多个职责的重构案例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/449537

相关文章

Golang操作DuckDB实战案例分享

《Golang操作DuckDB实战案例分享》DuckDB是一个嵌入式SQL数据库引擎,它与众所周知的SQLite非常相似,但它是为olap风格的工作负载设计的,DuckDB支持各种数据类型和SQL特性... 目录DuckDB的主要优点环境准备初始化表和数据查询单行或多行错误处理和事务完整代码最后总结Duck

使用SQL语言查询多个Excel表格的操作方法

《使用SQL语言查询多个Excel表格的操作方法》本文介绍了如何使用SQL语言查询多个Excel表格,通过将所有Excel表格放入一个.xlsx文件中,并使用pandas和pandasql库进行读取和... 目录如何用SQL语言查询多个Excel表格如何使用sql查询excel内容1. 简介2. 实现思路3

python实现pdf转word和excel的示例代码

《python实现pdf转word和excel的示例代码》本文主要介绍了python实现pdf转word和excel的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一、引言二、python编程1,PDF转Word2,PDF转Excel三、前端页面效果展示总结一

在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码

《在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码》在MyBatis的XML映射文件中,trim元素用于动态添加SQL语句的一部分,处理前缀、后缀及多余的逗号或连接符,示... 在MyBATis的XML映射文件中,<trim>元素用于动态地添加SQL语句的一部分,例如SET或W

使用C#代码计算数学表达式实例

《使用C#代码计算数学表达式实例》这段文字主要讲述了如何使用C#语言来计算数学表达式,该程序通过使用Dictionary保存变量,定义了运算符优先级,并实现了EvaluateExpression方法来... 目录C#代码计算数学表达式该方法很长,因此我将分段描述下面的代码片段显示了下一步以下代码显示该方法如

MySQL不使用子查询的原因及优化案例

《MySQL不使用子查询的原因及优化案例》对于mysql,不推荐使用子查询,效率太差,执行子查询时,MYSQL需要创建临时表,查询完毕后再删除这些临时表,所以,子查询的速度会受到一定的影响,本文给大家... 目录不推荐使用子查询和JOIN的原因解决方案优化案例案例1:查询所有有库存的商品信息案例2:使用EX

python多进程实现数据共享的示例代码

《python多进程实现数据共享的示例代码》本文介绍了Python中多进程实现数据共享的方法,包括使用multiprocessing模块和manager模块这两种方法,具有一定的参考价值,感兴趣的可以... 目录背景进程、进程创建进程间通信 进程间共享数据共享list实践背景 安卓ui自动化框架,使用的是

SpringBoot生成和操作PDF的代码详解

《SpringBoot生成和操作PDF的代码详解》本文主要介绍了在SpringBoot项目下,通过代码和操作步骤,详细的介绍了如何操作PDF,希望可以帮助到准备通过JAVA操作PDF的你,项目框架用的... 目录本文简介PDF文件简介代码实现PDF操作基于PDF模板生成,并下载完全基于代码生成,并保存合并P

SpringBoot基于MyBatis-Plus实现Lambda Query查询的示例代码

《SpringBoot基于MyBatis-Plus实现LambdaQuery查询的示例代码》MyBatis-Plus是MyBatis的增强工具,简化了数据库操作,并提高了开发效率,它提供了多种查询方... 目录引言基础环境配置依赖配置(Maven)application.yml 配置表结构设计demo_st

SpringCloud集成AlloyDB的示例代码

《SpringCloud集成AlloyDB的示例代码》AlloyDB是GoogleCloud提供的一种高度可扩展、强性能的关系型数据库服务,它兼容PostgreSQL,并提供了更快的查询性能... 目录1.AlloyDBjavascript是什么?AlloyDB 的工作原理2.搭建测试环境3.代码工程1.