在发布以下答案后,我更改了操作方式。我用了一个
HandlerMethodReturnValueHandle河
我必须创建一个程序化的Web配置来覆盖该顺序,因为自定义返回值处理程序是最后触发的。我需要在默认设置之前触发它们。
@Configurationpublic class WebConfig extends WebMvcConfigurationSupport { ...}希望这将使某人朝比我在下面的答案更好的方向前进。
这使我可以将任何对象直接序列化为JSON。在@RequestMapping中产生了=“ application /
json”之后,我总是将返回值序列化为JSON。
除了使用之外,我对参数绑定也做了同样的事情
HandlerMethodArgumentResolver。只需使用您选择的注释为您的类添加注释(我使用了JPA
@Entity,因为我通常会序列化成模型)。
现在,您可以在Spring控制器中实现无缝POJO到JSON反序列化,而无需任何样板程序代码。
奖励:我使用的参数解析器将检查参数的@Id标记,如果JSON包含ID的键,则将检索实体并将JSON应用于持久对象。am
public class EntityArgumentResolver implements HandlerMethodArgumentResolver { @Autowired private SessionFactory sessionFactory; private final ObjectMapper objectMapper = new ObjectMapper(); private static final Logger log = Logger.getLogger(EntityArgumentResolver.class); //whether to log the incoming JSON private boolean doLog = false; @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.getParameterType().getAnnotation(Entity.class) != null; } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); String requestBody = IOUtils.toString(request.getReader()); Class<?> targetClass = parameter.getParameterType(); Object entity = this.parse(requestBody, targetClass); Object entityId = getId(entity); if(doLog) { log.info(requestBody); } if(entityId != null) { return copyObjectToPersistedEntity(entity, getKeyValueMap(requestBody), entityId); } else { return entity; } } @SuppressWarnings("unchecked") private Map<String, Object> getKeyValueMap(String rawJson) throws JsonParseException, JsonMappingException, IOException { return objectMapper.readValue(rawJson, HashMap.class); } private Object copyObjectToPersistedEntity(Object changesObject, Map<String, Object> changesMap, Object id) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { Session session = sessionFactory.openSession(); Object persistedObject = session.get(changesObject.getClass(), (Serializable) id); session.close(); if(persistedObject == null) { throw new ValidationException(changesObject.getClass().getSimpleName() + " #" + id + " not found."); } Class<?> clazz = persistedObject.getClass(); for(Method getterMethod : ReflectionUtils.getAllDeclaredMethods(clazz)) { Column column = getterMethod.getAnnotation(Column.class); //Column annotation is required if(column == null) { continue; } //Is the field allowed to be updated? if(!column.updatable()) { continue; } //Was this change a part of JSON request body? //(prevent fields false positive copies when certain fields weren't included in the JSON body) if(!changesMap.containsKey(BeanUtils.toFieldName(getterMethod))) { continue; } //Is the new field value different from the existing/persisted field value? if(ObjectUtils.equals(getterMethod.invoke(persistedObject), getterMethod.invoke(changesObject))) { continue; } //Copy the new field value to the persisted object log.info("Update " + clazz.getSimpleName() + "(" + id + ") [" + column.name() + "]"); Object obj = getterMethod.invoke(changesObject); Method setter = BeanUtils.toSetter(getterMethod); setter.invoke(persistedObject, obj); } return persistedObject; } private Object getId(Object entity) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { for(Method method : ReflectionUtils.getAllDeclaredMethods(entity.getClass())) { if(method.getAnnotation(Id.class) != null) { method.setAccessible(true); return method.invoke(entity); } } return null; } private <T> T parse(String json, Class<T> clazz) throws JsonParseException, IOException { try { return objectMapper.readValue(json, clazz); } catch(JsonMappingException e) { throw new ValidationException(e); } } public void setDoLog(boolean doLog) { this.doLog = doLog; }}


