扩展操作日志字段,实现操作日志界面显示自定义字段

注:该功能在pamirs-core 4.3.27 / 4.7.8.12以上版本可用

  1. 在模块依赖里新增DataAuditModule.MODULE_MODULE模块依赖。

    @Module(
           name = DemoModule.MODULE_NAME,
           dependencies = {
                   CommonModule.MODULE_MODULE,
                   DataAuditModule.MODULE_MODULE
           },
           displayName = "****",
           version = "1.0.0"
    )
  2. 继承OperationBody模型,设置需要在操作日志中显示的字段,并重写clone方法,设置自定义字段值。用于在计入日志处传递参数。

    public class MyOperationBody extends OperationBody {
       public MyOperationBody(String operationModel, String operationName) {
           super(operationModel, operationName);
       }
    
       private String itemNames;
    
       public String getItemNames() {
           return itemNames;
       }
    
       public void setItemNames(String itemNames) {
           this.itemNames = itemNames;
       }
    
       @Override
       public OperationBody clone() {
            //设置自定义字段值
           MyOperationBody body = OperationBody.transfer(this, new MyOperationBody(this.getOperationModel(), this.getOperationName()));
           body.setItemNames(this.getItemNames());
           return body;
       }
    }
  3. 继承OperationLog模型,新增需要在操作日志中显示的字段。用于界面展示该自定义字段。

    @Model.model(MyOperationLog.MODEL_MODEL)
    @Model(displayName = "自定义操作日志", labelFields = {"itemNames"})
    public class MyOperationLog extends OperationLog {
    
       public static final String MODEL_MODEL = "operation.MyOperationLog";
    
       @Field(displayName = "新增日志字段")
       @Field.String
       private String itemNames;
    }
  4. 定义一个常量

    public interface OperationLogConstants {
    
    String MY_SCOPE = "MY_SCOPE";
    }
  5. 在计入日志处,构造出MyOperationBody对象,向该对象中设置自定义日志字段。构造OperationLogBuilder对象并设置scope的值,用于跳转自定义服务实现。

    MyOperationBody body = new MyOperationBody(CustomerCompanyUserProxy.MODEL_MODEL, CustomerCompanyUserProxyDataAudit.UPDATE);
    body.setItemNames("新增日志字段");
    OperationLogBuilder builder = OperationLogBuilder.newInstance(body);
    //设置一个scope,用于跳转自定义服务实现.OperationLogConstants.MY_SCOPE是常量,请自行定义
    builder.setScope(OperationLogConstants.MY_SCOPE);
    //记录日志
    builder.record(data.queryByPk(), data);
  6. 实现OperationLogService接口,加上@SPI.Service()注解,并设置常量,一般为类名。定义scope(注意:保持和计入日志处传入的scope值一致),用于计入日志处找到该自定义服务实现。根据逻辑重写父类中方法,便可以扩展操作日志,实现自定义记录了。

    @Slf4j
    @Service
    @SPI.Service("myOperationLogServiceImpl")
    public class MyOperationLogServiceImpl< T extends D > extends OperationLogServiceImpl< T > implements OperationLogService< T >{
    
        //定义scope,用于计入日志处找到该自定义服务实现
        private static final String[] MY_SCOPE = new String[]{OperationLogConstants.MY_SCOPE};
    
        @Override
        public String[] scopes() {
            return MY_SCOPE;
        }
    
        //此方法用于创建操作日志
        @Override
        protected OperationLog createOperationLog(OperationBody body, OperationLogConfig config) {
           MyOperationBody body1 = (MyOperationBody) body;
           return new MyOperationLog().setItemNames(body1.getItemNames())
                   .setLogConfig(config)
                   .setModel(body.getOperationModel())
                   .setOperationName(body.getOperationName())
                   .setRemark(body.getRemark())
                   .setBusinessId(body.getBusinessId())
                   .setBusinessCode(body.getBusinessCode())
                   .setBusinessName(body.getBusinessName())
                   .setPartnerId(body.getPartnerId())
                   .setPartnerCode(body.getPartnerCode())
                   .setExtId(body.getExtId())
                   .setExtName(body.getExtName())
                   .setOperatorId(ObjectHelper.getOrDefault(body.getOperatorId(), PamirsSession.getUserId()))
                   .setOperatorName(ObjectHelper.getOrDefault(body.getOperatorName(), PamirsSession.getUserName()));
       }
    
    }
    

Oinone社区 作者:yexiu原创文章,如若转载,请注明出处:https://doc.oinone.top/backend/14174.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

Like (0)
yexiu's avataryexiu数式员工
Previous 2024年6月27日 pm12:09
Next 2024年6月28日 am10:28

相关推荐

  • Oinone远程调用链路源码分析

    前提 源码分析版本是 5.1.x版本 概要 在服务启动时,获取注解REMOTE的函数,通过dubbo的泛化调用发布。在调用函数时,通过dubbo泛化调用获取结果。 注册服务者 在spring 启动方法installOrLoad中初始化 寻找定义REMOTE的方法 组装dubbo的服务配置 组装服务对象实现引用,内容如下,用于注册 调用前置处理 放信息到SessionApi 函数调用链追踪,放到本地TransmittableThreadLocal 从redis中获取到的数据进行反序列化并存在到本地的线程里 Trace信息,放一份在sessionApi中 和ThreadLocal 调用函数执行 返回数据转成特定格式 通过线程组调用dubbo的ServiceConfig.export 服务发布 时序图 源码分析 根据条件判断,确定向dubbo进行服务发布RemoteServiceLoader public void publishService(List<FunctionDefinition> functionList,Map<String,Runnable> isPublished) { // 因为泛化接口只能控制到namespace,控制粒度不能到fun级别,这里进行去重处理 Map<String, Function> genericNamespaceMap = new HashMap<>(); for (FunctionDefinition functionDefinition : functionList) { Function function = new Function(functionDefinition) try { //定义REMOTE, 才给予远程调用 if (FunctionOpenEnum.REMOTE.in(function.getOpen()) && !ClassUtils.isInterface(function.getClazz())) { genericNamespaceMap.putIfAbsent(RegistryUtils.getRegistryInterface(function), function); } } catch (PamirsException e) { } } // 发布远程服务 for (String namespace : genericNamespaceMap.keySet()) { Function function = genericNamespaceMap.get(namespace); if(isPublished.get(RegistryUtils.getRegistryInterface(function)) == null){ // 发布,注册远程函数服务,底层使用dubbo的泛化调用 Runnable registryTask = () -> remoteRegistry.registryService(function); isPublished.put(RegistryUtils.getRegistryInterface(function),registryTask); }else{ } } } 构造ServiceConfig方法,设置成泛化调用,进行发布export()DefaultRemoteRegistryComponent public void registryGenericService(String interfaceName, List<MethodConfig> methods, String group, String version, Integer timeout, Integer retries) { …. try { ServiceConfig<GenericService> service = new ServiceConfig<>(); // 服务接口名 service.setInterface(interfaceName); // 服务对象实现引用 service.setRef(genericService(interfaceName)); if (null != methods) { service.setMethods(methods); } // 声明为泛化接口 service.setGeneric(Boolean.TRUE.toString()); // 基础元数据 constructService(group, version, timeout, retries, service); service.export(); } catch (Exception e) { ….. } } // 服务对象实现引用 private GenericService genericService(String interfaceName) { return (method, parameterTypes, args) -> { PamirsSession.clear(); Function function = Objects.requireNonNull(PamirsSession.getContext()).getFunction(RegistryUtils.getFunctionNamespace(method), RegistryUtils.getFunctionFun(method)); if (log.isDebugEnabled()) { log.debug("interfaceName: " + interfaceName + ",…

    2024年9月4日
    1.8K00
  • 技术精要:数据导出与固化实用指南

    数据被认为是企业发展和决策的重要资产。随着业务的不断发展和数据量的不断增加,企业通常需要将数据从不同的源头导出,并将其固化到产品中,以便进行进一步的分析、处理和利用。数据导出与固化的过程涉及到数据的提取、清洗、整合和存储,是确保数据长期有效性和可用性的关键步骤。 了解数据导出与固化的流程和方法对于企业具有重要意义。通过有效的数据导出和固化,企业可以更好地管理和利用数据资源,提升决策的准确性和效率,实现业务的持续发展和创新。本次讨论将重点探讨数据导出与固化的流程和关键步骤,帮助参与者深入了解如何将数据从导出到产品中,为企业数据管理和应用提供有力支持。 1. 数据导出与固化:将数据从导出到产品中的流程 1.1. pom依赖: <dependency> <groupId>pro.shushi.pamirs.metadata.manager</groupId> <artifactId>pamirs-metadata-manager</artifactId> </dependency> 1.2 将第⼆步下载后的⽂件放⼊项⽬中(注意⽂件放置的位置)。放置⼯程的resources 下⾯。例如: 1.3 项⽬启动过程中,将⽂件中的数据导⼊(通常放在core模型的init包下 ⾯)。⽰例代码: package pro.shushi.pamirs.sys.setting.enmu; import com.google.common.collect.Lists; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; import pro.shushi.pamirs.boot.common.api.command.AppLifecycleCom mand; import pro.shushi.pamirs.boot.common.api.init.LifecycleCompleted AllInit; import pro.shushi.pamirs.boot.common.extend.MetaDataEditor; import pro.shushi.pamirs.core.common.InitializationUtil; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.meta.api.dto.meta.Meta; import pro.shushi.pamirs.meta.domain.module.ModuleDefinition; import pro.shushi.pamirs.metadata.manager.core.helper.DesignerIn stallHelper; import pro.shushi.pamirs.metadata.manager.core.helper.WidgetInst allHelper; import java.util.List; import java.util.Map; @Slf4j @Component public class DemoAppMetaInstall implements MetaDataEditor, LifecycleCompletedAllInit { @Autowired private ApplicationContext applicationContext; @Override public void edit(AppLifecycleCommand command, Map<String, Meta> metaMap) { if (!doImport()) { return; } log.info("[设计器业务元数据导⼊]"); InitializationUtil bizInitializationUtil = InitializationUtil.get(metaMap, DemoModule.MODULE_MODULE/ ***改成⾃⼰的Module*/, DemoModule.MODULE_NAME/***改成⾃⼰的 Module*/); DesignerInstallHelper.mateInitialization(bizInitializatio nUtil, "install/meta.json"); log.info("[⾃定义组件元数据导⼊]"); // 写法1: 将组件元数据导⼊到⻚⾯设计器. 只有在安装设计器的 服务中执⾏才有效果 WidgetInstallHelper.mateInitialization(metaMap, "install/widget.json"); // 写法2: 与写法1相同效果 InitializationUtil uiInitializationUtil = InitializationUtil.get(metaMap, "ui_designer", "uiDesigner"); if (uiInitializationUtil != null) { DesignerInstallHelper.mateInitialization(uiInitialization Util, "install/widget.json"); } // 写法3: 业务⼯程和设计器分布式部署,且希望通过业务⼯程导⼊ ⾃定义组件元数据. 业务模块需要依赖⻚⾯设计器模块,然后指定业务模块导 ⼊ DesignerInstallHelper.mateInitialization(bizInitializatio nUtil, "install/widget.json"); } @Override public void process(AppLifecycleCommand command, Map<String, ModuleDefinition> runModuleMap) { if (!doImport()) { return; } log.info("[设计器业务数据导⼊]"); // ⽀持远程调⽤,但是执⾏的⽣命周期必须是 LifecycleCompletedAllInit或之后. 本地如果安装了设计器,则没有要 求 DesignerInstallHelper.bizInitialization("install/ meta.json"); log.info("[⾃定义组件业务数据导⼊]"); // 当开发环境和导⼊环境的⽂件服务不互通时, 可通过指定js和 css的⽂件压缩包,⾃动上传到导⼊环境,并替换导⼊组件数据中的⽂件url // WidgetInstallHelper.bizInitialization("install/ widget.json", "install/widget.zip"); WidgetInstallHelper.bizInitialization("install/ widget.json"); return; } private boolean doImport() { // ⾃定义导⼊判断. 避免⽤于设计的开发环境执⾏导⼊逻辑 String[] envs = applicationContext.getEnvironment().getActiveProfiles(); List<String> envList = Lists.newArrayList(envs); return…

    2024年2月27日
    2.6K00
  • Oinone离线部署设计器镜像

    概述 Oinone平台为合作伙伴提供了多种部署方式,这篇文章将介绍如何在私有云环境部署Oinone平台Docker镜像。 本文以5.2.20.1版本为例进行介绍,使用amd64架构的体验镜像进行部署。具体版本号以数式提供的为准 部署环境要求 包含全部中间件及设计器服务的环境要求 CPU:8 vCPU 内存(RAM):16G以上 硬盘(HDD/SSD):60G以上 仅设计器服务的环境要求 CPU:8 vCPU 内存(RAM):8G以上 硬盘(HDD/SSD):40G以上 部署准备 一台安装了Docker环境的服务器(私有云环境);以下简称部署环境; 一台安装了Docker环境的电脑(可访问公网);以下简称本地环境; 部署清单 下面列举了文章中在本地环境操作结束后的全部文件: 设计器镜像:oinone-designer-full-v5-5.2.20.1-amd64.tar 离线部署结构包:oinone-designer-full-standard-offline.zip Oinone许可证:****-trial.lic(实际文件名以Oinone颁发的许可证为准) 第三方数据库驱动包(非MySQL数据库必须) PS:如需一次性拷贝所有部署文件到部署环境,可以将文档步骤在本地环境执行后,一次性将所有文件进行传输。 在部署环境创建部署目录 mkdir -p /home/admin/oinone-designer-full mkdir -p /home/admin/oinone-designer-full/images 检查部署环境服务器架构 确认部署环境是amd64还是arm64架构,若本文提供的查看方式无法正确执行,可自行搜索相关内容进行查看。 使用uname命令查看 uname -a PS:此步骤非常重要,如果部署环境的服务器架构与本地环境的服务器架构不一致,将导致镜像无法正确启动。 在本地环境准备镜像 在Oinone发布版本一览中选择最新版本的发布日志,找到需要部署的镜像版本。 登录Oinone镜像仓库(若已登录,可忽略此步骤) docker login https://harbor.oinone.top # input username # input password 获取Oinone平台镜像 docker pull harbor.oinone.top/oinone/oinone-designer-full-v5.2:5.2.20.1-amd64 保存镜像到.tar文件 docker save -o oinone-designer-full-v5-5.2.20.1-amd64.tar oinone-designer-full-v5.2:5.2.20.1-amd64 若报错`Error response from daemon: reference does not exist`脚本改成下面这个: docker save -o oinone-designer-full-v5-5.2.20.1-amd64.tar harbor.oinone.top/oinone/oinone-designer-full-v5.2:5.2.20.1-amd64 # docker save [OPTIONS] IMAGE [IMAGE…] 上传.tar到部署环境 scp ./oinone-designer-full-v5-5.2.20.1-amd64.tar admin@127.0.0.1:/home/admin/oinone-full/images/ PS:若无法使用scp方式上传,可根据部署环境的具体情况将镜像文件上传至部署环境的部署目录。 在部署环境加载镜像 加载镜像文件到Docker中 cd /home/admin/oinone-full/images docker load -i oinone-designer-full-v5-5.2.20.1-amd64.tar 查看镜像是否正确加载 docker images 查看输出内容,对比REPOSITORY、TAG、IMAGE ID与本地环境完全一致即可。 设计器服务部署 为了方便起见,服务器操作文件显得不太方便,因此,我们可以在本地环境将部署脚本准备妥善后,传输到部署环境进行部署结构包(oinone-designer-full-standard-offline.)需上传到要部署的服务器中,后面的操作均在这个目中进行 下载离线部署结构包(以数式发出的为准) oinone-designer-full-standard-offline.zip 将Pamirs许可证移动到config目录下,并重命名为****-trial.lic(实际文件名以Oinone颁发的许可证为准) mv ****-trial.lic config/****-trial.lic 加载非MySQL数据库驱动(按需) 将驱动jar文件移动到lib目录下即可。 以KDB8数据库驱动kingbase8-8.6.0.jar为例 mv kingbase8-8.6.0.jar lib/ PS:lib目录为非设计器内置包的外部加载目录(外部库),可以添加任何jar包集成到设计器中。 修改脚本中的配置 修改启动脚本startup.sh 修改对应的镜像版本号, 将IP从192.168.0.121改成宿主机IP configDir=$(pwd) version=5.1.16 IP=192.168.0.121 修改mq/broker.conf 修改其中brokerIP1的IP从192.168.0.121改成宿主机IP brokerClusterName = DefaultCluster namesrvAddr=127.0.0.1:9876 brokerIP1=192.168.0.121 brokerName = broker-a brokerId = 0 deleteWhen = 04 fileReservedTime = 48 brokerRole = ASYNC_MASTER flushDiskType = ASYNC_FLUSH autoCreateTopicEnable=true listenPort=10991 transactionCheckInterval=1000 #存储使用率阀值,当使用率超过阀值时,将拒绝发送消息请求 diskMaxUsedSpaceRatio=98 #磁盘空间警戒阈值,超过这个值则停止接受消息,默认值90 diskSpaceWarningLevelRatio=99 #强制删除文件阈值,默认85 diskSpaceCleanForciblyRatio=97 执行startup.sh脚本启动 sh startup.sh 访问服务 使用http://127.0.0.1:88访问服务

    2024年11月1日
    1.4K00
  • 【OceanBase】后端部署使用 OceanBase 数据库(海扬/OB)

    OceanBase 数据库配置 驱动配置 Maven配置(4.2.5.3版本可用) <oceanbase.version>2.4.14</oceanbase.version> <dependency> <groupId>com.oceanbase</groupId> <artifactId>oceanbase-client</artifactId> <version>${oceanbase.version}</version> </dependency> PS: oceanbase 驱动必须使用 2.4.5 版本或以上,低于此版本的驱动无法使用自增ID功能,无法正常启动。点击查看官方JDBC版本发布记录 JDBC连接配置 OceanBase – Oracle 版 pamirs: datasource: base: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.alipay.oceanbase.jdbc.Driver url: jdbc:oceanbase://10.xxx.xxx.xxx:1001/BASE?useServerPrepStmts=true&useOraclePrepareExecute=true&defaultFetchSize=4096 username: xxxxxx password: xxxxxx validConnectionCheckerClassName: com.alibaba.druid.pool.vendor.OracleValidConnectionChecker validationQuery: SELECT 1 FROM DUAL OceanBase – MySQL 版 pamirs: datasource: base: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.alipay.oceanbase.jdbc.Driver url: jdbc:oceanbase://10.xxx.xxx.xxx:1001/base username: xxxxxx password: xxxxxx 连接 URL 配置 点击查看官方JDBC连接配置说明 URL 格式(OceanBase – Oracle 版) jdbc:oceanbase://${host}:${port}/${database}?useServerPrepStmts=true&useOraclePrepareExecute=true&defaultFetchSize=4096 在jdbc连接配置时,useServerPrepStmts=true&useOraclePrepareExecute=true 必须配置,否则自增主键无法正常使用。 defaultFetchSize=4096 意味着在使用服务端预处理时,游标每次获取的结果集行数,驱动默认值为 10,在进行大量数据获取时会出现卡顿的现象,因此推荐使用 4096 作为其结果集大小。过大可能会导致 OOM,过小可能还是会出现卡顿,该值需要按实际情况进行配置。 其他连接参数如需配置,可自行查阅相关资料进行调优。 方言配置(OceanBase – Oracle 版) PS:OceanBase – MySQL 版无需配置方言,只需修改数据库连接即可正常使用。 pamirs方言配置 pamirs: dialect: ds: base: type: OceanBase version: 4.2.5.3 major-version: oracle-4.2 pamirs: type: OceanBase version: 4.2.5.3 major-version: oracle-4.2 plus: configuration: jdbc-type-for-null: "NULL" using-model-as-property: true using-statement-handler-dialect: true mapper: batch: collectionCommit default-batch-config: read: 500 write: 100 数据库版本 type version majorVersion 4.2.5.3 OceanBase 4.2.5.3 oracle-4.2 PS:由于方言开发环境为4.2.5.3版本,其他类似版本(4.x)原则上不会出现太大差异,如出现其他版本无法正常支持的,可在文档下方留言。 schedule方言配置 pamirs: event: enabled: true schedule: enabled: true dialect: type: Oracle version: 12.2 major-version: 12c type version majorVersion Oracle 12.2 12c PS:由于 schedule 的方言与 Oracle 数据库并无明显差异,OceanBase 数据库可以直接使用 Oracle 数据库方言。 其他配置(OceanBase – Oracle 版) 逻辑删除的值配置 pamirs: mapper: global: table-info: logic-delete-value: (CAST(SYSTIMESTAMP AS DATE) – TO_DATE('1970-01-01 08:00:00', 'YYYY-MM-DD HH24:MI:SS')) * 8640000000000

    2025年7月21日
    1.2K00
  • 后端代码规范

    前言 虽然oinone框架减少了很多的代码,但是低代码部分的代码质量也需要高度关注,不管是写的代码bug多,或者说被吐槽代码不行,还是说写的代码经常被重构,核心点还是没有代码规范的意识和技巧,下面摘录了一些常见的规范要求,去提高后端的代码质量,代码质量提高后,自然效率也会提升。 常见代码规范 **1、规范命名** 命名是写代码中最频繁的操作,比如类、属性、方法、参数等。好的名字应当能遵循以下几点: **见名知意** 比如需要定义一个变量需要来计数 int i = 0; 名称 i 没有任何的实际意义,没有体现出数量的意思,所以我们应当指明数量的名称 int count = 0; **能够读的出来** 如下代码: private String sfzh; private String dhhm; 这些变量的名称,根本读不出来,更别说实际意义了。 所以我们可以使用正确的可以读出来的英文来命名 private String idCardNo; private String phone; **2、规范代码格式** 好的代码格式能够让人感觉看起来代码更加舒适。 好的代码格式应当遵守以下几点: 合适的空格 代码对齐,比如大括号要对齐 及时换行,一行不要写太多代码 好在现在开发工具支持一键格式化,可以帮助美化代码格式,大家统一使用idea的规范即可。 **3、写好代码注释** 在《代码整洁之道》这本书中作者提到了一个观点,注释的恰当用法是用来弥补我们在用代码表达意图时的失败。换句话说,当无法通过读代码来了解代码所表达的意思的时候,就需要用注释来说明。 书的作者之所以这么说,是因为作者觉得随着时间的推移,代码可能会变动,如果不及时更新注释,那么注释就容易产生误导,偏离代码的实际意义。而不及时更新注释的原因是,程序员不喜欢写注释。😒 但是这不意味着可以不写注释,当通过代码如果无法表达意思的时候,就需要注释,比如如下代码: for (Integer id : ids) { if (id == 0) { continue; } //做其他事 } 为什么 id == 0 需要跳过,代码是无法看出来了,就需要注释了。 好的注释应当满足一下几点: 解释代码的意图,说明为什么这么写,用来做什么 对参数和返回值注释,入参代表什么,出参代表什么 有警示作用,比如说入参不能为空,或者代码是不是有坑 当代码还未完成时可以使用 todo 注释来标记 代码review发现漏洞时 可以使用 fixme 注释来标记 **4、try catch 内部代码抽成一个方法** try catch代码有时会干扰我们阅读核心的代码逻辑,这时就可以把try catch内部主逻辑抽离成一个单独的方法 如下图是Eureka服务端源码中服务下线的实现中的一段代码 整个方法非常长,try中代码是真正的服务下线的代码实现,finally可以保证读锁最终一定可以释放。 所以这段代码其实就可以对核心的逻辑进行抽取。 protected boolean internalCancel(String appName, String id, boolean isReplication) { try { read.lock(); doInternalCancel(appName, id, isReplication); } finally { read.unlock(); } // 剩余代码 } private boolean doInternalCancel(String appName, String id, boolean isReplication) { //真正处理下线的逻辑 } **5、方法别太长** 方法别太长就是字面的意思。一旦代码太长,给人的第一眼感觉就很复杂,让人不想读下去; 同时方法太长的代码可能读起来容易让人摸不着头脑,不知道哪一些代码是同一个业务的功能。 比如代码中有那种2000+行大类,各种if else判断,光理清代码思路就需要用很久时间。🤷🏻‍♀️ 所以一旦方法过长,可以尝试将相同业务功能的代码单独抽取一个方法,最后在主方法中调用即可。 **6、抽取重复代码** 当一份代码重复出现在程序的多处地方,就会造成程序又臭又长,当这份代码的结构要修改时,每一处出现这份代码的地方都得修改,导致程序的扩展性很差。 所以一般遇到这种情况,可以抽取成一个工具类,还可以抽成一个公共的父类。 **7、多用return** 在有时我们平时写代码的情况可能会出现if条件套if的情况,当if条件过多的时候可能会出现如下情况: if (条件1) { if (条件2) { if (条件3) { if (条件4) { if (条件5) { System.out.println("11111"); } } } } } 面对这种情况,可以换种思路,使用return来优化 if (!条件1) { return; } if (!条件2) { return; } if (!条件3) { return; } if (!条件4) { return; } if (!条件5) { return; } System.out.println("11111"); 这样优化就感觉看起来更加直观 **8、if条件表达式不要太复杂**…

    2024年12月11日
    3.1K00

Leave a Reply

Please Login to Comment