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
时间: 2024-10-18 07:36:26