PS:这个例子也演示了如何使用ActiveRecord + Control + Validator 完成 Crud 。
1.验证器
1.8.6以及更旧版本的验证器使用起来非常鸡肋。主要存在一下几个缺点:
基于上述两点,本次即将发布的版本1.9针对它们做了改善。请先看看下面这段代码;
Pet.java
@Entity @Table(name = "t_pet") public class Pet extends Model { public final static Pet inst = new Pet(); @Required @Length(min = 6, max = 6) private String num; @Required @Length(min = 2, max = 6) @Chinese @Forbid(words = {"性爱", "革命"}) private String name; @Size(min = 1, max = 10) private int age = 1; @Required @Enumer(words = { "猫", "狗" }) private String type; @Override public String toString() { return "Pet [num=" + num + ", name=" + name + ", age=" + age + ", type=" + type + ", id=" + id + "]"; } //setters and getters }
PetsControl.java
public class PetsControl { private final static String PAGE_INT = "分页参数必须是整数格式"; private final static String PAGE_VALID = "分页参数必须大于 0 "; private final static ListTYPES = Arrays.asList("狗", "猫"); private Pet pet = new Pet();// inject when create and update @Required @Size(min = 1) @Int private Long id; @Int(mess = PAGE_INT) @Size(min = 1, mess = PAGE_VALID) private int pageNum = 1; @Int(mess = PAGE_INT) @Size(min = 1, mess = PAGE_VALID) private int numPerPage = 10; private String keyword = ""; @Validate({ "pageNum", "numPerPage" }) public String index(Validation val, Map model) { if (val.hasErr()) return JsonConverter.convert(val.getAllErr()); model.put("pets", Pet.inst.find().fetch(pageNum, numPerPage)); model.put("dpc", new DivPageComp(pageNum, numPerPage, Pet.inst.count())); return "html"; } public String doSearchAtGet(Map model) { model.put("pets", Pet.inst.find("name like ?", "%" + keyword + "%") .fetch()); return "fmt:pets/view/list.html"; } @Validate("pet.*") @Transactional public String create(Validation val, Map model) { if (val.hasErr()) return JsonConverter.convert(val.getAllErr()); pet.create(); model.put("types", TYPES); return "index"; } @Validate({ "id", "pet.*" }) @Transactional public String update(Validation val, Map model) { if (val.hasErr()) return JsonConverter.convert(val.getAllErr()); pet.setId(id); pet.save(); model.put("types", TYPES); return "index"; } @Validate("id") @Transactional public String destroy(Validation val) { if (val.hasErr()) return JsonConverter.convert(val.getAllErr()); pet.setId(id); pet.delete(); return "index"; } @Validate("id") public String show(Validation val) { if (val.hasErr()) return JsonConverter.convert(val.getAllErr()); pet.setId(id); pet.load(); return "html"; } @Validate("id") public String edit(Validation val, Map model) { if (val.hasErr()) return JsonConverter.convert(val.getAllErr()); pet.setId(id); pet.load(); model.put("types", TYPES); return "html"; } public String editNew(Map model) { model.put("types", TYPES); return "html"; } //setters and getters }
上面有个 doSearchAtGet 方法不是默认约定的方法,是属于自定义的Action方法。请对照前面博文中提到的 Action 方法名字新语法支持的内容。
注意对照 7 个默认的方法:
HTTP Method | URI | Class.Method | Params |
GET | /demo | DemoControl.index | |
POST | /demo | DemoControl.create | |
PUT | /demo/{id} | DemoControl.update | id={id} |
DELETE | /demo/{id} | DemoControl.destroy | id={id} |
GET | /demo/{id} | DemoControl.show | id={id} |
GET | /demo/{id}/edit | DemoControl.edit | id={id} |
GET | /demo/new | DemoControl.editNew | id={id} |
当执行 GET /pets/new 打开 new.html后,直接什么也不填写就提交,然后验证器生效,页面上会打印:
{"pet.num":"请完成必填内容","pet.name":"请填写全中文"}
可以看到好几个Action方法上面都有 @Validate 注解。这个注解填写一个字符串数组。这些数组声明了在执行这个Action的时候哪些参数需要被验证。具体的验证规则交由属性上的那些类似 @Required @Size @Forbid 这样的注解来定义。也就是说:
验证过程分为两点:
1.定义规则, 在属性上面标注 @Required 等等的注解。
2.触发验证行为, 在Action方法上标注 @Validate({"param1", "param2"}),来声明那些需要被验证的参数
还有最后一个就是验证行为一旦触发,并且检测到错误消息后,框架不再截断当前Action的执行,而是将验证信息封装到一个 Validation 对象里面,就像:
@Validate({ "id", "pet.*" }) @Transactional public String update(Validation val, Map model) { if (val.hasErr()) return JsonConverter.convert(val.getAllErr()); return "通过验证啦..."; }
具体怎么判断是否验证不通过,直接调用:
boolean flag = val.hasErr();
然后取出所有的参数验证信息:
Maperrors = val.getAllErr();
上面这个 Map 里面是 “参数名”-“验证信息”这样的结构的。只要某个参数违反了验证规则的话,那么这个Map里面就会存在该参数以及对应的验证错误消息。
例如:
{"pet.age":"请填写一个大小介于 1 到 10 之间的整数","pet.num":"请填写长度介于6到6之间的文本","pet.name":"请不要包含下列字眼:[性爱#革命] "}
这个PetControl的代码最好细细品读。方能理解一些约定思想。
最后重申:约定优于配置, 配置覆盖约定。