1. 程式人生 > >傳智:自己簡單實現一個struts2框架的demo

傳智:自己簡單實現一個struts2框架的demo

throws for request 運行 本地化 color ray run main

struts2的結構圖:

技術分享

代碼實現:

組織結構:

技術分享

主要代碼:

package cn.itcast.config;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import
java.util.List; import java.util.Map; /** * Created by zhen on 2017-08-04. * 讀取struts.xml配置信息 */ public class ConfigurationManager { private static final Logger logger = Logger.getLogger(ConfigurationManager.class); //讀取Interceptor public static List<String> getInterceptors(){ List
<String> interceptors = null; SAXReader saxReader = new SAXReader(); InputStream inputStream = ConfigurationManager.class.getResourceAsStream("/struts.xml"); Document document = null; try { document = saxReader.read(inputStream); } catch (DocumentException e) { logger.error(e.getMessage());
throw new RuntimeException("配置文件解析異常" ,e); } String xpath = "//interceptor"; List<Element> list = document.selectNodes(xpath); if(list != null && list.size() > 0){ interceptors = new ArrayList<String>(); for(Element ele: list){ String className = ele.attributeValue("class"); interceptors.add(className); } } return interceptors; } //讀取Constant public static String getConstant(String name){ String value = null; SAXReader saxReader = new SAXReader(); InputStream is = ConfigurationManager.class.getResourceAsStream("/struts.xml"); Document document = null; try { document = saxReader.read(is); } catch (DocumentException e) { logger.error(e.getMessage()); throw new RuntimeException("配置文件解析異常" ,e); } String xPath = "//constant[@name=‘" + name + "‘]"; List<Element> ele = document.selectNodes(xPath); if(ele != null && ele.size() > 0){ value = ele.get(0).attributeValue("value"); } return value; } //讀取Action public static Map<String, ActionConfig> getActions(){ Map<String, ActionConfig> actions = null; SAXReader saxReader = new SAXReader(); InputStream is = ConfigurationManager.class.getResourceAsStream("/struts.xml"); Document document = null; try { document = saxReader.read(is); } catch (DocumentException e) { logger.error(e.getMessage()); throw new RuntimeException("配置文件解析異常" ,e); } String xPath = "//action"; List<Element> list = document.selectNodes(xPath); if(list != null && list.size() > 0){ actions = new HashMap<String, ActionConfig>(); for(Element element : list){ ActionConfig actionConfig = new ActionConfig(); String name = element.attributeValue("name"); String method = element.attributeValue("method"); String className = element.attributeValue("class"); Map<String, String> results = null; List<Element> resultElements = element.elements("result"); if(resultElements != null && resultElements.size() > 0){ results = new HashMap(); for(Element ele: resultElements){ String resultName = ele.attributeValue("name"); String resultValue = ele.getTextTrim(); results.put(resultName, resultValue); } } actionConfig.setName(name); actionConfig.setMethod(method == null || method.trim().equals("") ? "execute" : method.trim()); actionConfig.setClassName(className); actionConfig.setResults(results); actions.put(name, actionConfig); } } return actions; } }

package cn.itcast.invocation;

import cn.itcast.config.ActionConfig;
import cn.itcast.context.ActionContext;
import cn.itcast.interceptor.Interceptor;
import org.apache.log4j.Logger;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Created by zhen on 2017-08-06.
 */
public class ActionInvocation {
    private static final Logger logger = Logger.getLogger(ActionInvocation.class);
    private Iterator<Interceptor> interceptors;
    private Object action;
    private ActionConfig actionConfig;
    private ActionContext actionContext;
    private String resultUrl;

    public ActionContext getActionContext() {
        return actionContext;
    }


    public ActionInvocation(List<String> classNames, ActionConfig actionConfig, HttpServletRequest request, HttpServletResponse response){
        //裝載Interceptor鏈
        if(classNames != null && classNames.size() > 0){
            List<Interceptor> interceptorList = new ArrayList<Interceptor>();
            for(String className : classNames){
                try {
                    Interceptor interceptor = (Interceptor) Class.forName(className).newInstance();
                    interceptor.init();
                    interceptorList.add(interceptor);
                } catch (Exception e) {
                    logger.error(e.getMessage());
                    throw new RuntimeException("創建Interceptor失敗,Interceptor Name:" + className ,e);
                }
            }
            interceptors =  interceptorList.iterator();
        }

        //準備action實例
        this.actionConfig = actionConfig;
        try {
            action = Class.forName(actionConfig.getClassName()).newInstance();
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw new RuntimeException("創建Action實例失敗!" + actionConfig.getClass(), e);
        }

        //準備數據中心
        actionContext = new ActionContext(request, response, action);
    }

    public String invoke(){
       if(interceptors != null && interceptors.hasNext() && resultUrl == null){
           Interceptor interceptor = interceptors.next();
           resultUrl = interceptor.invoke(this);
       }else{
           try{
               Method executeMethod = Class.forName(actionConfig.getClassName()).getMethod(actionConfig.getMethod());
               resultUrl = (String) executeMethod.invoke(action);
           }catch(Exception ex){
               logger.error(ex.getMessage());
               throw new RuntimeException("您配置的action方法不存在" + actionConfig.getClassName());
           }
       }
       return resultUrl;
    }
}

package cn.itcast.filter;

import cn.itcast.config.ActionConfig;
import cn.itcast.config.ConfigurationManager;
import cn.itcast.context.ActionContext;
import cn.itcast.invocation.ActionInvocation;
import org.apache.log4j.Logger;
import org.junit.Test;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * Created by zhen on 2017-08-06.
 */
public class StrutsPrepareAndExecuteFilter implements Filter {
    private static final Logger logger = Logger.getLogger(StrutsPrepareAndExecuteFilter.class);
    private List<String> interceptorClassNames;
    private  String extension;
    private Map<String, ActionConfig> actionConfigs;

    public void init(FilterConfig filterConfig) throws ServletException {
        //裝載配置信息
        interceptorClassNames = ConfigurationManager.getInterceptors();
        extension = ConfigurationManager.getConstant("struts.action.extension");
        actionConfigs = ConfigurationManager.getActions();
    }

    public static void main(String[] args){
        Logger logger = Logger.getLogger(StrutsPrepareAndExecuteFilter.class);
    }


    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //執行
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        String urlPath = request.getRequestURI();
        if(!urlPath.endsWith(extension)){
            filterChain.doFilter(request, response);
            return;
        }
        String actionName = urlPath.substring(urlPath.lastIndexOf("/") + 1).replace("." + extension, "");
        ActionConfig actionConfig = actionConfigs.get(actionName);
        if(actionConfig == null){
            throw new RuntimeException("找不到對應的action!" + actionName);
        }
        ActionInvocation actionInvocation = new ActionInvocation(interceptorClassNames, actionConfig, request, response);
        String result = actionInvocation.invoke();
        String dispatcherPath = actionConfig.getResults().get(result);
        if(dispatcherPath == null || "".equals(dispatcherPath)){
            throw new RuntimeException("找不到對應的返回路徑!");
        }
        request.getRequestDispatcher(dispatcherPath).forward(request, response);
        ActionContext.tl.remove();
    }

    public void destroy() {

    }
}

寫後感想:

struts2模擬

1、關註點分離思想。類似java中的解耦合,插拔。將功能拆分成各個攔截器實現。攔截器運行過程中拼接出想要的功能。
2、MVC思想。 filter-C Action-M jsp_url-V

需要掌握知識:
    XML解析,Xpath表達式(dom4j)
    Servlet技術
    java內省(BeanUtils)
    ThreadLocal線程本地化類
    遞歸調用
    
需要補充的知識:
    dom4j解析
    xpath語法
    獲取資源文件路徑
    
理解:
    對於值棧的模擬不要拘泥於數組,也可以使用現有的類進行封裝,比如使用ArrayList模擬。
    經常遞歸調用使用的局部變量可以放在循環外或者說是方法外。

項目路徑:

https://github.com/gzdx/MyStruts2.git

傳智:自己簡單實現一個struts2框架的demo