(1) 添加校验项
修改文件
src/main/resources/com/mycompany/app/model/Person-validation.xml
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<validators>
<field name="person.firstname">
<field-validator type="requiredstring">
<message key="errors.required"/>
</field-validator>
</field>
<field name="person.lastname">
<field-validator type="requiredstring">
<message key="errors.required"/>
</field-validator>
</field>
</validators>
重新编译,重新访问添加人员的页面,姓、名设置为空直接保存,报错
校验起了作用
(2) struts.xml文件的配置说明
......
<!-- Constants -->
<!-- 常量设置 -->
<!--
是否处于开发模式下
设置为true则表示处在开发模式下,应用出现异常和错误时将给开发人员提供更有益于调试的错误信息
设置为false则表示不处在开发模式下,一般应用在应用发布之后
-->
<constant name="struts.devMode" value="false"/>
<!-- 指定应用的默认编码 -->
<constant name="struts.i18n.encoding" value="UTF-8"/>
<!-- 指定符合哪种后缀格式的请求由struts来处理 -->
<constant name="struts.action.extension" value="html"/>
<!-- 指定默认的ObjectFactory,设置值为spring后将由spring管理bean -->
<constant name="struts.objectFactory" value="spring"/>
<!-- 指定应用国际化需要的资源文件,多种时以逗号分隔 -->
<constant name="struts.custom.i18n.resources" value="ApplicationResources,errors"/>
<!-- 指定struts2的上传组件请求内容的最大字节数 -->
<constant name="struts.multipart.maxSize" value="2097152"/>
<!-- 指定模板主题,其它的还有simple,xhtml -->
<constant name="struts.ui.theme" value="css_xhtml"/>
<!-- 指定应用jsp文件的根路径 -->
<constant name="struts.codebehind.pathPrefix" value="/WEB-INF/pages/"/>
<!-- 是否允许在Action名中使用斜线 -->
<constant name="struts.enable.SlashesInActionNames" value="true"/>
。。。。。。
(3) 校验流程分析
struts.xml中定义默认包时
<!-- 定义default包,继承自struts-default包,将自动拥有struts-default包的所有配置 -->
<package name="default" extends="struts-default">
而在struts-default.xml中,配置了如下的拦截器
<interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
<interceptor-stack name="paramsPrepareParamsStack">
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel</param>
</interceptor-ref>
</interceptor-stack>
当执行添加操作时会被validation拦截器拦截
AnnotationValidationInterceptor中的doIntercept方法
protected String doIntercept(ActionInvocation invocation) throws Exception {
Object action = invocation.getAction();
if (action != null) {
Method method = getActionMethod(action.getClass(), invocation.getProxy().getMethod());
SkipValidation skip = (SkipValidation) method.getAnnotation(SkipValidation.class);
if (skip != null) {
return invocation.invoke();
}
}
return super.doIntercept(invocation);
}
再看父类的doIntercept方法
protected String doIntercept(ActionInvocation invocation) throws Exception {
doBeforeInvocation(invocation);
return invocation.invoke();
}
再看触发前要执行的方法doBeforeInvocation(invocation)
protected void doBeforeInvocation(ActionInvocation invocation) throws Exception {
Object action = invocation.getAction();
String context = invocation.getProxy().getActionName();
String method = invocation.getProxy().getMethod();
if (log.isDebugEnabled()) {
log.debug("Validating "
+ invocation.getProxy().getNamespace() + "/" + invocation.getProxy().getActionName() + " with method "+ method +".");
}
if (validateAnnotatedMethodOnly) {
ActionValidatorManagerFactory.getInstance().validate(action, context, method);
} else {
ActionValidatorManagerFactory.getInstance().validate(action, context);
}
}
再看ActionValidatorManagerFactory.getInstance()
public class ActionValidatorManagerFactory {
private static final Log LOG = LogFactory.getLog(ActionValidatorManagerFactory.class);
private static ActionValidatorManager instance = new DefaultActionValidatorManager();
static {
try {
Class c = ClassLoaderUtil.loadClass("com.opensymphony.xwork2.validator.AnnotationActionValidatorManager", ActionValidatorManagerFactory.class);
LOG.info("Detected AnnotationActionValidatorManager, initializing it...");
instance = (ActionValidatorManager) c.newInstance();
} catch (ClassNotFoundException e) {
// this is fine, just fall back to the default object type determiner
} catch (Exception e) {
throw new XWorkException(e);
}
}
public static void setInstance(ActionValidatorManager instance) {
ActionValidatorManagerFactory.instance = instance;
}
public static ActionValidatorManager getInstance() {
return instance;
}
}
再看com.opensymphony.xwork2.validator.AnnotationActionValidatorManager中的validate(Object object, String context, ValidatorContext validatorContext, String method)方法
public void validate(Object object, String context, ValidatorContext validatorContext, String method) throws ValidationException {
List<Validator> validators = getValidators(object.getClass(), context, method);
Set<String> shortcircuitedFields = null;
for (final Validator validator: validators) {
try {
validator.setValidatorContext(validatorContext);
if (LOG.isDebugEnabled()) {
LOG.debug("Running validator: " + validator + " for object " + object + " and method " + method);
}
FieldValidator fValidator = null;
String fullFieldName = null;
if (validator instanceof FieldValidator) {
fValidator = (FieldValidator) validator;
fullFieldName = fValidator.getValidatorContext().getFullFieldName(fValidator.getFieldName());
if ((shortcircuitedFields != null) && shortcircuitedFields.contains(fullFieldName)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Short-circuited, skipping");
}
continue;
}
}
if (validator instanceof ShortCircuitableValidator && ((ShortCircuitableValidator) validator).isShortCircuit())
{
// get number of existing errors
List<String> errs = null;
if (fValidator != null) {
if (validatorContext.hasFieldErrors()) {
Collection<String> fieldErrors = (Collection<String>) validatorContext.getFieldErrors().get(fullFieldName);
if (fieldErrors != null) {
errs = new ArrayList<String>(fieldErrors);
}
}
} else if (validatorContext.hasActionErrors()) {
Collection<String> actionErrors = validatorContext.getActionErrors();
if (actionErrors != null) {
errs = new ArrayList<String>(actionErrors);
}
}
validator.validate(object);
if (fValidator != null) {
if (validatorContext.hasFieldErrors()) {
Collection<String> errCol = (Collection<String>) validatorContext.getFieldErrors().get(fullFieldName);
if ((errCol != null) && !errCol.equals(errs)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Short-circuiting on field validation");
}
if (shortcircuitedFields == null) {
shortcircuitedFields = new TreeSet<String>();
}
shortcircuitedFields.add(fullFieldName);
}
}
} else if (validatorContext.hasActionErrors()) {
Collection<String> errCol = validatorContext.getActionErrors();
if ((errCol != null) && !errCol.equals(errs)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Short-circuiting");
}
break;
}
}
continue;
}
validator.validate(object);
} finally {
validator.setValidatorContext( null );
}
}
}
最后看一下校验必填项的实现
<validator name="requiredstring" class ="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/>
public class RequiredFieldValidator extends FieldValidatorSupport {
public void validate(Object object) throws ValidationException {
String fieldName = getFieldName();
Object value = this.getFieldValue(fieldName, object);
if (value == null) {
addFieldError(fieldName, object);
}
}
}
到这里,校验表单,出错后将执行addFieldError方法