2013-10-17 75 views
4

對於在Spring MVC中實現的簡單RESTful JSON api,我可以使用Bean Validation(JSR-303)來驗證傳入處理程序方法的路徑變量嗎?如何驗證Spring MVC @PathVariable的值?

例如:

@RequestMapping(value = "/number/{customerNumber}") 
@ResponseBody 
public ResponseObject searchByNumber(@PathVariable("customerNumber") String customerNumber) { 
... 
} 

在這裏,我需要使用Bean驗證驗證爲CustomerNumber變量的長度。這是可能的與Spring MVC v3.x.x?如果不是,這種驗證最好的方法是什麼?

謝謝。

回答

18

春天在處理方法@PathVariable註釋參數不支持@Valid。有一個改進請求,但它仍然是unresolved

最好的辦法就是在處理程序方法體中進行自定義驗證。

0

路徑變量可能不會與系統中的任何bean鏈接。你想用JSR-303註釋來註釋什麼? 要驗證路徑變量,你應該使用這種方法Problem validating @PathVariable url on spring 3 mvc

+0

你給的鏈接說: 「如果PathVariable參數驗證失敗,那麼Spring將錯誤自動添加到請求的BindingResult,你不需要做你自己「。 這是否意味着@PathVariable params上的bean驗證是可能的?它沒有清楚地說出它是否可能。可能是我誤解了。我已經按照建議的方式嘗試過了,但是當驗證失敗時,綁定結果沒有任何錯誤。 – Grover

3

@PathVariable並不意味着爲了向用戶發送可讀消息而進行驗證。作爲原則,pathVariable不應該是無效的。如果路徑變量無效,原因可能是:

  1. 一個錯誤生成了一個錯誤的URL(例如jsp中的href)。沒有@Valid是 需要和沒有消息是必要的,只是修復代碼;
  2. 「用戶」正在操縱網址。 再次,沒有@Valid是必要的,沒有有意義的消息給用戶應該給予 。

在這兩種情況下,只留下一個異常泡沫,直到它被 以產生一個很好的 錯誤頁面或指示錯誤有意義的JSON響應擦肩而過,通常春天的ExceptionHandlers。在 爲了得到這個結果,你可以使用自定義編輯器做一些驗證。

創建CustomerNumber類,可能是不可變的(實施CharSequence沒有必要的,但允許就好像它是一個String你基本上用它)

public class CustomerNumber implements CharSequence { 

    private String customerNumber; 

    public CustomerNumber(String customerNumber) { 
     this.customerNumber = customerNumber; 
    } 

    @Override 
    public String toString() { 
     return customerNumber == null ? null : customerNumber.toString(); 
    } 

    @Override 
    public int length() { 
     return customerNumber.length(); 
    } 

    @Override 
    public char charAt(int index) { 
     return customerNumber.charAt(index); 
    } 

    @Override 
    public CharSequence subSequence(int start, int end) { 
     return customerNumber.subSequence(start, end); 
    } 

    @Override 
    public boolean equals(Object obj) { 
     return customerNumber.equals(obj); 
    } 

    @Override 
    public int hashCode() { 
     return customerNumber.hashCode(); 
    } 
} 

創建編輯器實現您的驗證邏輯(在此情況下,沒有空格和固定的長度,只是作爲一個例子)

public class CustomerNumberEditor extends PropertyEditorSupport { 

    @Override 
    public void setAsText(String text) throws IllegalArgumentException { 

     if (StringUtils.hasText(text) && !StringUtils.containsWhitespace(text) && text.length() == YOUR_LENGTH) { 
      setValue(new CustomerNumber(text)); 
     } else { 
      throw new IllegalArgumentException(); 
      // you could also subclass and throw IllegalArgumentException 
      // in order to manage a more detailed error message 
     } 
    } 

    @Override 
    public String getAsText() { 
     return ((CustomerNumber) this.getValue()).toString(); 
    } 
} 

註冊在控制器中的編輯器

@InitBinder 
public void initBinder(WebDataBinder binder) { 

    binder.registerCustomEditor(CustomerNumber.class, new CustomerNumberEditor()); 
    // ... other editors 
} 

更改您的控制器方法的簽名接受CustomerNumber而不是String(無論您的ResponseObject是...)

@RequestMapping(value = "/number/{customerNumber}") 
@ResponseBody 
public ResponseObject searchByNumber(@PathVariable("customerNumber") CustomerNumber customerNumber) { 
    ... 
} 
5

你可以使用這樣的: 使用org.springframework.validation.annotation.Validated爲有效RequestParamPathVariable

* 
* Variant of JSR-303's {@link javax.validation.Valid}, supporting the 
* specification of validation groups. Designed for convenient use with 
* Spring's JSR-303 support but not JSR-303 specific. 
* 

STEP.1初始化ValidationConfig

@Configuration 
public class ValidationConfig { 
    @Bean 
    public MethodValidationPostProcessor methodValidationPostProcessor() { 
     MethodValidationPostProcessor processor = new MethodValidationPostProcessor(); 
     return processor; 
    } 
} 

step.2添加@Validated到控制器處理程序類,像:

@RequestMapping(value = "poo/foo") 
@Validated 
public class FooController { 
... 
} 

STEP.3開始添加validators到您的處理方法:

@RequestMapping(value = "{id}", method = RequestMethod.DELETE) 
    public ResponseEntity<Foo> delete(
      @PathVariable("id") @Size(min = 1) @CustomerValidator int id) throws RestException { 
     // do something 
     return new ResponseEntity(HttpStatus.OK); 
    } 

最後一步。異常解析器添加到您的上下文:

@Component 
public class BindExceptionResolver implements HandlerExceptionResolver { 

    @Override 
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { 
     if (ex.getClass().equals(BindException.class)) { 
      BindException exception = (BindException) ex; 

      List<FieldError> fieldErrors = exception.getFieldErrors(); 
      return new ModelAndView(new MappingJackson2JsonView(), buildErrorModel(request, response, fieldErrors)); 
     } 
    } 
}