简略的Struts1.0的实现
简单的Struts1.0的实现
前一段时间写了一个仿Struts的框架,就是一个简单内核。我看过很多关于Struts的书,大多是一些应用方面的书,所以很多JAVA爱好者不能满足对于应用方面的知识,我们需要了解它的原理,想知道它是怎么来的(借用一下赵本山的话)。
简单的说一下原理,第一步,写一个自己的Servlet,在里面解析struts-config.xml;第二步,通过解析后的struts-config.xml找要访问的Action,再把请求的参数映射到Form里。就这么简单,它就是被包装后的Servlet。
类图
1、web.xml与同普通Struts的配置一样
com.swstruts.action.ActionServlet就是我的核心Servlet。
2、ActionServlet
其实它就是普通的Servlet。通过上面web.xml的映射,只要是.do的访问都会先能过这个Servlet过滤到想要访问的Action里。因为这个Servlet的load-on-startup设置为0,所以Tomcat启动时,会执行init方法。ConfigInit类就是我的struts-config.xml解析器。
3、ConfigInit类
struts-config.xml解析器。对于xml文件的解析,我这里用的dom4j,其实应该自己写一个,但这里的主题不是如何解析xml文件,把dom4j作为一个工具,让自己的代码简捷一点。把解析后的结点保存到MappingAction里,MappingAction是我封装的一个类。如何解析看代码。
另附
struts-config.xml,与普通的Struts一样。(既然Struts前辈已经写好了定义,也没有必要别出心裁的创造一个struts-config.xml来证明这是我写的Struts。)
Mappings类
4、Processor核心,代码其实并不多,能解决问题就行。简单说一下原理,process方法就是控制分配的功能,找到*.do对应的Acrtion类,用newInstance()实例后,再调用execute实现具体机能。(原理就是继承)具体Acrtion类要继承Process接口,必须实现execute方法。setActionForm这个方法也很重要,这就是Struts区分Servlet的不同之处。把Parameter封装到Form中。具体实现看代码。
另附
Process接口
ActionForm类
原理里的内容就说到这里,写一个小例子来验证一下。
首先写一个login的jsp。
其次login的Action
再次login的Form
最后login成功的jsp
前一段时间写了一个仿Struts的框架,就是一个简单内核。我看过很多关于Struts的书,大多是一些应用方面的书,所以很多JAVA爱好者不能满足对于应用方面的知识,我们需要了解它的原理,想知道它是怎么来的(借用一下赵本山的话)。
简单的说一下原理,第一步,写一个自己的Servlet,在里面解析struts-config.xml;第二步,通过解析后的struts-config.xml找要访问的Action,再把请求的参数映射到Form里。就这么简单,它就是被包装后的Servlet。
类图
1、web.xml与同普通Struts的配置一样
<?xml version="1.0" encoding="UTF-8"?> <web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name>SWStruts</display-name> <welcome-file-list> <welcome-file>/WEB-INF/index.jsp</welcome-file> </welcome-file-list> <servlet> <servlet-name>action</servlet-name> <servlet-class>com.swstruts.action.ActionServlet</servlet-class> <init-param> <param-name>config</param-name> <param-value>/WEB-INF/struts-config.xml</param-value> </init-param> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> </web-app>
com.swstruts.action.ActionServlet就是我的核心Servlet。
2、ActionServlet
其实它就是普通的Servlet。通过上面web.xml的映射,只要是.do的访问都会先能过这个Servlet过滤到想要访问的Action里。因为这个Servlet的load-on-startup设置为0,所以Tomcat启动时,会执行init方法。ConfigInit类就是我的struts-config.xml解析器。
package com.swstruts.action; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ActionServlet extends HttpServlet { protected static String config = "/WEB-INF/struts-config.xml"; private Processor processor = new Processor(); public void init() throws ServletException { initialize(); ConfigInit.init(config); } private void initialize() { try { config = getServletContext().getRealPath("/") + getInitParameter("config"); } catch (Exception e) { e.printStackTrace(); } } public void destroy() { } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processor.process(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processor.process(request, response); } }
3、ConfigInit类
struts-config.xml解析器。对于xml文件的解析,我这里用的dom4j,其实应该自己写一个,但这里的主题不是如何解析xml文件,把dom4j作为一个工具,让自己的代码简捷一点。把解析后的结点保存到MappingAction里,MappingAction是我封装的一个类。如何解析看代码。
package com.swstruts.action; 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.swstruts.bean.MappingAction; public class ConfigInit { public static void init(String config) { try { File f = new File(config); SAXReader reader = new SAXReader(); Document doc = reader.read(f); Element root = doc.getRootElement(); Element formmappings = (Element) root.element("form-beans"); for (Iterator i = formmappings.elementIterator("form-bean"); i .hasNext();) { Element form = (Element) i.next(); Mappings.forms.put((String) form.attributeValue("name"), (String) form.attributeValue("type")); Mappings.formInstances.put( (String) form.attributeValue("name"), Class.forName( (String) form.attributeValue("type")) .newInstance()); } Element actionmappings = (Element) root.element("action-mappings"); for (Iterator j = actionmappings.elementIterator("action"); j .hasNext();) { Element am = (Element) j.next(); MappingAction action = new MappingAction(); action.setParameter(am.attributeValue("parameter")); action.setName(am.attributeValue("name")); action.setType(am.attributeValue("type")); Map forward = new HashMap(); for (Iterator k = am.elementIterator("forward"); k.hasNext();) { Element fo = (Element) k.next(); forward.put((String) fo.attributeValue("name"), (String) fo .attributeValue("path")); } action.setForward(forward); Mappings.actions .put((String) am.attributeValue("path"), action); } } catch (Exception e) { e.printStackTrace(); } } }
另附
struts-config.xml,与普通的Struts一样。(既然Struts前辈已经写好了定义,也没有必要别出心裁的创造一个struts-config.xml来证明这是我写的Struts。)
<?xml version="1.0" encoding="UTF-8"?> <struts-config> <form-beans > <form-bean name="TestForm" type="example.form.TestForm"/> </form-beans> <action-mappings > <action path="/login" parameter="showLogoutView" type="example.action.Test" name="TestForm"> <forward name="success" path="/WEB-INF/success.jsp" /> <forward name="fail" path="/WEB-INF/index.jsp" /> </action> <action path="/testout" parameter="showLogoutView" type="example.action.CsvOut" name="TestForm"> <forward name="success" path="/WEB-INF/success.jsp" /> <forward name="fail" path="/WEB-INF/index.jsp" /> </action> </action-mappings> </struts-config>
Mappings类
public class Mappings { public static Map actions = new HashMap(); public static Map forms = new HashMap(); public static Map formInstances = new HashMap(); } MappingAction类 package com.swstruts.bean; import java.util.HashMap; import java.util.List; import java.util.Map; public class MappingAction { private String parameter; private String name; private String type; private Map forward = new HashMap(); public String getParameter() { return parameter; } public void setParameter(String parameter) { this.parameter = parameter; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getType() { return type; } public void setType(String type) { this.type = type; } public Map getForward() { return forward; } public void setForward(Map forward) { this.forward = forward; } }
4、Processor核心,代码其实并不多,能解决问题就行。简单说一下原理,process方法就是控制分配的功能,找到*.do对应的Acrtion类,用newInstance()实例后,再调用execute实现具体机能。(原理就是继承)具体Acrtion类要继承Process接口,必须实现execute方法。setActionForm这个方法也很重要,这就是Struts区分Servlet的不同之处。把Parameter封装到Form中。具体实现看代码。
package com.swstruts.action; import java.beans.IntrospectionException; import java.lang.reflect.InvocationTargetException; import javax.servlet.RequestDispatcher; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.swstruts.bean.MappingAction; import com.swstruts.io.Process; public class Processor { public void process(HttpServletRequest request, HttpServletResponse response) { String url = request.getServletPath(); String mapping = url.split(".do")[0]; MappingAction action = (MappingAction) Mappings.actions.get(mapping); if (action != null) { try { ActionForm form = setActionForm(request, action); Process process = (Process) Class.forName(action.getType()) .newInstance(); String result = process.execute(request, response, form); if (result != null) { String destination = (String) action.getForward().get( result); RequestDispatcher dispatcher = request .getRequestDispatcher(destination); dispatcher.forward(request, response); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } else { System.out.println("not find action!"); } } private ActionForm setActionForm(HttpServletRequest request, MappingAction action) { String formpath = (String) Mappings.forms.get(action.getName()); ActionForm actionform = null; if (formpath != null) { try { actionform = (ActionForm) Class.forName(formpath).newInstance(); java.beans.BeanInfo info = java.beans.Introspector .getBeanInfo(actionform.getClass()); java.beans.PropertyDescriptor pd[] = info .getPropertyDescriptors(); for (int i = 0; i < pd.length; i++) { String fieldName = pd[i].getName(); if (fieldName != null && !fieldName.equals("class")) { java.lang.reflect.Method writeMethod = pd[i] .getWriteMethod(); String[] parValues = request .getParameterValues(fieldName); if (parValues == null) { writeMethod.invoke(actionform, ""); } else { if (parValues.length == 1) { writeMethod.invoke(actionform, parValues[0]); } else { writeMethod.invoke(actionform, parValues); } } } } } catch (IntrospectionException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } return actionform; } }
另附
Process接口
package com.swstruts.io; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.swstruts.action.ActionForm; public interface Process { public String execute(HttpServletRequest req, HttpServletResponse res,ActionForm form); }
ActionForm类
package com.swstruts.action; public class ActionForm implements java.io.Serializable { }
原理里的内容就说到这里,写一个小例子来验证一下。
首先写一个login的jsp。
<html> <head> </head> <body> <form action="login.do" method="POST"> <p> username:<input type="text" name="name"/> </p> <p> password:<input type="password" name="password"/> </p> <p> <input type="submit" value="login"/> </p> </form> <%String message =(String)request.getAttribute("message"); if(message == null){ message = ""; } %> <%=message%> <form action="testout.do" method="POST"> <p> <input type="submit" value="textout"/> </p> </form> </body> </html>
其次login的Action
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.swstruts.action.ActionForm; import com.swstruts.io.Process; import example.form.TestForm; public class Test implements Process { public String execute(HttpServletRequest request, HttpServletResponse response, ActionForm form) { if (form != null && form instanceof TestForm) { TestForm testform = (TestForm) form; String name = testform.getName(); String password = testform.getPassword(); if (name.equals("123") && password.equals("123")) { request.setAttribute("username", name); return "success"; } else { request .setAttribute("message", "username or password is wrong"); return "fail"; } } else { return "fail"; } } }
再次login的Form
package example.form; import com.swstruts.action.ActionForm; public class TestForm extends ActionForm { private String name; private String password; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
最后login成功的jsp
<h1>success!</h1> welcome <%=request.getAttribute("username")%>