怎么做查询网站吗,上传文件网站,做食品行业网站,袜子技术支持北京网站建设可以对数据加密#xff0c;解密#xff0c;对数据库加密的数据进行解密显示#xff0c;对数据库没有加密的数据进行加密处理展示前端等待 1#xff1a;引入数据如下结构 1-1#xff1a;SensitiveDecode脱敏解密注解
package com.example.poi.desensitization.annotation;… 可以对数据加密解密对数据库加密的数据进行解密显示对数据库没有加密的数据进行加密处理展示前端等待 1引入数据如下结构 1-1SensitiveDecode脱敏解密注解
package com.example.poi.desensitization.annotation;import java.lang.annotation.*;/*** 脱敏解密注解* Author xu* create 2023/9/4 19*/
Documented
Retention(RetentionPolicy.RUNTIME)
Target({ElementType.METHOD})
public interface SensitiveDecode {/*** 指明需要脱敏的实体类class* return*/Class entity() default Object.class;
} 1-2SensitiveEncode脱敏加密注解
package com.example.poi.desensitization.annotation;import java.lang.annotation.*;/*** 脱敏加密注解* Author xu* create 2023/9/4 19*/
Documented
Retention(RetentionPolicy.RUNTIME)
Target({ElementType.METHOD})
public interface SensitiveEncode {/*** 指明需要脱敏的实体类class* return*/Class entity() default Object.class;
} 1-3SensitiveField字段注解
package com.example.poi.desensitization.annotation;import com.example.poi.desensitization.enums.SensitiveEnum;import java.lang.annotation.*;/*** 字段上定义标识字段存储的信息是敏感的* Author xu* create 2023/9/4 19*/
Documented
Retention(RetentionPolicy.RUNTIME)
Target(ElementType.FIELD)
public interface SensitiveField {/*** 不同类型处理不同* return*/SensitiveEnum type() default SensitiveEnum.ENCODE;
} 1-4SensitiveDataAspect敏感数据切面处理类
package com.example.poi.desensitization.aspect;import com.example.poi.desensitization.annotation.SensitiveDecode;
import com.example.poi.desensitization.annotation.SensitiveEncode;
import com.example.poi.desensitization.utils.SensitiveInfoUtil;
import lombok.extern.slf4j.Slf4j;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;
import java.util.List;/*** 敏感数据切面处理类* Author xu* create 2023/9/4 20*/
Slf4j
Aspect
Component
public class SensitiveDataAspect {/*** 定义切点Pointcut*/Pointcut(annotation(com.example.poi.desensitization.annotation.SensitiveEncode) || annotation(com.example.poi.desensitization.annotation.SensitiveDecode))public void sensitivePointCut() {}Around(sensitivePointCut())public Object around(ProceedingJoinPoint point) throws Throwable {// 处理结果Object result point.proceed();if(result null){return result;}Class resultClass result.getClass();log.debug( resultClass {} , resultClass);if(resultClass.isPrimitive()){//是基本类型 直接返回 不需要处理return result;}// 获取方法注解信息是哪个实体、是加密还是解密boolean isEncode true;Class entity null;MethodSignature methodSignature (MethodSignature) point.getSignature();Method method methodSignature.getMethod();SensitiveEncode encode method.getAnnotation(SensitiveEncode.class);if(encodenull){SensitiveDecode decode method.getAnnotation(SensitiveDecode.class);if(decode!null){entity decode.entity();isEncode false;}}else{entity encode.entity();}long startTimeSystem.currentTimeMillis();if(resultClass.equals(entity) || entity.equals(Object.class)){// 方法返回实体和注解的entity一样如果注解没有申明entity属性则认为是(方法返回实体和注解的entity一样)SensitiveInfoUtil.handlerObject(result, isEncode);} else if(result instanceof List){// 方法返回List实体SensitiveInfoUtil.handleList(result, entity, isEncode);}else{// 方法返回一个对象SensitiveInfoUtil.handleNestedObject(result, entity, isEncode);}long endTimeSystem.currentTimeMillis();log.info((isEncode ? 加密操作 : 解密操作) Aspect程序耗时 (endTime - startTime) ms);return result;}}1-5SensitiveEnum
package com.example.poi.desensitization.enums;/*** 敏感字段信息类型* Author xu* create 2023/9/4 19*/
public enum SensitiveEnum {/*** 加密*/ENCODE,/*** 中文名*/CHINESE_NAME,/*** 身份证号*/ID_CARD,/*** 座机号*/FIXED_PHONE,/*** 手机号*/MOBILE_PHONE,/*** 地址*/ADDRESS,/*** 电子邮件*/EMAIL,/*** 银行卡*/BANK_CARD,/*** 公司开户银行联号*/CNAPS_CODE;} 1-6AesEncryptUtil加密工具类
package com.example.poi.desensitization.utils.encryption;import cn.hutool.core.codec.Base64;
import cn.hutool.crypto.SecureUtil;
//import org.apache.shiro.codec.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;/*** Description: AES 加密* Author xu* create 2023/9/4 19*/
public class AesEncryptUtil {/*** 使用AES-128-CBC加密模式 key和iv可以相同*/private static String KEY EncryptedString.key;private static String IV EncryptedString.iv;/*** 加密方法* param data 要加密的数据* param key 加密key* param iv 加密iv* return 加密的结果* throws Exception*/public static String encrypt(String data, String key, String iv) throws Exception {try {//算法/模式/补码方式NoPadding PkcsPaddingCipher cipher Cipher.getInstance(AES/CBC/NoPadding);int blockSize cipher.getBlockSize();byte[] dataBytes data.getBytes();int plaintextLength dataBytes.length;if (plaintextLength % blockSize ! 0) {plaintextLength plaintextLength (blockSize - (plaintextLength % blockSize));}byte[] plaintext new byte[plaintextLength];System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);SecretKeySpec keyspec new SecretKeySpec(key.getBytes(), AES);IvParameterSpec ivspec new IvParameterSpec(iv.getBytes());cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);byte[] encrypted cipher.doFinal(plaintext);return Base64.encode(encrypted);//return Base64.encodeToString(encrypted);} catch (Exception e) {e.printStackTrace();return null;}}/*** 解密方法* param data 要解密的数据* param key 解密key* param iv 解密iv* return 解密的结果* throws Exception*/public static String desEncrypt(String data, String key, String iv) throws Exception {//update-begin-author:taoyan date:2022-5-23 for:VUEN-1084 【vue3】online表单测试发现的新问题 6、解密报错 ---解码失败应该把异常抛出去在外面处理byte[] encrypted1 Base64.decode(data);Cipher cipher Cipher.getInstance(AES/CBC/NoPadding);SecretKeySpec keyspec new SecretKeySpec(key.getBytes(), AES);IvParameterSpec ivspec new IvParameterSpec(iv.getBytes());cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);byte[] original cipher.doFinal(encrypted1);String originalString new String(original);//加密解码后的字符串会出现\u0000return originalString.replaceAll(\\u0000, );//update-end-author:taoyan date:2022-5-23 for:VUEN-1084 【vue3】online表单测试发现的新问题 6、解密报错 ---解码失败应该把异常抛出去在外面处理}/*** 使用默认的key和iv加密* param data* return* throws Exception*/public static String encrypt(String data) throws Exception {return encrypt(data, KEY, IV);}/*** 使用默认的key和iv解密* param data* return* throws Exception*/public static String desEncrypt(String data) throws Exception {return desEncrypt(data, KEY, IV);}/*** 测试*/public static void main(String args[]) throws Exception {String test1 sa;String test new String(test1.getBytes(),UTF-8);String data 4I80jJsZ/aRnMsRd7qw;String key KEY;String iv IV;String jiemi desEncrypt(data, key, iv).trim();System.out.println(解密jiemi);String aa1234567897891;String encrypt SecureUtil.aes(key.getBytes()).encryptBase64(aa);String s SecureUtil.aes(key.getBytes()).decryptStr(encrypt);System.out.println();}
}1-7EncryptedString
package com.example.poi.desensitization.utils.encryption;import lombok.Data;/*** 秘钥和偏移量* Author xu* create 2023/9/4 19*/
Data
public class EncryptedString {/*** 长度为16个字符*/public static String key 1234567890adbcde;/*** 长度为16个字符*/public static String iv 1234567890hjlkew;
} 1-8CommonConstant通用常量
package com.example.poi.desensitization.utils;/*** Description: 通用常量* Author xu* create 2023/9/4 19*/
public interface CommonConstant {/*** 未知的*/String UNKNOWN unknown;/*** String 类型的空值*/String STRING_NULL null;} 1-9oConvertUtils
package com.example.poi.desensitization.utils;import lombok.extern.slf4j.Slf4j;import org.apache.commons.io.IOUtils;
import org.springframework.beans.BeanUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.sql.Date;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;Slf4j
public class oConvertUtils {public static boolean isEmpty(Object object) {if (object null) {return (true);}if (.equals(object)) {return (true);}if (CommonConstant.STRING_NULL.equals(object)) {return (true);}return (false);}public static boolean isNotEmpty(Object object) {if (object ! null !.equals(object) !object.equals(CommonConstant.STRING_NULL)) {return (true);}return (false);}public static String decode(String strIn, String sourceCode, String targetCode) {String temp code2code(strIn, sourceCode, targetCode);return temp;}SuppressWarnings(AlibabaLowerCamelCaseVariableNaming)public static String StrToUTF(String strIn, String sourceCode, String targetCode) {strIn ;try {strIn new String(strIn.getBytes(ISO-8859-1), GBK);} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();}return strIn;}private static String code2code(String strIn, String sourceCode, String targetCode) {String strOut null;if (strIn null || .equals(strIn.trim())) {return strIn;}try {byte[] b strIn.getBytes(sourceCode);for (int i 0; i b.length; i) {System.out.print(b[i] );}strOut new String(b, targetCode);} catch (Exception e) {e.printStackTrace();return null;}return strOut;}public static int getInt(String s, int defval) {if (s null || s ) {return (defval);}try {return (Integer.parseInt(s));} catch (NumberFormatException e) {return (defval);}}public static int getInt(String s) {if (s null || s ) {return 0;}try {return (Integer.parseInt(s));} catch (NumberFormatException e) {return 0;}}public static int getInt(String s, Integer df) {if (s null || s ) {return df;}try {return (Integer.parseInt(s));} catch (NumberFormatException e) {return 0;}}public static Integer[] getInts(String[] s) {if (s null) {return null;}Integer[] integer new Integer[s.length];for (int i 0; i s.length; i) {integer[i] Integer.parseInt(s[i]);}return integer;}public static double getDouble(String s, double defval) {if (s null || s ) {return (defval);}try {return (Double.parseDouble(s));} catch (NumberFormatException e) {return (defval);}}public static double getDou(Double s, double defval) {if (s null) {return (defval);}return s;}/*public static Short getShort(String s) {if (StringUtil.isNotEmpty(s)) {return (Short.parseShort(s));} else {return null;}}*/public static int getInt(Object object, int defval) {if (isEmpty(object)) {return (defval);}try {return (Integer.parseInt(object.toString()));} catch (NumberFormatException e) {return (defval);}}public static Integer getInt(Object object) {if (isEmpty(object)) {return null;}try {return (Integer.parseInt(object.toString()));} catch (NumberFormatException e) {return null;}}public static int getInt(BigDecimal s, int defval) {if (s null) {return (defval);}return s.intValue();}public static Integer[] getIntegerArry(String[] object) {int len object.length;Integer[] result new Integer[len];try {for (int i 0; i len; i) {result[i] new Integer(object[i].trim());}return result;} catch (NumberFormatException e) {return null;}}public static String getString(String s) {return (getString(s, ));}/*** 转义成Unicode编码* param s* return*//*public static String escapeJava(Object s) {return StringEscapeUtils.escapeJava(getString(s));}*/public static String getString(Object object) {if (isEmpty(object)) {return ;}return (object.toString().trim());}public static String getString(int i) {return (String.valueOf(i));}public static String getString(float i) {return (String.valueOf(i));}public static String getString(String s, String defval) {if (isEmpty(s)) {return (defval);}return (s.trim());}public static String getString(Object s, String defval) {if (isEmpty(s)) {return (defval);}return (s.toString().trim());}public static long stringToLong(String str) {Long test new Long(0);try {test Long.valueOf(str);} catch (Exception e) {}return test.longValue();}/*** 获取本机IP*/public static String getIp() {String ip null;try {InetAddress address InetAddress.getLocalHost();ip address.getHostAddress();} catch (UnknownHostException e) {e.printStackTrace();}return ip;}/*** 判断一个类是否为基本数据类型。* * param clazz* 要判断的类。* return true 表示为基本数据类型。*/private static boolean isBaseDataType(Class clazz) throws Exception {return (clazz.equals(String.class) || clazz.equals(Integer.class) || clazz.equals(Byte.class) || clazz.equals(Long.class) || clazz.equals(Double.class) || clazz.equals(Float.class) || clazz.equals(Character.class) || clazz.equals(Short.class) || clazz.equals(BigDecimal.class) || clazz.equals(BigInteger.class) || clazz.equals(Boolean.class) || clazz.equals(Date.class) || clazz.isPrimitive());}/*** param request* IP* return IP Address*/public static String getIpAddrByRequest(HttpServletRequest request) {String ip request.getHeader(x-forwarded-for);if (ip null || ip.length() 0 || CommonConstant.UNKNOWN.equalsIgnoreCase(ip)) {ip request.getHeader(Proxy-Client-IP);}if (ip null || ip.length() 0 || CommonConstant.UNKNOWN.equalsIgnoreCase(ip)) {ip request.getHeader(WL-Proxy-Client-IP);}if (ip null || ip.length() 0 || CommonConstant.UNKNOWN.equalsIgnoreCase(ip)) {ip request.getRemoteAddr();}return ip;}/*** return 本机IP* throws SocketException*/public static String getRealIp() throws SocketException {// 本地IP如果没有配置外网IP则返回它String localip null;// 外网IPString netip null;EnumerationNetworkInterface netInterfaces NetworkInterface.getNetworkInterfaces();InetAddress ip null;// 是否找到外网IPboolean finded false;while (netInterfaces.hasMoreElements() !finded) {NetworkInterface ni netInterfaces.nextElement();EnumerationInetAddress address ni.getInetAddresses();while (address.hasMoreElements()) {ip address.nextElement();// 外网IPif (!ip.isSiteLocalAddress() !ip.isLoopbackAddress() ip.getHostAddress().indexOf(:) -1) {netip ip.getHostAddress();finded true;break;} else if (ip.isSiteLocalAddress() !ip.isLoopbackAddress() ip.getHostAddress().indexOf(:) -1) {// 内网IPlocalip ip.getHostAddress();}}}if (netip ! null !.equals(netip)) {return netip;} else {return localip;}}/*** java去除字符串中的空格、回车、换行符、制表符* * param str* return*/public static String replaceBlank(String str) {String dest ;if (str ! null) {String reg \\s*|\t|\r|\n;Pattern p Pattern.compile(reg);Matcher m p.matcher(str);dest m.replaceAll();}return dest;}/*** 判断元素是否在数组内* * param substring* param source* return*/public static boolean isIn(String substring, String[] source) {if (source null || source.length 0) {return false;}for (int i 0; i source.length; i) {String aSource source[i];if (aSource.equals(substring)) {return true;}}return false;}/*** 获取Map对象*/public static MapObject, Object getHashMap() {return new HashMap(5);}/*** SET转换MAP* * param str* return*/public static MapObject, Object setToMap(SetObject setobj) {MapObject, Object map getHashMap();for (Iterator iterator setobj.iterator(); iterator.hasNext();) {Map.EntryObject, Object entry (Map.EntryObject, Object) iterator.next();map.put(entry.getKey().toString(), entry.getValue() null ? : entry.getValue().toString().trim());}return map;}public static boolean isInnerIp(String ipAddress) {boolean isInnerIp false;long ipNum getIpNum(ipAddress);/*** 私有IPA类 10.0.0.0-10.255.255.255 B类 172.16.0.0-172.31.255.255 C类 192.168.0.0-192.168.255.255 当然还有127这个网段是环回地址**/long aBegin getIpNum(10.0.0.0);long aEnd getIpNum(10.255.255.255);long bBegin getIpNum(172.16.0.0);long bEnd getIpNum(172.31.255.255);long cBegin getIpNum(192.168.0.0);long cEnd getIpNum(192.168.255.255);String localIp 127.0.0.1;isInnerIp isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd) || localIp.equals(ipAddress);return isInnerIp;}private static long getIpNum(String ipAddress) {String[] ip ipAddress.split(\\.);long a Integer.parseInt(ip[0]);long b Integer.parseInt(ip[1]);long c Integer.parseInt(ip[2]);long d Integer.parseInt(ip[3]);long ipNum a * 256 * 256 * 256 b * 256 * 256 c * 256 d;return ipNum;}private static boolean isInner(long userIp, long begin, long end) {return (userIp begin) (userIp end);}/*** 将下划线大写方式命名的字符串转换为驼峰式。* 如果转换前的下划线大写方式命名的字符串为空则返回空字符串。/br* 例如hello_world-helloWorld* * param name* 转换前的下划线大写方式命名的字符串* return 转换后的驼峰式命名的字符串*/public static String camelName(String name) {StringBuilder result new StringBuilder();// 快速检查if (name null || name.isEmpty()) {// 没必要转换return ;} else if (!name.contains(SymbolConstant.UNDERLINE)) {// 不含下划线仅将首字母小写//update-begin--Author:zhoujf Date:20180503 forTASK #2500 【代码生成器】代码生成器开发一通用模板生成功能//update-begin--Author:zhoujf Date:20180503 forTASK #2500 【代码生成器】代码生成器开发一通用模板生成功能return name.substring(0, 1).toLowerCase() name.substring(1).toLowerCase();//update-end--Author:zhoujf Date:20180503 forTASK #2500 【代码生成器】代码生成器开发一通用模板生成功能}// 用下划线将原始字符串分割String[] camels name.split(_);for (String camel : camels) {// 跳过原始字符串中开头、结尾的下换线或双重下划线if (camel.isEmpty()) {continue;}// 处理真正的驼峰片段if (result.length() 0) {// 第一个驼峰片段全部字母都小写result.append(camel.toLowerCase());} else {// 其他的驼峰片段首字母大写result.append(camel.substring(0, 1).toUpperCase());result.append(camel.substring(1).toLowerCase());}}return result.toString();}/*** 将下划线大写方式命名的字符串转换为驼峰式。* 如果转换前的下划线大写方式命名的字符串为空则返回空字符串。/br* 例如hello_world,test_id-helloWorld,testId* * param names* 转换前的下划线大写方式命名的字符串* return 转换后的驼峰式命名的字符串*/public static String camelNames(String names) {if(namesnull||.equals(names)){return null;}StringBuffer sf new StringBuffer();String[] fs names.split(,);for (String field : fs) {field camelName(field);sf.append(field ,);}String result sf.toString();return result.substring(0, result.length() - 1);}//update-begin--Author:zhoujf Date:20180503 forTASK #2500 【代码生成器】代码生成器开发一通用模板生成功能/*** 将下划线大写方式命名的字符串转换为驼峰式。(首字母写)* 如果转换前的下划线大写方式命名的字符串为空则返回空字符串。/br* 例如hello_world-HelloWorld* * param name* 转换前的下划线大写方式命名的字符串* return 转换后的驼峰式命名的字符串*/public static String camelNameCapFirst(String name) {StringBuilder result new StringBuilder();// 快速检查if (name null || name.isEmpty()) {// 没必要转换return ;} else if (!name.contains(SymbolConstant.UNDERLINE)) {// 不含下划线仅将首字母小写return name.substring(0, 1).toUpperCase() name.substring(1).toLowerCase();}// 用下划线将原始字符串分割String[] camels name.split(_);for (String camel : camels) {// 跳过原始字符串中开头、结尾的下换线或双重下划线if (camel.isEmpty()) {continue;}// 其他的驼峰片段首字母大写result.append(camel.substring(0, 1).toUpperCase());result.append(camel.substring(1).toLowerCase());}return result.toString();}//update-end--Author:zhoujf Date:20180503 forTASK #2500 【代码生成器】代码生成器开发一通用模板生成功能/*** 将驼峰命名转化成下划线* param para* return*/public static String camelToUnderline(String para){int length 3;if(para.length()length){return para.toLowerCase(); }StringBuilder sbnew StringBuilder(para);//定位int temp0;//从第三个字符开始 避免命名不规范 for(int i2;ipara.length();i){if(Character.isUpperCase(para.charAt(i))){sb.insert(itemp, _);temp1;}}return sb.toString().toLowerCase(); }/*** 随机数* param place 定义随机数的位数*/public static String randomGen(int place) {String base qwertyuioplkjhgfdsazxcvbnmQAZWSXEDCRFVTGBYHNUJMIKLOP0123456789;StringBuffer sb new StringBuffer();Random rd new Random();for(int i0;iplace;i) {sb.append(base.charAt(rd.nextInt(base.length())));}return sb.toString();}/*** 获取类的所有属性包括父类* * param object* return*/public static Field[] getAllFields(Object object) {Class? clazz object.getClass();ListField fieldList new ArrayList();while (clazz ! null) {fieldList.addAll(new ArrayList(Arrays.asList(clazz.getDeclaredFields())));clazz clazz.getSuperclass();}Field[] fields new Field[fieldList.size()];fieldList.toArray(fields);return fields;}/*** 将map的key全部转成小写* param list* return*/public static ListMapString, Object toLowerCasePageList(ListMapString, Object list){ListMapString, Object select new ArrayList();for (MapString, Object row : list) {MapString, Object resultMap new HashMap(5);SetString keySet row.keySet(); for (String key : keySet) { String newKey key.toLowerCase(); resultMap.put(newKey, row.get(key)); }select.add(resultMap);}return select;}/*** 将entityList转换成modelList* param fromList* param tClass* param F* param T* return*/public staticF,T ListT entityListToModelList(ListF fromList, ClassT tClass){if(fromList null || fromList.isEmpty()){return null;}ListT tList new ArrayList();for(F f : fromList){T t entityToModel(f, tClass);tList.add(t);}return tList;}public staticF,T T entityToModel(F entity, ClassT modelClass) {log.debug(entityToModel : Entity属性的值赋值到Model);Object model null;if (entity null || modelClass null) {return null;}try {model modelClass.newInstance();} catch (InstantiationException e) {log.error(entityToModel : 实例化异常, e);} catch (IllegalAccessException e) {log.error(entityToModel : 安全权限异常, e);}BeanUtils.copyProperties(entity, model);return (T)model;}/*** 判断 list 是否为空** param list* return true or false* list null : true* list.size() 0 : true*/public static boolean listIsEmpty(Collection list) {return (list null || list.size() 0);}/*** 判断 list 是否不为空** param list* return true or false* list null : false* list.size() 0 : false*/public static boolean listIsNotEmpty(Collection list) {return !listIsEmpty(list);}/*** 读取静态文本内容* param url* return*/public static String readStatic(String url) {String json ;try {//换个写法解决springboot读取jar包中文件的问题InputStream stream oConvertUtils.class.getClassLoader().getResourceAsStream(url.replace(classpath:, ));json IOUtils.toString(stream,UTF-8);} catch (IOException e) {log.error(e.getMessage(),e);}return json;}
} 1-10SensitiveInfoUtil
package com.example.poi.desensitization.utils;import com.example.poi.desensitization.enums.SensitiveEnum;
import com.example.poi.desensitization.annotation.SensitiveField;
import com.example.poi.desensitization.utils.encryption.AesEncryptUtil;
import lombok.extern.slf4j.Slf4j;import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.Collections;
import java.util.List;/*** Author xu* create 2023/9/4 20*/
Slf4j
public class SensitiveInfoUtil {/*** 处理嵌套对象* param obj 方法返回值* param entity 实体class* param isEncode 是否加密true: 加密操作 / false:解密操作* throws IllegalAccessException*/public static void handleNestedObject(Object obj, Class entity, boolean isEncode) throws IllegalAccessException {Field[] fields obj.getClass().getDeclaredFields();for (Field field : fields) {if(field.getType().isPrimitive()){continue;}if(field.getType().equals(entity)){// 对象里面是实体field.setAccessible(true);Object nestedObject field.get(obj);handlerObject(nestedObject, isEncode);break;}else{// 对象里面是List实体if(field.getGenericType() instanceof ParameterizedType){ParameterizedType pt (ParameterizedType)field.getGenericType();if(pt.getRawType().equals(List.class)){if(pt.getActualTypeArguments()[0].equals(entity)){field.setAccessible(true);Object nestedObject field.get(obj);handleList(nestedObject, entity, isEncode);break;}}}}}}/*** 处理Object* param obj 方法返回值* param isEncode 是否加密true: 加密操作 / false:解密操作* return* throws IllegalAccessException*/public static Object handlerObject(Object obj, boolean isEncode) throws IllegalAccessException {log.debug( obj -- obj.toString());long startTimeSystem.currentTimeMillis();if (oConvertUtils.isEmpty(obj)) {return obj;}// 判断是不是一个对象Field[] fields obj.getClass().getDeclaredFields();for (Field field : fields) {boolean isSensitiveField field.isAnnotationPresent(SensitiveField.class);if(isSensitiveField){// 必须有SensitiveField注解 才作处理if(field.getType().isAssignableFrom(String.class)){//必须是字符串类型 才作处理field.setAccessible(true);String realValue (String) field.get(obj);if(realValuenull || .equals(realValue)){continue;}SensitiveField sf field.getAnnotation(SensitiveField.class);if(isEncodetrue){//加密String value SensitiveInfoUtil.getEncodeData(realValue, sf.type());field.set(obj, value);}else{//解密只处理 encode类型的if(sf.type().equals(SensitiveEnum.ENCODE)){String value SensitiveInfoUtil.getDecodeData(realValue);field.set(obj, value);}}}}}//long endTimeSystem.currentTimeMillis();//log.info((isEncode ? 加密操作 : 解密操作) 当前程序耗时 (endTime - startTime) ms);return obj;}/*** 处理 List实体* param obj* param entity* param isEncodetrue: 加密操作 / false:解密操作*/public static void handleList(Object obj, Class entity, boolean isEncode){List list (List)obj;if(list.size()0){Object first list.get(0);if(first.getClass().equals(entity)){for(int i0; ilist.size(); i){Object temp list.get(i);try {handlerObject(temp, isEncode);} catch (IllegalAccessException e) {e.printStackTrace();}}}}}/*** 处理数据 获取解密后的数据* param data* return*/public static String getDecodeData(String data){String result null;try {result AesEncryptUtil.desEncrypt(data);} catch (Exception exception) {log.debug(数据解密错误原数据:data);}//解决debug模式下加解密失效导致中文被解密变成空的问题if(oConvertUtils.isEmpty(result) oConvertUtils.isNotEmpty(data)){result data;}return result;}/*** 处理数据 获取加密后的数据 或是格式化后的数据* param data 字符串* param sensitiveEnum 类型* return 处理后的字符串*/public static String getEncodeData(String data, SensitiveEnum sensitiveEnum){String result;switch (sensitiveEnum){case ENCODE:try {result AesEncryptUtil.encrypt(data);} catch (Exception exception) {log.error(数据加密错误, exception.getMessage());result data;}break;case CHINESE_NAME:result chineseName(data);break;case ID_CARD:result idCardNum(data);break;case FIXED_PHONE:result fixedPhone(data);break;case MOBILE_PHONE:result mobilePhone(data);break;case ADDRESS:result address(data, 3);break;case EMAIL:result email(data);break;case BANK_CARD:result bankCard(data);break;case CNAPS_CODE:result cnapsCode(data);break;default:result data;}return result;}/*** [中文姓名] 只显示第一个汉字其他隐藏为2个星号* param fullName 全名* return 例子李***/private static String chineseName(String fullName) {if (oConvertUtils.isEmpty(fullName)) {return ;}return formatRight(fullName, 1);}/*** [中文姓名] 只显示第一个汉字其他隐藏为2个星号* param familyName 姓* param firstName 名* return 例子李***/private static String chineseName(String familyName, String firstName) {if (oConvertUtils.isEmpty(familyName) || oConvertUtils.isEmpty(firstName)) {return ;}return chineseName(familyName firstName);}/*** [身份证号] 显示最后四位其他隐藏。共计18位或者15位。* param id 身份证号* return 例子*************5762*/private static String idCardNum(String id) {if (oConvertUtils.isEmpty(id)) {return ;}return formatLeft(id, 4);}/*** [固定电话] 后四位其他隐藏* param num 固定电话* return 例子****1234*/private static String fixedPhone(String num) {if (oConvertUtils.isEmpty(num)) {return ;}return formatLeft(num, 4);}/*** [手机号码] 前三位后四位其他隐藏* param num 手机号码* return 例子:138******1234*/private static String mobilePhone(String num) {if (oConvertUtils.isEmpty(num)) {return ;}int len num.length();if(len11){return num;}return formatBetween(num, 3, 4);}/*** [地址] 只显示到地区不显示详细地址我们要对个人信息增强保护* param address 地址* param sensitiveSize 敏感信息长度* return 例子北京市海淀区*****/private static String address(String address, int sensitiveSize) {if (oConvertUtils.isEmpty(address)) {return ;}int len address.length();if(lensensitiveSize){return address;}return formatRight(address, sensitiveSize);}/*** [电子邮箱] 邮箱前缀仅显示第一个字母前缀其他隐藏用星号代替及后面的地址显示* param email 电子邮箱* return 例子:g**163.com*/private static String email(String email) {if (oConvertUtils.isEmpty(email)) {return ;}int index email.indexOf();if (index 1){return email;}String begin email.substring(0, 1);String end email.substring(index);String stars **;return begin stars end;}/*** [银行卡号] 前六位后四位其他用星号隐藏每位1个星号* param cardNum 银行卡号* return 例子:6222600**********1234*/private static String bankCard(String cardNum) {if (oConvertUtils.isEmpty(cardNum)) {return ;}return formatBetween(cardNum, 6, 4);}/*** [公司开户银行联号] 公司开户银行联行号,显示前两位其他用星号隐藏每位1个星号* param code 公司开户银行联号* return 例子:12*********/private static String cnapsCode(String code) {if (oConvertUtils.isEmpty(code)) {return ;}return formatRight(code, 2);}/*** 将右边的格式化成** param str 字符串* param reservedLength 保留长度* return 格式化后的字符串*/private static String formatRight(String str, int reservedLength){String name str.substring(0, reservedLength);String stars String.join(, Collections.nCopies(str.length()-reservedLength, *));return name stars;}/*** 将左边的格式化成** param str 字符串* param reservedLength 保留长度* return 格式化后的字符串*/private static String formatLeft(String str, int reservedLength){int len str.length();String show str.substring(len-reservedLength);String stars String.join(, Collections.nCopies(len-reservedLength, *));return stars show;}/*** 将中间的格式化成** param str 字符串* param beginLen 开始保留长度* param endLen 结尾保留长度* return 格式化后的字符串*/private static String formatBetween(String str, int beginLen, int endLen){int len str.length();String begin str.substring(0, beginLen);String end str.substring(len-endLen);String stars String.join(, Collections.nCopies(len-beginLen-endLen, *));return begin stars end;}} 1-11SymbolConstant
package com.example.poi.desensitization.utils;/*** Description: 符号和特殊符号常用类* Author xu* create 2023/9/4 19*/
public class SymbolConstant {/*** 符号点*/public static final String SPOT .;/*** 符号双斜杠*/public static final String DOUBLE_BACKSLASH \\;/*** 符号冒号*/public static final String COLON :;/*** 符号逗号*/public static final String COMMA ,;/*** 符号左花括号 }*/public static final String LEFT_CURLY_BRACKET {;/*** 符号右花括号 }*/public static final String RIGHT_CURLY_BRACKET };/*** 符号井号 #*/public static final String WELL_NUMBER #;/*** 符号单斜杠*/public static final String SINGLE_SLASH /;/*** 符号双斜杠*/public static final String DOUBLE_SLASH //;/*** 符号感叹号*/public static final String EXCLAMATORY_MARK !;/*** 符号下划线*/public static final String UNDERLINE _;/*** 符号单引号*/public static final String SINGLE_QUOTATION_MARK ;/*** 符号星号*/public static final String ASTERISK *;/*** 符号百分号*/public static final String PERCENT_SIGN %;/*** 符号美元 $*/public static final String DOLLAR $;/*** 符号和 */public static final String AND ;/*** 符号../*/public static final String SPOT_SINGLE_SLASH ../;/*** 符号..\\*/public static final String SPOT_DOUBLE_BACKSLASH ..\\;/*** 系统变量前缀 #{*/public static final String SYS_VAR_PREFIX #{;/*** 符号 {{*/public static final String DOUBLE_LEFT_CURLY_BRACKET {{;/*** 符号[*/public static final String SQUARE_BRACKETS_LEFT [;/*** 符号]*/public static final String SQUARE_BRACKETS_RIGHT ];}2必须导入的POM的依赖
dependencygroupIdorg.springframework/groupIdartifactIdspring-aspects/artifactIdversion5.2.6.RELEASE/version
/dependency
dependencygroupIdcommons-io/groupIdartifactIdcommons-io/artifactIdversion2.6/version
/dependency
dependencygroupIdcn.hutool/groupIdartifactIdhutool-all/artifactIdversion5.7.10/version
/dependency