【设计模式活用】之代码重构之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

相关文章

Java集合之Iterator迭代器实现代码解析

《Java集合之Iterator迭代器实现代码解析》迭代器Iterator是Java集合框架中的一个核心接口,位于java.util包下,它定义了一种标准的元素访问机制,为各种集合类型提供了一种统一的... 目录一、什么是Iterator二、Iterator的核心方法三、基本使用示例四、Iterator的工

Java 线程池+分布式实现代码

《Java线程池+分布式实现代码》在Java开发中,池通过预先创建并管理一定数量的资源,避免频繁创建和销毁资源带来的性能开销,从而提高系统效率,:本文主要介绍Java线程池+分布式实现代码,需要... 目录1. 线程池1.1 自定义线程池实现1.1.1 线程池核心1.1.2 代码示例1.2 总结流程2. J

JS纯前端实现浏览器语音播报、朗读功能的完整代码

《JS纯前端实现浏览器语音播报、朗读功能的完整代码》在现代互联网的发展中,语音技术正逐渐成为改变用户体验的重要一环,下面:本文主要介绍JS纯前端实现浏览器语音播报、朗读功能的相关资料,文中通过代码... 目录一、朗读单条文本:① 语音自选参数,按钮控制语音:② 效果图:二、朗读多条文本:① 语音有默认值:②

Vue实现路由守卫的示例代码

《Vue实现路由守卫的示例代码》Vue路由守卫是控制页面导航的钩子函数,主要用于鉴权、数据预加载等场景,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着... 目录一、概念二、类型三、实战一、概念路由守卫(Navigation Guards)本质上就是 在路

uni-app小程序项目中实现前端图片压缩实现方式(附详细代码)

《uni-app小程序项目中实现前端图片压缩实现方式(附详细代码)》在uni-app开发中,文件上传和图片处理是很常见的需求,但也经常会遇到各种问题,下面:本文主要介绍uni-app小程序项目中实... 目录方式一:使用<canvas>实现图片压缩(推荐,兼容性好)示例代码(小程序平台):方式二:使用uni

JAVA实现Token自动续期机制的示例代码

《JAVA实现Token自动续期机制的示例代码》本文主要介绍了JAVA实现Token自动续期机制的示例代码,通过动态调整会话生命周期平衡安全性与用户体验,解决固定有效期Token带来的风险与不便,感兴... 目录1. 固定有效期Token的内在局限性2. 自动续期机制:兼顾安全与体验的解决方案3. 总结PS

C#中通过Response.Headers设置自定义参数的代码示例

《C#中通过Response.Headers设置自定义参数的代码示例》:本文主要介绍C#中通过Response.Headers设置自定义响应头的方法,涵盖基础添加、安全校验、生产实践及调试技巧,强... 目录一、基础设置方法1. 直接添加自定义头2. 批量设置模式二、高级配置技巧1. 安全校验机制2. 类型

Python屏幕抓取和录制的详细代码示例

《Python屏幕抓取和录制的详细代码示例》随着现代计算机性能的提高和网络速度的加快,越来越多的用户需要对他们的屏幕进行录制,:本文主要介绍Python屏幕抓取和录制的相关资料,需要的朋友可以参考... 目录一、常用 python 屏幕抓取库二、pyautogui 截屏示例三、mss 高性能截图四、Pill

使用MapStruct实现Java对象映射的示例代码

《使用MapStruct实现Java对象映射的示例代码》本文主要介绍了使用MapStruct实现Java对象映射的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、什么是 MapStruct?二、实战演练:三步集成 MapStruct第一步:添加 Mave

Java抽象类Abstract Class示例代码详解

《Java抽象类AbstractClass示例代码详解》Java中的抽象类(AbstractClass)是面向对象编程中的重要概念,它通过abstract关键字声明,用于定义一组相关类的公共行为和属... 目录一、抽象类的定义1. 语法格式2. 核心特征二、抽象类的核心用途1. 定义公共接口2. 提供默认实