zoukankan      html  css  js  c++  java
  • mybatis拦截器修改相应参数

    最近在做一个对特定的执行参数进行值加密的功能,mybatis本身提供了Interceptor拦截器接口,可以去修改sql的执行内容。

    参考:

    https://www.cnblogs.com/luoxn28/p/6417892.html

    https://blog.csdn.net/luanlouis/article/details/40422941

    https://blog.csdn.net/hfmbook/article/details/41985853

    https://blog.csdn.net/Mr_SeaTurtle_/article/details/73053103

    https://blog.csdn.net/isea533/article/details/44002219

    https://www.cnblogs.com/linkstar/p/6039513.html

    https://www.cnblogs.com/liu-s/p/8000293.html

    原理就是获取StatementHandler,然后获取BoundSql,然后修改参数。

    这里需要注意的就是:对于集合参数的操作,会放到BoundSql的additionalParameters里面

    BoundSql.java  源码

    /**
     *    Copyright 2009-2017 the original author or authors.
     *
     *    Licensed under the Apache License, Version 2.0 (the "License");
     *    you may not use this file except in compliance with the License.
     *    You may obtain a copy of the License at
     *
     *       http://www.apache.org/licenses/LICENSE-2.0
     *
     *    Unless required by applicable law or agreed to in writing, software
     *    distributed under the License is distributed on an "AS IS" BASIS,
     *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     *    See the License for the specific language governing permissions and
     *    limitations under the License.
     */
    package org.apache.ibatis.mapping;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.apache.ibatis.reflection.MetaObject;
    import org.apache.ibatis.reflection.property.PropertyTokenizer;
    import org.apache.ibatis.session.Configuration;
    
    /**
     * An actual SQL String got from an {@link SqlSource} after having processed any dynamic content.
     * The SQL may have SQL placeholders "?" and an list (ordered) of an parameter mappings 
     * with the additional information for each parameter (at least the property name of the input object to read 
     * the value from). 
     * </br>
     * Can also have additional parameters that are created by the dynamic language (for loops, bind...).
     *
     * @author Clinton Begin
     */
    public class BoundSql {
    
      private final String sql;
     //参数 --- key的map集合
    private final List<ParameterMapping> parameterMappings;
     //参数对象
    private final Object parameterObject;
     //额外的参数,不是直接写到mybatis mapper文件的参数,list集合的每个item参数 其动态生成规则为 _frcn_{自定义item名称}_{index}
    private final Map<String, Object> additionalParameters; private final MetaObject metaParameters; public BoundSql(Configuration configuration, String sql, List<ParameterMapping> parameterMappings, Object parameterObject) { this.sql = sql; this.parameterMappings = parameterMappings; this.parameterObject = parameterObject; this.additionalParameters = new HashMap<String, Object>(); this.metaParameters = configuration.newMetaObject(additionalParameters); } public String getSql() { return sql; } public List<ParameterMapping> getParameterMappings() { return parameterMappings; } public Object getParameterObject() { return parameterObject; } public boolean hasAdditionalParameter(String name) { String paramName = new PropertyTokenizer(name).getName(); return additionalParameters.containsKey(paramName); } public void setAdditionalParameter(String name, Object value) { metaParameters.setValue(name, value); } public Object getAdditionalParameter(String name) { return metaParameters.getValue(name); } }

    拦截器主要拦截statementHandler.class的prepare方法

    StatementHandler.java 接口源码  

    /**
     *    Copyright 2009-2016 the original author or authors.
     *
     *    Licensed under the Apache License, Version 2.0 (the "License");
     *    you may not use this file except in compliance with the License.
     *    You may obtain a copy of the License at
     *
     *       http://www.apache.org/licenses/LICENSE-2.0
     *
     *    Unless required by applicable law or agreed to in writing, software
     *    distributed under the License is distributed on an "AS IS" BASIS,
     *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     *    See the License for the specific language governing permissions and
     *    limitations under the License.
     */
    package org.apache.ibatis.executor.statement;
    
    import java.sql.Connection;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.List;
    
    import org.apache.ibatis.cursor.Cursor;
    import org.apache.ibatis.executor.parameter.ParameterHandler;
    import org.apache.ibatis.mapping.BoundSql;
    import org.apache.ibatis.session.ResultHandler;
    
    /**
     * @author Clinton Begin
     */
    public interface StatementHandler {
    
      Statement prepare(Connection connection, Integer transactionTimeout)
          throws SQLException;
    
      void parameterize(Statement statement)
          throws SQLException;
    
      void batch(Statement statement)
          throws SQLException;
    
      int update(Statement statement)
          throws SQLException;
    
      <E> List<E> query(Statement statement, ResultHandler resultHandler)
          throws SQLException;
    
      <E> Cursor<E> queryCursor(Statement statement)
          throws SQLException;
    
      BoundSql getBoundSql();
    
      ParameterHandler getParameterHandler();
    
    }

    BaseStatementHandler.java 源码

    /**
     *    Copyright 2009-2016 the original author or authors.
     *
     *    Licensed under the Apache License, Version 2.0 (the "License");
     *    you may not use this file except in compliance with the License.
     *    You may obtain a copy of the License at
     *
     *       http://www.apache.org/licenses/LICENSE-2.0
     *
     *    Unless required by applicable law or agreed to in writing, software
     *    distributed under the License is distributed on an "AS IS" BASIS,
     *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     *    See the License for the specific language governing permissions and
     *    limitations under the License.
     */
    package org.apache.ibatis.executor.statement;
    
    import java.sql.Connection;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    import org.apache.ibatis.executor.ErrorContext;
    import org.apache.ibatis.executor.Executor;
    import org.apache.ibatis.executor.ExecutorException;
    import org.apache.ibatis.executor.keygen.KeyGenerator;
    import org.apache.ibatis.executor.parameter.ParameterHandler;
    import org.apache.ibatis.executor.resultset.ResultSetHandler;
    import org.apache.ibatis.mapping.BoundSql;
    import org.apache.ibatis.mapping.MappedStatement;
    import org.apache.ibatis.reflection.factory.ObjectFactory;
    import org.apache.ibatis.session.Configuration;
    import org.apache.ibatis.session.ResultHandler;
    import org.apache.ibatis.session.RowBounds;
    import org.apache.ibatis.type.TypeHandlerRegistry;
    
    /**
     * @author Clinton Begin
     */
    public abstract class BaseStatementHandler implements StatementHandler {
    
      protected final Configuration configuration;
      protected final ObjectFactory objectFactory;
      protected final TypeHandlerRegistry typeHandlerRegistry;
      protected final ResultSetHandler resultSetHandler;
      protected final ParameterHandler parameterHandler;
    
      protected final Executor executor;
      protected final MappedStatement mappedStatement;
      protected final RowBounds rowBounds;
    
      protected BoundSql boundSql;
    
      protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        this.configuration = mappedStatement.getConfiguration();
        this.executor = executor;
        this.mappedStatement = mappedStatement;
        this.rowBounds = rowBounds;
    
        this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
        this.objectFactory = configuration.getObjectFactory();
    
        if (boundSql == null) { // issue #435, get the key before calculating the statement
          generateKeys(parameterObject);
          boundSql = mappedStatement.getBoundSql(parameterObject);
        }
    
        this.boundSql = boundSql;
    
        this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
        this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
      }
    
      @Override
      public BoundSql getBoundSql() {
        return boundSql;
      }
    
      @Override
      public ParameterHandler getParameterHandler() {
        return parameterHandler;
      }
    
      @Override
      public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
        ErrorContext.instance().sql(boundSql.getSql());
        Statement statement = null;
        try {
          statement = instantiateStatement(connection);
          setStatementTimeout(statement, transactionTimeout);
          setFetchSize(statement);
          return statement;
        } catch (SQLException e) {
          closeStatement(statement);
          throw e;
        } catch (Exception e) {
          closeStatement(statement);
          throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
        }
      }
    
      protected abstract Statement instantiateStatement(Connection connection) throws SQLException;
    
      protected void setStatementTimeout(Statement stmt, Integer transactionTimeout) throws SQLException {
        Integer queryTimeout = null;
        if (mappedStatement.getTimeout() != null) {
          queryTimeout = mappedStatement.getTimeout();
        } else if (configuration.getDefaultStatementTimeout() != null) {
          queryTimeout = configuration.getDefaultStatementTimeout();
        }
        if (queryTimeout != null) {
          stmt.setQueryTimeout(queryTimeout);
        }
        StatementUtil.applyTransactionTimeout(stmt, queryTimeout, transactionTimeout);
      }
    
      protected void setFetchSize(Statement stmt) throws SQLException {
        Integer fetchSize = mappedStatement.getFetchSize();
        if (fetchSize != null) {
          stmt.setFetchSize(fetchSize);
          return;
        }
        Integer defaultFetchSize = configuration.getDefaultFetchSize();
        if (defaultFetchSize != null) {
          stmt.setFetchSize(defaultFetchSize);
        }
      }
    
      protected void closeStatement(Statement statement) {
        try {
          if (statement != null) {
            statement.close();
          }
        } catch (SQLException e) {
          //ignore
        }
      }
    
      protected void generateKeys(Object parameter) {
        KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
        ErrorContext.instance().store();
        keyGenerator.processBefore(executor, mappedStatement, null, parameter);
        ErrorContext.instance().recall();
      }
    
    }

    自定义拦截器

    package com.j1cn.poc.interceptor;
    
    import com.flysand.utils.AesUtils;
    import org.apache.ibatis.executor.statement.StatementHandler;
    import org.apache.ibatis.mapping.BoundSql;
    import org.apache.ibatis.mapping.ParameterMapping;
    import org.apache.ibatis.mapping.ParameterMode;
    import org.apache.ibatis.plugin.*;
    
    import java.sql.Connection;
    import java.util.List;
    import java.util.Properties;
    
    /**
     * @author flysand on 2018/07/06
     **/
    
    @Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
    public class PrepareInterceptor implements Interceptor {
    
        private String key;
    
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
            //获取statementHandler
            StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
            //获取绑定sql
            BoundSql boundSql = statementHandler.getBoundSql();
    
            //获取参数
            List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
            //筛选动态list参数,并加密后重新赋值
            for (int i = 0; i < parameterMappings.size(); i++) {
                ParameterMapping parameterMapping = parameterMappings.get(i);
                if (parameterMapping.getMode() != ParameterMode.OUT) {
                    Object value;
                    String propertyName = parameterMapping.getProperty();
                    if (boundSql.hasAdditionalParameter(propertyName)) {
                        value = boundSql.getAdditionalParameter(propertyName);
                //可根据需求自定义加密规则,这里使用aes加密 另外可以对参数进行自定义配置,如:只有某种规则的参数才进行修改 String encryptValue
    = AesUtils.encrypt(value.toString(), this.key); boundSql.setAdditionalParameter(propertyName, encryptValue); } } } return invocation.proceed(); } @Override public Object plugin(Object target) { if (target instanceof StatementHandler) { return Plugin.wrap(target, this); } else { return target; } } @Override public void setProperties(Properties properties) { this.key = properties.getProperty("key"); } }

    需要把自定义拦截器加入到mybatis配置文件的plugins节点下。

    mybatis-config.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <settings>
            <setting name="cacheEnabled" value="true"/>
            <setting name="lazyLoadingEnabled" value="true"/>
            <setting name="multipleResultSetsEnabled" value="true"/>
            <setting name="useColumnLabel" value="true"/>
            <setting name="useGeneratedKeys" value="true"/>
            <setting name="defaultExecutorType" value="SIMPLE"/>
            <setting name="defaultStatementTimeout" value="25000"/>
        </settings>
        <plugins>
            <plugin interceptor="com.j1cn.poc.dal.PrepareInterceptor">
                <property name="key" value="123456"/>
            </plugin>
        </plugins>
    </configuration>
  • 相关阅读:
    CentOS7.6下安装qt-creator
    chromedriver下载地址
    selenium 基于Autolt工具对于Windows窗口上传文件操作
    Selenium+java
    jmeter删除历史打开的脚本记录
    echarts 各种特效图
    SpringBoot启动-问题解决:Could not locate executable nullinwinutils.exe in the Hadoop binaries
    pinyin4j
    JMeter内存溢出:java.lang.OutOfMemoryError: Java heap space解决方法
    selenium自动化测试中升级chrome78版本带来的问题
  • 原文地址:https://www.cnblogs.com/flysand/p/9274997.html
Copyright © 2011-2022 走看看