【问题标题】:Spring MVC - Rest endpoint that receives a List may receive a single objectSpring MVC - 接收列表的 Rest 端点可能会接收单个对象
【发布时间】:2018-12-24 02:55:55
【问题描述】:

我有一个 Spring 4.3.3 @RestController,它通过 Lists 管理实体类型。

@RestController
@RequestMapping("...")
public class EntityRestController {
    @PostMapping
    public void doSomeWork(@RequestBody final List<Entity> entities) { ... }
}

我发现有时我可能会收到一个请求,其中正文不是由数组组成,而是由单个 JSON 对象组成。 我使用 Gson 作为默认的序列化器/反序列化器,显然它会引发异常。

JSON parse error: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT

解决这个问题的更好方法是(在控制器级别)?

【问题讨论】:

  • 你能单独做一些事情吗?为单个实体设置不同的映射并在将一个对象转换为列表后只执行另一个映射?
  • @zack6849 不幸的是,我现在无法控制调用方请求 URL。所以我只能在这个控制器上工作。
  • spring 是否允许您重载 post 映射,以便您可以根据匹配的映射有不同的方法?
  • @zack6849 实际上你不能在不修改 URL 的情况下重载 RequestMapping 方法。它会抛出一个“模糊映射”异常。

标签: java json spring-mvc


【解决方案1】:

您可以在方法参数中使用HttpServletRequest,例如:

@RestController
@RequestMapping("...")
public class EntityRestController {
    @PostMapping
    public void doSomeWork(HttpServletRequest request) {
        // Do your things here..
    }
}

this question 有很多关于如何在 HttpServletRequest 中解析请求正文的答案:

  1. 使用apache commons-IOIOUtils.toString(request.getReader())
  2. 使用request.getParameterMap()

    Map<String, String[]> map = request.getParameterMap();
    for(String paramName : map.keySet()) {
        String[] paramValues = map.get(paramName);
    
        for(String valueOfParam : paramValues) {
            // Do your things..
        }
    }
    

或其他基于您的需要和偏好的技术。

HTH

【讨论】:

  • 它肯定会起作用,但如果可能的话,我更喜欢更清洁的解决方案。
  • 您可以只接受Object 并对其进行反省以查看对象的类型,然后将其映射到控制器中,但除非您区分端点,否则没有什么更干净的。跨度>
  • @LppEdd 正如您在其他 cmets 中提到的,其他更清洁的解决方案会导致不明确的映射异常。这样想:如果你认为有更简洁的方法,Controller的方法参数中应该使用什么对象?
  • 包装 HttpServletRequest(并修改 getReader() 方法)的过滤器可能是最佳解决方案,因为它可以应用于多个 URL 并使用 Java 配置进行注册
猜你喜欢
  • 1970-01-01
  • 2021-05-12
  • 2021-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-08
  • 2014-05-25
相关资源
最近更新 更多