首次登录修改密码和自定义密码规则等

场景描述

在某些场景下,可能需要实现 用户首次登录强制修改密码的功能,或者存在修改平台默认密码等校验规则等需求;本文将讲解不改变平台代码的情况下,如何实现这些功能需求。

首次登录修改密码

方案概述

自定义User增加是否是第一次登录的属性,登录后执行一个扩展点。 判断是否是一次登录,如果是则返回对应的状态码,前端根据状态码重定向到修改密码的页面。修改完成则充值第一次登录的标识。

PS:首次登录的标识平台前端已默认实现

扩展PamirsUser(例如:DemoUser)

/**
 * @author wangxian
 */
@Model.model(DemoUser.MODEL_MODEL)
@Model(displayName = "用户", labelFields = {"nickname"})
@Model.Advanced(index = {"companyId"})
public class DemoUser extends PamirsUser {
    public static final String MODEL_MODEL = "demo.DemoUser";

    @Field.Integer
    @Field.Advanced(columnDefinition = "bigint DEFAULT '0'")
    @Field(displayName = "公司ID", invisible = true)
    private Long companyId;

    /**
     * 默认true->1
     */
    @Field.Boolean
    @Field.Advanced(columnDefinition = "tinyint(1) DEFAULT '1'")
    @Field(displayName = "是否首次登录")
    private Boolean firstLogin;
}

定义扩展点接口(实际项目按需要增加和删减接口的定义)

import pro.shushi.pamirs.meta.annotation.Ext;
import pro.shushi.pamirs.meta.annotation.ExtPoint;
import pro.shushi.pamirs.user.api.model.tmodel.PamirsUserTransient;

@Ext(PamirsUserTransient.class)
public interface PamirsUserTransientExtPoint {

    @ExtPoint
    PamirsUserTransient loginAfter(PamirsUserTransient user);

    @ExtPoint
    PamirsUserTransient loginCustomAfter(PamirsUserTransient user);

    @ExtPoint
    PamirsUserTransient firstResetPasswordAfter(PamirsUserTransient user);
    @ExtPoint
    PamirsUserTransient firstResetPasswordBefore(PamirsUserTransient user);

    @ExtPoint
    PamirsUserTransient modifyCurrentUserPasswordAfter(PamirsUserTransient user);

    @ExtPoint
    PamirsUserTransient modifyCurrentUserPasswordBefore(PamirsUserTransient user);
}

编写扩展点实现(例如:DemoUserLoginExtPoint)

@Order(0)
@Component
@Ext(PamirsUserTransient.class)
@Slf4j
public class DemoUserLoginExtPoint implements PamirsUserTransientExtPoint {

    @Override
    @ExtPoint.Implement
    public PamirsUserTransient loginAfter(PamirsUserTransient user) {
        return checkFirstLogin(user);
    }

    private PamirsUserTransient checkFirstLogin(PamirsUserTransient user) {
        //首次登录需要修改密码
        Long userId = PamirsSession.getUserId();

        if (userId == null) {
            return user;
        }

        DemoUser companyUser = new DemoUser().queryById(userId);
        // 判断用户是否是第一次登录,如果是第一次登录,需要返回错误码,页面重新向登录
        Boolean isFirst = companyUser.getFirstLogin();
        if (isFirst) {
            //如果是第一次登录,返回一个标识给前端。
            // 首次登录的标识平台已默认实现
            user.setBroken(Boolean.TRUE);
            user.setErrorCode(UserExpEnumerate.USER_FIRST_LOGIN_ERROR.code());
            return user;
        }

        return user;
    }

    @Override
    public PamirsUserTransient loginCustomAfter(PamirsUserTransient user) {
        return checkFirstLogin(user);
    }

    @Override
    @ExtPoint.Implement
    public PamirsUserTransient firstResetPasswordAfter(PamirsUserTransient user) {
        return updateFirstLogin(user);
    }

    private PamirsUserTransient updateFirstLogin(PamirsUserTransient user) {
        Long userId = PamirsSession.getUserId();
        if (userId == null) {
            return user;
        }
        //修改密码后 将首次登录标识改为false
        Integer update = new DemoUser().updateByWrapper(new DemoUser().setFirstLogin(Boolean.FALSE),
                Pops.<DemoUser>lambdaUpdate()
                        .from(DemoUser.MODEL_MODEL)
                        .eq(IdModel::getId, userId)
        );
        if (update != 1) {
            user.setBroken(Boolean.TRUE);
            user.setErrorCode(UserExpEnumerate.USER_CHANGE_PWD_NO_USER.code());
        }

        return user;
    }

    @Override
    @ExtPoint.Implement
    public PamirsUserTransient modifyCurrentUserPasswordAfter(PamirsUserTransient user) {
        return updateFirstLogin(user);
    }
}

修改平台密码规则

密码规则平台内置SPI

平台已提供内置SPI:UserPatternCheckApi 支持用户自定义密码、用户Nick、邮箱等指定以校验规则。内置SPI接口定义如下:

@SPI(factory = SpringServiceLoaderFactory.class)
public interface UserPatternCheckApi {

    default Boolean userPatternCheck(PamirsUser pamirsUser) {
        // 过滤掉系统用户(即系统用户的密码修改不受扩展点影响)8848:eip_system.; 10088L:workflow_system; 10086L:trigger_system
        if (pamirsUser.getId()!=null && (8848L==pamirsUser.getId() || 10086L==pamirsUser.getId() || 10088L==pamirsUser.getId())) {
            return Boolean.TRUE;
        }

        UserPatternCheckApi checkApi = Spider.getLoader(UserPatternCheckApi.class).getDefaultExtension();
        Boolean result ;
        result = checkApi.checkInitialPassword(pamirsUser.getInitialPassword());
        if(Boolean.FALSE.equals(result)){
            return result;
        }

        result = checkApi.checkPassword(pamirsUser.getPassword());
        if(Boolean.FALSE.equals(result)){
            return result;
        }

        result = checkApi.checkEmail(pamirsUser.getEmail());
        if(Boolean.FALSE.equals(result)){
            return result;
        }

        result = checkApi.checkContactEmail(pamirsUser.getContactEmail());
        if(Boolean.FALSE.equals(result)){
            return result;
        }

        result = checkApi.checkPhone(pamirsUser.getPhone());
        if(Boolean.FALSE.equals(result)){
            return result;
        }

        result = checkApi.checkLogin(pamirsUser.getLogin());
        if(Boolean.FALSE.equals(result)){
            return result;
        }

        result = checkApi.checkName(pamirsUser.getName());
        if(Boolean.FALSE.equals(result)){
            return result;
        }

        result = checkApi.checkNickName(pamirsUser.getNickname());
        if(Boolean.FALSE.equals(result)){
            return result;
        }

        result = checkApi.checkRealName(pamirsUser.getRealname());
        if(Boolean.FALSE.equals(result)){
            return result;
        }

        result = checkApi.checkIdCard(pamirsUser.getIdCard());
        if(Boolean.FALSE.equals(result)){
            return result;
        }
        return result;
    }

    default Boolean checkInitialPassword(String initPassword) {
        UserPatternCheckUtils.checkPassword(initPassword, Boolean.TRUE);
        return Boolean.TRUE;
    }

    default Boolean checkPassword(String password) {
        UserPatternCheckUtils.checkPassword(password, Boolean.TRUE);
        return Boolean.TRUE;
    }

    default Boolean checkEmail(String email) {
        UserPatternCheckUtils.checkEmail(email, Boolean.TRUE);
        return Boolean.TRUE;
    }

    default Boolean checkContactEmail(String contactEmail) {
        UserPatternCheckUtils.checkEmail(contactEmail, Boolean.TRUE);
        return Boolean.TRUE;
    }

    default Boolean checkLogin(String login) {
        UserPatternCheckUtils.checkLogin(login, Boolean.TRUE);
        return Boolean.TRUE;
    }

    default Boolean checkPhone(String phone) {
        UserPatternCheckUtils.checkPhone(phone, Boolean.TRUE);
        return Boolean.TRUE;
    }

    default Boolean checkName(String name) {
        UserPatternCheckUtils.checkName(name, Boolean.TRUE);
        return Boolean.TRUE;
    }

    default Boolean checkNickName(String nickname) {
        UserPatternCheckUtils.checkNickName(nickname, Boolean.TRUE);
        return Boolean.TRUE;
    }

    default Boolean checkRealName(String realname) {
        UserPatternCheckUtils.checkRealName(realname, Boolean.TRUE);
        return Boolean.TRUE;
    }

    default Boolean checkIdCard(String idCard) {
        UserPatternCheckUtils.checkIdCard(idCard, Boolean.TRUE);
        return Boolean.TRUE;
    }
}

项目上密码规则自定义示例

下面的示例实现自定义校验:
1、用户账号不检验格式,只检验登录login不为空;
2、密码不检验格式,只校验长度是 3 到 8位;

@Slf4j
@SPI.Service
@Order(50) //默认优先级最低,业务配置需要配置成为优先级高
@Component
public class DemoUserPatternCheckApi implements UserPatternCheckApi {

    /**
     * 按需(无特殊逻辑无需实现),修改密码的校验规则
     **/
    @Override
    public Boolean checkPassword(String password) {
        //自定义校验逻辑
        checkPasswordPattern(password);
        return Boolean.TRUE;
    }

    /**
     * 按需(无特殊逻辑无需实现),修改Login的校验规则
     **/
    @Override
    public Boolean checkLogin(String login) {
        if (StringUtils.isBlank(login)) {
            throw PamirsException.construct(EMPLOYEE_LOGIN_NOT_BLANK).errThrow();
        }
        return Boolean.TRUE;
    }

    private static void checkPasswordPattern(String password) {
        if (StringUtils.isBlank(password)) {
            throw PamirsException.construct(EMPLOYEE_PASSWORD_NOT_BLANK).errThrow();
        }
        int length = password.length();
        boolean mark = length >= 3 && length <= 8;
        if (!mark) {
            throw PamirsException.construct(EMPLOYEE_PASSWORD_CHECK_RULE).errThrow();
        }
    }
}

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

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

Like (0)
望闲's avatar望闲数式管理员
Previous 2024年5月25日 pm4:19
Next 2024年5月25日 pm5:20

相关推荐

  • Oinone设计器部署参数说明

    概述 Oinone提供两种设计器部署方式,合作伙伴可以自行选择适合自己的部署方式。 Docker配置参数 环境变量 ARG_ENV:指定spring.profiles.active(默认:dev) ARG_LIFECYCLE:指定-Plifecycle(默认:INSTALL) JVM_OPTIONS:jvm参数 PROGRAM_ARGS:程序参数 JVM_OPTIONS和PROGRAM_ARGS参数说明 java [JVM_OPTIONS?] -jar boot.jar [PROGRAM_ARGS?] 端口说明 PS:以下为目前设计器镜像的全部端口,不同类型镜像的端口由于内置服务不同,使用的端口数量不同,但端口号是完全一致的。 80:前端服务端口(设计器访问入口) 8091:后端服务端口 8093:后端EIP服务端口 20880:Dubbo端口 3306:内置MySQL端口 2181:内置Zookeeper端口 6379:内置Redis端口 9876/10991:内置RocketMQ端口 9999:内置本地OSS默认端口 挂载目录说明(挂载虚拟卷) /opt/pamirs为镜像的工作目录,所有挂载目录均在该目录下。 /opt/pamirs/ext:应用配置文件目录;包含application.yml、logback.xml、license.lic等配置文件 /opt/pamirs/nginx/vhost:Nginx配置文件目录 /opt/pamirs/logs:后端服务日志目录 /opt/mq/conf/broker.conf:RocketMQ的broker配置文件 /opt/pamirs/outlib:非设计器内置包的外部加载目录(外部库),可以添加任何jar包集成到设计器中。 /opt/pamirs/dist:前端服务目录 /opt/pamirs/static:前端静态文件目录;LOCAL类型的OSS上传和下载目录; docker run启动常用参数 -e:指定环境变量 -p:指定端口映射 -v:指定挂载目录(挂载虚拟卷) docker run [OPTIONS] IMAGE [COMMAND] [ARG…] docker compose启动常用配置 services: container: image: $IMAGE container_name: $CONTAINER_NAME restart: always # docker run -e environment: KEY1: VALUE1 KEY2: VALUE2 … # docker run -p ports: – $machinePort1:$containerPort1 – $machinePort2:$containerPort2 … # docker run -v volumes: – $machinePath1:$containerPath1 – $machinePath2:$containerPath2 … docker compose常用命令 # 使用docker-compose.yaml启动 docker compose up -d # 使用docker-compose.yaml停止并删除容器 docker compose down -v # 指定配置文件启动 docker compose -f config.yaml up -d # 指定配置文件停止并删除容器 docker compose -f config.yaml down -v JAR包方式启动 下载Oinone专属启动器 oinone-boot-starter.zip 启动命令变化 # 原命令 java -jar boot.jar # 变更后命令 boot-starter java -jar boot.jar PS:更多命令可查看后端无代码设计器Jar包启动方法

    2024年11月4日
    1.9K00
  • 查询时自定义排序字段和排序规则

    指定字段排序 平台默认排序字段,参考IdModel,按创建时间和ID倒序(ordering = "createDate DESC, id DESC") 方法1:模型指定排序 模型定义增加排序字段。@Model.Advanced(ordering = "xxxxx DESC, yyyy DESC") @Model.model(PetShop.MODEL_MODEL) @Model(displayName = "宠物店铺",summary="宠物店铺",labelFields ={"shopName"}) @Model.Code(sequence = "DATE_ORDERLY_SEQ",prefix = "P",size=6,step=1,initial = 10000,format = "yyyyMMdd") @Model.Advanced(ordering = "createDate DESC") public class PetShop extends AbstractDemoIdModel { public static final String MODEL_MODEL="demo.PetShop"; // ………… } 方法2:Page查询中可以自定排序规则 API参考 pro.shushi.pamirs.meta.api.dto.condition.Pagination#orderBy public <G, R> Pagination<T> orderBy(SortDirectionEnum direction, Getter<G, R> getter) { if (null == getSort()) { setSort(new Sort()); } getSort().addOrder(direction, getter); return this; } 具体示例 @Function.Advanced(type= FunctionTypeEnum.QUERY) @Function.fun(FunctionConstants.queryPage) @Function(openLevel = {FunctionOpenEnum.API}) public Pagination<PetShop> queryPage(Pagination<PetShop> page, IWrapper<PetShop> queryWrapper){ page.orderBy(SortDirectionEnum.DESC, PetShop::getCreateDate); page = new PetShop().queryPage(page, queryWrapper); return page; } 方法3:查询的wapper中指定 API参考:pro.shushi.pamirs.framework.connectors.data.sql.AbstractWrapper#orderBy @Override public Children orderBy(boolean condition, boolean isAsc, R… columns) { if (ArrayUtils.isEmpty(columns)) { return typedThis; } SqlKeyword mode = isAsc ? ASC : DESC; for (R column : columns) { doIt(condition, ORDER_BY, columnToString(column), mode); } return typedThis; } 具体示例 public List<PetShop> queryList(String name) { List<PetShop> petShops = Models.origin().queryListByWrapper( Pops.<PetShop>lambdaQuery().from(PetShop.MODEL_MODEL) .orderBy(true, true, PetShop::getCreateDate) .orderBy(true, true, PetShop::getId) .like(PetShop::getShopName, name)); return petShops; } 设置查询不排序 方法1:关闭平台默认排序字段,设置模型的ordering,改成:ordering = "1=1" 模型定义增加排序字段。@Model.Advanced(ordering = "1=1") @Model.model(PetShop.MODEL_MODEL) @Model(displayName = "宠物店铺",summary="宠物店铺",labelFields ={"shopName"}) @Model.Code(sequence = "DATE_ORDERLY_SEQ",prefix = "P",size=6,step=1,initial = 10000,format = "yyyyMMdd") @Model.Advanced(ordering =…

    2024年5月25日
    3.0K00
  • 如何自定义覆盖内置模块的页面

    1.首先通过sql查询找到我们需要的页面,从其中的template字段复制出原视图的配置 通过模型编码model在base_view查找需要修改的视图 select * from base_view where model='workflow.WorkflowUserTask' and is_deleted = 0; 2.将base_view的template内容复制到java的core工程的resources目录下新建一个xml文件,修改里面的动作名称 <view widget="WorkFlowImplement"> <template slot="actions"> <action name="$$internal_GotoListTableRouter" priority="1" model="workflow.WorkflowUserTask" tag="contextFreeAction"/> <action name="approveStaging" widget="FlowTaskCommonAction" invisible="!(activeRecord.allowStaging)" priority="2" label="新暂存" model="workflow.WorkflowUserTask" displayName="新暂存"/> <action name="workflow_agree" invisible="!(activeRecord.allowAgree && activeRecord.status == &apos;ACTIVE&apos;)" priority="3" label="新同意" model="workflow.WorkflowUserTask" load="fetchDetailReadOnly" displayName="新同意" goBack="true" validateForm="true" loadRootData="true"/> <action name="workflow_rejust" invisible="!(activeRecord.allowReject && activeRecord.status == &apos;ACTIVE&apos;)" priority="4" label="新拒绝" model="workflow.WorkflowUserTask" displayName="新拒绝" goBack="true" loadRootData="true" tag="contextFreeAction"/> <action name="workflow_turnon" invisible="!(activeRecord.taskType == &apos;APPROVE&apos; && activeRecord.allowTransfer && activeRecord.status == &apos;ACTIVE&apos;)" priority="5" label="新转交" model="workflow.WorkflowUserTask" load="fetchDetailReadOnly" displayName="新转交" goBack="true" loadRootData="true" tag="contextFreeAction"/> <action name="workflow_addsign" invisible="!(activeRecord.taskType == &apos;APPROVE&apos; && activeRecord.allowAddSign && activeRecord.status == &apos;ACTIVE&apos;)" priority="6" label="新加签" model="workflow.WorkflowUserTask" load="fetchDetailReadOnly" displayName="新加签" goBack="true" loadRootData="true" tag="contextFreeAction"/> <action name="workflow_write_fallback" invisible="!(activeRecord.taskType == &apos;WRITE&apos; && activeRecord.allowFallback && activeRecord.status == &apos;ACTIVE&apos;)" priority="7" label="新回退" model="workflow.WorkflowUserTask" displayName="新回退" goBack="true" loadRootData="true" tag="contextFreeAction"/> <action name="workflow_sharing" priority="8" label="新分享" model="workflow.WorkflowUserTask" displayName="新分享" goBack="true" loadRootData="true" tag="contextFreeAction"/> </template> <template slot="fields"> <field name="remark" widget="TextArea" invisible="activeRecord.taskType != &apos;APPROVE&apos;" priority="8" model="workflow.WorkflowUserTask" data="remark" displayName="意见备注"/> </template> </view> 3.在生命周期的元数据编辑方法内覆盖视图 package pro.shushi.pamirs.demo.core.init; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import pro.shushi.pamirs.boot.common.api.command.AppLifecycleCommand; import pro.shushi.pamirs.boot.common.extend.MetaDataEditor; import pro.shushi.pamirs.core.common.InitializationUtil; import pro.shushi.pamirs.demo.api.DemoModule; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.meta.api.dto.meta.Meta; import pro.shushi.pamirs.meta.enmu.ViewTypeEnum; import pro.shushi.pamirs.workflow.app.api.model.WorkflowUserTask; import java.util.Map; @Slf4j @Component @Order(Ordered.LOWEST_PRECEDENCE) public class DemoModuleMetaInstall implements MetaDataEditor { @Override public void edit(AppLifecycleCommand command,…

    2024年7月2日
    2.1K00
  • 引入搜索(增强模型Channel)常见问题解决办法

    总体描述 引入Oinone的搜索(即Channel模块)后,因错误的配置、缺少配置或者少引入一些Jar包,会出现一些报错。 问题1:启动报类JCTree找不到 具体现象 启动过程可能会出现报错:java.lang.NoClassDefFoundError: com/sun/tools/javac/tree/JCTree$JCExpression 产生原因 引入Channel模块后,启动过程中会扫描Class包找寻Enhance的注解,Pamirs底层有使用到jdk的tools中的类, com/sun/tools/javac/tree/JCTree$JCExpression 特定版本的jdk可能会缺少tools.jar导致启动失败 具体报错 at org.springframework.boot.loader.Launcher.launch(Launcher.java:107) [pamirs-venus-boot.jar:na] at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) [pamirs-venus-boot.jar:na] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88) [pamirs-venus-boot.jar:na] Caused by: java.util.concurrent.ExecutionException: java.lang.NoClassDefFoundError: com/sun/tools/javac/tree/JCTree$JCExpression at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357) ~[na:1.8.0_381] at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1908) ~[na:1.8.0_381] at pro.shushi.pamirs.boot.common.initial.PamirsBootMainInitial.init(PamirsBootMainInitial.java:66) ~[pamirs-boot-api-4.6.10.jar!/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_381] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_381] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_381] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_381] at org.springframework.context.event.ApplicationListenerMethodAdapter.doInvoke(ApplicationListenerMethodAdapter.java:305) ~[spring-context-5.2.12.RELEASE.jar!/:5.2.12.RELEASE] … 20 common frames omitted Caused by: java.lang.NoClassDefFoundError: com/sun/tools/javac/tree/JCTree$JCExpression at java.lang.Class.forName0(Native Method) ~[na:1.8.0_381] at java.lang.Class.forName(Class.java:264) ~[na:1.8.0_381] at pro.shushi.pamirs.meta.util.ClassUtils.getClasses(ClassUtils.java:157) ~[pamirs-meta-model-4.6.8.jar!/:na] at pro.shushi.pamirs.meta.util.ClassUtils.getClassesByPacks(ClassUtils.java:73) ~[pamirs-meta-model-4.6.8.jar!/:na] at pro.shushi.pamirs.channel.core.manager.EnhanceModelScanner.enhanceModel(EnhanceModelScanner.java:51) ~[pamirs-channel-core-4.6.15.jar!/:na] at pro.shushi.pamirs.channel.core.init.ChannelSystemBootAfterInit.init(ChannelSystemBootAfterInit.java:31) 解决办法 方式一【推荐】、配置channel的扫描路径 pamirs: channel: packages: – com.pamirs.ic 方式二、使用Oracle版本的jdk,确保jdk的lib目录,tools.jar有com/sun/tools/javac/tree/JCTree对应的类 问题2:启动报类JsonProvider找不到 具体报错 如果启动报错信息如下: Caused by: java.lang.NoClassDefFoundError: jakarta/json/spi/JsonProvider at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_181] at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[na:1.8.0_181] at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) ~[na:1.8.0_181] at java.net.URLClassLoader.defineClass(URLClassLoader.java:467) ~[na:1.8.0_181] 产生原因 项目中只引入了pamirs-channel-core,但未引入elasticsearch相关的包 解决办法 <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-client</artifactId> <version>8.4.1</version> </dependency> <dependency> <groupId>jakarta.json</groupId> <artifactId>jakarta.json-api</artifactId> <version>2.1.1</version> </dependency> 其他参考: Oinone引入搜索引擎步骤:https://doc.oinone.top/backend/7235.html

    2024年5月17日
    1.8K00
  • 扩展操作日志字段,实现操作日志界面显示自定义字段

    注:该功能在pamirs-core 4.3.27 / 4.7.8.12以上版本可用 在模块依赖里新增DataAuditModule.MODULE_MODULE模块依赖。 @Module( name = DemoModule.MODULE_NAME, dependencies = { CommonModule.MODULE_MODULE, DataAuditModule.MODULE_MODULE }, displayName = “****”, version = “1.0.0” ) 继承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; } } 继承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; } 定义一个常量 public interface OperationLogConstants { String MY_SCOPE = “MY_SCOPE”; } 在计入日志处,构造出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); 实现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)…

    2024年6月27日 • 后端
    1.9K00

Leave a Reply

Please Login to Comment