从 Spring 控制器方法发送 Json 响应的最佳实践

Posted

技术标签:

【中文标题】从 Spring 控制器方法发送 Json 响应的最佳实践【英文标题】:Best practice to send Json response from Spring controller methods 【发布时间】:2017-11-22 18:14:31 【问题描述】:

我想从 spring 控制器返回一个字符串(json 字符串)作为对它接收到的 AJAX 调用的响应,根据我是否提交了 @Valid 表单,响应可能会有所不同。这就是我处理它的方式,并想知道这是否被认为是最佳实践? 请注意我正在使用@RestController,所以@ResonseBody 应用所有方法。

    @RequestMapping(value = "/save" , method = RequestMethod.POST)
public String saveScheduledAlert(@Valid ScheduledAlertForm scheduledAlertForm, BindingResult bindingResult) 
    StringBuilder jsonString = new StringBuilder();
    if(bindingResult.hasErrors())
        jsonString.append("\"success\" : \"false\"");
        for(ObjectError error : bindingResult.getAllErrors())
            jsonString.append(",\"").append(((FieldError) error).getField()).append("\":\"").append(error.getDefaultMessage()).append("\"");
     else 
        //save the data
        jsonString.append("\"success\" : \"true\"");
    

    jsonString.append("");
    return jsonString.toString();



【问题讨论】:

@ResponseBody 注释? - ***.com/questions/28646332/… 我正在使用 @RestController 它是一个 Spring Boot 应用程序 【参考方案1】:

老问题,但对于其他需要帮助的人,我为此使用了自定义 ApiResponse 类。我的班级是这样的:

public class ApiResponse<T> 
    String message;
    int statusCode;
    T data

    //....getters and setters

这样,我可以使用“SUCCESS”或“ERROR”作为消息,适当的HttpStatus 代码,然后任何类型作为我要发送的数据。

然后,在控制器中,我只是这样做:

@PostMapping("/sign-up")
public ResponseEntity<String> signUp(@RequestBody Account account) 
  
  if (accountService.getAccountByEmail(account.getEmail()) != null) 
      ApiResponse<String> apiResponse = new ApiResponse<>("A user with that email  
          already exist", HttpStatus.CONFLICT.value(), null);
         return new ResponseEntity<String>(new Gson().toJson(apiResponse), HttpStatus.CONFLICT);
  

 // ... rest of controller code 

如您所见,我使用 Gson 依赖项来创建我的 JSON 字符串。

【讨论】:

【参考方案2】:

所以基本上你想要做的是生成 2 个 pojos

public class RestWrapperDTO 
    protected boolean success;
    public boolean isSuccess() 
        return success;
    
    public void setSuccess(boolean value) 
        success = value
    

还有另一个错误 DTO

public class RestErrorDTO extends RestWrapperDTO 
    private Map<String, String> errors;

    public Map<String, String> getErrors() 
        return errors;
    
    public void setErrors(Map<String, String> value) 
        errors = value
    

和你的控制器

@RequestMapping(value = "/save" , method = RequestMethod.POST)
public RestWrapperDTO saveScheduledAlert(@Valid ScheduledAlertForm scheduledAlertForm, BindingResult bindingResult) 
    StringBuilder jsonString = new StringBuilder();

    if(bindingResult.hasErrors())
        RestErrorDTO errorDTO = new RestErrorDTO();
        // fill map with errors here
        return errorDTO;
     else 
        RestWrapperDTO wrapperDTO = new RestWrapperDTO();
        wrapperDTO.setSuccess(true);
        return wrapperDTO;
    

这不是最充分的代码,但它应该可以帮助你:D

如果你使用简单的@Controller 注解——你是什么 寻找的是@ResponseBody-annotation

或者如果你使用@RestController 而不是它已经可用

你可以简单地返回一个带有 Serializable 接口的对象——一个 简单的 POJO 和 spring 将处理其余部分。

进一步阅读:

https://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-responsebody How exactly works the Spring @ResponseBody annotation in this RESTful application example? 对于@RestController 的小解释Difference between spring @Controller and @RestController annotation

【讨论】:

我已经将 ResonseBody 应用于所有方法,因为我正在使用@RestController,此外,我想要做的只是返回成功:如果一切顺利,则返回 true 或发送成功:false,然后验证错误作为 json 中的键值对仅此而已。 基本上我有解释和@nick savenia 代码示例 我的建议, 我之前想过 return Object 但想知道如何发送成功 : false 消息以在客户端发现出现问题? 谢谢,这是有道理的,但为什么我不应该只使用一个带有布尔标志和 Map 的类来处理错误呢?这还不够简单吗?【参考方案3】:

创建一个 POJO,如下所示:

public class SuccessPOJO
private String success;

.....
getters and setters
.....

现在您可以设置成功消息的值并返回此SuccessPOJO 对象。在浏览器中,您将收到带有成功消息的JSON 格式化对象!

【讨论】:

是的,但我也想发送数量可变的验证错误,我该如何发送?

以上是关于从 Spring 控制器方法发送 Json 响应的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

从 Spring Boot 控制器返回非 JSON 数据(对象列表)

如何将 json 数据从我的 jsp 页面发送到 spring rest 控制器

如何在 Javascript 中从 Spring 获取 JSON 响应

使用 JSON Sanitizer 清理来自 Spring MVC 控制器的响应 JSON?

在 Spring MVC 3.1 控制器的处理程序方法中直接流到响应输出流

如何在spring mvc中的操作之前发送响应