分步学习Struts(四) 自己写Struts框架
上次我们已经讲解分析了一下Struts原理,这次我们来自己构建一个简单的Struts框架,通过构建Struts框架来了解Struts是如何实现MVC的。
1、回顾Struts原理分析
不解释,接上篇博客,链接地址如下:
http://blog.csdn.net/zs15932616453/article/details/8919349
2、解析XML文件
在上篇博客中,我们已经看出Struts做的就是将MVC中的每一层进行联系,而这些联系其实就是由XML配置文件进行关联的,所以这里我们自己写的Struts框架的第一步就是XML文件的解析。我们使用Struts框架默认的名称struts-config.xml,如下图所示。
解析xml文件,我们用dom4j解析。步骤如下
1)拷贝jar包
2)编写代码,代码比较简单,不做多余解释
package control; import java.io.InputStream; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.io.SAXReader; public class XmlConfigReader { private static XmlConfigReader instance = new XmlConfigReader(); private XmlConfigReader() { } public static XmlConfigReader getInstance() { return instance; } /** * 将XML文档转换成为Document对象 * @param filepath XML文档对象路径 * @return 转换之后的Document对象 */ public Document XML2Document(String filepath){ SAXReader reader = new SAXReader(); Document document = null; InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(filepath); try { document = reader.read(in); } catch (DocumentException e) { e.printStackTrace(); } return document; } }
注意事项:在Java程序中使用dom4j解析xml文件需要注意路径问题,因为web项目发布之后,有些xml文件是不会发布到项目中的,所以就造成了一些文件无法解析在发布的时候找不到。另外web项目发布之后,一些xml文件的相对位置会发生变化,所以在项目中执行很对的xml文件解析也会出现文件未找到错误。具体内容,我们以后专门进行分析。
3、分析结构
上一步我们已经能够将xml文件进行解析,接下来我们分析一下XML文件中各个部分分别对应MVC中的那些部分和各个部分之间如何联系,这一点在上一篇中已经做了相依的解释,这里我们不做多余的解释。
MVC对应关系部分
各部分联系,参见博客,链接如下:
http://blog.csdn.net/zs15932616453/article/details/8901418
4、基础类编写。
了解了各个部分对应关系之后,我们来看一下一些基础类的代码,这些代码与真正的Struts代码基本雷同,所以我们这里不做多余的解释代码如下:
Action.java,代码如下:
package control; importjavax.servlet.ServletRequest; importjavax.servlet.ServletResponse; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; importmodel.ActionForm; publicclass Action { public ActionForward execute( ActionMapping mapping, ActionForm form, ServletRequest request, ServletResponse response) throws Exception { try { return execute( mapping, form, (HttpServletRequest) request, (HttpServletResponse)response); } catch (ClassCastException e) { return null; } } public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { return null; } }
LoginAction.java,代码如下:
package control; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import model.ActionForm; import model.LoginActionForm; public class LoginAction extends Action { @Override public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { String name=((LoginActionForm)form).getUserName(); String forward=""; //业务处理部分,我们仅作简单的判断是否是“hello” if("hello".equals(name)){ forward="success"; }else{ forward="error"; } return mapping.getActionForwards(forward); } }
ActionForward.java,代码如下:
package control; public class ActionForward { private String name; private String path; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } }
ActiionMapping.java,代码如下:
package control; import java.util.HashMap; public class ActionMapping { private String path; private String type; private String name; private String scope; private HashMap<String,ActionForward> actionForwardMap=new HashMap<String,ActionForward>(); public String getPath() { return path; } public void setPath(String path) { this.path = path; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getScope() { return scope; } public void setScope(String scope) { this.scope = scope; } public ActionForward getActionForwards(String ActionForwardName) { ActionForward actionforward=actionForwardMap.get(ActionForwardName); return actionforward; } public void addActionForward(ActionForward actionForward) { actionForwardMap.put(actionForward.getName(), actionForward); } }
ActionForm.java,代码如下:
package model; public abstract class ActionForm { }
LoginActionForm.java,代码如下:
package model; public class LoginActionForm extends ActionForm { private String userName; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } }
5、初始化
了解一些基础类之后,我们接下来重点将一些Strtus框架的核心类ActionServlet。首先我们分析Struts初始化工作,Struts初始化执行工作大致分为几个部分,我们这里只讲我们自己写的Struts都执行哪些工作,真正的Struts框架初始化是比较复杂的,我们等到以后再具体分析这些。
在ActionServlet中的init()方法中,我们主要将配置文件中的各个部分读取到Map中,代码如下:
package control; import java.io.IOException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import model.ActionForm; import org.dom4j.Document; import org.dom4j.Element; public class ActionServlet extends HttpServlet { private String config; private HashMap<String,ActionMapping> actionMappingMap=new HashMap<String,ActionMapping>(); private HashMap<String,String> actionFormMap=new HashMap<String,String>(); @Override public void init(){ //初始化配置文件 initConfig(); } /** * 将struts-config.xml文件中的各个部分初始化到Map中 * */ private void initConfig(){ //获取struts-config.xml文件位置,这里我们不错处理,取默认即可 config=getServletConfig().getInitParameter("config"); String filePath="../.."+config; //读取XML文件,存储到document中 Document doc=XmlConfigReader.getInstance().XML2Document(filePath); //读取配置信息到列表中, List<?> actionFormList=doc.selectNodes("struts-config/form-beans/form-bean"); List<?> actionList=doc.selectNodes("struts-config/action-mappings/action"); List<?> actionForwardList=doc.selectNodes("struts-config/action-mappings/action/forward"); //遍历ActionForm列表,将配置信息中的ActionForm信息保存到Map中 for(int i=0;i<actionFormList.size();i++){ String actionFormName=((Element)actionFormList.get(i)).attributeValue("name"); String actionFormType=((Element)actionFormList.get(i)).attributeValue("type"); actionFormMap.put(actionFormName, actionFormType); } //遍历ActionMapping列表,将配置信息中的ActionMapping信息保存到Map中 for(int i=0;i<actionList.size();i++){ String actionName = ((Element)actionList.get(i)).attributeValue("name"); String actionType = ((Element)actionList.get(i)).attributeValue("type"); String actionPath = ((Element)actionList.get(i)).attributeValue("path"); String actionScope = ((Element)actionList.get(i)).attributeValue("scope"); ActionMapping actionMapping=new ActionMapping(); //将配置信息加载到ActionMapping中 actionMapping.setName(actionName); actionMapping.setPath(actionPath); actionMapping.setType(actionType); actionMapping.setScope(actionScope); //遍历ActionForward配置部分,将该部分保存到Action中 for(int j=0;j<actionForwardList.size();j++){ ActionForward actionForward=new ActionForward(); //将配置的ActionForward信息添加到ActionForwar对象中 String actionForwardName=((Element)actionForwardList.get(j)).attributeValue("name"); String actionForwardPath=((Element)actionForwardList.get(j)).attributeValue("path"); actionForward.setName(actionForwardName); actionForward.setPath(actionForwardPath); //将ActionFormWard对象添加到Action中 actionMapping.addActionForward(actionForward); } //将Action对象添加到ActionMapping中 actionMappingMap.put(actionMapping.getPath(),actionMapping); } } }
6、处理客户端请求
ActionServlet初始化完成之后,我们就可以接受客户请求了,具体的执行代码如下:
package control; import java.io.IOException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import model.ActionForm; import org.dom4j.Document; import org.dom4j.Element; public class ActionServlet extends HttpServlet { private String config; private HashMap<String,ActionMapping> actionMappingMap=new HashMap<String,ActionMapping>(); private HashMap<String,String> actionFormMap=new HashMap<String,String>(); @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { process(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { process(request, response); } protected void process(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { try { //取得URL String url=request.getRequestURL().toString();//http://192.168.24.170:8080/StrutsTest/login.do int start=url.lastIndexOf("/"); int end=url.lastIndexOf("."); String actionDo=url.substring(start,end);// /login //获取指定的ActionMapping ActionMapping actionMapping=(ActionMapping)actionMappingMap.get(actionDo); //实例化ActionForm String actionFormType=actionFormMap.get(actionMapping.getName()); ActionForm actionForm=(ActionForm)Class.forName(actionFormType).newInstance(); //获取所有ActionForm中的方法名 Method[] methods=actionForm.getClass().getDeclaredMethods(); //遍历所有方法,将调用所有setter方法初始化 for(int i=0;i<methods.length;i++){ String methodName=methods[i].getName(); if(methodName.contains("set")== true){ String attributeName=methodName.toLowerCase().charAt(3)+methodName.substring(4,methodName.length()); actionForm.getClass().getMethod( methodName,new Class[]{String.class}).invoke(actionForm, new Object[]{request.getParameter(attributeName)}); } } //实例化Action Action action = (Action)Class.forName(actionMapping.getType()).newInstance(); //获取指定的ActionForward对象 ActionForward actionForward=action.execute(actionMapping, actionForm, request, response); //转发到指定的页面 request.getRequestDispatcher(actionForward.getPath()).forward(request, response); } catch (Exception e) { e.printStackTrace(); } } }
整合ActionServlet的初始化和客户端请求之后,我们自己写的Struts框架基本就编写完毕了,当然,这只是一个非常简单的实例,很多地方我们都可以进行一些优化。这里主要为了演示,我们就不做过多的工作了。
本文我们主要演示了一个自己写的Struts框架,实例比较简单,下次我们分析一下本篇文章中的XML文件读取的路径相关问题。