Spring MVCで実装された単純なRESTful JSON APIの場合、Bean Validation(JSR-303)を使用してハンドラーメソッドに渡されたパス変数を検証できますか?
例えば:
@RequestMapping(value = "/number/{customerNumber}")
@ResponseBody
public ResponseObject searchByNumber(@PathVariable("customerNumber") String customerNumber) {
...
}
ここでは、Bean検証を使用してcustomerNumber変数の長さを検証する必要があります。これはSpring MVC v3.x.xで可能ですか?そうでない場合、このタイプの検証に最適なアプローチは何ですか?
ありがとう。
Springは、ハンドラメソッドの@javax.validation.Valid
アノテーション付きパラメータの@PathVariable
をサポートしていません。改善リクエストがありましたが、まだ 未解決 です。
最善の策は、ハンドラメソッドの本文でカスタム検証を行うか、他の回答で提案されているorg.springframework.validation.annotation.Validated
の使用を検討することです。
次のように使用できます。org.springframework.validation.annotation.Validated
を使用して、RequestParam
またはPathVariable
を有効にします。
*
* 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 init 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));
}
}
}
@PathVariable
は、ユーザーに読み取り可能なメッセージを返信するために検証されることを意図していません。原則として、pathVariableは無効にしないでください。 pathVariableが無効な場合、理由は次のとおりです。
@Valid
が必要で、メッセージは必要ありません。コードを修正してください。@Valid
が必要です。ユーザーに意味のあるメッセージを与える必要はありません。どちらの場合も、Niceエラーページまたはエラーを示す意味のあるjson応答を生成するために、通常のSpring ExceptionHandlerによってキャッチされるまで、例外バブルをそのままにしておきます。この結果を得るために、カスタムエディターを使用して検証を行うことができます。
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) {
...
}
解決策は簡単です:
@GetMapping(value = {"/", "/{hash:[a-fA-F0-9]{40}}"})
public String request(@PathVariable(value = "hash", required = false) String historyHash)
{
// Accepted requests: either "/" or "/{40 character long hash}"
}
そして、はい、パス変数は、ユーザー入力と同様に検証されることを意図しています。
パス変数は、システム内のどのBeanともリンクされていない可能性があります。 JSR-303アノテーションで何をアノテーションしたいですか?パス変数を検証するには、このアプローチを使用する必要があります Spring 3 mvcで@PathVariable urlを検証する問題