java - 从 JSON 负载中获取特定属性作为 MVC 方法参数

标签 java json spring spring-mvc

我之前问过一个类似的问题:this one

现在我有一个类似但不同的问题。

我的 Spring MVC Controller 模型是一个 JSON 有效负载,具有一组已定义的属性,不幸的是,这些属性不属于我的项目中的类的一部分。

例如

{
    "userId" : "john",
    "role" : "admin"
}

我需要将 userIdrole 视为单独的 String

我目前有两种方法来声明 Controller 方法

public ResponseObject mvc(@RequestBody MyCustomDTO dto){

    String userId = dto.getUserId();
    String role = dto.getRole();
}

public ResponseObject mvc(@RequestBody ModelMap map){
    String userId = (String)map.get("userId");
    String role = (String)map.get("role");
}

我被要求寻找不同的实现,因为 1) 需要为每个参数组合创建一个自定义 DTO 类(大多数情况需要 1 个命名参数,例如 delete(productId))和 2 )涉及一个没有严格定义的实体。特别是在处理列表时,它可以包含需要在运行时检查的任意值。

据我发现,Spring MVC 不支持从 JSON 请求正文解析 @ModelAttribute。我做错了什么还是只是 Spring 没有这样做?我可以从请求正文中获取特定属性(无论是普通原语还是整个 POJO)到方法参数中吗?

在第二种情况下,最好向 Spring 开发人员请求有用的功能。

Spring 版本是 4.2.x。 这个问题与之前链接的问题相关,但不同之处在于,现在我将把单个属性封装到一个 Javascript 对象中,因此 Jackson 需要反序列化的对象不是一个基元,而是一个 POJO。

最佳答案

您将无法轻松获得个人成员,只是因为 Spring MVC 没有任何内置工具可以做到这一点。一种选择是编写自己的注释来描述异常(exception) JSON 对象主体根部的参数。然后写入并注册一个新的HandlerMethodArgumentResolver在处理程序方法参数上处理该注释的实现。

这不是一个简单的任务。由于您无法多次使用请求内容,因此您必须以某种方式保存它,例如保存在 Filter 中。现在,让我们忽略这一限制并假设我们只需要一个参数。您需要定义一个注释

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@interface JsonObjectProperty {
    String name();
}

以及HandlerMethodArgumentResolver

class JsonObjectPropertyResolver implements HandlerMethodArgumentResolver {
    /**
     * Configured as appropriate for the JSON you expect.
     */
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(JsonObjectProperty.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
            WebDataBinderFactory binderFactory) throws Exception {
        Class<?> parameterType = parameter.getParameterType();

        HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
        ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);
        MediaType contentType = inputMessage.getHeaders().getContentType();
        if (!contentType.equals(MediaType.APPLICATION_JSON_UTF8)) {
            throw new HttpMessageNotReadableException(
                    "Could not read document. Expected Content-Type " + MediaType.APPLICATION_JSON_UTF8 + ", was " + contentType + ".");
        }
        // handle potential exceptions from this as well
        ObjectNode rootObject = objectMapper.readValue(inputMessage.getBody(), ObjectNode.class);
        if (parameterType == String.class) {
            JsonObjectProperty annotation = parameter.getParameterAnnotation(JsonObjectProperty.class);
            return rootObject.get(annotation.name()).asText();
        }
        // handle more
        throw new HttpMessageNotReadableException("Could not read document. Parameter type " + parameterType + " not parseable.");
    }
}

最后是处理程序方法

@RequestMapping(value = "/json-new", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public String handleJsonProperty(@JsonObjectProperty(name = "userId") String userId) {
    String result = userId;
    System.out.println(result);
    return result;
}

您必须正确注册JsonObjectPropertyResolver。一旦完成,它将能够将该 JSON 属性直接提取到参数中。

关于java - 从 JSON 负载中获取特定属性作为 MVC 方法参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37923571/

相关文章:

java - 如何在 Spring Security 中启用选择性 http 模式的内容安全策略

java - 带有 UTC 时间的进度条

java - 使 Spring 服务类最终化?

java - 网络抓取器

javascript - 在 JavaScript 中操作 JSON 和组键

java - org.springframework.data.domain.Sort 为什么会出错

java - 尝试运行在线项目时出现 CannotGetJDBCConnectionException

javascript - AJAX 和 PHP 响应给出 "SyntaxError: Unexpected end of JSON input"

javascript - 添加值数组

java - 审计数据库回滚