Spring中SimpleFormController & MultiActionController合并
关键字: Java Spring
SimpleFormController & MultiActionController
表面看来
SimpleFormController
用来处理与
Form
相关的提交,并且无法进行多个提交处理,必须自己判断提交类型。而
MultiActionController
可以用来处理如同过方法名字区别的不同提交,便于多个相似业务处理集中,但是却无法处理与
Form
相关的操作,比较遗憾。如果能将二者结合就好了。
下面有两种解决方案:
1>
自己定义
MultiDispachController extends SimpleFormController;
这样
MultiDispachController
已经具备处理
Form
功能,然后自己定义
MethodNameResolver
,并且在
onSubmit(HttpServletRequest request,
HttpServletResponse response, Object command, BindException error)
函数中通过
MethodNameResolver
解析函数名字,并通过反射调用对应函数。
优点:可以灵活配置
Form
缺点:使用反射,性能有所损失
2>
直接使用
MultiActionController
实现
通过对
MultiActionController
源代码观察,发现以下玄机:
在函数派发的时候
MultiActionController
会调用如下函数:
invokeNamedMethod
而此函数中
//
如果调用参数大于
=3
,并且第三个参数为
HttpSession
if (method.getParameterTypes().length >= 3 &&method.getParameterTypes()[2].equals(HttpSession.class) )
{
HttpSession session = request.getSession(false);
if (session == null) {
throw new HttpSessionRequiredException("Pre-existing session required for handler method '" + methodName + "'");
}
params.add(session);
}
//
如果调用参数大于
=3
,并且第三个参数不是
HttpSession,Spring框架默认为一个//Command,并尝试进行Form绑定操作,如下
// If last parameter isn't of HttpSession type, it's a command.
if (method.getParameterTypes().length >= 3 && !method.getParameterTypes()[method.getParameterTypes().length - 1].equals(HttpSession.class))
{
Object command =newCommandObject(method.getParameterTypes()[method.getParameterTypes().length - 1]);
params.add(command);
bind(request, command);
}
所以基于此隐秘的操作我们可以如下实现,下面是一个简单例子
package com.app.domain;
/**
* @author xh94799
·
一个业务实体包含用户名,密码
*/
public class UserInfo {
private String userName;
private String password;
public UserInfo() {}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
/**
·
一个更详细的业务实体
·
包含用户名,地址,ID 但实际上页面只有用户名密码,此类是用来测试绑定的
*/
package com.app.domain;
public class UserDetailInfo {
private String userName;
private String address;
private String custID;
public UserDetailInfo() { super(); // TODO Auto-generated constructor stub }
public String toString() {
// TODO Auto-generated method stub
StringBuffer sb = new StringBuffer();
sb.append("UserName: " + this.userName).append("Add: " + this.address) .append("CustID: " + this.custID);
return sb.toString();
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getCustID() {
return custID;
}
public void setCustID(String custID) {
this.custID = custID;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
下面是我们的Controller
package com.app.web.controller;
// 处理登陆相关多个业务,从MultiActionController派生
public class LoginController extends MultiActionController {
private static Logger _logger = LogManager.getLogger(LoginController.class);
public LoginController() throws ApplicationContextException {
_logger.info("log4j constructor ActionController");
}
/**
* Init Login Form jsp
* 处理页面第一次加载显示,根据函数名识别
*/
public ModelAndView loadLoginView(HttpServletRequest request,
HttpServletResponse response) throws ServletException {
_logger.info("log4j loadLoginView init");
return new ModelAndView(ViewConstant.LOGIN_VIEW);
}
/**
·
do Login on user submit 处理登陆校验业务
·
注意第三个参数,为一个Form对象
*/
public ModelAndView doLogin(HttpServletRequest req, HttpServletResponse res,
UserInfo cmd ) throws Exception {
// TODO Auto-generated method stub
_logger.info("LoginController doLogin()");
UserInfo info = cmd;
if ( cmd != null )
{
_logger.info("UserName: " + info.getUserName());
_logger.info("Password: " + info.getPassword());
}
return new ModelAndView(ViewConstant.LOGIN_VIEW);
}
/**
·
do Login on user submit 处理登陆细节业务,
·
注意第三个参数,为一个Form对象
·
此处真正的Form为UserInfo,这里用作测试
*/
public ModelAndView doDetailProcess(HttpServletRequest req, HttpServletResponse res,
UserDetailInfo cmd ) throws Exception {
_logger.info("LoginController doDetailProcess()");
UserDetailInfo info = cmd;
if( info != null )
{
_logger.info(info.toString());
}
return new ModelAndView(ViewConstant.LOGIN_VIEW);
}
//可以自定义注册绑定
protected void initBinder(ServletRequest arg0, ServletRequestDataBinder arg1) throws Exception {
// TODO Auto-generated method stub
super.initBinder(arg0, arg1);
SimpleDateFormat dateFormat = new SimpleDateFormat(Constant.DATE_FORMAT);
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, null, new CustomDateEditor(dateFormat, false));
}
}
Action配置
<
bean
id
=
"urlMapping"
class
=
"org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"
>
<
property
name
=
"mappings"
>
<
props
>
<
prop
key
=
"/login.htm"
>
LoginController
</
prop
>
<
prop
key
=
"/doLogin.htm"
>
LoginController
</
prop
>
<
prop
key
=
"/doDetailProcess.htm"
>
LoginController
</
prop
>
</
props
>
</
property
>
</
bean
>
<
bean
id
=
"LoginController"
class
=
"com.app.web.controller.LoginController"
abstract
=
"false"
singleton
=
"true"
>
<
property
name
=
"methodNameResolver"
>
<
bean
class
=
"org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver"
>
<
property
name
=
"mappings"
>
<
props
>
<
prop
key
=
"/login.htm"
>
loadLoginView
</
prop
>
<
prop
key
=
"/doLogin.htm"
>
doLogin
</
prop
>
<
prop
key
=
"/doDetailProcess.htm"
>
doDetailProcess
</
prop
>
</
props
>
</
property
>
</
bean
>
</
property
>
</
bean
>
JSP
页面
<
form
name
=
"loginFrm"
action
=
<
c:url
value
=
"/servlet/doLogin.htm"
/>
method
=
"post"
>
<
p
align
=
"center"
>
Login
</
p
>
<
br
>
UserName:
<
input
type
=
"text"
name
=
"userName"
>
<
br
>
Password:
<
input
type
=
"password"
name
=
"password"
>
<
br
>
<
p
>
<
input
type
=
"submit"
value
=
"Submit"
name
=
"btnLogin"
>
<
input
type
=
"reset"
value
=
"Reset"
name
=
"btnReset"
>
<
input
type
=
"submit"
value
=
"DetailSubmit"
name
=
"btnDetail"
onclick
=
"doSubmit'<c:urlvalue='/servlet/doDetailProcess.htm'/>')">
</
p
>
</
form