Controller及其流程介绍
Controller及其流程介绍
1.1. Controller总体架构
图4.1
此图是从Spring In Action中摘录出来。
如图,除ThrowawayController外,其余的Controller都继承AbstractController,实现Controller。下面有两个分支Mutil-ActionControllers和Command-Controllers。StoreAdmin项目生成的Controller分别继承了MultiActionController和SimpleFormController。
需要注意的是:MultiActionController提供了bind(request,command),SimpleFormController则提供了bindAndValidate(request,command)方法,两个方法都可以实现将表单数据绑定到指定的command对象上。对于MultiActionController而言,所有Object都可以通过这个方法来手工进行绑定,对于SimpleFormController则当需要绑定的对象大于一个时需要使用bindAndValidate绑定方法,第一个Object,可以直接调用方法的Object command参数取得,SimpleFormController会自动完成绑定操作。
下面将详细介绍SimpleFormController和MultiActionController。
1.2. SimpleFormController
使用情况:需要给用户显示一个输入表单,并且处理输入表单的数据。
1.2.1. 类结构
图4.2
1.2.2. 实现流程分析
以下为在处理Controller的时候,每个步骤会调用的方法,这些方法一般在Spring的Controller都有基本实现,如果我们要需要这些方法实现处理,那么实现在我们自己的Controller类里实现这些方法。
由于SimpleFormController是继承AbstractFormController,在该AbstractFormController中的handleRequestInternal方法需要判断当前提交的方法是Get还是Post,如果是Get则是New一个View,如果是Post则是运行客户端业务逻辑,然后跳转到成功页面。
n 通过Get 方式请求一个View
1、Controller受到一个Get请求;
2、formBackingObject()方法,如果需要读取数据库,这里是一个比较好的地方去做这件事情。然后将Object通过request.setAttribute来传递到页面;如果页面表单需要绑定多个Object,可以在这里读取数据库取得,然后设置到页面上。
3、initBinder() 这里是用来进行数据格式化转换的;如果在页面上显示某些类型需要进行格式化显示,那么需要在XXXXFormController中重载该方法,指定特定的转换器完成对特定Object的设置。如对于日期格式需要在本方法中增加如下代码:
binder.registerCustomEditor(Date.class, null, new CustomDateEditor(
new SimpleDateFormat("MM/dd/yyyy"),true));
4、调用AbstractFormController.handleRequestInternal方法,在该方法中判断,如果是新建一个Form View,则调用ShowNewForm方法,在ShowNewForm方法中调用了ShowForm方法,SimpleFormController实现了此方法,指向的url是Controller中注册的formView参数。
6、View 模块完成,显示给用户。
n 通过Post方式提交一个Form
1、 提交后根据Action指向的URL在urlMapping配置中找到指定的Controller;
2、 如果配置了Validator则使用该Validator(见applicationContext-validation.xml)进行相关的验证;缺省是beanValidator。错误信息写入到errors参数里。
3、 调用AbstractFormController.handleRequestInternal方法,在该方法中判断是通过Post来调用此方法,则调用processFormSubmission方法,该方法会先判断errors中是否有验证错误,如果有则返回到原表单页面,显示错误信息。
4、 验证通过后进入onSubmit方法,该方法的command参数对应绑定到页面的对象,
如果在表单中有多个对象需要进行绑定,那么其它对象可以通过this.bindAndValidate(HttpServletRequest request, Object command);方法来进行绑定。
5、 做相关的业务操作。
6、 往返回界面上输出结果提示信息,通过getText和saveMessage()方法完成。getText()第一个参数是在资源文件中的信息代码,第二个参数是发给该信息的参数,在该信息中通过{0}来读取,第三个参数是当前使用的Locale。saveMessage()的信息显示是通过common/messages.jsp来进行。
7、 返回一个ModelAndView(new RedirectView(success)),success对应action-servlet.xml文件该Controller所配置successView,跳转路径是相对路径。
1.3. MultiActionController
优点及开发注意:
l 应用系统中有多个相似的动作处理或相关逻辑。
l 配置文件比较简单,需要手工写的代码稍多些。
l 注意将重复的代码抽取出来,避免一个方法过于庞大。
l 每个action只做一件事情,不要再在action中进行逻辑判断调用那个方法。
l 可以轻松绑定多个对象。
l 支持一到多个Validator
1.3.1. 类结构
图4.3
1.3.2. 实现流程分析
MultiActionController相对比较简单。该Controller的实现有两类方法,一个是缺省调
用的方法,一个是通过参数名称来指向的需要调用的Action。
图4.4
如图,设置的缺省方法名称为defaultAction,意思是当没有检查到当前的提交申请中包含doAction参数,则直接调用defaultAction方法,否则则调用url?doAction=methodName所指向的方法名称。
所以当我们使用MultiActionController,提交表单的时候需要在actionurl后面加参数如:
url?doAction=methodName。这样就会提交到该方法中执行了。
需要注意的是,当使用Post方式提交到本Controller,而又希望调用的方式是缺省方法时,如果在表单有参数名为doAction(如是Hidden的),那么需要设置url?doAction=defaultAction。
一个MultiActionController的方法一般有四种形式:
1)public ModelAndView methodName(HttpServletRequest request,
HttpServletResponse response) {…}
2)public ModelAndView methodName(HttpServletRequest request,
HttpServletResponse response,
Object command) {…}
3)public ModelAndView methodName(HttpServletRequest request,
HttpServletResponse response,
HttpSession session) {…}
4)public ModelAndView methodName(HttpServletRequest request,
HttpServletResponse response,
HttpSession session,
Object command) {…}
其中第3、4种主要是设置参数中带有session参数。StoreAdmin系统中暂时没有出现,那么平时使用一般是第1、2种。
对于第一种大家都比较熟悉了,根据传入的request和response进行业务逻辑处理,然后返回一个ModelAndView。
对于其它的方法类型,MultiActionController的处理是这样的:
它先会判断调用的方法的参数是否大于等于3,如果是则:
判断第三个参数的类型是否是HttpSession,如果是则从Request中取得session,放入参数列表中。
HttpSession session = request.getSession(false);
如果取不到将抛出SessionRequiredException例外。
如果第三个参数不是HttpSession,那么MultiActionController将认为这个就是需要做绑定操作的对象,会自动将表单的数据和该对象进行绑定。
所以当我们在使用MultiActionController时,当表单的Object为一个时可以使用上面第2种形式,即第3个参数为需要绑定的对象,然后在方法体中无须再调用bind方法,直接可以对其进行操作了。
如果表单涉及多个Object,那么可以选择使用第1或2种方法,但是没有做自动绑定的Object需要在该Action方法体里面手动调用
bind(request, command);
方法来将request和command进行绑定。