一直想寫Struts2的底層實現,醞釀了兩個星期,今天把它實現。
首先,我們在運用的時候都會使用action,實現跳轉,下面我們寫一個UserAction:
public class UserAction { public String toAddUser(){ return "success"; } public String addUser(){ return "adduser"; } }
我們在使用Struts2的時候,一個很重要的配置檔案是:struts.xml,因此我們需要讀取它,知道他裡面的內容,java解析xml我寫過了一篇文章,可以去看看。
下面我們寫一個配置檔案:
<?xml version="1.0" encoding="UTF-8"?> <struts> <package name="user" namespace="/user" > <action name="userAction" class="actions.UserAction" > <result name="success">/success.jsp</result> <result name="adduser">/addUser.jsp</result> </action> </package> </struts>
之後我們就需要去讀取這個配置檔案,但是之前我們需要我們需要建立幾個實體類去儲存這些元素,由外到內排列:
1.package的實體類
import java.util.List; public class PackageEntity { private String name; private String namespace; private List<ActionEntity> actions; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getNamespace() { return namespace; } public void setNamespace(String namespace) { this.namespace = namespace; } public List<ActionEntity> getActions() { return actions; } public void setActions(List<ActionEntity> actions) { this.actions = actions; } }
private List<ActionEntity> actions;是吧action實體類的內容放到package中。
2.action的實體類
import java.util.List; public class ActionEntity { private String name; private String classname; private List<ResultEntity> results; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getClassname() { return classname; } public void setClassname(String classname) { this.classname = classname; } public List<ResultEntity> getResults() { return results; } public void setResults(List<ResultEntity> results) { this.results = results; } }
private List<ResultEntity> results;是把result的實體類放到action中。
3.result的實體類
public class ResultEntity { private String name; private String page; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPage() { return page; } public void setPage(String page) { this.page = page; } }
page是指後面的jsp。
經過兩個list就把配置檔案中所有的元素集中到package中,便於下面的跳轉。
下面寫一個配置的工具類:
public class ConfigUtils { //new一個package的物件,便於呼叫元素 public static PackageEntity pe=new PackageEntity(); public static void config(){ SAXReader reader=new SAXReader(); try { //讀取struts.xml Document doc=reader.read(Thread.currentThread().getContextClassLoader().getResourceAsStream("struts.xml")); //讀取根元素 Element root=doc.getRootElement(); //得到根元素下的節點元素 Element packageElement=root.element("package"); List<ActionEntity> actions=new ArrayList<ActionEntity>(); pe.setName(packageElement.attributeValue("name")); pe.setNamespace(packageElement.attributeValue("namespace")); //得到根元素下的節點元素 List<Element> listActions=packageElement.elements("action"); for(Element actionElement:listActions){ ActionEntity ae=new ActionEntity(); //得到子節點 ae.setName(actionElement.attributeValue("name")); ae.setClassname(actionElement.attributeValue("class")); //得到根元素下的節點元素 List<Element> resultElements=actionElement.elements("result"); List<ResultEntity> results=new ArrayList<ResultEntity>(); for(Element resultEle:resultElements){ ResultEntity re=new ResultEntity(); //得到子節點 re.setName(resultEle.attributeValue("name")); re.setPage(resultEle.getText()); results.add(re); } ae.setResults(results); actions.add(ae); } pe.setActions(actions); } catch (DocumentException e) { e.printStackTrace(); } } }
寫一個index.jsp,為了寫跳轉連結進行驗證:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>首頁</title> </head> <body> <a href="<%=path%>/user/userAction!toAddUser.action">跳轉</a> <br/> <a href="<%=path%>/user/userAction!addUser.action">新增使用者</a> </body> </html>
跳轉是跳到到success.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP `success.jsp` starting page</title> </head> <body> This is my JSP page. <br> 成功了 </body> </html>
新增使用者是跳到adduser.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP `addUser.jsp` starting page</title> </head> <body> This is my JSP page. <br> 新增使用者了 </body> </html>
寫好了jsp之後我們就要過濾這些連線,進行跳轉,寫一個struts2的過濾器:
public class StrutsFilter implements Filter { @Override public void destroy() { } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request=(HttpServletRequest)req; String path=request.getServletPath(); System.out.println(path); String[] pathArr=path.split("/"); String namespace=pathArr[1]; String actionString=pathArr[2]; String actionname=actionString.split("!")[0]; String methodname=actionString.split("!")[1].split("\.")[0]; System.out.println(actionname+":"+methodname); PackageEntity pe=ConfigUtils.pe; List<ActionEntity> actions=pe.getActions(); ActionEntity doAction=null; for(ActionEntity ae:actions){ if(ae.getName().equals(actionname)){ doAction=ae; break; } } try { Class actioncls=Class.forName(doAction.getClassname()); Object actionObj=actioncls.newInstance(); Class cls=actionObj.getClass(); Method actionMethod=cls.getDeclaredMethod(methodname); String resultValue=(String)actionMethod.invoke(actionObj,null); List<ResultEntity> results=doAction.getResults(); ResultEntity re=null; for(ResultEntity result:results){ if(resultValue.equals(result.getName())){ re=result; break; } } request.getRequestDispatcher(re.getPage()).forward(request, res); } catch (Exception e) { e.printStackTrace(); } } @Override public void init(FilterConfig filterConfig) throws ServletException { ConfigUtils.config(); } }
下面建立一個web的過濾器測試一下:
import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class TestFilter implements Filter { @Override public void destroy() { } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request=(HttpServletRequest)req; HttpServletResponse response=(HttpServletResponse)res; request.getRequestDispatcher("/success.jsp").forward(request,response); } @Override public void init(FilterConfig filterConfig) throws ServletException { } }
建立一個web的servlet測試一下:
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 TestServlet extends HttpServlet { public void doGet(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{ request.getRequestDispatcher("/success.jsp").forward(request, response); } }
別忘了把解析xml的包導進去。
希望對你們理解框架有幫助!!!