在平常使用struts开发项目中,我们只需要通过添加struts的支持的jar包以及在配置文件中web.xml中配置核心过滤器以及编写相应的struts,xml配置文件,我们就可以在Action实现类中添加属性以及get和set方法,便可以获得封装在给属性中的信息;那么它是怎么实现的呢,下面通过一个案例实现其核心的功能:
①新建项目relizeStruts(实现加减乘除四则运算)
目录结构如下:
首先我们知道,在struts2中用到了配置文件,配置文件的结构如下:
<struts>
<action name =”…..” class=”……”>
<result name=”….resultName”>…..resultPath</result>
</action>
</struts>
新建节点的配置文件mystruts.xml
<?xml version="1.0"encoding="UTF-8"?>
<struts>
<!-- 配置请求名和请求的全类名 -->
<action name="add" class="com.xiyou.jackielin.action.AddAction">
<result name="success">result.jsp</result>
</action>
<action name="plus" class="com.xiyou.jackielin.action.PlusAction">
<result name="success">result.jsp</result>
</action>
<action name="mul" class="com.xiyou.jackielin.action.MulAction">
<result name="success">result.jsp</result>
</action>
<action name="divide" class="com.xiyou.jackielin.action.DivideAction">
<result name="success">result.jsp</result>
</action>
</struts>
注意:配置文件的name(add)应和Action(AddAction )的前半段相同
②新建 result 节点的封装类:ResultMapping/**
* 用于封装配置文件中result节点的信息
* @author Administrator
*
*/
public class ResultMapping{
private String resultName;//逻辑名称
private String resultPath;//物理路径
public String getResultName() {
return resultName;
}
public void setResultName(String resultName) {
this.resultName = resultName;
}
public String getResultPath() {
return resultPath;
}
public void setResultPath(String resultPath) {
this.resultPath = resultPath;
}
}
③ 新建action节点的封装类:ActionMapping
/**
* 用于封装配置文件中Action节点的信息
* @author Administrator
*
*/
public class ActionMapping {
private String actionName;//封装name属性的值
private String actionClass;//封装class属性的值
//封装action节点下的所有result节点的信息,以result的name属性值做key,以resultMapping对象信息做value
private Map<String,ResultMapping> resulsMap = new HashMap<String,ResultMapping>();
public String getActionName() {
return actionName;
}
public void setActionName(String actionName) {
this.actionName = actionName;
; }
public String getActionClass() {
return actionClass;
}
public void setActionClass(String actionClass) {
this.actionClass = actionClass;
}
public Map<String, ResultMapping> getResulsMap() {
return resulsMap;
}
public void setResulsMap(Map<String, ResultMapping> resulsMap
){
this.resulsMap = resulsMap;
}
}
④新建ActionMappingManager类并添加解析配置文件的方法,得到action节点信息的集合
/**
* Action节点的管理类
* @author Administrator
*/
public class ActionMappingManager {
//封装配置文件中所有的action节点信息,以action的name属性值做key,以actionMapping对象做value
Map<String,ActionMapping> actionsMap = new HashMap<String, ActionMapping>();
/**
* 解析配置文件mystruts.xml 将action节点封装成ActionMapping对象
*/
public void parseXML() {
//将配置文件转换为字节流
InputStream ips = this.getClass().getResourceAsStream("/mystruts.xml");
//这里要导入dom4j支持包
SAXReader saxReader = new SAXReader();
try {
//读取流中配置文件信息并转为文档树对象类型
Document document = saxReader.read(ips);
//获取根节点<struts><action></action></struts>
Element root = document.getRootElement();
//迭代根节点下的子节点,获取要封装的action信息
for(Iterator<Element> actionIter = root.elementIterator();actionIter.hasNext();) {
Element action = actionIter.next(); //获取action节点的信息
//获取action的name和class属性值
String actionName = action.attributeValue("name");
String actionClass = action.attributeValue("class");
//创建Action节点的封装类对象用于封装Action节点的信息
ActionMapping actionMapping = new ActionMapping();
actionMapping.setActionName(actionName);
actionMapping.setActionClass(actionClass);
//获取action节点的子节点信息(result节点)
for(Iterator<Element> resultIter = action.elementIterator();resultIter.hasNext();) {
Element result = resultIter.next();//获取result节点信息
String resultName = result.attributeValue("name");
String resultPath = result.getText();
//创建ResultMapping对象用来封装result节点的信息
ResultMapping resultMapping = new ResultMapping();
resultMapping.setResultName(resultName);
resultMapping.setResultPath(resultPath);
//将resultMapping添加到ActionMapping中的result节点信息中
actionMapping.getResultsMap().put(resultName, resultMapping);
}
//将actionMapping添加到actionsMap中
actionsMap.put(actionName, actionMapping);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
⑤创建Action接口
public interface Action {
public String execute(HttpServletRequest request,HttpServletResponse response);
}
⑥创建ActionManager并添加动态创建Action的方法(这里主要通过反射机制创建类)
public class ActionManager {
/**
* 根据全类名(包名+类名)动态创建Action对象
* eg:com.xiyou.jackielin.action.AddAction
* @param actionClass
* @return
*/
public static Action createActionByClassName(String actionClass) {
Action action = null;
try {
//根据全类名来创建一个Action对象
action = (Action)Class.forName(actionClass).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return action;
}
}
⑦ 编写核心的控制器:ActionServlet并且注意在web.xml中配置servlet过滤所有以.action结尾的请求连接
/**
* 编写处理业务的业务类
* @author Administrator
*/
public class ActionServlet extends HttpServlet {
//创建action节点的业务管理类
ActionMappingManager actionMappingManager;
//当ActionServlet创建的时候解析配置文件
@Override
public void init() throws ServletException {
actionMappingManager = new ActionMappingManager();
actionMappingManager.parseXML();//调用解析方法解析配置文件
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//获取请求的路径(http://127.0.0.1:8080/relizeStruts/add.action)
String uri = req.getRequestURI();
//截取地址栏(/relizeStruts/add.action)-->add
String actionName = uri.substring(uri.lastIndexOf("/")+1, uri.lastIndexOf("."));
System.out.println(actionName);
//第一版
/*Action action = null;
if(actionName.equals("add")) {
action = new AddAction();
}else if(actionName.equals("plus")){
action = new PlusAction();
}else if(actionName.equals("mul")){
action = new MulAction();
}else if(actionName.equals("divide")) {
action = new DivideAction();
}
String pathName = action.execute(req, resp);
String path = actionMappingManager.actionsMap.get(actionName).getResultsMap().get(pathName).getResultPath();
req.getRequestDispatcher(path).forward(req, resp);*/
//第二版
Map<String,ActionMapping> actionsMap = actionMappingManager.actionsMap;
//根据action节点的name在配置文件中查找对应的action节点信息
ActionMapping actionMapping = actionsMap.get(actionName);
String actionClass = actionMapping.getActionClass();
//根据全类名创建相应的类
Action action = ActionManager.createActionByClassName(actionClass);
String resultName = action.execute(req, resp);//执行execute方法,返回逻辑名称
//得到actin中封装的result节点信息
ResultMapping resultMapping = actionMapping.getResultsMap().get(resultName);
String resultPath = resultMapping.getResultPath();//获得结果节点对应的物理路径
req.getRequestDispatcher(resultPath).forward(req, resp);//实现跳转到成功页面
}
}
在核心控制器中,处理业务的方式有两种,在第一种的做法中,如果我们不采用反射机制通过全类名创建相应的类,那么我们必须判断地址请求中要请求的是哪个Action,显然我们知道这种做法是很低效率的,当有很多Action时我们需要花费很大的功夫去判断,那么我们可以通过actionName取到action的节点中的actionClass(全类名),再通过全类名动态创建Action;
配置servlet:
<!-- 这里记得配置servlet去拦截所有的.action结尾的链接 -->
<servlet>
<servlet-name>actionServlet</servlet-name>
<servlet-class>com.xiyou.jackielin.framework.ActionServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>actionServlet</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
⑧编写业务逻辑接口Action,实现Action接口;
新建处理业加减乘除业务逻辑类,AddAction,PlusAction,MulAction,DivideAction
/**
* 两个数相加的动作
* @author Administrator
*
*/
public class AddAction implements Action{
public String execute(HttpServletRequest request,
HttpServletResponse response) {
String num1Str = request.getParameter("num1");
String num2Str = request.getParameter("num2");
int num1 = Integer.parseInt(num1Str);
int num2 = Integer.parseInt(num2Str);
CalcBiz calcBiz = new CalcBiz();
int result = calcBiz.add(num1, num2);
request.setAttribute("result", result);
return "success";
}
}
其他减乘除只要将业务调处理调用方法改为相应的运算就可以。即calcBiz.plus(num1,num2)..
⑨编写测试页面index.jsp:
<head>
<base href="<%=basePath%>">
<title>My JSP 'index.jsp' starting page</title>
<script type="text/javascript">
function doSubmit(op) {
if(op=='+'){
document.myform.action='add.action';
}else if(op=='-'){
document.myform.action='plus.action';
}else if(op=='*'){
document.myform.action='mul.action';
}else if(op=='/'){
document.myform.action='divide.action';
}
document.myform.submit();//提交表单
}
</script>
</head>
<body>
<FORM METHOD=POST ACTION="" name="myform">
<TABLE>
<TR>
<TD>第一个数:</TD>
<TD><INPUT TYPE="text" NAME="num1"></TD>
</TR>
<TR>
<TD>第二个数:</TD>
<TD><INPUT TYPE="text" NAME="num2"></TD>
</TR>
<TR>
<TD><INPUT TYPE="button" VALUE="+" ONCLICK="doSubmit('+')"><INPUT TYPE="button" VALUE="-" ONCLICK="doSubmit('-')"></TD>
<TD><INPUT TYPE="button" VALUE="*" ONCLICK="doSubmit('*')"><INPUT TYPE="button" VALUE="/" ONCLICK="doSubmit('/')"></TD>
</TR>
</TABLE>
</FORM>
</body>
通过调用相应的Action运算之后,我们得到了计算成功时的路径,编写计算结果页面
<body>
结果:${result}
</body>
取出得到运算结果;
10.测试运算结果
点击相加:
到这里我们通过手写实现了struts2的核心部分功能,通过解析配置文件,及动态创建Action,希望对你理解struts2的实现有所帮助,有问题请多多指教!