【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。下篇博客见!



郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。