摆脱困境:向REST API添加验证
我對此感到有些to愧,但直到昨天,我才知道我可以使用@Valid和@RequestBody批注將驗證添加到REST API中。 這在Spring MVC 3.0中不起作用,由于某種原因,我沒有注意到在Spring MVC 3.1中添加了對此功能的支持 。 我從不喜歡舊的方法,因為我不得不
當我發現不再需要執行這些操作時,我決定寫這篇博客文章,并與大家分享我的發現。
注意:如果我們想在Spring Framework中使用JSR-303支持的驗證,我們必須向我們的類路徑添加JSR-303提供程序。 本博客文章的示例應用程序使用Hibernate Validator 4.2.0,它是Bean驗證API(JSR-303)的參考實現。
讓我們首先看一下本博客文章中使用的DTO類。 CommentDTO類的源代碼如下所示:
import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.NotEmpty;public class CommentDTO {@NotEmpty@Length(max = 140)private String text;//Methods are omitted. }讓我們繼續前進,了解如何使用Spring MVC 3.1向REST API添加驗證。
Spring MVC 3.1是一個好的開始
我們可以按照以下步驟將驗證添加到REST API:
以下小節將介紹這兩個步驟。
實施控制器
我們可以通過執行以下步驟來實現我們的控制器:
CommentController類的源代碼如下所示:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*;import javax.validation.Valid;@Controller public class CommentController {@RequestMapping(value = "/api/comment", method = RequestMethod.POST)@ResponseBodypublic CommentDTO add(@Valid @RequestBody CommentDTO comment) {return comment;} }現在,我們向控制器添加了新方法,并對其進行了驗證。 驗證失敗時,將引發MethodArgumentNotValidException 。 讓我們找出驗證失敗時如何向API用戶返回有意義的響應。
處理驗證錯誤
通過執行以下步驟,我們可以實現處理驗證錯誤的邏輯:
下面將更詳細地描述這些步驟。
創建數據傳輸對象
首先,我們必須創建數據傳輸對象,其中包含返回給REST API用戶的信息。 我們可以按照以下步驟進行操作:
讓我們開始吧。
第一個DTO的源代碼如下所示:
public class FieldErrorDTO {private String field;private String message;public FieldErrorDTO(String field, String message) {this.field = field;this.message = message;}//Getters are omitted. }第二個DTO的實現非常簡單。 它包含一個FieldErrorDTO對象列表和一個用于向列表中添加新字段錯誤的方法。 ValidationErrorDTO的源代碼如下所示:
import java.util.ArrayList; import java.util.List;public class ValidationErrorDTO {private List<FieldErrorDTO> fieldErrors = new ArrayList<>();public ValidationErrorDTO() {}public void addFieldError(String path, String message) {FieldErrorDTO error = new FieldErrorDTO(path, message);fieldErrors.add(error);}//Getter is omitted. }以下清單提供了一個示例Json文檔,當驗證失敗時,該文檔將發送回我們的API用戶:
{"fieldErrors":[{"field":"text","message":"error message"}] }讓我們看看如何實現異常處理程序方法,該方法創建一個新的ValidationErrorDTO對象并返回創建的對象。
實現異常處理程序方法
我們可以按照以下步驟將異常處理程序方法添加到我們的控制器中:
讓我們仔細看看processValidationError()方法的實現。 我們可以通過執行以下步驟來實現此方法:
CommentController類的源代碼如下所示:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.*;import javax.validation.Valid; import java.util.List; import java.util.Locale;@Controller public class CommentController {private MessageSource messageSource;@Autowiredpublic CommentController(MessageSource messageSource) {this.messageSource = messageSource;}//The add() method is omitted.@ExceptionHandler(MethodArgumentNotValidException.class)@ResponseStatus(HttpStatus.BAD_REQUEST)@ResponseBodypublic ValidationErrorDTO processValidationError(MethodArgumentNotValidException ex) {BindingResult result = ex.getBindingResult();List<FieldError> fieldErrors = result.getFieldErrors();return processFieldErrors(fieldErrors);}private ValidationErrorDTO processFieldErrors(List<FieldError> fieldErrors) {ValidationErrorDTO dto = new ValidationErrorDTO();for (FieldError fieldError: fieldErrors) {String localizedErrorMessage = resolveLocalizedErrorMessage(fieldError);dto.addFieldError(fieldError.getField(), localizedErrorMessage);}return dto;}private String resolveLocalizedErrorMessage(FieldError fieldError) {Locale currentLocale = LocaleContextHolder.getLocale();String localizedErrorMessage = messageSource.getMessage(fieldError, currentLocale);//If the message was not found, return the most accurate field error code instead.//You can remove this check if you prefer to get the default error message.if (localizedErrorMessage.equals(fieldError.getDefaultMessage())) {String[] fieldErrorCodes = fieldError.getCodes();localizedErrorMessage = fieldErrorCodes[0];}return localizedErrorMessage;} }這就對了。 讓我們花點時間評估我們剛剛完成的工作。
我們就快到了
現在,我們已經使用Spring MVC 3.1將驗證添加到了REST API中。 與舊方法相比,此實現有一個主要優點:
我們可以使用@Valid批注來觸??發驗證過程。
但是,僅當從包含異常處理程序方法的控制器類中拋出配置的異常時,才會觸發使用@ExceptionHandler注釋進行注釋的方法。 這意味著,如果我們的應用程序具有多個控制器,則必須為控制器創建一個通用基類,并將處理驗證錯誤的邏輯移至該類。 這聽起來似乎沒什么大不了,但是我們應該更喜歡組合而不是繼承 。
Spring MVC 3.2提供了可用于從控制器中消除繼承需求的工具。 讓我們繼續前進,找出實現方法。
Spring MVC 3.2搶救
Spring MVC 3.2引入了一個新的@ControllerAdvice批注 ,我們可以使用該批注實現一個異常處理程序組件,該組件處理控制器拋出的異常。 我們可以通過執行以下步驟來實現此組件:
在以下小節中將更詳細地說明這些步驟。
從我們的控制器中刪除異常處理邏輯
我們可以按照以下步驟從控制器中刪除異常處理邏輯:
CommentController類的源代碼如下所示:
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*;import javax.validation.Valid;@Controller public class CommentController {@RequestMapping(value = "/api/comment", method = RequestMethod.POST)@ResponseBodypublic CommentDTO add(@Valid @RequestBody CommentDTO comment) {return comment;} }我們的下一步是創建異常處理程序組件。 讓我們看看這是如何完成的。
創建異常處理程序組件
我們可以按照以下步驟創建異常處理程序組件:
RestErrorHandler類的源代碼如下所示:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.http.HttpStatus; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus;import java.util.List; import java.util.Locale;@ControllerAdvice public class RestErrorHandler {private MessageSource messageSource;@Autowiredpublic RestErrorHandler(MessageSource messageSource) {this.messageSource = messageSource;}@ExceptionHandler(MethodArgumentNotValidException.class)@ResponseStatus(HttpStatus.BAD_REQUEST)@ResponseBodypublic ValidationErrorDTO processValidationError(MethodArgumentNotValidException ex) {BindingResult result = ex.getBindingResult();List<FieldError> fieldErrors = result.getFieldErrors();return processFieldErrors(fieldErrors);}private ValidationErrorDTO processFieldErrors(List<FieldError> fieldErrors) {ValidationErrorDTO dto = new ValidationErrorDTO();for (FieldError fieldError: fieldErrors) {String localizedErrorMessage = resolveLocalizedErrorMessage(fieldError);dto.addFieldError(fieldError.getField(), localizedErrorMessage);}return dto;}private String resolveLocalizedErrorMessage(FieldError fieldError) {Locale currentLocale = LocaleContextHolder.getLocale();String localizedErrorMessage = messageSource.getMessage(fieldError, currentLocale);//If the message was not found, return the most accurate field error code instead.//You can remove this check if you prefer to get the default error message.if (localizedErrorMessage.equals(fieldError.getDefaultMessage())) {String[] fieldErrorCodes = fieldError.getCodes();localizedErrorMessage = fieldErrorCodes[0];}return localizedErrorMessage;} }我們終于到了
感謝Spring MVC 3.2,我們現在實現了一種優雅的解決方案,其中,驗證由@Valid注釋觸發,并且異常處理邏輯移至單獨的類。 我認為我們可以稱之為一天,享受工作成果。
摘要
這篇博客文章告訴我們
- 如果要在使用Spring 3.0時向REST API添加驗證,則必須自己實現驗證邏輯。
- Spring 3.1通過使用@Valid批注將驗證添加到REST API成為可能。 但是,我們必須創建一個包含異常處理邏輯的通用基類。 每個需要驗證的控制器都必須擴展此基類。
- 當使用Spring 3.2時,我們可以通過使用@Valid批注來觸??發驗證過程,并將異常處理邏輯提取到單獨的類中。
Github上提供了此博客的示例應用程序( Spring 3.1和Spring 3.2 )
翻譯自: https://www.javacodegeeks.com/2013/05/spring-from-the-trenches-adding-validation-to-a-rest-api.html
總結
以上是生活随笔為你收集整理的摆脱困境:向REST API添加验证的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 老项目备案情况说明怎么写(老项目备案情况
- 下一篇: DDoS防火墙(ddos网页防火墙)