【发布时间】:2010-11-05 23:07:52
【问题描述】:
我不确定让验证器根据数据库状态验证命令是否是一个好的设计决策。例如,如果除了检查电子邮件和用户名是否为空等之外,我还需要验证用户 bean。如果它们已被使用,我还需要拒绝这些值。这种逻辑应该放在验证器还是服务对象中?
【问题讨论】:
标签: java validation spring spring-mvc
我不确定让验证器根据数据库状态验证命令是否是一个好的设计决策。例如,如果除了检查电子邮件和用户名是否为空等之外,我还需要验证用户 bean。如果它们已被使用,我还需要拒绝这些值。这种逻辑应该放在验证器还是服务对象中?
【问题讨论】:
标签: java validation spring spring-mvc
好吧,您的验证器只是 spring bean,对,所以它们可以被注入处理数据访问的服务对象。您可以让您的验证器从数据库中获取数据,而不会影响设计。
【讨论】:
这在很大程度上取决于您如何定义验证。考虑一下:您正在买东西,然后输入您的信用卡号。如果校验位不匹配,则验证失败。没有尝试过交易。但是,如果它是一个有效的信用卡号,但它与您的邮政编码不匹配(需要 DB/第三方交互),那么这是一个付款错误。
现在考虑一下:您正在输入您的地址,并且您输入 Mastiffica 作为您的国家。为什么系统甚至允许您输入 - 他们应该将界面限制为仅有效条目(无需 DB 后条目)。
或者您在银行付款屏幕的金额字段中输入“五十”。为什么它允许那里的字母 - 验证失败(不需要数据库)。但是您随后在金额字段中输入 50,结果您的帐户中没有 50 英镑。那是验证错误吗?还是交易失败?
现在,假设您已通过所有基本输入验证(信用卡校验和、国家/地区、数字、邮政编码)并且交易失败,因为您的信用卡已过期。是验证错误,还是交易失败?
您可以将验证视为用户不会输入完全野蛮数据的基本保证,或者您可以将验证视为“我可以使用已提供的数据完成此交易”。我个人倾向于前者,但同样,这是定义问题。
然后是作为安全措施的第一行验证方面 - 通过您的顶级 UI 层接受的野数据可能是安全风险(例如 SQL 注入)
【讨论】:
不,恕我直言,验证器应该很小,side-effect free 以便让它们轻松组合。确实,验证器应该与持久层解耦。
【讨论】:
我检查了我的一个,我正在从验证器调用服务层:
@Service
public final class StartFormValidator {
private FacilityService facilityService;
private AdminService adminService;
/**
* Verify that they've selected a facility. Verify that they've selected a
* valid facility. Verify that they've selected a view and that it's a valid
* view.
*
* @param startForm
* @param errors
* @return true if no errors were set
*/
public boolean isValid(final StartForm startForm, final Errors errors) {
if (startForm.getFacilityId() == 0) {
errors.rejectValue("facilityId", "facilityIdEmpty",
"Select a facility.");
}
if (!this.facilityService.isFacilWaitlistEnabled(startForm
.getFacilityId())) {
errors.rejectValue("facilityId", "facilityInvalid",
"Invalid facility");
}
if (StringUtils.isBlank(startForm.getPassword())) {
errors.rejectValue("password", "passwordEmpty",
"Enter the password.");
return (false);
}
if (!this.adminService.validateAdmin(startForm.getPassword()))
errors.rejectValue("password", "passwordInvalid",
"Incorrect password");
return (!errors.hasErrors());
}
/**
* @param _facilityService
*/
@Autowired
public void setFacilityService(final FacilityService _facilityService) {
this.facilityService = _facilityService;
}
/**
* @param _adminService
*/
@Autowired
public void setAdminService(final AdminService _adminService) {
this.adminService = _adminService;
}
}
【讨论】:
如果你真的相信“MVC”,那么我不这么认为,你会希望你的验证器进入数据库。验证是一个从业务逻辑的角度验证数据的阶段。
数据库不需要知道验证器将如何使用它,验证器也不应该知道数据库是什么样的。这不适合 MVC 模型。明天,如果您有来自多个来源的数据,您是否仍会继续告诉您的验证器,它应该在什么条件下访问具体的哪个来源。这本身将构成甚至不需要的逻辑。在应用中。
您正在寻找的验证类型将作为业务对象的一部分使用,这将确保在服务对象甚至被调用之前;这种组合尚不存在。
Service 对象也不应该包含业务验证,因此它既不属于验证器也不属于 Service 对象。但是,是的,如果应用程序足够小而不必担心太多层,那么偏斜的方法就可以了,但只要“始终遵循它作为标准”即可。
简而言之,我觉得 Spring 验证器是用于基本验证而不是真正的业务验证。
【讨论】:
由于最终用户的可用性,我赞成使用数据库的验证。
在提交注册表单时,您要检查用户名在语法上是否正确以及该用户名是否尚未提供(需要数据库访问权限)。
表单可以立即返回所有错误。它可以向用户显示所有问题。用户可以修复它并再次发送表单。
我知道您可以使用 ajax 等更智能地做到这一点,这不是重点。
我总是检查一切。我检查此表格是否将由即将进行的交易处理。如果没有,我会因为一些可以轻松处理的并发访问而出现异常。
【讨论】: