对字段进行加密存储

需求:

模型字段上使用 pro.shushi.pamirs.user.api.crypto.annotation.EncryptField 注解
模型动作上使用 pro.shushi.pamirs.user.api.crypto.annotation.NeedDecrypt 注解

示例:

对需要加密的字段添加@EncryptField注解

@Model.model(Student.MODEL_MODEL)
@Model(displayName = "学生", summary = "学生")
public class Student extends IdModel {

    public static final String MODEL_MODEL = "top.Student";

    @Field(displayName = "学生名字")
    @Field.String
    private String studentName;

    @Field(displayName = "学生ID")
    @Field.Integer
    private Long studentId;

    @Field(displayName = "学生卡号")
    @Field.String
    @EncryptField
    private String studentCard;
}

对函数添加@NeedDecrypt注解

   @Action.Advanced(name = FunctionConstants.create, managed = true)//默认取的是方法名
    @Action(displayName = "确定", summary = "添加", bindingType = ViewTypeEnum.FORM)
    @Function(name = FunctionConstants.create)//默认取的是方法名
    @Function.fun(FunctionConstants.create)//默认取的是方法名
    @NeedDecrypt
    public Student create(Student data) {
        String studentCard = data.getStudentCard();
        if (studentCard != null) {
        //自定义加密方法
            data.setStudentCard(StudentEncoder.encode(studentCard));
        }
        return data.create();
    }

Oinone社区 作者:yexiu原创文章,如若转载,请注明出处:https://doc.oinone.top/dai-ma-shi-jian/18227.html

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

(0)
yexiu的头像yexiu数式员工
上一篇 2024年10月9日 pm5:26
下一篇 2024年10月10日 pm9:55

相关推荐

  • Oinone登录扩展:对接SSO(适应于4.7.8及之后的版本)

    适配版本 4.7.8及其之后的版本 概述 在企业内部,对于已有一套完整的登录系统(SSO)的情况下,通常会要求把所有的系统都对接到SSO中;本文主要讲解用Oinone开发的项目对接SSO的具体实现。 对接步骤 1、项目自定义实现UserCookieLogin,可参考示例说明: pro.shushi.pamirs.user.api.login.UserCookieLoginFree 2、对接SSO示例 对接流程说明: 1)【必须】从请求头Header或者Query中获取到token; 2)【必须】去SSO服务端验证token的有效性; 3)【可选】根据token去服务端获取用户信息;如果token可以直接反解析出用户信息,则该步骤忽略; 4)【可选】根据实际情况用户信息是否进行DB的存储; 5)【必须】验证token有效后,生成Session和Cookie(即token换cookie); 注意超时时间需要 <= SSO服务端token失效时间。 package pro.shushi.pamirs.demo.core.sso; import com.alibaba.fastjson.JSON; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import pro.shushi.pamirs.demo.core.sso.constant.HttpConstant; import pro.shushi.pamirs.demo.core.sso.constant.SessionUserTypeEnum; import pro.shushi.pamirs.demo.core.sso.model.ApiCommonTransient; import pro.shushi.pamirs.demo.core.sso.model.PermissionInfoResp; import pro.shushi.pamirs.demo.core.sso.utils.AuthenticateUtils; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.meta.api.dto.model.PamirsUserDTO; import pro.shushi.pamirs.meta.api.session.PamirsSession; import pro.shushi.pamirs.meta.common.exception.PamirsException; import pro.shushi.pamirs.meta.common.spring.BeanDefinitionUtils; import pro.shushi.pamirs.resource.api.enmu.UserSignUpType; import pro.shushi.pamirs.user.api.cache.UserCache; import pro.shushi.pamirs.user.api.constants.UserConstant; import pro.shushi.pamirs.user.api.enmu.UserExpEnumerate; import pro.shushi.pamirs.user.api.enmu.UserLoginTypeEnum; import pro.shushi.pamirs.user.api.login.IUserLoginChecker; import pro.shushi.pamirs.user.api.login.UserCookieLogin; import pro.shushi.pamirs.user.api.login.UserCookieLoginSimple; import pro.shushi.pamirs.user.api.model.PamirsUser; import pro.shushi.pamirs.user.api.model.tmodel.PamirsUserTransient; import pro.shushi.pamirs.user.api.service.UserService; import pro.shushi.pamirs.user.api.utils.CookieUtil; import javax.servlet.http.HttpServletResponse; /** * * @author shushi * * 完全自定义login的过程 * 需要实现登陆部分login 以及拦截部分fetchUserIdByReq * 如果fetchUserIdByReq返回值为null的时候 将会被拦截 */ @Slf4j @Order(0) @Component public class DemoUserSSOCookieLogin extends UserCookieLogin<PamirsUser> { //刷新令牌 private static String REFRESH_TOKEN = "refreshToken"; //系统id private static String CLIENT_ID = "client-id"; //访问令牌 private static String AUTHORIZATION = "Authorization"; private IUserLoginChecker checker; @Autowired private UserService userService; @Autowired private RedisTemplate<String, String> redisTemplate; @Override public String type() { return UserLoginTypeEnum.COOKIE.value(); } @Override public PamirsUser resolveAndVerification(PamirsUserTransient user) { if (checker == null) { checker = BeanDefinitionUtils.getBean(IUserLoginChecker.class); } return checker.check4login(user); } /** * 重写登录拦截功能 * 该函数主要作用,通过三方权限校验. * @return */ // 版本升级需要修改 @Override public PamirsUserDTO fetchUserIdByReq() { String sessionId =…

    2024年4月2日
    2.1K00
  • 非存储字段搜索,适应灵活的搜索场景

    1、非存储字段搜索 1.1 描述 通常根据本模型之外的信息作为搜索条件时,通常会把 这些字段放在代理模型上。这类场景我们称之为 非存储字段搜索 1.2 场景一 非存储字段为基本的String。1.代码定义:非存储字段为基本的包装数据类型 @Field(displayName = "确认密码", store = NullableBoolEnum.FALSE) private String confirmPassword; 2.设计器拖拽:列表中需要有退拽这个字段,字段是否隐藏的逻辑自身业务是否需要决定。3.页面通过非存储字段为基本的包装数据类型进行搜索时。会拼在 queryWrapper 的属性queryData中,queryData为Map,key为字段名,value为搜索值。4.后台逻辑处理代码示例: Map<String, Object> queryData = queryWrapper.getQueryData(); if (null != queryData) { Object productIdObj = queryData.get(PRODUCT_ID); if (Objects.nonNull(productIdObj)) { String productId = productIdObj.toString(); queryWrapper.lambda().eq(MesProduceOrderProxy::getProductId, productId); } } 1.3 场景二 非存储字段为非存储对象。 定义 为非存储的 @Field(displayName = "款", store = NullableBoolEnum.FALSE) @Field.many2one @Field.Relation(store = false) private MesProduct product; 2.页面在搜索栏拖拽非存储字段作为搜索条件 3.后台逻辑处理代码示例: try { if (null != queryData && !queryData.isEmpty()) { List<Long> detailId = null; BasicSupplier supplier = JsonUtils.parseMap2Object((Map<String, Object>) queryData.get(supplierField), BasicSupplier.class); MesProduct product = JsonUtils.parseMap2Object((Map<String, Object>) queryData.get(productField), MesProduct.class); MesMaterial material = JsonUtils.parseMap2Object((Map<String, Object>) queryData.get(materialField), MesMaterial.class); if (supplier != null) { detailId = bomService.queryBomDetailIdBySupplierId(supplier.getId()); if (CollectionUtils.isEmpty(detailId)) { detailId.add(-1L); } } if (product != null) { List<Long> produceOrderId = produceOrderService.queryProductOrderIdByProductIds(product.getId()); if (CollectionUtils.isNotEmpty(produceOrderId)) { queryWrapper.lambda().in(MesProduceBomSizes::getProduceOrderId, produceOrderId); } } if (material != null) { //找出两个bom列表的并集 List<Long> materBomDetailId = bomService.queryBomDetailIdByMaterialId(material.getId()); if (CollectionUtils.isNotEmpty(detailId)) { detailId = detailId.stream().filter(materBomDetailId::contains).collect(Collectors.toList()); } else { detailId = new ArrayList<>(); if (CollectionUtils.isEmpty(materBomDetailId)) { detailId.add(-1L); } else { detailId.addAll(materBomDetailId); } } } if (CollectionUtils.isNotEmpty(detailId)) { queryWrapper.lambda().in(MesProduceBomSizes::getProductBomId, detailId); } } } catch (Exception e) { log.error("queryData处理异常", e); } 注意:…

    2024年2月20日
    1.5K00
  • 集成设计器数据流程、流程设计器可以暴露接口触发

    集成设计器数据流程暴露接口触发 需求:在集成设计器配置的连接器、数据流程链接到外部接口,需要可以有一个管理页面,统一管理这些集成配置。比如对接多个医院的挂号系统,希望可以配置好数据流程之后,能够在已经实现的开放接口上,动态的调用集成平台配置的数据流程。 连接器暴露接口触发 设计连接器资源配置模型。使用业务ID+接口唯一标识+连接器实现连接器资源和业务唯一。 @Model.model(EipConnectorResourceSetting.MODEL_MODEL) @Model(displayName = "连接器资源配置", summary = "连接器资源配置") @Model.Advanced(unique = {"hospitalId, interfaceUnique"}) public class EipConnectorResourceSetting extends IdModel { public static final String MODEL_MODEL = "hr.simple.EipConnectorResourceSetting"; @UxTableSearch.FieldWidget(@UxWidget()) @Field(displayName = "医院", required = true) @Field.Relation(relationFields = {"hospitalId"}, referenceFields = {"id"}) private Hospital hospital; @Field.Integer @Field(displayName = "医院ID", invisible = true) private Long hospitalId; @UxTableSearch.FieldWidget(@UxWidget()) @Field.String @Field(displayName = "接口唯一标识", required = true) private String interfaceUnique; @UxTableSearch.FieldWidget(@UxWidget()) @Field.many2one @Field(displayName = "连接器", required = true) @Field.Relation(relationFields = {"connectorId"}, referenceFields = {"id"}) private EipConnector connector; @Field.Integer @Field(displayName = "连接器ID", invisible = true) private Long connectorId; @UxTableSearch.FieldWidget(@UxWidget()) @Field.many2one @Field(displayName = "连接器接口", required = true) @Field.Relation(relationFields = {"integrationInterfaceId"}, referenceFields = {"id"}, domain = "connectorId==${activeRecord.connector.id}") private EipConnectorResource connectorResource; @Field.Integer @Field(displayName = "连接器接口ID", invisible = true) private Long connectorResourceId; } 开放接口定义,文档参考:https://doc.oinone.top/oio4/9326.html外部平台调用开放接口,实现动态调用连接器资源 @Model.model(HospitalSection.MODEL_MODEL) @Model(displayName = "医院科室", summary = "医院科室") public class HospitalSection extends IdModel { public static final String MODEL_MODEL = "net.example.HospitalSection"; @Field(displayName = "科室Code", required = true) private String deptCode; @Field(displayName = "科室名称", required = true) private String deptName; @Field(displayName = "科室描述") private String deptDesc; } @Slf4j @Fun @Component public class TestOpenService { @Resource private TestCommonService testCommonService;…

    2025年4月21日
    72400
  • 查询时自定义排序字段和排序规则

    指定字段排序 平台默认排序字段,参考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日
    2.0K00
  • 工作流:通过业务数据操作工作流程(催办、撤销等)

    一、抽象模型,需要操作流程的模型继承此模型 定义流程相关的一些信息在模型中;如果直接定义在存储模型中,下面这些字段都是显示的指定为非存储字段。更好的建议:1、如果有多个业务模型有这类需要,则可以把这些字段抽取到抽象模型中2、如果仅有一个业务模型需要,则可以放到代理模型中 /** * 定义流程相关的一些信息在模型中 */ @Model.model(DemoBaseAbstractModel.MODEL_MODEL) @Model(displayName = "抽象模型") @Model.Advanced(type= ModelTypeEnum.ABSTRACT) public abstract class DemoBaseAbstractModel extends IdModel { public static final String MODEL_MODEL = "hr.simple.DemoBaseAbstractModel"; // 流程相关 @Field.Integer @Field(displayName = "工作流用户任务ID", summary = "业务数据列表中审核流程使用", invisible = true, store = NullableBoolEnum.FALSE) private Long workflowUserTaskId; @Field.Integer @Field(displayName = "流程实例ID", summary = "业务数据列表中催办使用", invisible = true, store = NullableBoolEnum.FALSE) private Long instanceId; @Field.String @UxForm.FieldWidget(@UxWidget(invisible = "true")) @UxDetail.FieldWidget(@UxWidget(invisible = "true")) @Field(displayName = "当前流程节点", store = NullableBoolEnum.FALSE) private String currentFlowNode; @Field.Boolean @Field(displayName = "能否催办", invisible = true, defaultValue = "false", store = NullableBoolEnum.FALSE) private Boolean canUrge; // 审批状态控制申请单是否可以被发起流程、能否编辑等控制 @Field.Enum @Field(displayName = "审批状态", defaultValue = "NC") @UxForm.FieldWidget(@UxWidget(invisible = "true")) private ApprovalStatusEnum approvalStatus; } @Dict(dictionary = ApprovalStatusEnum.dictionary, displayName = "审批状态") public enum ApprovalStatusEnum implements IEnum<String> { NC("NC", "待提交", "待提交"), PENDING("PENDING", "已提交", "已提交,待审批"), APPROVED("APPROVED", "已批准", "已批准"), REJECTED("REJECTED", "已拒绝", "已拒绝"); public static final String dictionary = "land.enums.LandApprovalStatusEnum"; private final String value; private final String displayName; private final String help; ApprovalStatusEnum(String value, String displayName, String help) { this.value = value; this.displayName = displayName; this.help = help; } public String getValue() { return value; } public String getDisplayName() { return…

    2025年6月26日
    72900

Leave a Reply

登录后才能评论