添加ocr识别简历
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
package com.ruoyi.common.annotation;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.ruoyi.common.config.serializer.SensitiveSerialize;
|
||||
import com.ruoyi.common.enums.SensitiveType;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 自定义数据脱敏注解
|
||||
*/
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@JacksonAnnotationsInside
|
||||
@JsonSerialize(using = SensitiveSerialize.class)
|
||||
public @interface CustomSensitive {
|
||||
|
||||
// 脱敏类型
|
||||
SensitiveType type() default SensitiveType.DEFAULT;
|
||||
|
||||
// 自定义前缀保留长度
|
||||
int prefix() default 0;
|
||||
|
||||
// 自定义后缀保留长度
|
||||
int suffix() default 0;
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
package com.ruoyi.common.config.serializer;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.BeanProperty;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
|
||||
import com.ruoyi.common.annotation.CustomSensitive;
|
||||
import com.ruoyi.common.enums.SensitiveType;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 数据回显前端前的数据脱敏序列化实现类
|
||||
*/
|
||||
public class SensitiveSerialize extends JsonSerializer<String> implements ContextualSerializer {
|
||||
|
||||
private SensitiveType type;
|
||||
private int prefix;
|
||||
private int suffix;
|
||||
|
||||
public SensitiveSerialize() {}
|
||||
|
||||
public SensitiveSerialize(SensitiveType type, int prefix, int suffix) {
|
||||
this.type = type;
|
||||
this.prefix = prefix;
|
||||
this.suffix = suffix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers)
|
||||
throws IOException {
|
||||
if (StringUtils.isBlank(value)) {
|
||||
gen.writeString(value);
|
||||
return;
|
||||
}
|
||||
|
||||
String result;
|
||||
switch (type) {
|
||||
case CHINESE_NAME:
|
||||
result = desensitizeChineseName(value);
|
||||
break;
|
||||
case ENGLISH_NAME:
|
||||
result = desensitizeEnglishName(value);
|
||||
break;
|
||||
case ID_CARD:
|
||||
result = desensitizeIdCard(value);
|
||||
break;
|
||||
case PHONE:
|
||||
result = desensitizePhone(value);
|
||||
break;
|
||||
case EMAIL:
|
||||
result = desensitizeEmail(value);
|
||||
break;
|
||||
case BANK_CARD:
|
||||
result = desensitizeBankCard(value);
|
||||
break;
|
||||
case LIVE_ADDRESS:
|
||||
result = desensitizeLiveAddress(value);
|
||||
break;
|
||||
case CUSTOM:
|
||||
result = desensitizeCustom(value, prefix, suffix);
|
||||
break;
|
||||
default:
|
||||
result = desensitizeDefault(value);
|
||||
}
|
||||
gen.writeString(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)
|
||||
throws JsonMappingException
|
||||
{
|
||||
CustomSensitive annotation = property.getAnnotation(CustomSensitive.class);
|
||||
if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass()))
|
||||
{
|
||||
this.type = annotation.type();
|
||||
return this;
|
||||
}
|
||||
return prov.findValueSerializer(property.getType(), property);
|
||||
}
|
||||
|
||||
public String desensitizeChineseName(String name) {
|
||||
if (name.length() <= 1) return name;
|
||||
String str = "";
|
||||
for(int i = 0; i < name.length()-1; i++) {
|
||||
str = str+"*";
|
||||
}
|
||||
return str+name.charAt(name.length()-1);
|
||||
}
|
||||
|
||||
public String desensitizeEnglishName(String fullName) {
|
||||
// 先 trim 再按一个或多个空格分段
|
||||
String[] parts = fullName.trim().split("\\s+");
|
||||
if (parts.length < 2) {
|
||||
return fullName.trim(); // 只有一段,保持原样
|
||||
}
|
||||
// 脱敏第一段
|
||||
String first = parts[0];
|
||||
if (first.length() == 1) {
|
||||
parts[0] = "*"; // 单字符直接变 *
|
||||
} else {
|
||||
char last = first.charAt(first.length() - 1);
|
||||
StringBuilder sb = new StringBuilder(first.length());
|
||||
for (int i = 0; i < first.length() - 1; i++) {
|
||||
sb.append('*');
|
||||
}
|
||||
sb.append(last);
|
||||
parts[0] = sb.toString();
|
||||
}
|
||||
// 用单个空格重新拼接
|
||||
return String.join(" ", parts);
|
||||
}
|
||||
|
||||
public String desensitizeIdCard(String idCard) {
|
||||
String str = "";
|
||||
for (int i = 0; i < idCard.length(); i++) {
|
||||
if(i < 1 || i > idCard.length()-2) {
|
||||
str = str+idCard.charAt(i);
|
||||
}else{
|
||||
str = str+"*";
|
||||
}
|
||||
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public String desensitizePhone(String phone) {
|
||||
String str = "";
|
||||
for (int i = 0; i < phone.length(); i++) {
|
||||
if(i < 3 || i > phone.length()-3) {
|
||||
str = str+phone.charAt(i);
|
||||
}else{
|
||||
str = str+"*";
|
||||
}
|
||||
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public String desensitizeEmail(String email) {
|
||||
int atIndex = email.indexOf("@");
|
||||
if(atIndex > -1){
|
||||
String[] strs = email.split("@");
|
||||
String str = "";
|
||||
for (int i = 0; i < strs[0].length(); i++) {
|
||||
str = str+"*";
|
||||
}
|
||||
str = str+"@"+strs[1];
|
||||
return str;
|
||||
}else{
|
||||
return email;
|
||||
}
|
||||
}
|
||||
|
||||
public String desensitizeBankCard(String bankCard) {
|
||||
String str = "";
|
||||
for (int i = 0; i < bankCard.length(); i++) {
|
||||
if(i > bankCard.length()-5) {
|
||||
str = str+bankCard.charAt(i);
|
||||
}else{
|
||||
str = str+"*";
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public String desensitizeCustom(String value, int prefix, int suffix) {
|
||||
if (value.length() <= prefix + suffix) return value;
|
||||
String prefixStr = value.substring(0, prefix);
|
||||
String suffixStr = suffix > 0 ? value.substring(value.length() - suffix) : "";
|
||||
int maskLength = value.length() - prefix - suffix;
|
||||
String mask = StringUtils.repeat('*', maskLength);
|
||||
return prefixStr + mask + suffixStr;
|
||||
}
|
||||
|
||||
public String desensitizeLiveAddress(String value) {
|
||||
int length = value.length();
|
||||
int num = 0;
|
||||
if(length >= 12){
|
||||
num = 6;
|
||||
}else{
|
||||
num = (int) Math.floor(length/2f);
|
||||
}
|
||||
value = value.substring(0,num)+"********";
|
||||
return value;
|
||||
}
|
||||
|
||||
public String desensitizeDefault(String value) {
|
||||
if (value.length() <= 2){
|
||||
return value.substring(0, 1) + "*";
|
||||
};
|
||||
if(value.length() > 2 && value.length() < 9){
|
||||
return value.substring(0, 1) + "*" + value.substring(value.length() - 1);
|
||||
}
|
||||
if(value.length()%3 == 0){
|
||||
int num = value.length()/3;
|
||||
return value.substring(0, num) + "*" + value.substring(value.length() - num);
|
||||
}else{
|
||||
double num = Math.floor(value.length()/3f);
|
||||
String number = String.format("%.0f",num);
|
||||
return value.substring(0, Integer.parseInt(number)+1) + "*" + value.substring(value.length()-Integer.parseInt(number));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.ruoyi.common.enums;
|
||||
|
||||
/**
|
||||
* 数据脱敏类型枚举
|
||||
*/
|
||||
public enum SensitiveType {
|
||||
|
||||
/**
|
||||
* 默认(缺省值脱敏)
|
||||
*/
|
||||
DEFAULT,
|
||||
/**
|
||||
* 中文名
|
||||
*/
|
||||
CHINESE_NAME,
|
||||
/**
|
||||
* 英文名
|
||||
*/
|
||||
ENGLISH_NAME,
|
||||
/**
|
||||
* 身份证号
|
||||
*/
|
||||
ID_CARD,
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
PHONE,
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
EMAIL,
|
||||
/**
|
||||
* 银行卡
|
||||
*/
|
||||
BANK_CARD,
|
||||
/**
|
||||
* 户籍所在地活现居住地
|
||||
*/
|
||||
LIVE_ADDRESS,
|
||||
/**
|
||||
* 自定义
|
||||
*/
|
||||
CUSTOM
|
||||
|
||||
}
|
||||
@@ -1,8 +1,14 @@
|
||||
package com.ruoyi.common.utils.bean;
|
||||
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -107,4 +113,33 @@ public class BeanUtils extends org.springframework.beans.BeanUtils
|
||||
{
|
||||
return m1.substring(BEAN_METHOD_PROP_INDEX).equals(m2.substring(BEAN_METHOD_PROP_INDEX));
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制属性时忽略空值
|
||||
* @param dest 目标对象
|
||||
* @param src 源对象
|
||||
*/
|
||||
public static void copyPropertiesIgnoreNull(Object dest,Object src) {
|
||||
BeanUtils.copyProperties(src, dest, getNullPropertyNames(src));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取源对象中值为null的属性名数组
|
||||
*/
|
||||
private static String[] getNullPropertyNames(Object source) {
|
||||
final BeanWrapper src = new BeanWrapperImpl(source);
|
||||
PropertyDescriptor[] pds = src.getPropertyDescriptors();
|
||||
|
||||
Set<String> emptyNames = new HashSet<>();
|
||||
for (PropertyDescriptor pd : pds) {
|
||||
// 获取属性值
|
||||
Object srcValue = src.getPropertyValue(pd.getName());
|
||||
if (srcValue == null) {
|
||||
emptyNames.add(pd.getName());
|
||||
}
|
||||
}
|
||||
|
||||
String[] result = new String[emptyNames.size()];
|
||||
return emptyNames.toArray(result);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user