【SSH进阶之路】一步步重构MVC实现Struts框架——完善转向页面,大功告成(六)
目录:
【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。下篇博客见!
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。