目录:
【SSH进阶之路】Struts基本原理 + 实现简单登录(二)
【SSH进阶之路】一步步重构MVC实现Struts框架——从一个简单MVC开始(三)
【SSH进阶之路】一步步重构MVC实现Struts框架——封装业务逻辑和跳转路径(四)
【SSH进阶之路】一步步重构MVC实现Struts框架——彻底去掉逻辑判断(五)
【SSH进阶之路】一步步重构MVC实现Struts框架——完善转向页面,大功告成(六)
第四篇博客【SSH进阶之路】一步步重构MVC实现Struts框架——封装业务逻辑和跳转路径(四),我们解决了第一个问题:封装业务逻辑和跳转路径。第五篇博客【SSH进阶之路】一步步重构MVC实现Struts框架——彻底去掉Servlet中的逻辑判断(五),我们解决了第二个问题:彻底去掉Servlet中的逻辑判断。这篇我们解决最后一个问题,完善转向页面,显示和控制分离。
比如添加用户逻辑,成功不仅仅可以返回成功页面,失败也可以返回失败页面,代码如下:
AddUserAction
- package com.liang.action;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import com.liang.manager.UserManager;
- public class AddUserAction implements Action {
- @Override
- public String execute(HttpServletRequest req, HttpServletResponse resp)
- throws Exception {
- //获取参数
- String username = req.getParameter("username");
- //调用业务逻辑
- UserManager userManager = new UserManager();
- try{
- //添加的业务逻辑
- userManager.add(username);
- }catch(Exception e){
- //返回添加失败的界面
- return "/add_error.jsp";//转向路径可以通过配置文件读取
- }
- //返回添加成功的界面
- return "/add_success.jsp";//转向路径可以通过配置文件读取
- }
- }
从上篇博客中,我们知道,若想系统变的灵活,所有变化都配置到配置文件中,修改时,修改配置文件即可。因此,我们只需要在struts-config.xml中配置转向页面,不仅仅要有成功的转向页面,而且要有失败的转向页面。
我们修改一下struts-config.xml,代码如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <action-config>
- <action-mappings>
- <!--根据不同的path路径,访问各自的Action -->
- <action path="/servlet/addUser" type="com.liang.action.AddUserAction">
- <!-- 转向页面 -->
- <forward name="success" path="/add_success.jsp"></forward>
- <forward name="error" path="/add_error.jsp"></forward>
- </action>
- <action path="/servlet/delUser" type="com.liang.action.DelUserAction">
- <forward name="success" path="/del_success.jsp"></forward>
- <forward name="error" path="/del_error.jsp"></forward>
- </action>
- <action path="/servlet/modifyUser" type="com.liang.action.ModifyUserAction">
- <forward name="success" path="/modify_success.jsp"></forward>
- <forward name="error" path="/modify_error.jsp"></forward>
- </action>
- <action path="/servlet/queryUser" type="com.liang.action.QueryUserAction">
- <forward name="success" path="/query_success.jsp">/</forward>
- <forward name="error" path="/query_error.jsp"></forward>
- </action>
- </action-mappings>
- </action-config>
我们修改了配置文件,使用dom4j读取配置,配置信息也需要放到一个map结构中,我们需要一个存储转向信息的map,因此,在ActionMapping中增加一个map。
ActionMapping
- package com.liang.action;
- import java.util.HashMap;
- import java.util.Map;
- public class ActionMapping {
- private String path;
- private String type;
- //存储转向信息的map
- Map forward = new HashMap();
- public Map getForward() {
- return forward;
- }
- public void setForward(Map forward) {
- this.forward = forward;
- }
- public String getType() {
- return type;
- }
- public void setType(String type) {
- this.type = type;
- }
- public String getPath() {
- return path;
- }
- public void setPath(String path) {
- this.path = path;
- }
- }
读取配置需要发生相应的变化,但是我们有了上篇博客的例子,修改起来并不难。
ConfigInit
- package com.liang.servlet;
- import java.io.File;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.Map;
- import org.dom4j.Document;
- import org.dom4j.Element;
- import org.dom4j.io.SAXReader;
- import com.liang.action.*;
- public class ConfigInit {
- public static void init(String config) {
- // 创建saxReader对象
- SAXReader reader = new SAXReader();
- File f = new File(config);
- try {
- // 通过read方法读取xml文件, 转换成Document对象
- Document doc = reader.read(f);
- // 得到配置文件的根结点
- Element root = doc.getRootElement();
- Element actionmappings = (Element) root.element("action-mappings");
- // 解析action结点的所有参数
- for (Iterator j = actionmappings.elementIterator("action"); j
- .hasNext();) {
- Element am = (Element) j.next();
- ActionMapping actionMapping = new ActionMapping();
- // 设置actionMapping的path和type
- actionMapping.setPath(am.attributeValue("path"));
- actionMapping.setType(am.attributeValue("type"));
- Map forward = new HashMap();
- // 解析forward结点的所有参数
- for (Iterator k = am.elementIterator("forward"); k.hasNext();) {
- Element fo = (Element) k.next();
- forward.put((String) fo.attributeValue("name"), (String) fo
- .attributeValue("path"));
- }
- // 设置forward
- //如果是添加ActionMapping的存储如下;
- /*
- * actionMapping{ path="/servlet/addUser";
- * type="com.liang.action.AddUserAction"
- <span style="white-space:pre"> </span> *forwardMap{
- * <span style="white-space:pre"> </span>key="success",value="/add_success.jsp"
- * <span style="white-space:pre"> </span>key="error",value="/add_error.jsp" }
- <span style="white-space:pre"> </span> *}
- */
- actionMapping.setForward(forward);
- /*
- * 上面Mappings.actions的存储结构相当于将配置信息与映射一一对应
- * map.put("/servlet/delUser", actionMapping);
- * map.put("/servlet/addUser", actionMapping);
- * map.put("/servlet/modifyUser", actionMapping);
- * map.put("/servlet/queryUser", actionMapping);
- */
- Mappings.actions.put((String) am.attributeValue("path"),
- actionMapping);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
我们的TestServlet只需要增加一句话,如下所示:
TestServlet
- package com.liang.servlet;
- import java.io.IOException;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import com.liang.action.Action;
- import com.liang.action.ActionMapping;
- import com.liang.action.Mappings;
- /**
- * 使用servlet做相关的控制,转向多个(V)视图
- * @author liang
- *
- */
- public class TestServlet extends HttpServlet {
- //需要读取的文件名
- protected static String config = "/WEB-INF/struts-config.xml";
- public void init() throws ServletException {
- //获得文件的路径
- //initialize();
- //根据web.xml中映射的目录获得文件在对应服务器中的真实路径
- config = getServletContext().getRealPath("/")+ getInitParameter("config");
- //解析struts-config.xml配置文件
- ConfigInit.init(config);
- }
- //根据web.xml中映射的目录获得文件在对应服务器中的真实路径
- // private void initialize() {
- // try {
- // config = getServletContext().getRealPath("/")
- // + getInitParameter("config");
- // } catch (Exception e) {
- // e.printStackTrace();
- // }
- // }
- @Override
- protected void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- //取得访问的URI
- String reqeuestURI = request.getRequestURI();
- //截取URI,获得路径
- String path = reqeuestURI.substring(reqeuestURI.indexOf("/",1), reqeuestURI.indexOf("."));
- Mappings mapings = new Mappings();
- // 根据截取的URL请求,到Map中取得本次请求对应的Action类
- ActionMapping actionMapping = (ActionMapping)mapings.actions.get(path);
- //取得本请求对应的Action类的完整路径
- String type = actionMapping.getType(); //com.liang.action.DelUserAction
- //采用反射,动态实例化Action
- try {
- Action action = (Action)Class.forName(type).newInstance();
- // 采用多态的机制,动态调用Action中的execute方法,返回转向路径
- String result = action.execute(request, response);
- //获得真实转向页面
- String forward =(String)actionMapping.getForward().get(result);
- //根据转向路径完成转向
- request.getRequestDispatcher(forward).forward(request, response);
- } catch (InstantiationException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- @Override
- protected void doPost(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- doGet(request,response);
- }
- }
最后,我们看一下AddUserAction已经变得非常灵活了。
- package com.liang.action;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import com.liang.manager.UserManager;
- public class AddUserAction implements Action {
- @Override
- public String execute(HttpServletRequest req, HttpServletResponse resp)
- throws Exception {
- //获取参数
- String username = req.getParameter("username");
- //调用业务逻辑
- UserManager userManager = new UserManager();
- try{
- //添加的业务逻辑
- userManager.add(username);
- }catch(Exception e){
- //返回添加失败的界面
- return "error";//和配置文件的配置一致
- }
- //返回添加成功的界面
- return "success";//和配置文件的配置一致
- }
- }
大功告成,如果我们想换一个视图显示,我们只需要修改一个配置文件即可。我们用一张类图回顾一下我们重构和封装的历程。
到此刻为止,我们重构MVC实现Struts框架的所有步骤都做完了。不难发现,其实框架并不难,只是咋一看特别神秘,当我们一步步重构,不断封装,不断完善,Struts的雏形已经展现在我们的面前了。框架就是封装的高度化,抽象的高度化。
当然,它既然是一个雏形就绝对还有不完美的地方,比如,我们没有像Struts一样封装ActionForm,自动完成数据类型的转化,当然我们也可以从现在的基础上进一步完善,但是我们就不再往下做了,我们了解它的基本思想就好,况且我们后面还有更加艰巨的任务。
经过几篇博客的重构,我们实现了一个Struts的雏形,它可以让我们认识mvc和struts的异同点,以及struts的封装过程,对我们更加深入struts埋下了伏笔。下篇博客【SSH进阶之路】Struts详细实现流程,深入Struts(七),通过学习Struts的流程,进一步深入Struts。下篇博客见!