数据脱敏sensitive(前端或数据库加密,解密)

可以对数据加密,解密,对数据库加密的数据进行解密显示,对数据库没有加密的数据进行加密处理展示前端等待

1:引入数据如下结构

在这里插入图片描述

1-1:SensitiveDecode脱敏解密注解

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-2:SensitiveEncode脱敏加密注解

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-3:SensitiveField字段注解

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-4:SensitiveDataAspect敏感数据切面处理类

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(encode==null){SensitiveDecode decode = method.getAnnotation(SensitiveDecode.class);if(decode!=null){entity = decode.entity();isEncode = false;}}else{entity = encode.entity();}long startTime=System.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 endTime=System.currentTimeMillis();log.info((isEncode ? "加密操作," : "解密操作,") + "Aspect程序耗时:" + (endTime - startTime) + "ms");return result;}}

1-5:SensitiveEnum

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-6:AesEncryptUtil加密工具类

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 = "4I80+jJsZ/aR+n+MsRd7qw==";String key =  KEY;String iv = IV;String jiemi =desEncrypt(data, key, iv).trim();System.out.println("解密:"+jiemi);String aa="1234567897891";String encrypt = SecureUtil.aes(key.getBytes()).encryptBase64(aa);String s = SecureUtil.aes(key.getBytes()).decryptStr(encrypt);System.out.println("");}
}

1-7:EncryptedString

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-8:CommonConstant通用常量

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-9:oConvertUtils

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;Enumeration<NetworkInterface> netInterfaces = NetworkInterface.getNetworkInterfaces();InetAddress ip = null;// 是否找到外网IPboolean finded = false;while (netInterfaces.hasMoreElements() && !finded) {NetworkInterface ni = netInterfaces.nextElement();Enumeration<InetAddress> 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 Map<Object, Object> getHashMap() {return new HashMap<>(5);}/*** SET转换MAP* * @param str* @return*/public static Map<Object, Object> setToMap(Set<Object> setobj) {Map<Object, Object> map = getHashMap();for (Iterator iterator = setobj.iterator(); iterator.hasNext();) {Map.Entry<Object, Object> entry = (Map.Entry<Object, 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);/*** 私有IP:A类 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 for:TASK #2500 【代码生成器】代码生成器开发一通用模板生成功能//update-begin--Author:zhoujf  Date:20180503 for:TASK #2500 【代码生成器】代码生成器开发一通用模板生成功能return name.substring(0, 1).toLowerCase() + name.substring(1).toLowerCase();//update-end--Author:zhoujf  Date:20180503 for:TASK #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(names==null||"".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 for:TASK #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 for:TASK #2500 【代码生成器】代码生成器开发一通用模板生成功能/*** 将驼峰命名转化成下划线* @param para* @return*/public static String camelToUnderline(String para){int length = 3;if(para.length()<length){return para.toLowerCase(); }StringBuilder sb=new StringBuilder(para);//定位int temp=0;//从第三个字符开始 避免命名不规范 for(int i=2;i<para.length();i++){if(Character.isUpperCase(para.charAt(i))){sb.insert(i+temp, "_");temp+=1;}}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 i=0;i<place;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();List<Field> 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 List<Map<String, Object>> toLowerCasePageList(List<Map<String, Object>> list){List<Map<String, Object>> select = new ArrayList<>();for (Map<String, Object> row : list) {Map<String, Object> resultMap = new HashMap<>(5);Set<String> 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 static<F,T> List<T> entityListToModelList(List<F> fromList, Class<T> tClass){if(fromList == null || fromList.isEmpty()){return null;}List<T> tList = new ArrayList<>();for(F f : fromList){T t = entityToModel(f, tClass);tList.add(t);}return tList;}public static<F,T> T entityToModel(F entity, Class<T> 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-10:SensitiveInfoUtil

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 startTime=System.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(realValue==null || "".equals(realValue)){continue;}SensitiveField sf = field.getAnnotation(SensitiveField.class);if(isEncode==true){//加密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 endTime=System.currentTimeMillis();//log.info((isEncode ? "加密操作," : "解密操作,") + "当前程序耗时:" + (endTime - startTime) + "ms");return obj;}/*** 处理 List<实体>* @param obj* @param entity* @param isEncode(true: 加密操作 / 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 i=0; i<list.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(len<11){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(len<sensitiveSize){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-11:SymbolConstant

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的依赖

<dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.2.6.RELEASE</version>
</dependency>
<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version>
</dependency>
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.10</version>
</dependency>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/68862.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

将 Python 与 RStudio IDE 配合使用(R与Python系列第一篇)

目录 前言&#xff1a; 1-安装reticulate包 2-安装Python 3-选择Python的默认版本&#xff08;配置Python环境&#xff09; 4-使用Python 4.1 运行一个简单的Python脚本 4.2 在RStudio上安装Python模块 4.3 在 R 中调用 Python 模块 4.4 在RStudio上调用Python脚本写的…

vue前端解决跨域

1,首先 axios请求&#xff0c;看后端接口路径&#xff0c;http://122.226.146.110:25002/api/xx/ResxxList&#xff0c;所以baseURL地址改成 ‘/api’ let setAxios originAxios.create({baseURL: /api, //这里要改掉timeout: 20000 // request timeout}); export default s…

【C++ 二叉搜索树】

目录 1.什么是二叉搜索树2.构建二叉搜索树2.1首先搭建树的框架2.2搭建搜索树的框架 3.二叉搜索树的插入3.1非递归式插入3.2递归式插入 4.二叉搜索树的查找4.1非递归查找4.2递归查找 5.二叉搜索树的删除5.1非递归删除5.2递归删除 6.整个代码实现 1.什么是二叉搜索树 简单来讲就…

NSSCTF web 刷题记录1

文章目录 前言题目[GXYCTF 2019]禁止套娃方法一方法二 [NCTF 2019]Fake XML cookbook[NSSRound#7 Team]ec_RCE[NCTF 2018]Flask PLUS 前言 今天是2023.9.3&#xff0c;大二开学前的最后一天。老实说ctf的功力还是不太够做的题目太少&#xff0c;新学期新气象。不可急于求成&am…

设置 Hue Server 与 Hue Web 界面之间的会话超时时间

设置 Hue Server 与 Hue Web 界面之间的会话超时时间 在 CDH 的 Hue 中&#xff0c;Auto Logout Timeout 参数表示用户在不活动一段时间后将自动注销&#xff08;登出&#xff09;的超时时间。当用户在 Hue 中处于不活动状态超过该设定时间时&#xff0c;系统将自动注销用户&am…

FreeRTOS中断与任务之间同步(Error:..\..\FreeRTOS\portable\RVDS\ARM_CM4F\port.c,422 )

前言&#xff1a; FreeRTOS中&#xff0c;中断需要注意几点&#xff1a; 何时使用中断&#xff1b;中断服务函数&#xff08;ISR&#xff09;要处理的数据量有多大&#xff0c;通常我们希望中断的切换越快越好&#xff0c;也就是说&#xff0c;ISR尽量采用耗时较少的处理方式…

撮合前端平台在低代码平台的落地实践 | 京东云技术团队

在京东技术的发展当下&#xff0c;不同的业务线&#xff0c;不同的区域&#xff0c;甚至于很多触达消费者的端&#xff0c;正在被中台架构能力所支撑。大家都很清楚&#xff0c;中台建设能够带来技术的规模化效应&#xff0c;具有提高业务协同、加速创新和交付速度、提高系统稳…

Java问题诊断和排查工具

文章目录 一、前言二、Java问题诊断和排查工具1、JDK自带工具2、常用命令3、JAVA Dump&#xff1a;3.1、jps3.2、jstack3.3、jmap3.3.1、jmap -heap pid:查看堆使用情况3.3.2、jmap -histo pid&#xff1a;查看堆中对象数量和大小3.3.3、jmap -dump:formatb,fileheapdump pid&a…

K8S的介绍和架构

仅供入门 K8S的介绍和架构 一. 什么是kubernetes二、Kubernetes架构和组件 2.1 核心组件 2.1.1 Kubernetes Master控制组件&#xff0c;调度管理整个系统&#xff08;集群&#xff09;&#xff0c;包含如下组件: a、Kubernetes API Serverb、Kubernetes Schedulerc、Kubernet…

springboot自动装配原理,手写一个starter。

文章目录 springboot自动装配原理手写starter手写starter总结&#xff1a; springboot自动装配原理 口述&#xff1a; springboot自动装配的话它其实就是只需要我们添加一个starter起步依赖&#xff0c;它就能完成这个依赖组件相关Bean的自动注入&#xff0c;其实就是自动的将…

SpringMVC的工作流程及入门

目录 一、概述 ( 1 ) 是什么 ( 2 ) 作用 二、工作流程 ( 1 ) 流程 ( 2 ) 步骤 三、入门实例 ( 1 ) 入门实例 ( 2 ) 静态资源处理 给我们带来的收获 一、概述 ( 1 ) 是什么 SpringMVC是一个基于Java的Web应用开发框架&#xff0c;它是Spring Framework的一部…

5.bs4的基本使用

bs4是python的一个第三方库&#xff0c;用来做数据解析的 目录 1 安装bs4 2 解析本地的html文件 3 解析网上的html 4 找到指定的标签 4.1 获取页面中第一个指定标签的内容 4.2 查找页面中的第一个符合要求的内容 BeautifulSoup.find() 4.2.1 标签 4.2.2 类名 …

Linux--进程概念

1.什么是程序&#xff1f;什么是进程&#xff1f;有什么区别&#xff1f; 程序&#xff1a;是静态的概念&#xff0c;gcc xxx.c -o pro 磁盘中生成的pro文件&#xff0c;叫做程序。 进程&#xff1a;是程序的一种与运行活动&#xff0c;通俗的意思是程序跑起来了&#xff0c;系…

linux免密登录最简单--图文详解

最简单的免密登录 1.A电脑生成秘钥 ssh-keygen -t rsa 2.A电脑将秘钥传给B电脑 ssh-copy-id root192.168.1.129 #将秘钥直接传给B电脑 需要输入B电脑的密码&#xff0c;可以看到成功。 3.测试 同理&#xff1a;如果B->A也需要免密登录&#xff0c;统一的操作。 大功告…

PHP8的数组-PHP8知识详解

今天开始学习数组&#xff0c; 本文主要讲了三点&#xff1a;什么是数组、php8中数组的改进、数组函数。 一、什么是数组 在PHP8中&#xff0c;数组是非常重要的数据类型。相对于其他的数据类型&#xff0c;数组更像一种结构&#xff0c;而这种结构可以储存一系列数值。 数组…

【SpringSecurity】八、集成图片验证码

文章目录 1、生成图片验证码2、创建验证码过滤器3、将过滤器加入SpringSecurity过滤链4、修改登录页 SpringSecurity是通过过滤器链来完成的&#xff0c;接下来的验证码&#xff0c;可以尝试创建一个过滤器放到Security的过滤器链中&#xff0c;在自定义的过滤器中比较验证码。…

90、00后严选出的数据可视化工具:奥威BI工具

90、00后主打一个巧用工具&#xff0c;绝不低效率上班&#xff0c;因此当擅长大数据智能可视化分析的BI数据可视化工具出现后&#xff0c;自然而然地就成了90、00后职场人常用的数据可视化工具。 奥威BI工具三大特点&#xff0c;让职场人眼前一亮&#xff01; 1、零编程&…

医学影像工作站PACS系统源码,医院PACS系统源码

医学影像(PACS)系统主要进行病人信息和影像的获取、处理、存储、调阅、检索、管理&#xff0c;并通过网络向全院提供病人检查影像及诊断报告&#xff1b;各影像科室之间共享不同设备的病人检查影像及诊断报告&#xff1b;在诊断工作站上&#xff0c;调阅HIS中病人的其它信息&am…

Android架构 架构和 CPU ABI - NDK

查看设备架构 adb -s emulator-5554 shell getprop ro.product.cpu.abi C:\Users\liyd>adb -s emulator-5554 shell getprop ro.product.cpu.abi x86_64C:\Users\liyd>adb -s 804c11f1 shell getprop ro.product.cpu.abi arm64-v8amumu模拟器12 C:\Users\liyd>adb …

ElasticSearch入门

一、基本命令_cat 1、查看节点信息 http://192.168.101.132:9200/_cat/nodes2、查看健康状况 http://192.168.101.132:9200/_cat/health3、查看主节点的信息 http://192.168.101.132:9200/_cat/master4、查看所有索引 http://192.168.101.132:9200/_cat/indices二、索引一…