描述整体流程

  1. 加密工具类实现(加密时通过前缀判断兼容已加密未加密数据) 设置秘钥
  2. 处理器继承重写类型处理器父类-非空存加密&非空查加密方法重写
  3. 实体类字段指定类型处理器
  4. 数据库表结构字段长度放大
  5. 梳理加密字段作为查询条件的需要调用加密方法
  6. 自己定义业务实现, 调用数据更新同步加密旧数据. 反射注解判断类属性列表中存在注解TableField(属性typeHandler instance Of EncryptHandler.class))

借鉴文档

https://sq.sf.163.com/blog/article/177903091005186048
https://sq.sf.163.com/blog/article/175742652561199104

编码应用

设置秘钥

fwc.sm4Key = "xhx$weo@810)Jo18"

加密工具类实现(加密时通过前缀判断兼容已加密未加密数据)


/**
 * @Author: 达文西(俊)
 * @Date: 2023/02/16
 * @Description:
 */
@Component
public class SM4Util {
    @Value("${fwc.sm4Key:xhx$weo@810)Jo18}")
    private String sm4Key;
    private static String SM4_KEY;
    public static final String DEFAULT_KEY = "xhx$weo@810)Jo18";

    @PostConstruct
    public void getSM4_KEY() {
        SM4_KEY = this.sm4Key;
    }

    /**
     * 密文前缀
     * 通过密文前缀判断内容是否被加密
     */
    public static final String PREFIX = "PWD:";


    /**
     * SM4加密
     *
     * @param value
     * @return
     */
    public static String encrypt(String value) {
        if (!StringUtils.hasText(value)) {
            return value;
        }
        if (value.startsWith(PREFIX)) {
            return value;
        }
        String encryptHex = null;
        String key = StringUtils.hasText(SM4_KEY) ? SM4_KEY : DEFAULT_KEY;
        if (key.length() != 16) {
            throw new RuntimeException("密钥长度必须是16位");
        }
        try {
            SymmetricCrypto sm4 = SmUtil.sm4(key.getBytes());
            encryptHex = sm4.encryptHex(value);
        } catch (Exception e) {
            throw new RuntimeException("加密失败:" + e.getMessage());
        }
        return PREFIX + encryptHex;
    }


    /**
     * SM4解密
     *
     * @param value
     * @return
     */
    public static String decrypt(String value) {
        if (!StringUtils.hasText(value)) {
            return value;
        }
        if (!value.startsWith(PREFIX)) {
            return value;
        }
        String decryptStr = null;
        String key = StringUtils.hasText(SM4_KEY) ? SM4_KEY : DEFAULT_KEY;
        if (key.length() != 16) {
            throw new RuntimeException("密钥长度必须是16位");
        }
        try {
            SymmetricCrypto sm4 = SmUtil.sm4(key.getBytes());
            value = value.substring(PREFIX.length());
            decryptStr = sm4.decryptStr(value, CharsetUtil.CHARSET_UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("解密失败:" + e.getMessage());
        }
        return decryptStr;
    }

}

处理器继承重写类型处理器父类-非空存加密&非空查加密方法重写==>

/**
 * @Author:  达文西(俊)
 * @Date: 2023/02/22
 * @Description: 加密入库,解密查询
 */
@MappedJdbcTypes(JdbcType.VARCHAR)
public class EncryptHandler extends BaseTypeHandler<String> {
    /**
     * 入库加密
     * @param ps
     * @param i
     * @param parameter
     * @param jdbcType
     * @throws SQLException
     */
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        if (StringUtils.isEmpty(parameter)) {
            ps.setString(i, null);
            return;
        }
        ps.setString(i, SM4Util.encrypt(parameter));
    }

    /**
     * 查询解密
     * @param rs
     *          the rs
     * @param columnName
     *          Column name, when configuration <code>useColumnLabel</code> is <code>false</code>
     * @return
     * @throws SQLException
     */
    @Override
    public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return SM4Util.decrypt(rs.getString(columnName));
    }

    @Override
    public String getResult(ResultSet rs, int columnIndex) throws SQLException {
        return SM4Util.decrypt(rs.getString(columnIndex));
    }

    @Override
    public String getResult(CallableStatement cs, int columnIndex) throws SQLException {
        return SM4Util.decrypt(cs.getString(columnIndex));
    }

    @Override
    public String getResult(ResultSet rs, String columnName) throws SQLException {
        return SM4Util.decrypt(rs.getString(columnName));
    }

    @Override
    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return SM4Util.decrypt(rs.getString(columnIndex));
    }

    @Override
    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return SM4Util.decrypt(cs.getString(columnIndex));
    }
}

实体类字段指定类型处理器==>

@TableField(typeHandler = EncryptHandler.class)

梳理加密字段作为查询条件,的需要调用加密方法==>

this.lambdaQuery()
        .eq(PatientCardBind::getOpenUserId,openUserID)
        .eq(PatientCardBind::getIdCard,SM4Util.encrypt(openIDCard))
        .eq(PatientCardBind::getStatus,0)
        .eq(PatientCardBind::getCardProperty, 2)
        .eq(ObjectUtil.isNotEmpty(patientName), PatientCardBind::getPatientName, SM4Util.encrypt(patientName.toString()))
        .list();
/**
 * @Author: 达文西
 * @Date: 2023/03/22
 * @Description: 批量处理加密数据
 */
@Slf4j
@RestController
@RequestMapping("/encrypt")
public class EncryptedDataController {
    private final EncryptedDataService encryptedDataService;

    public EncryptedDataController(EncryptedDataService encryptedDataService) {
        this.encryptedDataService = encryptedDataService;
    }


    @PostMapping("/batchProcessEncrypted")
    public ResultDTO batchProcessEncryptedData() {
        Boolean result = false;
        try {
            result = encryptedDataService.batchProcessEncryptedData();
        } catch (Exception ex) {
            log.error("更新加密数据失败,异常信息:{}", ex.getMessage());
            if (ex instanceof BadSqlGrammarException || ex instanceof DataIntegrityViolationException) {
                return new ResultDTO<>(ResultCodeEnum.SQL_FAILURE.getCode(), ResultCodeEnum.SQL_FAILURE.getMsg());
            }
            return new ResultDTO<>(ResultCodeEnum.OTHER_FAIL.getCode(), ResultCodeEnum.OTHER_FAIL.getMsg());
        }
        return new ResultDTO<>(result);
    }
}
/**
 * @Author: 达文西
 * @Date: 2023/03/22
 * @Description: 加密数据处理service层
 */
public interface EncryptedDataService {
    /**
     * 批量处理患者表订单表未加密数据
     * @return
     */
    Boolean batchProcessEncryptedData();
}
@Slf4j
@Service("encryptedDataServiceImpl")
@Transactional(rollbackFor = Exception.class)
public class EncryptedDataServiceImpl implements EncryptedDataService {
    
    /**
     * 批量处理患者表订单表未加密数据
     *
     * @return
     */
    @Override
    public Boolean batchProcessEncryptedData() {
        //查询未加密的数据
        List<PatientCardBind> patientCardBindList = new ArrayList<>();
        this.updatePatientUnencrypted(patientCardBindList);
        int patientResult = 1;
        serviceImpl.updateBatch(patientCardBindList);
        if (patientCardBindList.size() > 0) {
            log.info("更新加密用户数据共【{}】条", patientCardBindList.size());
        }
        return patientResult > 0;
    }


    /**
     * 更新患者未加密数据
     *
     * @param patientCardBindList
     */
    private void updatePatientUnencrypted(List<PatientCardBind> patientCardBindList) {
        for (PatientCardBind patientCardBind : patientCardBindList) {
            //判断源数据是否需要加密,如果未加密则进行加密否则不做更改
            Object obj = patientCardBind;
			patientCardBind = (patientCardBind) reflectionSettingSncrypted(obj);
        }
        }
        }

反射判断属性列表中存在注解TableField ,进行加密赋值

Object obj = tradeOrder;
tradeOrder = (TradeOrder) reflectionSettingSncrypted(obj);

private Object reflectionSettingSncrypted(Object obj) throws IllegalAccessException {
Field[] declaredFields = obj.getClass().getDeclaredFields();
for (Field declaredField : declaredFields) {
    TableField annotation = declaredField.getAnnotation(TableField.class);
    Class<? extends TypeHandler> aClass = annotation.typeHandler();
    Class<? extends TypeHandler> bClass = EncryptHandler.class;
    //这里对比可能有些问题
    if (aClass == bClass) {
        String field_value = SM4Util.encrypt(declaredField.get(obj).toString());
        declaredField.set(obj,field_value);
    }
}
return obj;
}
Logo

数据库是今天社会发展不可缺少的重要技术,它可以把大量的信息进行有序的存储和管理,为企业的数据处理提供了强大的保障。

更多推荐