Mybatis custom plug-in and PageHelper conflict resolution and public parameter writing

Accumulate a little every day, and you will succeed another day

catalogue

background

Technical scheme

Technical scheme selection

Implementation steps

Query interceptor

Operation interceptor

public entity

Configuring Interceptors

Query interceptor does not take effect

Problem solving

background

        In some systems, in order to ensure the security of system data storage, some public fields in our system need to be encrypted and stored. When they are read into memory, we need to decrypt them.

Technical scheme

1. Data encryption and decryption during warehousing code and query

2. The persistence layer uses AOP interception to encrypt and decrypt according to public parameters

3. Define your own Mybatis interceptor implementation

Technical scheme selection

1. The code of scheme 1 is relatively coupled, and the main code is relatively repeated

2. The common parameters of the old system are messy and not suitable

3. More suitable; Put the public parameters into the input parameters through the interceptor, decrypt them in SQL, and encrypt them directly in the interceptor when the storage is relatively single.

Implementation steps

Query interceptor

@Intercepts(
        {
                @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),

        }
)
public class GloableParamInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement) args[0];
        Object parameter = args[1];
        //Various processes to be carried out by TODO
        if (!Objects.isNull(parameter)) {
            if (parameter instanceof Map) {
                ((Map) parameter).put("secretKey", "secret key");
            } else if (parameter instanceof Long) {
                Long id = (Long) parameter;
                Map parameters = new HashMap<>();
                parameters.put("id", id);
                parameters.put("secretKey", "secret key");
                args[1] = parameters;
            } else if (parameter instanceof Long) {
                String id = (String) parameter;
                Map parameters = new HashMap<>();
                parameters.put("id", id);
                parameters.put("secretKey", "secret key");
                args[1] = parameters;
            }
        }
        return  invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
    }

}

Note: ParamType in Mybatis Xml configuration cannot be configured with a value, otherwise an error will be reported

Operation interceptor

@Intercepts(
        {
           @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
           @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})

        }
)
public class OPInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        if (!CommonUtils.isNullOrEmpty(args)) {
            for (Object object: args) {
                if (object instanceof CommonVo) {
                    //Encryption processing
                   CommonVo object1 = (CommonVo) object;
                    object1.setName(AesEncode.enCode(object1.getName())) 

                }
            }
        }
        return  invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
    }

public entity

public class CommonVo implements Serializable {
    
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Configuring Interceptors

         There are many kinds of configuration interceptors. I'll just say one here, which is configured through code

@Configuration
public class GlobalVariableConfig {


    @Autowired
    private List<SqlSessionFactory> sqlSessionFactoryList;


    @PostConstruct
    public void addPageInterceptor() {
        GloableParamInterceptor gloableParamInterceptor = new GloableParamInterceptor();
        OpInterceptor opInterceptor = new OpInterceptor ();
        Properties properties = new Properties();
        //First put the properties configured in the general way
        properties.putAll(this.properties.getProperties());
        //When putting in the special configuration, because the attribute name of close conn is close conn instead of closeConn when using the above method, an additional step is required
        pageInterceptor.setProperties(properties);
        for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
            sqlSessionFactory.getConfiguration().addInterceptor(gloableParamInterceptor);
            sqlSessionFactory.getConfiguration().addInterceptor(insertOrUpdataInterceptor);
        }
    }
}

Query interceptor does not take effect

         Through analysis, it is found that there is a conflict between the interceptor and the paging interceptor defined by pagehelper. The paging interceptor is called first, and it does not move down after the call is completed.

In Mybatis, we have this automatic loading during integration:

groupId=com.github.pagehelper
artifactId=pagehelper-spring-boot-autoconfigure

The query interceptor we defined will not take effect

Problem solving

First, close the automatic loading configuration to exclude loading in the receipt

PageHelperAutoConfiguration
@SpringBootApplication(exclude = {PageHelperAutoConfiguration.class})

Modify configuration, copy   Initialize PageHelperAutoConfiguration and load ourselves

@Configuration
@EnableConfigurationProperties({PageHelperProperties.class})
public class GlobalVariableConfig {


    @Autowired
    private List<SqlSessionFactory> sqlSessionFactoryList;
    @Autowired
    private PageHelperProperties properties;
    /**
     * Accept additional properties of the paging plug-in
     *
     * @return
     */
    @Bean
    @ConfigurationProperties(prefix = "pagehelper")
    public Properties pageHelperProperties() {
        return new Properties();
    }

    @PostConstruct
    public void addPageInterceptor() {
        GloableParamInterceptor gloableParamInterceptor = new GloableParamInterceptor();
        PageInterceptor pageInterceptor = new PageInterceptor();
        OpInterceptor opInterceptor = new OpInterceptor();
        Properties properties = new Properties();
        //First put the properties configured in the general way
        properties.putAll(pageHelperProperties());
        properties.putAll(this.properties.getProperties());
        //When putting in the special configuration, because the attribute name of close conn is close conn instead of closeConn when using the above method, an additional step is required
        pageInterceptor.setProperties(properties);
        for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
            sqlSessionFactory.getConfiguration().addInterceptor(pageInterceptor);
            sqlSessionFactory.getConfiguration().addInterceptor(gloableParamInterceptor);
            sqlSessionFactory.getConfiguration().addInterceptor(opInterceptor );
        }
    }
}

Test effectiveness

Tags: Java JavaEE Spring jar

Posted on Fri, 03 Dec 2021 00:53:37 -0500 by cheshil