
Nous écrivons tous souvent des méthodes simples dans des contrôleurs travaillant à travers des identificateurs numériques.
@RequestMapping(value = {"/entityName/{entityId}/get"}, method = RequestMethod.GET) @ResponseBody public Entity get(@PathVariable(value = "entityId") Integer entityId) {
L'ID entrant doit être validé.
Par exemple, tous les utilisateurs n'ont pas accès à tous les ID.
Il est entendu que l'utilisation des UUID est plus sûre et plus fiable. Mais il doit être créé, stocké, indexé, etc. Pour toutes les entités, cela est long et difficile. Dans de nombreux cas, il est plus facile de travailler avec des identifiants numériques normaux.
La validation peut se faire de manière simple:
@RequestMapping(value = {"/entityName/{entityId}/get"}, method = RequestMethod.GET) @ResponseBody public Entity get(@PathVariable(value = "entityId") Integer entityId) { if(!@dao.validate(entityId)) return some_error;
Il n'y a qu'un seul plus dans cette solution. Simple et rapide.
Tout le reste est mauvais. Duplication de code, la validation n'est pas compatible avec la validation d'objet; un traitement séparé dans chaque méthode est nécessaire.
Je veux faire ça:
@RequestMapping(value = {"/entityName/{entityId}/get"}, method = RequestMethod.GET) @ResponseBody public Entity get(@Validated @PathVariable(value = "entityId") Integer entityId) {
Cette option simple et logique ne fonctionne pas. Le validateur n'est tout simplement pas appelé. La validation de PathVariable par Spring n'est pas prise en charge.
Pour que cette option fonctionne, vous devez transformer PathVariable en ModelAttribute:
@ModelAttribute private Integer integerAsModelAttribute(@PathVariable("entityId") Integer id) { return id; }
Et obtenez une erreur lors de l'accès au contrôleur. Les wrappers de types génériques n'ont pas de constructeur par défaut sans paramètres et il n'y a pas de setter. Cela permet de contourner l'utilisation de Facultatif. Il a à la fois un constructeur par défaut et un setter acceptant les entiers ordinaires.
Transformez l'entier en facultatif:
@ModelAttribute private Integer integerAsModelAttribute(@PathVariable("entityId") Optional<Integer> id) { return id.orElse(null); }
Et en conséquence, la méthode du contrôleur elle-même et la déclaration du validateur:
@InitBinder({"entityId"}) protected void initCommissionIdBinder(WebDataBinder binder) { binder.setValidator(validateEntityIdValidator); binder.setBindEmptyMultipartFiles(false); } @RequestMapping(value = {"/entityName/{entityId}/get"}, method = RequestMethod.GET) @ResponseBody public Entity get(@Validated @ModelAttribute(value = "entityId") Integer entityId) {
La classe de validateur est absolument normale:
public class ValidateIntegerValidator implements Validator { @Override public boolean supports(Class<?> aClass) { return Integer.class.equals(aClass); } @Override public void validate(Object o, Errors errors) { if(o instanceof Integer) { Integer integer = (Integer) o; if(!dao.checkId(integer)) { errors.reject("-1", "ERROR"); } } else { errors.reject("-2","WRONG TYPE"); } } }
Un exemple de travail complet peut être
pris ici .