【问题标题】:Spring Boot using Json as request parameters instead of an entity/modelSpring Boot 使用 Json 作为请求参数而不是实体/模型
【发布时间】:2018-09-09 11:24:06
【问题描述】:

我们公司正计划将我们的微服务技术切换到 Spring Boot。作为一项倡议,我做了一些高级阅读并记下它的潜在影响和语法等价物。我还开始移植我们拥有的最小服务作为一个副项目。

阻碍我前进的一个问题是尝试将我们的 Json 请求/响应交换转换为 Spring Boot。

这是代码示例:(这是 Nutz 框架,供不认识的人使用)

@POST
@At // These two lines are equivalent to @PostMapping("/create")
@AdaptBy(type=JsonAdapter.class)
public Object create(@Param("param_1") String param1, @Param("param_2) int param2) {
    MyModel1 myModel1 = new MyModel1(param1);
    MyModel2 myModel2 = new MyModel2(param2);
    myRepository1.create(myMode12);
    myRepository2.create(myModel2);
    return new MyJsonResponse();
}

在 PostMan 或任何其他 REST 客户端上,我只需传递 POST:

{
    "param_1" : "test",
    "param_2" : 1
}

我在 Spring Boot 中做到了这一点:

@PostMapping("/create")
public Object create(@RequestParam("param_1") String param1, @RequestParam("param_2) int param2) {
    MyModel1 myModel1 = new MyModel1(param1);
    MyModel2 myModel2 = new MyModel2(param2);
    myRepository1.create(myMode12);
    myRepository2.create(myModel2);
    return new MyJsonResponse();
} 

我不确定如何在此处执行类似于 JsonAdapter 的操作。 Spring 无法识别我传递的数据。

我试过了,但根据示例,它期望 Json 参数是实体的形式。

@RequestMapping(path="/wallet", consumes="application/json", produces="application/json")

但只有当我做这样的事情时,我才能让它工作:

public Object (@RequestBody MyModel1 model1) {}

我的问题是 MyModel1 可能不一定包含我的 json 数据所具有的字段/参数。

Nutz 非常有用的一点是,如果我删除了 JsonAdapter,它的行为就像 spring 中的常规表单请求端点一样。

我在 Stack 中找不到答案,或者如果可能的话,我对它的称呼与现有的 spring 开发人员的称呼不同。

我们的老板希望我们(不切实际地)实施这些更改,而不会强迫前端开发人员适应这些更改。 (自治和所有爵士乐)。如果这是不可避免的,那么合理的解释是什么?

【问题讨论】:

    标签: java json spring spring-boot jackson


    【解决方案1】:

    在这种情况下,您可以使用Map 类来读取输入 json,例如

    @PostMapping("/create")
    public Object create(@RequestBody Map<String, ?> input) {
         sout(input.get("param1")) // cast to String, int, ..
    }
    

    【讨论】:

    • 我现在要试一试。
    • 我确认这是我想要的。谢谢你。我将继续探索这种可能性。不过最后一件事。除了 Map,我还能用 RequestBody 做什么?
    【解决方案2】:

    我实际上想出了一个更直接的解决方案。

    显然这是可行的:

    @PostMapping("/endpoint")
    public Object endpoint(@RequestBody MyWebRequestObject request) {
        String value1 = request.getValue_1();
        String value2 = request.getValue_2();
    }
    

    json 载荷是这样的:

    {
       "value_1" : "hello",
       "value_2" : "world"
    }
    

    如果 MyRequestObject 像这样的 json 请求对象映射,则此方法有效。示例:

    public class MyWebRequestObject {
       String value_1;
       String value_2
    }
    

    未映射的值将被忽略。春天就是那样聪明。

    我知道这又回到了我开始的地方,但是由于我们引入了一个服务层供其余控件与之交互,因此创建我们自己的与持久性模型分开的请求模型对象 (DTO) 是有意义的。

    【讨论】:

      【解决方案3】:

      您可以使用@RequestBody Map 作为@PostMapping、@PutMapping 和@PatchMapping 的参数。对于@GetMapping 和@DeleteMapping,您可以编写一个实现Converter 的类,将json 格式的请求参数转换为Map。您可以将该类注册为带有 @Component 注释的 bean。然后你可以将你的参数绑定到@RequestParameter Map。

      下面是一个转换器的例子。

      @Component
      public class StringToMapConverter implements Converter<String, Map<String, Object>> {
      
          private final ObjectMapper objectMapper;
      
          @Autowired
          public StringToMapConverter(ObjectMapper objectMapper) {
              this.objectMapper = objectMapper;
          }
      
          @Override
          public Map<String, Object> convert(String source) {
              try {
                  return objectMapper.readValue(source, new TypeReference<Map<String, Object>>(){});
              } catch (IOException e) {
                  return new HashMap<>();
              }
          }
      
      }
      

      如果您想排除 MyModel1 类的特定字段,请在字段上使用 @JsonIgnore 注释,如下所示。

      class MyModel1 {
           private field1;
           @JsonIgnore field2;
      }
      

      那么,我想你可以使用你所做的。(我不确定。)

      public Object (@RequestBody MyModel1 model1) {}
      

      【讨论】:

      • 我的目标是避免在方法参数中使用模型(我想要原生数据类型)。 JsonIgnore 参数是如果我不想使用字段。我的问题是方法签名可能包含模型没有的参数。
      • 对我的误解深表歉意。我认为没有@RequestBody MyModel1 唯一可以做的就是用@RequestParam 编写所有必需的参数。但是,您不能通过使用正确实现 Converter 的类来实现您的目标吗?
      • 如果我对春天的期望无法实现,我其实很好。只是我必须有充分的理由告诉我的老板为什么不这样做。 ;)
      • 我明白了。通过经历这些,你已经知道了一个很好的理由,不是吗?其实我不知道 Nutz 和 JsonAdapter 执行的确切逻辑,但 @RequestParam 可以绑定一个参数,@RequestBody 可以绑定所有参数以及 spring 框架。我怕帮不上忙。祝你好运!
      【解决方案4】:

      我认为您可以使用涉及 dto 的策略 https://auth0.com/blog/automatically-mapping-dto-to-entity-on-spring-boot-apis/

      在您可以像实体一样映射或将其用于您的需要之后,您将 json 发送到您的 rest api,该 api 像 dto 对象一样映射

      【讨论】:

        猜你喜欢
        • 2019-05-19
        • 2022-11-13
        • 1970-01-01
        • 2017-07-01
        • 2022-11-19
        • 1970-01-01
        • 2019-10-07
        • 1970-01-01
        • 2020-07-09
        相关资源
        最近更新 更多