mybatis拦截器的使用

场景:自定义拦截器做数据的加解密。

  1. 注册自定义拦截器

    @Configuration
    public class MyBatisConfig {
    
    // TODO: 注册自定义拦截器
    @Bean
    @Order(999)
    public EncryptionInterceptor encryptionInterceptor() {
        return new EncryptionInterceptor();
    }
    }
  2. 使用mybatis拦截器拦截查询。

    @Intercepts({
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
    })
    public class EncryptionInterceptor implements Interceptor {
    
    @Autowired
    private EncryptionConfig encryptionConfig;
    
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
    
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement) args[0];
        Object parameter = args[1];
    
        // 判断操作类型是insert, update 或 delete
        if (ms.getSqlCommandType().equals(SqlCommandType.INSERT) ||
                ms.getSqlCommandType().equals(SqlCommandType.UPDATE) ||
                ms.getSqlCommandType().equals(SqlCommandType.DELETE)) {
            // TODO: 加密字段
            encryptFields(parameter);
        } else if (ms.getSqlCommandType().equals(SqlCommandType.SELECT)) {
            // TODO: 查询操作,在执行后需要对结果进行解密
            Object result = invocation.proceed();
            List<EncryptionConfig.Models> models = encryptionConfig.getModels();
            for (EncryptionConfig.Models model : models) {
                if (judgmentModel(parameter, model)) {
                    decryptFields(result);
                }
            }
            return result;
        }
    
        return invocation.proceed();
    }
    
    private Boolean judgmentModel(Object parameter, EncryptionConfig.Models model) {
        MetaObject metaObject = SystemMetaObject.forObject(parameter);
        if (metaObject.getOriginalObject() instanceof MapperMethod.ParamMap) {
            if (metaObject.hasGetter("ew")) {
                Object param1 = metaObject.getValue("ew");
                if (param1 != null) {
                    Object originalObject = SystemMetaObject.forObject(param1).getOriginalObject();
                    if (originalObject instanceof QueryWrapper) {
                        DataMap entity = (DataMap) ((QueryWrapper<?>) originalObject).getEntity();
                        if (entity != null) {
                            Object modelFieldName = entity.get(FieldConstants._d_modelFieldName);
                            if (modelFieldName != null) {
                                String modelName = modelFieldName.toString();
                                return model.getModel().equals(modelName);
                            }
                        }
                    }
                }
            }
        }
        return false;
    }
    
    private void encryptFields(Object parameter) throws Exception {
        List<EncryptionConfig.Models> models = encryptionConfig.getModels();
        MetaObject metaObject = SystemMetaObject.forObject(parameter);
        if (metaObject.getOriginalObject() instanceof MapperMethod.ParamMap) {
            if (metaObject.hasGetter("et")) {
                Object param1 = metaObject.getValue("et");
                // 确保 param1 不为空
                if (param1 != null) {
                    MetaObject param1MetaObject = SystemMetaObject.forObject(param1);
                    if (param1MetaObject.getOriginalObject() instanceof LinkedHashMap) {
                        // 再检查 _d_model 字段
                        if (param1MetaObject.hasGetter(FieldConstants._d_modelFieldName)) {
                            String value1 = (String) param1MetaObject.getValue(FieldConstants._d_modelFieldName);
                            for (EncryptionConfig.Models model : models) {
                                if (model.getModel().equals(value1)) {
                                    for (String field : model.getFields()) {
                                        // 使用反射获取字段值并进行加密
                                        Object value = metaObject.getValue("et." + field);
                                        if (value != null) {
                                            String encryptedValue = EncryptionUtil.encrypt(value.toString());
                                            metaObject.setValue("et." + field, encryptedValue);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    
    private void decryptFields(Object result) throws Exception {
        List<EncryptionConfig.Models> models = encryptionConfig.getModels();
        if (result instanceof ArrayList) {
            ArrayList<?> resultValue = (ArrayList<?>) result;
            for (EncryptionConfig.Models model : models) {
                for (String field : model.getFields()) {
                    for (Object o : resultValue) {
                        DataMap dataMap = (DataMap) o;
                        Object fieldName = dataMap.get(field);
                        if (fieldName != null) {
                            String encryptedValue = fieldName.toString();
                            String decryptedValue = EncryptionUtil.decrypt(encryptedValue);
                            dataMap.setValue(field, decryptedValue);
                        }
                    }
                }
            }
        }
    }
    
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }
    
    @Override
    public void setProperties(Properties properties) {
    }
    }
  3. 定义实体类,用于筛选模型

    @Configuration
    @ConfigurationProperties(prefix = "encryption")
    public class EncryptionConfig {
    private List<Models> models;
    
    public static class Models {
        private String model;
        private List<String> fields;
    
        public String getModel() {
            return model;
        }
    
        public void setModel(String model) {
            this.model = model;
        }
    
        public List<String> getFields() {
            return fields;
        }
    
        public void setFields(List<String> fields) {
            this.fields = fields;
        }
    }
    
    public List<Models> getModels() {
        return models;
    }
    
    public void setModels(List<Models> models) {
        this.models = models;
    }
    }

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

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

(0)
yexiu的头像yexiu数式员工
上一篇 2024年12月1日 pm7:18
下一篇 2024年12月3日 pm11:51

相关推荐

  • 左树右表,支撑不同场景的树表结构

    左树右表俩种情况 假设存在 A模型 B模型 1: 左树为A模型,右表为B模型 举例 A模型为类目 B模型为类目属性模型代码实例: @Model.model(AriesPlatformCategory.MODEL_MODEL) @Model(displayName = "平台后台类目", labelFields = "name") @Model.Advanced(type = ModelTypeEnum.PROXY) public class AriesPlatformCategory extends AriesCategory { public static final String MODEL_MODEL = "aries.item.AriesPlatformCategory"; @Field.many2one @Field.Relation(relationFields = {"parentCateCode"}, referenceFields = {"code"},store = true) @Field(displayName = "平台父类目") private AriesPlatformCategory platformCategory; @Field.one2many @Field(displayName = "类目属性") @Field.Relation(relationFields = "code", referenceFields = "categoryCode", store = true) private List<AriesPlatformCategoryAttr> platformCategoryAttrs; } @Model.model(AriesPlatformCategoryAttr.MODEL_MODEL) @Model(displayName = "Aries_平台类目属性", labelFields = "name") @Model.Advanced(type = ModelTypeEnum.PROXY) public class AriesPlatformCategoryAttr extends CategoryAttr { public static final String MODEL_MODEL = "aries.item.AriesPlatformCategoryAttr"; @Field.many2one @Field(displayName = "平台后台类目") @Field.Relation(relationFields = "categoryCode", referenceFields = "code", store = true) private AriesPlatformCategory platformCategory; } 在设计器设计左树右表之前,需要在模型 中配置好关联关系 。如下部分代码 配置好类目与父类目的关联关系。 @Field.many2one @Field.Relation(relationFields = {"parentCateCode"}, referenceFields = {"code"},store = true) @Field(displayName = "平台父类目") private AriesPlatformCategory platformCategory; 配置好 类目与类目属性的关联关系。一个类目可以有多个类目属性,一对多one2many @Field.one2many @Field(displayName = "类目属性") @Field.Relation(relationFields = "code", referenceFields = "categoryCode", store = true) private List<AriesPlatformCategoryAttr> platformCategoryAttrs; 在类目属性模型中,配置好属性与类目的关联关系,一个类目属性只属于一个类目,一个类目可以有多个类目属性。类目属性对类目多对一many2one @Field.many2one @Field(displayName = "平台后台类目") @Field.Relation(relationFields = "categoryCode", referenceFields = "code", store = true) private AriesPlatformCategory platformCategory; 设计器实例:1.需要选择 平台类目属性 做为主模型创建树表页面2.构建关联关系 选择平台后台类目 第一级的筛选条件 上级编码为空 表格关联关系字段 选择 平台类目属性。 3.表格拖拽好需要的属性字段 2: 左树为A模型,右表也为A模型 举例 左A模型 组织结构管理 右A模型 组织结构管理模型代码实例: @Model.model(BasicOrg.MODEL_MODEL) @Model(displayName = "组织结构管理", summary…

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

    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日
    98700
  • 如何扩展行为权限

    注意:5.2.8 以上版本适用 需求 我们的权限控制需要在页面上有交互才可以在管理中心控制该动作权限,在没有页面交互的动作是不能进行授权操作的。所以本文章将介绍如何将页面上没有交互的动作接入到系统权限中管理。 一、扩展系统权限的菜单页面 实现 步骤: 创建授权节点实现权限节点扩展接口:pro.shushi.pamirs.auth.api.extend.load.PermissionNodeLoadExtendApi#buildRootPermissions @Component @Order(88) public class MyTestNodeLoadExtend implements PermissionNodeLoadExtendApi { public static final String MODEL = AuthTest.MODEL_MODEL; public static final String MODULE = TopModule.MODULE_MODULE; public static final String FUN = "dataStatus"; @Override public List<PermissionNode> buildRootPermissions(PermissionLoadContext loadContext, List<PermissionNode> nodes) { //创建授权根节点 PermissionNode root = createMyNode(); List<PermissionNode> newNodes = new ArrayList<>(); //从缓存中读取需要授权的Action Action cacheAction = PamirsSession.getContext().getExtendCache(ActionCacheApi.class).get(MODEL, FUN); if (cacheAction != null) { //将该Action放入权限树 //权限鉴权的path路径是根据【cacheAction.getModel() + cacheAction.getName()】拼接的。和MODULE没有关系,这里MODULE可以自定义。 AuthNodeHelper.addNode(newNodes, root, AuthNodeHelper.createActionNode(MODULE, cacheAction, root)); } nodes.add(0, root); return newNodes; } private PermissionNode createMyNode() { return AuthNodeHelper.createNodeWithTranslate("MyNode", "自定义节点"); } } 在管理中心中我们可以看到代码里创建的授权节点。 给角色分配该动作的权限,调用我们配置的AuthTest模型的dataStatus动作看效果。 二、扩展菜单下的动作权限 实现 步骤: 创建viewAction用于作为权限菜单"permissionExtension"是自定义的viewAction的name,用于下面拼path路径鉴权。因为这里只需要在系统权限那边利用这个viewAction创建出授权节点。所以”权限扩展form“可以随意定义名字,系统会拿默认视图。 @Model.model(AuthTest.MODEL_MODEL) @Component @UxRouteButton( action = @UxAction(name = "permissionExtension", displayName = "权限扩展", label = "权限扩展", contextType = ActionContextTypeEnum.CONTEXT_FREE), value = @UxRoute(model = AuthTest.MODEL_MODEL, viewName = "权限扩展form", openType = ActionTargetEnum.ROUTER)) public class AuthTestAction { @Action(displayName = "启用", contextType = ActionContextTypeEnum.SINGLE) public AuthTest dataStatus(AuthTest data) { data.setOrgName("给个值"); return data; } } 创建授权节点实现权限节点扩展接口:pro.shushi.pamirs.auth.api.extend.load.PermissionNodeLoadExtendApi#buildRootPermissions @Component @Order(88) public class MyTestNodeLoadExtend implements PermissionNodeLoadExtendApi { //创建授权根节点 @Override public List<PermissionNode> buildRootPermissions(PermissionLoadContext loadContext, List<PermissionNode> nodes) { PermissionNode root = AuthNodeHelper.createNodeWithTranslate("CustomNode", "自定义节点"); List<PermissionNode> newNodes = new ArrayList<>(); newNodes.add(root); ViewAction viewAction = new ViewAction().setModel(AuthTest.MODEL_MODEL).setName("permissionExtension").queryOne(); //将该Action放入权限树 //权限鉴权的path路径是根据【viewAction.getModel(),…

    2024年11月1日
    50200
  • 如何改变调度策略,让Schedule独立执行线程

    1、后台创建task type相关的类,继承BaseScheduleNoTransactionTask,要加springbean的注解,参考:task type建议使用类名 2、提交任务的时候,设置tasktype为步骤1的TaskType 3、控制台新增策略和任务bean名称为步骤1的spring beanName,任务名称 $xxx,右边的占位符内容为yml里面配置的ownSign字段任务的名称也是步骤1的 spring beanName 4、配置完成后,控制台启动任务,就可以测试了

    2024年2月20日
    73100
  • 如何删除系统权限中默认的首页节点

    场景: 并没有设置过首页的配置,为什么在系统权限这里的配置菜单中却有首页的配置。而且显示当前资源未完成初始化设置,无法配置。这个文章将帮助你删除这个节点。 注意:如果添加了以下代码,后续如果需要使用首页的配置,则需要删除该代码。 扩展权限加载节点: 遍历权限加载的节点,找到需要删除的模块首页节点。删除节点。 @Component @Order(88) @SPI.Service public class MyTestNodeLoadExtend implements PermissionNodeLoadExtendApi { @Override public List<PermissionNode> buildRootPermissions(PermissionLoadContext loadContext, List<PermissionNode> nodes) { //删除 TopModule.MODULE_MODULE 的首页节点。 String homepage = TranslateUtils.translateValues(PermissionNodeLoaderConstants.HOMEPAGE_DISPLAY_VALUE); for (PermissionNode node : nodes) { //如果需要删除多个模块的首页,在这里多加一个逻辑与条件即可。 if (!(node instanceof ModulePermissionNode) || !TopModule.MODULE_MODULE.equals(((ModulePermissionNode) node).getModule())) { continue; } List<PermissionNode> permissionNodes = node.getNodes(); Iterator<PermissionNode> iterator = permissionNodes.iterator(); while (iterator.hasNext()) { PermissionNode permissionNode = iterator.next(); if (ResourcePermissionSubtypeEnum.HOMEPAGE.equals(permissionNode.getNodeType()) && homepage.equals(permissionNode.getDisplayValue())) { iterator.remove(); //如果是删除多个模块首页,这里的return改为break; return nodes; } } } return nodes; } } 看效果:首页节点成功删除。

    2024年12月31日
    76900

Leave a Reply

登录后才能评论