Как проверить значения Spring MVC @PathVariable?
Для простого RESTful JSON api, реализованного в Spring MVC, могу ли я использовать Bean Validation (JSR-303) для проверки переменных пути, переданных в метод обработчика?
Например:
@RequestMapping(value = "/number/{customerNumber}")
@ResponseBody
public ResponseObject searchByNumber(@PathVariable("customerNumber") String customerNumber) {
...
}
Здесь мне нужно проверить длину переменной customerNumber с помощью проверки Bean. Возможно ли это с помощью Spring MVC v3.x.x? Если нет, то какой лучший подход для этого типа валидации?
Спасибо.
Ответы
Ответ 1
Spring не поддерживает @javax.validation.Valid
@PathVariable
аннотированных параметров @PathVariable
в методах-обработчиках. Был запрос на улучшение, но он все еще не решен.
Лучше всего просто выполнить пользовательскую проверку в теле метода-обработчика или использовать org.springframework.validation.annotation.Validated
как предлагается в других ответах.
Ответ 2
Вы можете использовать следующее:
используйте org.springframework.validation.annotation.Validated
для действительных RequestParam
или PathVariable
.
*
* Variant of JSR-303 {@link javax.validation.Valid}, supporting the
* specification of validation groups. Designed for convenient use with
* Spring 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));
}
}
}
Ответ 3
Решение простое:
@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}"
}
И да, PathVariables должны быть проверены, как и любой пользовательский ввод.
Ответ 4
@PathVariable
не подлежит проверке, чтобы отправить обратно читаемое сообщение пользователю. Как правило, pathVariable никогда не должен быть недействительным. Если pathVariable недействителен, причиной может быть:
- ошибка сгенерировала плохой url (например, href в jsp). Нет
@Valid
необходимо и сообщение не требуется, просто исправьте код;
- "пользователь" манипулирует URL-адресом.
Опять же, no
@Valid
не требуется, никакое содержательное сообщение пользователю не должно
.
В обоих случаях просто оставляйте пузырь для исключения до тех пор, пока он не поймается обычный Spring ExceptionHandlers, чтобы создать приятный страницу ошибки или значимый ответ json, указывающий на ошибку. В Чтобы получить этот результат, вы можете выполнить некоторую проверку с помощью настраиваемых редакторов.
Создайте класс 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
Вместо использования @PathVariable вы можете воспользоваться возможностью Spring MVC для отображения переменных пути в bean-компонент:
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/{id}")
public void get(@Valid GetDto dto) {
// dto.getId() is the path variable
}
}
И бин содержит действительные правила проверки:
@Data
public class GetDto {
@Min(1) @Max(99)
private long id;
}
Убедитесь, что ваши переменные пути ({id}
) соответствуют полям бина (id
);
Ответ 6
Переменная пути не может быть связана с любым bean в вашей системе. Что вы хотите комментировать аннотациями JSR-303?
Чтобы проверить переменную пути, вы должны использовать этот подход Проблема проверки URL @PathVariable на spring 3 mvc