
我们大家经常在通过数字标识符工作的控制器中编写简单的方法。
@RequestMapping(value = {"/entityName/{entityId}/get"}, method = RequestMethod.GET) @ResponseBody public Entity get(@PathVariable(value = "entityId") Integer entityId) {
传入ID必须经过验证。
例如,并非所有用户都可以访问所有ID。
可以理解,使用UUID更安全,更可靠。 但是必须创建,存储,索引等。 对于所有实体,这样做都是漫长而困难的。 在许多情况下,使用常规数字ID会更容易。
验证可以通过一种简单的方式完成:
@RequestMapping(value = {"/entityName/{entityId}/get"}, method = RequestMethod.GET) @ResponseBody public Entity get(@PathVariable(value = "entityId") Integer entityId) { if(!@dao.validate(entityId)) return some_error;
该解决方案只有一个优点。 简单快捷。
其他一切都不好。 代码重复,验证与对象验证不兼容;每种方法都需要单独的处理。
我要这样做:
@RequestMapping(value = {"/entityName/{entityId}/get"}, method = RequestMethod.GET) @ResponseBody public Entity get(@Validated @PathVariable(value = "entityId") Integer entityId) {
此简单而逻辑的选项不起作用。 验证器根本就没有被调用。 不支持Spring验证PathVariable。
为了使此选项起作用,您需要将PathVariable转换为ModelAttribute:
@ModelAttribute private Integer integerAsModelAttribute(@PathVariable("entityId") Integer id) { return id; }
并且在访问控制器时出现错误。 泛型类型的包装器没有没有参数的默认构造函数,并且没有设置器。 使用Optional可以解决此问题。 他有一个默认构造函数和一个接受普通整数的setter。
将Integer转换为Optional:
@ModelAttribute private Integer integerAsModelAttribute(@PathVariable("entityId") Optional<Integer> id) { return id.orElse(null); }
相应地,控制器方法本身和验证器声明:
@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) {
验证器类是绝对正常的:
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"); } } }
一个完整的工作示例可以在
这里获得 。