SimpleFormController是AbstractFormController的具体实现,允许你在配置文件里通过successView和formView属性来配置成功视图(表单成功提交后要转向的页面)和表单视图(显示表单的页面);如果提交不合法(有三种可能:1.validator出错。2.bind错误,也就是说从请求中提取参数封装到command的过程中出现了类型转化错误,比如将一个含字母字符串转换为Integer。3.onBindAndValidate()方法出错),则会重新返回到表单视图;如果提交合法,onSubmit()方法的默认实现会转向成功页面,当然你可以覆写该方法在转向之前填充一些你想返回的信息。
SimpleFormController的的工作流与AbstractFormController差不多,唯一的不同是你不必自己去实现showForm()和processFormSubmission()。showForm()这个方法已经被类SimpleFormController实现了并被限定为final,你不可以在继承SimpleFormController的子类里覆写这个类。processFormSubmission()这个方法尽管可以去覆写但由于它几乎可以满足所有的要求,因此一般也不会有人去重写它。
它的处理流程是这样的:
get请求来到时,这样处理:
1) 请求传递给一个controller对象
2) 调用formBackingObject()方法,创建一个command对象的实例。
4) 调用showForm()方法,返回准备呈现给用户的视图 ,如果“bindOnNewForm”属性设为true,则ServletRequestDataBinder会将初始请求参数填入一个新的表单对象,并且执行onBindOnNewForm()方法。
5) 调用referenceData()方法,准备给用户显示相关的数据。如用户登录需要选择的年度信息
post请求来到时,这样处理:
1) 如果sessionForm属性没有设定,则调用formBackingObject()方法,创建一个command对象的实例。否则从session中取得表单对象
2) 将请求传来的参数写入command对象,看它的源代码,会发现它是这样来做的:
ServletRequestDataBinder binder = createBinder(request, command);
binder.bind(request);
3)执行onBind()方法,在绑定数据之后,验证数据之前对表单数据进行一些自制的修改动作。
4) 如果设置为要求验证(validateOnBinding属性被设定),则调用validator类进行数据验证
5) 调用onBindAndValidate()方法,该方法允许自定义数据绑定和校验处理
6)执行processFormSubmission()检验 Errors对象中含不含错误,如果含有错误则执行showForm()返回到填写表单页面;否则执行onSubmit()方法,进行提交表单,然后转向成功页面。
三
注意点:
XXX-severlet.xml
commandClass
validator
sucessView
formView
<property name="commandClass">
<value>org.springframework.samples.jpetstore.web.srx.register.RegisterInfo</value>
</property>
<property name="validator">
<ref local="XXXXValidator"/>
</property>
--------------------------------------------------------------------
valitator的实现类中的两个实现方法
1使用SimpleFormController时,您可以搭配一个org.springframework.validation.Validator介面的实作物件,帮助您作基本的伺服端资料验证工作,您可以设计一个通用的Validator,将之当作一个Bean注入给需要进行表单验证的其它Bean物件。
Validator介面有两个必须实作的方法,其定义如下所示:
package org.springframework.validation;
public interface Validator {
boolean supports(Class clazz);
void validate(Object obj, Errors errors);
}
supports()方法回传一个boolean值,表示是否支援对所传入的物件进行验证,只有在传回true的情况下,才会使用validate()方法进行验证工作,在validate()方法的参数中,obj表示传入的表单物件,您可以对它进行一些验证,如果有错误的话,可以使用Errors的 reject()或rejectValue()等方法加入错误讯息,在后续的处理中,若errors物件中包括错误讯息,会回到getViewPage ()所设定的页面。
来看一个简单的实作:
package onlyfun.caterpillar;
import org.springframework.validation.Validator;
import org.springframework.validation.Errors;
public class LoginValidator implements Validator {
public boolean supports(Class clazz) {
return clazz.equals(LoginForm.class);
}
public void validate(Object obj, Errors errors) {
LoginForm form = (LoginForm) obj;
if(form.getPassword().length() < 4 ) {
errors.rejectValue("password",
"less-than-four", null, "密码不得小于四个字元");
}
}
}
这个Validator类别可以搭配7.2.7介绍的SimpleFormDemo专案来使用,验证通常是在检查资料的完备性、安全性等条件,像是检查密码的格式就是一例,至于使用者名称与密码是否正确,这该算是后继的Controller的处理工作。
搭配SimpleFormController来使用Validator,您只要在Bean定义档中加入Validator的Bean定义,以及让SimpleFormController参考到它即可,例如:
...
<bean id="loginValidator"
class="onlyfun.caterpillar.LoginValidator"/>
<bean id="loginAction"
class="onlyfun.caterpillar.LoginAction">
<property name="commandClass">
<value>onlyfun.caterpillar.LoginForm</value>
</property>
<property name="validator">
<ref bean="loginValidator"/>
</property>
<property name="successView">
<value>success</value>
</property>
<property name="formView">
<value>form</value>
</property>
</bean>
...
"validator"属性参考至loginValidator实例,只要有设定"validator",SimpleFormController就会使用它。
在进行验证时,您可以使用org.springframework.validation.ValidationUtils,上面有一些方便的静态方法,像是rejectIfEmpty()、rejectIfEmptyOrWhitespace()等,可以查查线上API文件看如何使用。
另一方面,对于AbstractWizardFormController,您可以重新定义它的validatePage()方法来进行验证,例如:
...
protected void validatePage(Object command,
Errors errors, int page) {
(YourCommand) your = (YourCommand) command;
switch(page) {
case 1:
validator.validateSome(your, errors);
break;
case 2:
validator.validateOther(your, errors);
break;
....
}
}
..
每进行一页Wizard表单,都会呼叫该方法一次,让您针对该次送出的数据进行验证,"page"参数表示该次送出表单的页数,与 SimpleFormController的Validator不同的是,AbstractWizardFormController不会自动调用Validator的validate()方法,您要根据当次页面的资料自行进行对应的方法验证,通常采取如上的委托物件,将验证交由一个 Validator物件来执行。
SimpleFormController的的工作流与AbstractFormController差不多,唯一的不同是你不必自己去实现showForm()和processFormSubmission()。showForm()这个方法已经被类SimpleFormController实现了并被限定为final,你不可以在继承SimpleFormController的子类里覆写这个类。processFormSubmission()这个方法尽管可以去覆写但由于它几乎可以满足所有的要求,因此一般也不会有人去重写它。
注意是get还是post。区别很大。如果是url等注入就是get,action或者ajax中,设置过method为post,为post
处理总流程:
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
throws Exception {
// Form submission or new form to show?
if (isFormSubmission(request)) {
// Fetch form object from HTTP session, bind, validate, process submission.
try {
Object command = getCommand(request);
ServletRequestDataBinder binder = bindAndValidate(request, command);
BindException errors = new BindException(binder.getBindingResult());
return processFormSubmission(request, response, command, errors);
}
catch (HttpSessionRequiredException ex) {
// Cannot submit a session form if no form object is in the session.
if (logger.isDebugEnabled()) {
logger.debug("Invalid submit detected: " + ex.getMessage());
}
return handleInvalidSubmit(request, response);
}
}
else {
// New form to show: render form view.
return showNewForm(request, response);
}
}
它的处理流程是这样的:
get请求来到时,这样处理:
1) 请求传递给一个controller对象
2) 调用formBackingObject()方法,创建一个command对象的实例。
@Override
protected Object formBackingObject(HttpServletRequest request) throws Exception {
Date now = new Date();
Calendar c = Calendar.getInstance();
c.setTime(now);
c.add(Calendar.DATE, -1);
request.setAttribute("orderDateEnd", DateTimeUtils.formatPageDate(now));
request.setAttribute("orderDateBegin", DateTimeUtils.formatPageDate(c.getTime()));
return super.formBackingObject(request);
}
3) 调用initBinder(),注册需要的类型转换器
4) 调用showForm()方法,返回准备呈现给用户的视图 ,如果“bindOnNewForm”属性设为true,则ServletRequestDataBinder会将初始请求参数填入一个新的表单对象,并且执行onBindOnNewForm()方法。
5) 调用referenceData()方法,准备给用户显示相关的数据。如用户登录需要选择的年度信息
@SuppressWarnings("unchecked")
@Override
protected Map referenceData(HttpServletRequest request) throws Exception {
List<MerAccessAprvStatusDTO> statusList = statusList();
return new ModelMap().addAttribute(STATUSES_KEY, statusList);
}
6) 返回formView指定的视图
post请求来到时,这样处理:
1) 如果sessionForm属性没有设定,则调用formBackingObject()方法,创建一个command对象的实例。否则从session中取得表单对象
2) 将请求传来的参数写入command对象,看它的源代码,会发现它是这样来做的:
ServletRequestDataBinder binder = createBinder(request, command);
binder.bind(request);
3)执行onBind()方法,在绑定数据之后,验证数据之前对表单数据进行一些自制的修改动作。
4) 如果设置为要求验证(validateOnBinding属性被设定),则调用validator类进行数据验证
5) 调用onBindAndValidate()方法,该方法允许自定义数据绑定和校验处理
6)执行processFormSubmission()检验 Errors对象中含不含错误,如果含有错误则执行showForm()返回到填写表单页面;否则执行onSubmit()方法,进行提交表单,然后转向成功页面。
三
注意点:
XXX-severlet.xml
commandClass
validator
sucessView
formView
<property name="commandClass">
<value>org.springframework.samples.jpetstore.web.srx.register.RegisterInfo</value>
</property>
<property name="validator">
<ref local="XXXXValidator"/>
</property>
--------------------------------------------------------------------
valitator的实现类中的两个实现方法
1使用SimpleFormController时,您可以搭配一个org.springframework.validation.Validator介面的实作物件,帮助您作基本的伺服端资料验证工作,您可以设计一个通用的Validator,将之当作一个Bean注入给需要进行表单验证的其它Bean物件。
Validator介面有两个必须实作的方法,其定义如下所示:
package org.springframework.validation;
public interface Validator {
boolean supports(Class clazz);
void validate(Object obj, Errors errors);
}
supports()方法回传一个boolean值,表示是否支援对所传入的物件进行验证,只有在传回true的情况下,才会使用validate()方法进行验证工作,在validate()方法的参数中,obj表示传入的表单物件,您可以对它进行一些验证,如果有错误的话,可以使用Errors的 reject()或rejectValue()等方法加入错误讯息,在后续的处理中,若errors物件中包括错误讯息,会回到getViewPage ()所设定的页面。
来看一个简单的实作:
package onlyfun.caterpillar;
import org.springframework.validation.Validator;
import org.springframework.validation.Errors;
public class LoginValidator implements Validator {
public boolean supports(Class clazz) {
return clazz.equals(LoginForm.class);
}
public void validate(Object obj, Errors errors) {
LoginForm form = (LoginForm) obj;
if(form.getPassword().length() < 4 ) {
errors.rejectValue("password",
"less-than-four", null, "密码不得小于四个字元");
}
}
}
这个Validator类别可以搭配7.2.7介绍的SimpleFormDemo专案来使用,验证通常是在检查资料的完备性、安全性等条件,像是检查密码的格式就是一例,至于使用者名称与密码是否正确,这该算是后继的Controller的处理工作。
搭配SimpleFormController来使用Validator,您只要在Bean定义档中加入Validator的Bean定义,以及让SimpleFormController参考到它即可,例如:
...
<bean id="loginValidator"
class="onlyfun.caterpillar.LoginValidator"/>
<bean id="loginAction"
class="onlyfun.caterpillar.LoginAction">
<property name="commandClass">
<value>onlyfun.caterpillar.LoginForm</value>
</property>
<property name="validator">
<ref bean="loginValidator"/>
</property>
<property name="successView">
<value>success</value>
</property>
<property name="formView">
<value>form</value>
</property>
</bean>
...
"validator"属性参考至loginValidator实例,只要有设定"validator",SimpleFormController就会使用它。
在进行验证时,您可以使用org.springframework.validation.ValidationUtils,上面有一些方便的静态方法,像是rejectIfEmpty()、rejectIfEmptyOrWhitespace()等,可以查查线上API文件看如何使用。
另一方面,对于AbstractWizardFormController,您可以重新定义它的validatePage()方法来进行验证,例如:
...
protected void validatePage(Object command,
Errors errors, int page) {
(YourCommand) your = (YourCommand) command;
switch(page) {
case 1:
validator.validateSome(your, errors);
break;
case 2:
validator.validateOther(your, errors);
break;
....
}
}
..
每进行一页Wizard表单,都会呼叫该方法一次,让您针对该次送出的数据进行验证,"page"参数表示该次送出表单的页数,与 SimpleFormController的Validator不同的是,AbstractWizardFormController不会自动调用Validator的validate()方法,您要根据当次页面的资料自行进行对应的方法验证,通常采取如上的委托物件,将验证交由一个 Validator物件来执行。