struts2校验有两种实现方法:
1. 手工编写代码实现(基本验证)
2. 基于XML配置方式实现(验证框架)
- 手工编写代码实现(基本验证)
I:首先 创建一个EmployeeAction类继承于ActionSupport 对应的页面表单元素就一个empId
public class EmployeeAction extends ActionSupport {
private Integer empId;
public void setEmpId(Integer empId) {
System. out.println("setEmpId...." );
this.empId = empId;
}
public String save() {
System. out.println("save....." );
employeeService.save(empId );
return "save-success" ;
}
//手动验证 这个方法是从ActionSupport 中继承得到的 因为ActionSupport 类实现 了Validateable的验证接口
//public class ActionSupport implements Action, Validateable, ValidationAware
@Override
public void validate() {
//这个方法是实现ValidationAware接口得到 给empId 属性手动添加一个错误消息 然后返回到浏览器进行显示
this.addFieldError("empId" , "empId为空值" );
System. out.println("validate....." );
}
}
基本原理:
I: this .addFieldError("empId" , "empId为空值" );
//ActionSupport 类中
II: public void addFieldError (String fieldName, String errorMessage) {
validationAware.addFieldError(fieldName, errorMessage);
}
在ValidationAware的实现类中定义了这个方法接口的内容
III:
public class ValidationAwareSupport implements ValidationAware, Serializable {
private Collection<String> actionErrors ;
private Collection<String> actionMessages ;
private Map<String, List<String>> fieldErrors ;
public synchronized void addFieldError (String fieldName, String errorMessage) {
Map<String, List<String>> errors = internalGetFieldErrors();获取一个Map集合
//根据fieldName获取一个List集合
List<String> thisFieldErrors = errors.get(fieldName);
if (thisFieldErrors == null) {//判断集合是否为空 为空就创建一个List集合
thisFieldErrors = new ArrayList<String>();
errors.put(fieldName, thisFieldErrors);
}
thisFieldErrors.add(errorMessage);//把fieldName和错误消息 放入集合中
}
这个方法说明最终错误消息添加到fieldErrors Map集合中
private Map<String, List<String>> internalGetFieldErrors() {
if (fieldErrors == null) {
fieldErrors = new LinkedHashMap<String, List<String>>();
}
return fieldErrors ;
}
}
显示在debug中可以看到
总结:
Action中
* 要继承ActionSupport
* 重写Validateable接口中的validate()方法 ,在该方法中完成验证
* 步骤如下:
* validate()方法在其他的业务方法之前执行
* 验证出错转向的页面
struts.xml配置<result name="input">/validate/XXX.jsp</result>
其中input转向是在action中已经定义好的.
public static final String INPUT = "input";
* 什么时候表示验证出错(转向input所指向的页面)
* this.addFieldError("sss", "错误信息");方法指向的是一个集合
* 当集合不为空时,转向错误页面.
显示错误Jsp页面:
使用<s:fielderror/>显示错误消息
补充
validate()方法会校验action中所有与execute方法签名相同的方法。
* 要校验指定的方法通过重写validateXxx()方法实现, validateXxx()只会校验action中
方法名为Xxx的方法。其中Xxx的第一个字母要大写。
* 当某个数据校验失败时,调用addFieldError()方法往系统的fieldErrors添加校验失败
信息(为了使用addFieldError()方法,action可以继承ActionSupport ),如果系统
的fieldErrors包含失败信息,struts2会将请求转发到名为input的result。
* 在input视图中可以通过<s:fielderror/>显示失败信息。
validateXxx()方法使用例子:
public String add() throws Exception{
return "success";
}
对应的验证方法
public void validateAdd(){
//验证代码
}
在ValidationInterceptor拦截器中可以看到以validate开始的方法
源码中可以看到:
public class ValidationInterceptor extends MethodFilterInterceptor { private final static String VALIDATE_PREFIX = "validate"; private final static String ALT_VALIDATE_PREFIX = "validateDo"; protected void doBeforeInvocation(ActionInvocation invocation) throws Exception { Object action = invocation.getAction(); ActionProxy proxy = invocation.getProxy(); String context = this.getValidationContext(proxy); String method = proxy.getMethod(); if (declarative ) { if (validateAnnotatedMethodOnly ) { actionValidatorManager.validate(action, context, method); } else { actionValidatorManager.validate(action, context); } } if (action instanceof Validateable && programmatic) { Exception exception = null; Validateable validateable = (Validateable) action; try { //这个和Preparable 拦截器原理相同 //在这里获取带有方法前缀的的方法 进行调用 // VALIDATE_PREFIX = "validate" ; //ALT_VALIDATE_PREFIX = "validateDo" ; PrefixMethodInvocationUtil.invokePrefixMethod( invocation, new String[] { VALIDATE_PREFIX , ALT_VALIDATE_PREFIX }); } catch(Exception e) { exception = e; } } } @Override protected String doIntercept(ActionInvocation invocation) throws Exception { doBeforeInvocation(invocation); return invocation.invoke(); } } public class PrefixMethodInvocationUtil { public static void invokePrefixMethod (ActionInvocation actionInvocation, String[] prefixes) { Object action = actionInvocation.getAction(); String methodName = actionInvocation.getProxy().getMethod(); if (methodName == null) { methodName = DEFAULT_INVOCATION_METHODNAME; } //获取带前缀的方法 Method method = getPrefixedMethod(prefixes, methodName, action); if (method != null) { //调用对应的action方法 method.invoke(action, new Object[0]); } } } //获取带前缀的方法 public class PrefixMethodInvocationUtil { public static Method getPrefixedMethod (String[] prefixes, String methodName, Object action) { assert(prefixes != null); String capitalizedMethodName = capitalizeMethodName(methodName); for (String prefixe : prefixes) { String prefixedMethodName = prefixe + capitalizedMethodName; try { return action.getClass().getMethod(prefixedMethodName, EMPTY_CLASS_ARRAY); } catch (NoSuchMethodException e) { e } } return null ; } }
输入校验的流程:
1。类型转换器对请求参数执行类型转换,并把转换后的值赋给action中的属性。
2。如果在执行类型转换的过程中出现异常,系统会将异常信息保存到ActionContext,conversionError拦截器将异常信息封装到fieldErrors里,然后执行第3步。如果类型转换没有出现异常,则直接进入第3步。
3。系统通过反射技术调用action中的validateXxx()方法,Xxx为方法名。
4。调用action中的validate()方法。
5。经过上面4步,如果系统中的fieldErrors存在错误信息(即存放错误信息的集合的size大于0),系统自动将请求转发至名称为input的视图。如果系统中的fieldErrors没有任何错误信息,系统将执行action中的处理方法。