繁体   English   中英

使用spring RestController对错误请求的自定义响应

[英]Custom response on bad request using spring RestController

我有以下控制器。 我正在使用Spring创建Restful API。

@RestController
public class UserController extends RestControlValidator {

@RequestMapping(value = "/user/", method = RequestMethod.POST, headers = "Accept=application/json", consumes = "application/json", produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody List newUser(@RequestBody @Valid UserInput input,BindingResult result) 
            {Some code}

}

UserInput类如下所示:

public class UserInput{

    @NotEmpty
    private String emailId;
    @NotEmpty
    private String fName;
    private String lName;
    private int sex;

//getters and setters

现在,当我尝试使用数据{"sex":"Male"}访问/user/时,得到以下响应:

错误的请求响应

我希望这样的请求的响应是:

{"errors":{"sex":"The value must be an integer"}}

有什么方法可以在Spring中自定义BAD REQUEST响应?

考虑到当前情况,最理想的解决方案是更改HandlerMethodArgumentResolve的行为,因为@RequestBody构造的json转换为pojo失败,因为我们没有机会检查错误的数据,并且此检查可以很好地在自定义消息转换器中完成

答:首先,我们需要创建LanguageMes​​sageConverter,如下所示

public class LanguageMessageConverter extends
        AbstractHttpMessageConverter<Language> {
    private Gson gson = new Gson();
public LanguageMessageConverter() {
    super(new MediaType("application", "json", Charset.forName("UTF-8")));
}

@Override
protected boolean supports(Class<?> clazz) {
    return Language.class.equals(clazz);
}

Map<String, String> mp = new HashMap<>();

@Override
protected Language readInternal(Class<? extends Language> clazz,
        HttpInputMessage httpInputMessage) throws IOException,
        HttpMessageNotReadableException {
    Map langmp = gson.fromJson(
            convertStreamToString(httpInputMessage.getBody()), Map.class);

        for (Field field : clazz.getDeclaredFields()) {

            if (!langmp.get(field.getName()).getClass().getCanonicalName().equals(field.getType().getCanonicalName())) {
                if (field.getType().getCanonicalName().equals("java.lang.Integer")||field.getType().getCanonicalName().toString().equals("int")) {
                    langmp.put(field.getName(), "0");
                } else if (field.getType().equals("java.lang.String")) {
//TODO COde needs to be improved here because this check is not efficient
                    langmp.put(field.getName(), "wrong");
                }
            }
        }       
        Language lang = gson.fromJson(gson.toJson(langmp), clazz);
        return lang;
    }
  1. 我们需要设置媒体类型new MediaType(“ application”,“ json”,Charset.forName(“ UTF-8”)),以确保此类干预所提到的MIME类型
  2. 考虑到我们需要处理结果,我发现最好将其转换为映射langmp (可以使用更好的JSON解析器)
  3. 由于我们需要了解现有的类型,因此我使用了反射api通过getDeclaredFields()获取字段。
  4. 使用上面的方法,使用数据类型进行了逻辑检查,以了解该类型是否不正确,例如,如果字段数据类型为int且如果发现它为String,则将替换对应的映射值
  5. 一旦完成,映射将保存更新的值,如果数据错误,则将设置默认值,例如,如果int var设置为0,因为原始json中包含String。
  6. 完成此操作后,更新的地图将转换为相关的类。

B.其次,我们需要在调度程序xml中注册自定义MessageConverter,即LanguageMessageConverter

<mvc:annotation-driven >
   <mvc:message-converters register-defaults="true">       
       <bean class="com.comp.org.controller.LanguageMessageConverter" />
    </mvc:message-converters>
</mvc:annotation-driven>
  1. register-defaults="true"非常重要,因为我们要添加Custom MessageConverter,但是我们还需要其他现有的转换器与我们添加的转换器一起工作
  2. LanguageMes​​sageConverter需要在这里注册。

C.考虑到相关的pojo填充有必要的详细信息,它将在自定义转换器中到达我们的控制器后处理,现在我们将添加手动验证,例如。 如果int变量为0,则应返回必要的错误json

根据您的请求,即使json包含错误的数据,自定义消息转换器也应对其进行处理,因此在控制器中,我们可以验证上述条件。 该代码肯定可以进一步改进。 请让我知道此解决方案是否满足您的要求或代码的任何部分需要进一步阐述,并希望能解决您的问题。

我有同样的问题,而不是我这样解决的:

  1. 创建一个名为Error的对象,就像这样(不要忘记实现Serializable ...):

     private String fieldName; private String errorCode; private String defaultMessage; public Error() { } public Error(String fieldName, String errorCode, String defaultMessage) { this.fieldName = fieldName; this.errorCode = errorCode; this.defaultMessage = defaultMessage; } /* getters, setters */ 
  2. @RestController方法中,您必须调用inputValidator.validate()方法(如果您没有为UserInput创建对象验证器,那么我们实际上不是在说相同的语言...)

     // validating the userInput userInputValidator.validate(userInput, bindingResult); if (bindingResult.hasErrors()) { List<Error> errors = new ArrayList<>(bindingResult.getErrorCount()); for (FieldError fieldWithError : bindingResult.getFieldErrors()) { errors.add(new Error(fieldWithError.getField(), fieldWithError.getCode(), fieldWithError.getDefaultMessage())); } return errors; } // in case of success: return null; 
  3. 最后,您必须将JSON对象转换为客户端。 您将拥有两种对象:

    3.1。 null(根据您使用的语言undefined

    3.2。 像这样的JSON对象:

     [ { "fieldName": "name", "errorCode": "user.input.name.in.blank", "defaultMessage": "Insert a valid name!" }, { "fieldName": "firstPhone", "errorCode": "user.input.first.phone.blank", "defaultMessage": "Insert a valid first phone!" } ] 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM