spring aop给返回值添加额外字段
1、默认情况下直接修改返回值为新对象时无法达到预期结果、但可通过序列化方式达到给原对象增加字段的目的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | import cn.hutool.core.util.ReflectUtil; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.extern.slf4j.Slf4j; import cn.as.foundation.web.api.BusinessCode; import cn.as.foundation.web.exception.BusinessException; import cn.as.geekbidder.core.annotation.Dict; import cn.as.geekbidder.core.util.JacksonTool; import cn.as.maple.platform.api.model.User; import cn.as.maple.platform.api.service.UserService; import cn.as.maple.process.api.model.FlowTask; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.flowable.engine.TaskService; import org.flowable.identitylink.api.IdentityLink; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; @Aspect @Component @Slf4j public class AddCurrentUser { @Autowired private TaskService taskService; @Autowired private UserService userService; /** * Pointcut */ @Pointcut ( "execution(* cn.togeek.maple.process.controller.FlowTaskController.*(..))" ) public void joinPoint() {} private void addOtherInfo(Object result) { if (result instanceof IPage) { List<ObjectNode> items = new ArrayList<>(); List<?> records = ((IPage<?>) result).getRecords(); if (CollectionUtils.isEmpty(records)) { return ; } for (Object record : records) { ObjectNode item = doAdd(record); items.add(item); } ((IPage<ObjectNode>) result).setRecords(items); } } public ObjectNode doAdd(Object record) { //解决@JsonFormat注解解析不了的问题 String json = JacksonTool.object2String(record); ObjectNode item = JacksonTool.string2Object(json, ObjectNode. class ); if (Objects.isNull(item)) { throw new BusinessException(BusinessCode.SYSTEM_ERROR.getCode(), "返回值解析失败" ); } String taskId = (String) ReflectUtil.getFieldValue(record, "taskId" ); List<IdentityLink> idList = this .taskService.getIdentityLinksForTask(taskId); List<User> collect = idList.stream().map(e -> { List<User> users; if (e.getUserId() != null ) { users = userService.getUsersByIds(Collections.singletonList(e.getUserId())); } else { users = userService.getUserByRole(e.getGroupId()); } return users; }).flatMap(Collection::stream).collect(Collectors.toList()); String users = collect.stream().map(User::getName).collect(Collectors.joining( "," )); item.put( "currentUser" , users); return item; } @AfterReturning (value = "joinPoint()" , returning = "methodResult" ) public void afterRt(JoinPoint jp, Object methodResult) { addOtherInfo(methodResult); } } |
2、工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; import com.google.common.collect.Maps; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import java.io.IOException; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * json 工具类 * @author ludangxin * @date 2021/4/1 */ @Slf4j public class JacksonTool { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); private static final String STANDARD_PATTERN = "yyyy-MM-dd HH:mm:ss" ; private static final String DATE_PATTERN = "yyyy-MM-dd" ; private static final String TIME_PATTERN = "HH:mm:ss" ; static { //设置java.util.Date时间类的序列化以及反序列化的格式 OBJECT_MAPPER.setDateFormat( new SimpleDateFormat(STANDARD_PATTERN)); // 初始化JavaTimeModule JavaTimeModule javaTimeModule = new JavaTimeModule(); //处理LocalDateTime DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(STANDARD_PATTERN); javaTimeModule.addSerializer(LocalDateTime. class , new LocalDateTimeSerializer(dateTimeFormatter)); javaTimeModule.addDeserializer(LocalDateTime. class , new LocalDateTimeDeserializer(dateTimeFormatter)); //处理LocalDate DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(DATE_PATTERN); javaTimeModule.addSerializer(LocalDate. class , new LocalDateSerializer(dateFormatter)); javaTimeModule.addDeserializer(LocalDate. class , new LocalDateDeserializer(dateFormatter)); //处理LocalTime DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern(TIME_PATTERN); javaTimeModule.addSerializer(LocalTime. class , new LocalTimeSerializer(timeFormatter)); javaTimeModule.addDeserializer(LocalTime. class , new LocalTimeDeserializer(timeFormatter)); //处理Long SimpleModule simpleModule = new SimpleModule(); simpleModule.addSerializer(Long. class , ToStringSerializer.instance); OBJECT_MAPPER.registerModule(simpleModule); //注册时间模块, 支持支持jsr310, 即新的时间类(java.time包下的时间类) OBJECT_MAPPER.registerModule(javaTimeModule); // 包含所有字段 OBJECT_MAPPER.setSerializationInclusion(JsonInclude.Include.ALWAYS); // 在序列化一个空对象时时不抛出异常 OBJECT_MAPPER.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); // 忽略反序列化时在json字符串中存在, 但在java对象中不存在的属性 OBJECT_MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); } public static <T> String object2String(T object) { if (object == null ) { return null ; } try { return object instanceof String ? (String) object:OBJECT_MAPPER.writeValueAsString(object); } catch (IOException e) { log.warn( "Parse object to string error" , e); return null ; } } public static <T> String object2StringPretty(T object) { if (object == null ) { return null ; } try { return object instanceof String ? (String) object:OBJECT_MAPPER.writerWithDefaultPrettyPrinter() .writeValueAsString(object); } catch (IOException e) { log.warn( "Parse object to string error" , e); return null ; } } public static <T> T string2Object(String str, Class<T> clazz) { if (StringUtils.isEmpty(str) || clazz == null ) { return null ; } try { return clazz.equals(String. class ) ? (T) str : OBJECT_MAPPER.readValue(str, clazz); } catch (Exception e) { log.warn( "Parse String to object error!" , e); return null ; } } public static <T> T string2Object(String str, TypeReference<T> typeReference) { if (StringUtils.isEmpty(str) || typeReference == null ) { return null ; } try { return typeReference.getType().equals(String. class ) ? (T)str : OBJECT_MAPPER.readValue(str, typeReference); } catch (Exception e) { log.warn( "Parse String to object error!" , e); return null ; } } public static <T> T string2Object(String str, Class<?> collectionClass, Class<?>... elementClass) { JavaType javaType = OBJECT_MAPPER.getTypeFactory().constructParametricType(collectionClass, elementClass); try { return OBJECT_MAPPER.readValue(str, javaType); } catch (Exception e) { log.warn( "Parse String to object error!" , e); return null ; } } /** * 把对象转换为有序map,在序列化时确保对象的顺序和属性编排时一致 */ public static Map<String, Object> objectToLinkedHashMap(Object obj) { if ( null == obj) { return Maps.newHashMap(); } return objectToLikedMap(obj); } public static LinkedHashMap<String, Object> objectToLikedMap(Object data) { try { return string2Object(object2String(data), LinkedHashMap. class ); } catch (Exception e) { return Maps.newLinkedHashMap(); } } /** * json字符串转成list * * @param jsonString * @param cls * @return */ public static <T> List<T> jsonToList(String jsonString, Class<T> cls) { try { return OBJECT_MAPPER.readValue(jsonString, getCollectionType(List. class , cls)); } catch (JsonProcessingException e) { String className = cls.getSimpleName(); log.error( " parse json [{}] to class [{}] error:{}" , jsonString, className, e); } return null ; } /** * 获取泛型的Collection Type * * @param collectionClass 泛型的Collection * @param elementClasses 实体bean * @return JavaType Java类型 */ private static JavaType getCollectionType(Class<?> collectionClass, Class<?>... elementClasses) { return OBJECT_MAPPER.getTypeFactory().constructParametricType(collectionClass, elementClasses); } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具