0. 前言
熟悉了Struts的开发流程之后,一个新的问题出现了。一个表单对应一个Action和ActionForm是常见的事情,如果这个表单有两种提交的方式,一个Action是否能够解决呢?比如在一个页面上,用户输入账号和密码之后,可以选择“登录”按钮,也可以选择“注册”按钮。
一个表单对应两种截然不同的提交方式,用Action中的execute方法还能够很好的胜任吗?也许可以,但是这要求Action必须认识JSP页面的内容。这种被动的方式是开发过程中最为忌讳的。Action和JSP进行了耦合,违背了MVC的原则。
所以DispatchAction,就能够动态的处理上述问题。
1.DispatchAction
这里以购物车为例,用户可以选择把喜欢的书籍加入购物车,也可以选择从购物车删除。请求被发送到一个Action里面,利用DispatchAction可以解决Action过多,系统变得臃肿的问题。
buy.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>购买书籍</title>
</head>
<body>
<html:form action="/buy.do?method=add">
book<html:text property="book"></html:text>
<html:submit value="加入购物车"/>
</html:form><br>
<logic:present name="cart">
<logic:iterate id="book" name="cart">
<bean:write name="book"/>
<html:link action="/buy.do?method=delete" paramId="BOOK" paramName="book">删除</html:link>
</logic:iterate>
</logic:present>
</body>
</html>
上述代码的method是用户自主定义的,为了识别Action内的方法。
struts-config.xml:
<form-bean name="buyForm" type="Action.BuyForm"/>
<action name="buyForm" path="/buy" parameter="method" scope="request"
type="Action.BuyAction"/>
上述代码的parameter就是方便jsp认识Action内的方法。
BuyAction.jsp:
package Action;
import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DispatchAction;
import jdk.nashorn.internal.ir.RuntimeNode.Request;
/**
* 作用:
*@author 欧世乐
*/
public class BuyAction extends DispatchAction{
public ActionForward add(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
throws Exception {
BuyForm buyForm=(BuyForm)form;
String book=buyForm.getBook();
HttpSession session=request.getSession();
ArrayList cart=(ArrayList) session.getAttribute("cart");
if(cart==null) {
cart=new ArrayList();
}
cart.add(book);
session.setAttribute("cart", cart);
return new ActionForward("/buy.jsp");
}
public ActionForward delete(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
throws Exception {
String book=request.getParameter("BOOK");
HttpSession session=request.getSession();
ArrayList cart=(ArrayList) session.getAttribute("cart");
cart.remove(book);
session.setAttribute("cart", cart);
return new ActionForward("/buy.jsp");
}
}
但是这种方法也有缺陷,jsp页面必须要认识Action的方法,才可以调用。所以接下来要改进这种方法。
2.MappingDispatchAction
在Action中将继承的父类从DispatchAction改为MappingDispatchAction,在从配置文件里面,将ActionForm内的方法予以注册,这样jsp就可以调用配置文件内的方法进行提交表单,而不需要和Action有任何的交集。
Struts-config.xml:
<form-bean name="buyForm" type="Action.BuyForm"/>
<action name="buyForm" path="/add" parameter="add" scope="request" type="Action.BuyAction"/>
<action path="/delete" parameter="delete" type="Action.BuyAction"/>
BuyAction.jsp:
public class BuyAction extends MappingDispatchAction{
public ActionForward add(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
throws Exception {
BuyForm buyForm=(BuyForm)form;
String book=buyForm.getBook();
HttpSession session=request.getSession();
ArrayList cart=(ArrayList) session.getAttribute("cart");
if(cart==null) {
cart=new ArrayList();
}
cart.add(book);
session.setAttribute("cart", cart);
return new ActionForward("/buy.jsp");
}
public ActionForward delete(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
throws Exception {
String book=request.getParameter("BOOK");
HttpSession session=request.getSession();
ArrayList cart=(ArrayList) session.getAttribute("cart");
cart.remove(book);
session.setAttribute("cart", cart);
return new ActionForward("/buy.jsp");
}
}
3.LookUpDispatchAction
让我们回到前言里面的问题,一个页面,可以选择登录或者注册,提交表单后Action如何去认识呢?LookUpDispatchAction类可以提供新思路
流程:
1.建立ActionForm和相应的JSP,建立LookUpDispatchAction,此时按钮标签从资源文件获取。
2.重写getKeyMethodMap方法(用一个map保存资源文件key和方法名的映射)
3.编写方法
4.为Action建立参数
5.将提交按钮和property和参数名称一致
LookUpDispatchAction主要是利用资源文件对提交的按钮进行检索,而资源文件的内容会保存在map里面,这也是为什么强制要求重写getKeyMethodMap方法的原因。
LrAction.java:
package Action;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.LookupDispatchAction;
/**
* 作用:
*@author 欧世乐
*/
public class LrAction extends LookupDispatchAction{
@Override
protected Map getKeyMethodMap() {//用一个map保存资源文件key和方法名的映射
Map map=new HashMap();
map.put("info.tag.login", "login");
map.put("info.tag.reg", "reg");
return map;
}
public ActionForward login(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
throws Exception {
LrForm lrForm=(LrForm)form;
System.out.println("登录");
return null;
}
public ActionForward reg(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
throws Exception {
LrForm lrForm=(LrForm)form;
System.out.println("注册");
return null;
}
}
资源文件:
info.tag.login = Login
info.tag.reg = reg
lr.jsp:
<html:form action="/lr.do">
账号<html:text property="account"></html:text><br>
密码<html:password property="password"></html:password><br>
<html:submit property="method" ><bean:message key="info.tag.login"/></html:submit>
<html:submit property="method" ><bean:message key="info.tag.reg"/></html:submit>
</html:form>
这里的提交按钮是交给资源文件来校验的,不同的key对应不同的内容,这个内容在传送到Action的时候,map会自动去检索这个内容,究竟是login还是reg,然后调用相应的方法。
4.小结
Action还有许多的用法,和基础比起来,DispatchAction,MappingDispatchAction和LookUpDispatchAction都是比较高级的用法。他们的核心目的都在于满足需求的同时,减少和其他代码的耦合性和联系性,让一切联系都交由配置文件去完成,符合MVC的风格和要求。