添加ocr识别简历

This commit is contained in:
sh
2026-02-04 10:55:14 +08:00
parent 9d0ff4cbf7
commit f7f31ae0fa
10 changed files with 707 additions and 0 deletions

View File

@@ -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;
}

View File

@@ -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));
}
}
}

View File

@@ -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
}

View File

@@ -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);
}
}