一直想寫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的包導進去。

希望對你們理解框架有幫助!!!