您的位置:首页 > 产品设计 > UI/UE

数据校验:fluent_validator运用过程

2018-02-28 23:08 656 查看
前言:  话说写这篇博客已经拖了很久了, 一直没写.  怎么说:懒.  年后回来就没正常过,今儿个怎么想起了写呢?  我能说吃蓝莓吃多了,拉肚子不?
上回书说到使用fluent_validator做有关于逻辑的统一校验,但事已至此, 其实最终由于产品形态不一, 还是没能形成一个校验模板. 不过,有关于fluent这个东西,还是可以一说的.

一、思想的转变历程

我最开始, 是希望用注解做基本的输入校验, 而用fluent这个东西,封装一个通用的校验器。  我为什么会这样想呢? 首先: 保险标的,要么是人、要么是物。  当为人的时候, 有几个通用的校验点: 1, 当证件类型为身份证, 可不必输入性别和年龄;2,校验投保人和被保人的年龄 ,其余的不说, 至少这两点是很基本的。  而当为物的时候, 通常会有2个基本校验点:1, 当被保标的同投保企业的时候,不必输入标的属性; 2,当标的物同标的时,可不必输入标的物。  
所以,我的想法是: 将其公有属性抽象在一个基类中, 编辑一个基于此类的统一校验器。  却结果, too young too simple
让我自己感觉自己很年轻的现象有:
1, 我以为可以抽象的基本属性, 其实并不是每款产品都有,甚至是双数的条件都达不到。  比如说基本输入校验里的手机短信校验码, 有的产品不需要, 有的产品需要,这时候,我根本不能在基类的这个字段上让其不能为空
2, 同样是年龄校验, 有的单位是周岁、有的单位是天, 呵呵哒,听说还有按月的
3, 我们当时要做的模板, 和我理解的模板不一样,我理解的是我编辑基础的类,可以复用可以继承。 然而, 由于产品形态的多样性, 我们只需要抽象出基本的产品开发步骤和规范即可。  目前的产品形态, 支持不了做更细化的模板封装。

二、后来的结果



每个需要逻辑校验的产品, 都各自有一个校验器, 而一些公用的方法,被整理为了工具类, 比如说通过身份证号获取性别、年龄等。
虽然说没有做成一个统一公用的校验器, 但对于校验这块内容, 比起之前一堆的if else嵌套在一起,现在显得更为有条理性
其具体应用,可以参考上一篇博客中的链接加以深入理解, 也可以在其GitHub介绍上加以学习。 以下贴以下目前产品中的相应应用:

public class BabyProposalValidator extends ValitatorUtils implements Validator<BabyProposalFacadeDTO> {
@Override
public boolean accept(ValidatorContext validatorContext, BabyProposalFacadeDTO babyProposalFacadeDTO) {
return true;
}

@Override
public void onException(Exception e, ValidatorContext validatorContext,
BabyProposalFacadeDTO babyProposalFacadeDTO) {

}

@Override
public boolean validate(ValidatorContext context, BabyProposalFacadeDTO bo) {

//投保人校验
Boolean holderFlag = holderValidator(context, bo.getProposalHolderPerson(), 18, null, null);
if (holderFlag) {
//被保人校验
for (BabyProposalSubjectPersonMasterFacadeDTO subject : bo.getProposalSubjectPersonMasters()) {
Boolean subjectFlag = subjectValidator(context, subject, bo.getStartDate());
if (!subjectFlag) {
return false;
}
}
return true;
}
return false;
}

/**
* 被保人校验器
*
* @param context 上下文
* @param subject 被保人数据
* @param subjectEndDate 被保人年龄计算截止日期
* @return 通过校验返回true
*/
private Boolean subjectValidator(ValidatorContext context, BabyProposalSubjectPersonMasterFacadeDTO subject,
String subjectEndDate) {
Boolean certNoValidateRet = certNoValidator(context, subject.getCertType(), subject.getSex(),
subject.getBirthday(), subject.getCertNo(), "被");
if (certNoValidateRet) {
if(subject.getCertType()==1){
IDCodeInfo idCodeInfo = getIDCodeInfo(subject.getCertNo());
Integer sex = idCodeInfo.getSex();
subject.setSex(sex.equals(1) ? PolicyEnum.Sex.MALE.getCode() : sex.equals(0) ?
PolicyEnum.Sex.FEMALE.getCode() : PolicyEnum.Sex.OTHER.getCode());
subject.setBirthday(LocalDate.parse(idCodeInfo.getBirth()).toDate());
}
if (Days.daysBetween(new LocalDate(subject.getBirthday()), new LocalDate()).getDays() < 90) {
context.addErrorMsg("被保人出生需满90天");
return false;
}
if (Years.yearsBetween(new LocalDate(subject.getBirthday()),
LocalDate.parse(subjectEndDate.substring(0, 10))).getYears() > 10) {
context.addErrorMsg("被保人年龄需小于10周岁");
return false;
}
return true;
}
return false;
}

/**
* 投保人校验器
*
* @param context 校验上下文
* @param holder 投保人数据
* @param holderAgeMin 投保人最小年龄
* @param holderAgeMax 投保人最大年龄
* @param holderEndDate 计算截止日期
* @return 校验通过返回true
*/
private Boolean holderValidator(ValidatorContext context, BabyProposalHolderPersonFacadeDTO holder,
Integer holderAgeMin, Integer holderAgeMax, Date holderEndDate) {
Boolean holderValidateRet = certNoValidator(context, holder.getCertType(), holder.getSex(),
holder.getBirthday(), holder.getCertNo(), "投");
if (holderValidateRet) {
if(holder.getCertType()==1){
IDCodeInfo idCodeInfo = getIDCodeInfo(holder.getCertNo());
Integer sex = idCodeInfo.getSex();
holder.setSex(sex.equals(1) ? PolicyEnum.Sex.MALE.getCode() : sex.equals(0) ?
PolicyEnum.Sex.FEMALE.getCode() : PolicyEnum.Sex.OTHER.getCode());
holder.setBirthday(LocalDate.parse(idCodeInfo.getBirth()).toDate());
}
//校验投保人年龄
return holderAgeValidator(context, holder.getBirthday(), holderEndDate, holderAgeMin, holderAgeMax);
}
return false;
}

}魔法值是每个产品的不同点, 最开始这些参数都是从外传递的, 呃,后来整个就懒了嘛, 反正每个产品一个校验器,就直接写好了,嘿嘿(心情不好的时候, 写代码很是放纵,反正领导不会看我写博客叨叨,我无敌我怕谁)
使用示例: Result ret = FluentValidator.checkAll()
.on(bo, new BabyProposalValidator())
.doValidate()
.result(toSimple());

if (!ret.isSuccess()) {
return ResponseBzn.build("-1", ret.getErrors().get(0));
}备注: 可以设置这个校验器执行的时机(通过when语句),也可以设置一些参数

三、个人总结

最近一直在做产品的代码重构和迁移, 发现一个问题: 我格局太小。  就拿这个校验器的封装为例, 我就一心想做一个通用的出来, 但事实上结合到产品形态,我这想法本身就不成熟。 
当然,也不能说格局太小, 怎么说呢,也许是经历的太少了。  以前从来没有接触过保险产品, 也没有想到每个保险公司对接的产品都各有风格,甚至是同一保险公司对接的产品都各有风格,在只接触了少数合作公司和少数产品的基础上, 要去做一个通用的东西,总觉得不太现实,涵盖不了一些变态的东西。
总之: 多学习,多努力。  感谢现在的同事给我安排的工作, 因为我在完成的过程中, 对于保险产品的开发流程, 形态变化有了更深的理解。  最后,讲个笑话给大家听: 我也不知道我有一回是买啥了, 然后就告诉我免费送一份保险给我,让我填信息, 我了个去, 我一看就填个手机号,姓名,别的都没有了, 心里立马断定这玩意儿不靠谱!  ——职业病
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: