一、代码示例
此示例实现包含四个核心部分:
Dict
注解:用于标记需要转换的字段DictAspect
切面:自动拦截 Controller 返回结果并进行字典值转换User
实体类:演示如何使用注解UserController
:提供测试接口
使用时,只需在需要进行字典转换的字段上添加@Dict
注解,并指定字典类型。切面会自动将数值转换为对应的文本描述,并存储在指定的目标字段中。
//Dict.java
import java.lang.annotation.*;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Dict {
/**
* 字典类型
*/
String type();
/**
* 字典项文本存储字段
*/
String target() default "";
}
//DictAspect.java
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
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.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.*;
@Aspect
@Component
public class DictAspect {
// 定义切点:拦截所有Controller类中的方法
@Pointcut("execution(* com.example.demo.controller.*.*(..))")
public void controllerPointcut() {}
@Around("controllerPointcut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
// 执行原方法获取返回值
Object result = point.proceed();
// 处理返回值,进行字典值转换
processDict(result);
return result;
}
// 处理字典转换的核心方法
private void processDict(Object obj) {
if (obj == null) {
return;
}
// 处理集合类型
if (obj instanceof Collection) {
for (Object item : (Collection<?>) obj) {
if (item != null) {
processObjectDict(item);
}
}
}
// 处理数组类型
else if (obj.getClass().isArray()) {
Object[] array = (Object[]) obj;
for (Object item : array) {
if (item != null) {
processObjectDict(item);
}
}
}
// 处理单个对象
else {
processObjectDict(obj);
}
}
// 处理单个对象的字典转换
private void processObjectDict(Object obj) {
Class<?> clazz = obj.getClass();
// 遍历对象的所有字段
for (Field field : clazz.getDeclaredFields()) {
// 判断字段是否有@Dict注解
Dict dictAnnotation = field.getAnnotation(Dict.class);
if (dictAnnotation != null) {
try {
field.setAccessible(true);
Object fieldValue = field.get(obj);
if (fieldValue == null) {
continue;
}
// 获取字典类型和目标字段
String dictType = dictAnnotation.dictType();
String targetField = dictAnnotation.targetField();
// 根据字典类型获取对应的文本描述
String dictText = getDictText(dictType, fieldValue.toString());
// 设置转换后的文本到目标字段
if (dictText != null && !"".equals(dictText)) {
String targetFieldName = targetField;
if ("".equals(targetFieldName)) {
targetFieldName = field.getName() + "Text";
}
// 使用反射设置目标字段的值
setFieldValue(obj, targetFieldName, dictText);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 递归处理对象的嵌套属性
for (Field field : clazz.getDeclaredFields()) {
try {
field.setAccessible(true);
Object fieldValue = field.get(obj);
if (fieldValue != null) {
// 排除基本数据类型和字符串
if (!isPrimitiveOrString(field.getType())) {
processDict(fieldValue);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 根据字典类型和值获取对应的文本描述
private String getDictText(String dictType, String dictValue) {
// 这里应该从数据库或缓存中获取字典数据
// 为简化示例,我们使用硬编码的字典数据
Map<String, Map<String, String>> dictMap = new HashMap<>();
// 性别字典
Map<String, String> genderDict = new HashMap<>();
genderDict.put("1", "男");
genderDict.put("2", "女");
genderDict.put("3", "未知");
// 用户状态字典
Map<String, String> statusDict = new HashMap<>();
statusDict.put("0", "禁用");
statusDict.put("1", "启用");
statusDict.put("2", "锁定");
dictMap.put("gender", genderDict);
dictMap.put("status", statusDict);
// 根据字典类型获取对应的字典项
Map<String, String> dictItems = dictMap.get(dictType);
if (dictItems != null) {
return dictItems.get(dictValue);
}
return null;
}
// 使用反射设置对象字段的值
private void setFieldValue(Object obj, String fieldName, Object value) {
Class<?> clazz = obj.getClass();
try {
// 查找目标字段
Field targetField = null;
try {
targetField = clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
// 如果找不到字段,则尝试查找父类
Class<?> superClass = clazz.getSuperclass();
if (superClass != null && !superClass.equals(Object.class)) {
targetField = superClass.getDeclaredField(fieldName);
}
}
if (targetField != null) {
targetField.setAccessible(true);
// 类型转换
if (value instanceof String) {
if (targetField.getType() == Integer.class || targetField.getType() == int.class) {
value = Integer.valueOf((String) value);
} else if (targetField.getType() == Long.class || targetField.getType() == long.class) {
value = Long.valueOf((String) value);
}
}
targetField.set(obj, value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 判断是否为基本数据类型或字符串
private boolean isPrimitiveOrString(Class<?> clazz) {
return clazz.isPrimitive() ||
clazz == String.class ||
clazz == Integer.class ||
clazz == Long.class ||
clazz == Boolean.class ||
clazz == Double.class ||
clazz == Float.class ||
clazz == Short.class ||
clazz == Byte.class;
}
}
//User.java
public class User {
private String id;
private String name;
@Dict(type = "gender")
private String gender;
private String genderText; // 存储性别文本
@Dict(type = "status", target = "statusDesc")
private String status;
private String statusDesc; // 存储状态描述
// getters and setters
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getGender() { return gender; }
public void setGender(String gender) { this.gender = gender; }
public String getGenderText() { return genderText; }
public void setGenderText(String genderText) { this.genderText = genderText; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public String getStatusDesc() { return statusDesc; }
public void setStatusDesc(String statusDesc) { this.statusDesc = statusDesc; }
}
//UserController.java
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/api")
public class UserController {
@GetMapping("/users")
public List<User> getUsers() {
List<User> userList = new ArrayList<>();
User user1 = new User();
user1.setId("1");
user1.setName("张三");
user1.setGender("1");
user1.setStatus("1");
User user2 = new User();
user2.setId("2");
user2.setName("李四");
user2.setGender("2");
user2.setStatus("0");
userList.add(user1);
userList.add(user2);
return userList;
}
}
二、DictAspect.java 核心功能
1. 切面定义与切点
@Pointcut("execution(* com.example.demo.controller.*.*(..))")
public void controllerPointcut() {}
- 使用
@Pointcut
定义了一个切点,拦截所有 Controller 包下的方法- 这意味着所有 Controller 返回的数据都会被这个切面处理
2. 环绕通知处理
@Around("controllerPointcut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
Object result = point.proceed();
processDict(result);
return result;
}
@Around
注解定义了环绕通知,在目标方法执行前后进行增强- 先执行原方法获取返回结果,然后调用
processDict
方法处理字典转换
3. 字典处理核心逻辑
processDict
方法负责处理不同类型的返回值:
- 集合类型:遍历集合中的每个元素进行处理
- 数组类型:遍历数组中的每个元素进行处理
- 单个对象:直接处理对象
processObjectDict
方法处理单个对象的字典转换:
- 遍历对象的所有字段,查找带有
@Dict
注解的字段- 获取字段的值,并根据字典类型获取对应的文本描述
- 使用反射将文本描述设置到目标字段中
4.反射工具方法
setFieldValue
:使用反射设置对象字段的值,支持基本类型的自动转换isPrimitiveOrString
:判断是否为基本数据类型或字符串,用于递归处理嵌套对象
三、硬编码
硬编码是指在程序代码中直接写入固定值或常量,而不是通过变量、配置文件、用户输入或外部数据源动态获取这些值的编程方式。这些值在代码中被直接设置,并且在程序运行期间不会发生变化。如果需要修改这些值,就必须直接修改源代码并重新编译或部署程序。