Mybatis generator uses a custom TypeHandler to encrypt and decrypt

Posted by irwa82 on Tue, 21 Dec 2021 17:13:41 +0100

Background: the company needs to encrypt and store some verification codes, and decrypt them when querying.

Initial: in each logic code, the specified field needs to be encrypted when adding or modifying the field. Decrypt the fields during query (disadvantage: poor maintainability)

After improvement: after configuring with mybatis's TypeHandler, the specified field will be encrypted and decrypted automatically.

Let's take a look at the configuration!

1, First, customize a TypeHandler, the BaseTypeHandler I inherited here.

After inheritance, you can override four parent class methods. You can change the logic according to your business requirements (our company is encryption and decryption, and other field operations can be written here)

@MappedJdbcTypes(JdbcType.VARCHAR)
@MappedTypes(value = String.class)
public class SafetyAESTypeHandler extends BaseTypeHandler {

    /**
     * Encrypt when inserting database
     *
     * @param ps
     * @param i
     * @param parameter
     * @param jdbcType
     * @throws SQLException
     */
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, SafetyAESConstant.PREFIX + AESUtils.AESEncode(SafetyAESConstant.aesPassword, (String) parameter));
    }

    /**
     * Decrypt on query
     *
     * @param rs
     * @param columnName
     * @return
     * @throws SQLException
     */
    @Override
    public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String result = rs.getString(columnName);
        if (StringUtils.isNotBlank(result)) {
            if (result.startsWith(SafetyAESConstant.PREFIX)) {
                return AESUtils.AESDncode(SafetyAESConstant.aesPassword, result.substring(SafetyAESConstant.PREFIX_LEN));
            }
        }
        return result;
    }

    /**
     * Decrypt on query
     *
     * @param rs
     * @param columnIndex
     * @return
     * @throws SQLException
     */
    @Override
    public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String result = rs.getString(columnIndex);
        if (StringUtils.isNotBlank(result)) {
            if (result.startsWith(SafetyAESConstant.PREFIX)) {
                return AESUtils.AESDncode(SafetyAESConstant.aesPassword, result.substring(SafetyAESConstant.PREFIX_LEN));
            }
        }
        return result;
    }

    /**
     * Decrypt on query
     *
     * @param cs
     * @param columnIndex
     * @return
     * @throws SQLException
     */
    @Override
    public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String result = cs.getString(columnIndex);
        if (StringUtils.isNotBlank(result)) {
            if (result.startsWith(SafetyAESConstant.PREFIX)) {
                return AESUtils.AESDncode(SafetyAESConstant.aesPassword, result.substring(SafetyAESConstant.PREFIX_LEN));
            }
        }
        return result;
    }

}
 

2, When myabtis automatically generates mapper and other files, configure generatorconfig xml

Add configuration to the fields to be processed

<columnOverride column="old_value" jdbcType="VARCHAR" typeHandler="com.qkwl.service.user.handler.SafetyAESTypeHandler"/>

The typehandler property specifies the typehandler used by the column and configures the fully qualified name of the type processor

<table schema="" tableName="f_user" domainObjectName="UserEntity"
               modelType="flat" mapperName="base.UserBaseMapper"
               enableSelectByPrimaryKey="true" enableSelectByExample="true"
               enableDeleteByPrimaryKey="true" enableDeleteByExample="true"
               enableUpdateByPrimaryKey="true" enableUpdateByExample="true"
               enableCountByExample="true" enableInsert="true">
            <generatedKey column="fid" sqlStatement="MySql" identity="true"/>
            <columnOverride column="fauthenticator" jdbcType="VARCHAR" typeHandler="com.service.user.handler.SafetyAESTypeHandler"/>
            <columnOverride column="furl" jdbcType="VARCHAR" typeHandler="com.service.user.handler.SafetyAESTypeHandler"/>
        </table>

3, After automatic generation, mapper xml

In the field returned in resultMap, typeHandler="com.service.user.handler.SafetyAESTypeHandler" will be brought
<result column="fauthenticator" jdbcType="VARCHAR" property="fauthenticator" typeHandler="com.service.user.handler.SafetyAESTypeHandler" />
    <result column="furl" jdbcType="VARCHAR" property="furl" typeHandler="com.service.user.handler.SafetyAESTypeHandler" />

1. First note

Because sometimes we don't use this operation field from the beginning.

Therefore, many select returns are corresponding entity classes. In this case, this field is not decrypted during query.

Change the resultType used to the field to be customized to resultMap.

2. Second note

We must also pay attention to the insert and update manually added later. Add the typeHandler attribute, otherwise it will not be encrypted and saved. If you need to delete according to this field, you also need to!!

#{fauthenticator,jdbcType=VARCHAR,typeHandler=com.service.user.handler.SafetyAESTypeHandler}

Summary: I feel that it is still very simple to use when developing. However, the person who just took over this module needs to remind him of these configuration problems, otherwise later people don't know why there is no encryption.

If you have any questions, please point them out. Thank you very much!!

Topics: Java