struts2源码之仿写struts2

这次在struts2的源码中花了不少的时间。其中收获了不少,源码的功能实现我想如果分解开来人人都能写,关键是他们之间的层次,封装,和接口的应用,这次我就称之为框架的架构吧,虽然我不清楚这个名称是不是符合。struts2我不太会用,只是了解其中的一小部分机制,所以这里我只仿写了配置文件的读取和请求发送时,框架中的处理。关于其他的知识点暂时放着,之后零零碎碎记录

1:配置文件 note:package只有namespace,如果extends加上的话后面需要递归获取父包信息,所以第一次写尽量简单,后面不断完善。

<?xml version="1.0" encoding="UTF-8"?>

<struts>
	<package namespace="/center">
		<action name="skip" class="web.prim.UltimateServlet" method="test">
			<result name="success" type="dispatcher">index.jsp</result>
			<result name="fail" type="dispatcher">index.jsp</result>		
		</action>
	</package>
	<package namespace="/center1">
		<action name="skip_execute" class="web.prim.UltimateServlet">
			<result type="dispatcher">
				<param name="success">index.jsp</param>
				<param name="fail">fail.jsp</param>
			</result>
		</action>
	</package>

</struts>

2:web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
	xmlns="http://java.sun.com/xml/ns/javaee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  
  <filter>
  	<filter-name>dispatcher</filter-name>
  	<filter-class>com.filter.Struts2FileDispacher</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>dispatcher</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>
 
</web-app>



注意到上边有一个filter的过滤器,主要是拦截一切客户端的请求。接下啦我就从这个类展开。


Struts2FileDispacher 过滤器类

package com.filter;

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;

import com.dispatcher.Dispatcher;
import com.mapper.ActionMapping;

public class Struts2FileDispacher implements Filter{
	private Dispatcher dispatcher;
	
	public void destroy() {
		
	}

	public void doFilter(ServletRequest req, ServletResponse resp,
			FilterChain chain) throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest)req;
		HttpServletResponse response = (HttpServletResponse) resp;
		dispatcher.saveRequestAndResponse(request,response);
		ActionMapping actionMapping = dispatcher.getActionMapping(request);
		dispatcher.ActionService(actionMapping);
		chain.doFilter(req, resp);
	}
	
	public void init(FilterConfig arg0) throws ServletException {
		dispatcher = new Dispatcher();
		dispatcher.init();
	}

}

请看 init这个方法,里边初始化了Dispatcher对象,这个对象高度封装,什么是高度封装呢?就是在它的上一层(该拦截器类)想要什么,想实现什么,这个对象都能够提供,它就像是一个架构师,将它下面的层次的类或者方法组装成某个功能方法。现在请看init()方法的实现:


Dispatcher.init()

private static Map<String,Provider> providers = new HashMap<String,Provider>();

/** this method use to initialize the configuration file*/
	public void init(){
		//use an empty method instead of the special implementation
		//so that we can keep a clear head ,rapid development
		init_XMLContextProvider();
		
	}

 /** here we can concrete implement the empty method*/
	public void init_XMLContextProvider(){
		Provider provider = new XMLContextProvider().call();
		providers.put("xmlContextProvider",provider);
	}

这里我只初始化了struts2.xml的文件。所以只创建了一个实现类, Provider这是一个接口,统一提供了一个函数 call()。从这里我体会到了接口的一个好处。博主在晚上灌了一瓶啤酒,晕乎乎的,状态来了后,就可以写整体的框架,什么细节都不想,只按照伪代码,按照逻辑一层层下去。这里如果没有接口,我不得不考虑到底该创建同一种类型类那个具体实现类。而且,如果 这个实现类实现不知道,等待用户的编写,那么在框架中有怎么接收这个类呢?


下面是XMLContextProvider类,这里只是先贴出来,初始化配置文件只是创建这个对象而已。

package com.provide;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.strust2.domain.ActionConfig;
import com.strust2.domain.PackageConfig;
import com.strust2.domain.ResultConfig;
import com.util.StrutsUtil;

/**
 * store the user fill out information
 * at the struts.xml
 * @author Z.B.S.Y
 *
 */
public class XMLContextProvider implements Provider{
	// read package label informations and 
	// store in the variable of capsulation packageConfig class
	private static List<PackageConfig> packageConfigs;
	// provide the special configuration file' path
	private String filePath;
	// the Document is dom4j capsulation class
	private Document doc;
	
	public XMLContextProvider(){
	}
	//initialize the filePath global variable
	public XMLContextProvider(String filePath){
		this(filePath,null);
	}
	
	public XMLContextProvider(Document doc){
		this(null,doc);
	}
	public XMLContextProvider(String filePath,Document doc){
		this.filePath = filePath;
		this.doc = doc;
	}
	
	public XMLContextProvider call(){
		packageConfigs = getPackageConfiguration();
		return this;
	}
	/*
	 * when we make sure that the variable of doc
	 * is not null,we do the following things like below
	 */
	public List<PackageConfig> getPackageConfiguration(){
		List<PackageConfig> packageConfs = new ArrayList<PackageConfig>();
		//here only has one doc; but struts2 has more than 
		//one documents,if that is the case we need to loop operation
		if(filePath == null){
			filePath = "struts.xml";
		}
		doc = getDocument(filePath);
		//get root Element here
		Element root = doc.getRootElement();	
		//if the package Element has a lot of childElement
		//we use the way which I has mentioned 
		Iterator<Element> ite = root.elementIterator("package");
		while(ite.hasNext()){
			Element packageEle = ite.next();
			PackageConfig packageConf = loadPackage(packageEle);
			packageConfs.add(packageConf);
		}
		return packageConfs;
	}
	//when we only get filePath we should obtain the Document instance
	public Document getDocument(String fileName){
		//if the doc is empty we should create a new instance
		if(doc == null){
			//it's a bit of trouble to create new instance we need
			//filePath and capsulation class of dom4j. here we can 
			//provide a method which has no code to achieve
			conversionFilePathToDocument(fileName);
		}
		//otherwise we as long as return doc of class attribute variable
		return doc;
	}
	
	//we can achieve code here through the filePath.
	//Don't you think the use of this method of coding is very convenient?
	private void conversionFilePathToDocument(String fileName){
		//call the Utility class to get the real configuration path
		String filePath = StrutsUtil.getConfigurationPath(fileName);
		try {
			SAXReader saxReader = new SAXReader();
			doc = saxReader.read(new File(filePath));
		} catch (DocumentException e) {
			String error = "when read the configuration path "+filePath +
			"appear this error";
			System.out.println(error);
			e.printStackTrace();
		}
	}
	
	// wonderful! don't you think so ? let's finish the method
	private PackageConfig loadPackage(Element packageEle){
		//create PackageConfig instance at here 
		PackageConfig packageConfig = new PackageConfig();
		//create the List<ActionConfig> of Collection at here
		List<ActionConfig> actionConfigs = new ArrayList<ActionConfig>();
		// let'me think,we should get action label information here
		// through the loop to get all the action label
		List<Element> actionEles = packageEle.elements("action");
		for(int i = 0; i < actionEles.size(); i++){
			Element actionEle = actionEles.get(i);
			ActionConfig actionConfig = getActionConfig(actionEle);
			actionConfigs.add(actionConfig);
		}
		//store the collection into the variable of PackageConfig
		 
		//wait! we have almost forgotten the package variable
		//we get the action variable here
		//let's ignore other attributes,to perfect them in the future
		String namespace = packageEle.attributeValue("namespace");
		//ok! we capsulation all the information in the actionConf
		packageConfig.setNamespace(namespace);
		packageConfig.setActionConfs(actionConfigs);
		return packageConfig;
	}
	
	private ActionConfig getActionConfig(Element actionEle){
		//get the action's attribute here
		String name = actionEle.attributeValue("name");
		String clazz = actionEle.attributeValue("class");
		String method = actionEle.attributeValue("method");
		//there is no method we use the default method the struts2 provide
		if(method == null){
			method = "execute";
		}
		//create a ActionConfig instance at here
		ActionConfig actionConf = new ActionConfig();
		//Each ActionConfig has result labels so create ActionConfig
		//instance and obtain the resultConfg at here
		List<ResultConfig> resultConfs = getResultConfig(actionEle);
		//store the all the information in this ActionConfig variable
		actionConf.setClazz(clazz);
		actionConf.setMethod(method);
		actionConf.setName(name);
		actionConf.setResultConfigs(resultConfs);
		return actionConf;
	}
	
	/** this function to get the resultConfig */
	private List<ResultConfig> getResultConfig(Element actionEle){
		//here exist two ways to read the result Element 
		//like <result name="" type="">xxx.jsp</result>
		//<result type=""><param name="">content</param></result>
		List<ResultConfig> resultConfs = new ArrayList<ResultConfig>();
		List<Element> resultEles = actionEle.elements("result");
		for(int i = 0; i < resultEles.size(); i++){
			Element resultEle = resultEles.get(i);
			ResultConfig resultConfig = new ResultConfig();
			//get the result label attribute of type
			String type = resultEle.attributeValue("type");
			Map<String,String> params = loadParams(resultEle);
			resultConfig.setParams(params);
			resultConfig.setType(type);
			resultConfs.add(resultConfig);
		} 
		return resultConfs;
	}
	
	//get the result collection by this method
	private Map<String,String> loadParams(Element resultEle){
		//let's finish the last work to get the result values
		Map<String,String> params = new HashMap<String,String>();
		List<Element> childsParams = resultEle.elements("param");
		if(childsParams != null){
			for(int i = 0; i < childsParams.size(); i++){
				Element param = childsParams.get(i);
				String name = param.attributeValue("name");
				String content = param.getText();
				params.put(name, content);
			}
		}
		if(params.size() == 0){
			//in this case that the result Element has no child Element of param
			String name = resultEle.attributeValue("name");
			String content = resultEle.getText();
			params.put(name, content);
		}
		return params;
	}
	
}

接下去请看doFilter方法:

public void doFilter(ServletRequest req, ServletResponse resp,
			FilterChain chain) throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest)req;
		HttpServletResponse response = (HttpServletResponse) resp;
		dispatcher.saveRequestAndResponse(request,response);
		ActionMapping actionMapping = dispatcher.getActionMapping(request);
		dispatcher.ActionService(actionMapping);
		chain.doFilter(req, resp);
	}

上边的saveRequestAndResponse(request,response)方法的作用:在<result type="dispatcher" >这里需要实现dispatcher所指的对象,这个类需要用request.getRequestDispatcher(path).forward(req,resp)需要这两个变量


dispatcher.getActionMapping(request)


/** find out the action which match the request special path**/
	public ActionMapping getActionMapping(HttpServletRequest req){
		// here use the ActionMapper to get the action match the request' path.
		parsePathAndReturn(req);
		ActionMapping actionMapping = new ActionMapping();
		actionMapping.mapping();
		return actionMapping;
	}

/** parse the request path **/
	public void parsePathAndReturn(HttpServletRequest req){
		String path = req.getRequestURI();
		// path will be parsed into this form like objectname + namespace + actionname
		// http://localhost:8080/namespace/logon.action
		//get the class which action point to  and the method defined in the class
		//which derive action 
		String name = path.substring(path.lastIndexOf("/")+1);
		String namespace = path.substring(0,path.lastIndexOf("/"));
		//if not execute blew step,will contain the objectname
		namespace = namespace.substring(namespace.lastIndexOf("/"));
		name = removeSuffix(name);
		ActionStore.setNamespace(namespace);
		ActionStore.setName(name);
	}

/** if has the suffix of ".action" please remove it**/
	public String removeSuffix(String name){
		if(name.endsWith(".action")){
			name = name.substring(0,name.indexOf("."));
		}else{
			flag = false;
		}
		return name;
	}


ActionStore类 只是暂存从路径中解析出来的namespace 和method。 最终从配置文件找出来的信息我存在了ActionMapping这个类中。


actionMapping.mapping();
这个类是从配置文件中根据路径信息找到匹配的变量值,将他们封装到actionMapping中。

package com.mapper;


import java.util.List;
import java.util.Map;


import com.dispatcher.Dispatcher;
import com.provide.XMLContextProvider;
import com.store.ActionStore;
import com.strust2.domain.ActionConfig;
import com.strust2.domain.PackageConfig;
import com.strust2.domain.ResultConfig;
import com.util.StringUtil;


public class ActionMapping {
	private String namespace;
	private String method;
	private String name;
	private String clazz;
	private String type;
	private ActionConfig actionConfig;
	//in advance the result collection variable
	private List<ResultConfig> resultConfigs;
	// cache current result informations in to map 
	private Map<String,String> params; 
	
	public void mapping(){
		String snamespace = ActionStore.getNamespace();
		String name = ActionStore.getName();
		XMLContextProvider provide = (XMLContextProvider) Dispatcher.getProviders().get("xmlContextProvider");
		List<PackageConfig> packageConfs = provide.getPackageConfiguration();
		getMappingNamespace(packageConfs,snamespace,name);
	}
	
	public void getMappingNamespace(List<PackageConfig> packageConfs,String snamespace,String method){
		for(int i = 0; i < packageConfs.size(); i++){
			PackageConfig packageConfig = packageConfs.get(i);
			String tnamespace = packageConfig.getNamespace();
			if(tnamespace.equals(snamespace)){
				namespace = snamespace;
				List<ActionConfig> actionConfigs = packageConfig.getActionConfs();
				getMappingMethod(actionConfigs,method);
			}
		}
	}
	
	public void getMappingMethod(List<ActionConfig> actionConfigs,String name){
		for(int i = 0; i <actionConfigs.size(); i++){
			ActionConfig actionConfig = actionConfigs.get(i);
			if(StringUtil.matches(actionConfig.getName(),name)){
				this.actionConfig = actionConfig;
				this.name = name;
				this.clazz = actionConfig.getClazz();
				convertion(name);
				resultConfigs = actionConfig.getResultConfigs();
			}
		}
	}
	public void convertion(String name){
		if(name.indexOf("_") != -1){
			this.method = name.substring(name.indexOf("_")+1);
		}else{
			method = actionConfig.getMethod();
		}
	}
	
	/** this method was something wrong*/
	@Deprecated
	public String getParambySpecial(String key){
		return ActionStore.getParambySpecial(key);
	}
	/** get set methods */
	public String getNamespace() {
		return namespace;
	}


	public void setNamespace(String namespace) {
		this.namespace = namespace;
	}


	public String getMethod() {
		return method;
	}


	public void setMethod(String method) {
		this.method = method;
	}


	public String getName() {
		return name;
	}


	public void setName(String name) {
		this.name = name;
	}


	public ActionConfig getActionConfig() {
		return actionConfig;
	}


	public void setActionConfig(ActionConfig actionConfig) {
		this.actionConfig = actionConfig;
	}


	public List<ResultConfig> getResultConfigs() {
		return resultConfigs;
	}


	public void setResultConfigs(List<ResultConfig> resultConfigs) {
		this.resultConfigs = resultConfigs;
	}


	public String getClazz() {
		return clazz;
	}


	public void setClazz(String clazz) {
		this.clazz = clazz;
	}


	public String getType() {
		return type;
	}


	public void setType(String type) {
		this.type = type;
	}


	public void setParams(Map<String, String> params) {
		this.params = params;
	}


	public Map<String, String> getParams() {
		return params;
	}
	
	
	
}


在上边我就需要用之前缓存好的Provider的类提供的方法去得到packageConfig变量了,这个变量封装了<package>标签下的全部的信息。 然后通过路径指明的namespace 和 name去匹配,得到指定 action of class and method.


上边我要讲讲当name以 xxx_method.action的形式,是如何处理的:

public void getMappingMethod(List<ActionConfig> actionConfigs,String name){
		for(int i = 0; i <actionConfigs.size(); i++){
			ActionConfig actionConfig = actionConfigs.get(i);
			if(StringUtil.matches(actionConfig.getName(),name)){
				this.actionConfig = actionConfig;
				this.name = name;
				this.clazz = actionConfig.getClazz();
				convertion(name);
				resultConfigs = actionConfig.getResultConfigs();
			}
		}
	}
注意到if语句中的matches方法了吗,这里用正则表达式去判断符合那种情况。

//to convert target regex to regular expressions
	public static boolean matches(String regex,String input){
		//note: write the empty method to instead of finish it's function
		regex = convertToRegExp(regex);
		System.out.println(regex);
		Pattern pattern = Pattern.compile(regex);
	    Matcher matcher = pattern.matcher(input);
		return matcher.matches();
	}

convertToRegExp方法:如果是有_下斜杠我就认为是xxx_method.action的形式。拆分,组装成正则表达似乎。如果不是,添加头尾符号返回

private static String convertToRegExp(String regex){
		//if regex contain the character of "_"   "^skip(_(\\w+))?$";
		if(regex.indexOf("_")!=-1){
			regex = regex.substring(0,regex.indexOf("_"));
			regex = "^" + regex + "(_(\\w+))?$";
		}else{
			// add the first and end character like ^regex$";
			regex = "^" + regex + "$";
		}
		
		return regex;
	}

struts2源码的判断比较复杂,博主折中使用了这个简单的方法。


匹配好了,当然就要执行了

/** execute action and interceptor by this function**/
	public void ActionService(ActionMapping actionMapping){		
		//through the agent for the calling ActionInvocation class
		// if the path is not end with the suffix of ".action" ,will not execute agent
		if(flag){
			if(actionProxy == null){
				actionProxy = new DefaultActionProxy();
			}
			List<Interceptor> interceptors = new ArrayList<Interceptor>();
			ActionInvocation actionInvocation = new DefaultActionInvocation(interceptors,actionMapping);
			actionProxy.setActionInvocation(actionInvocation);
			actionProxy.execute();
		}
	}

创建代理类 然后赋予action执行类:DefaultActionInvocation。 我之前在想,action可以使用代理,那么我result执行也非得试一下代理,而且使用同一个代理类。 可以action 和 result之间有些差异啊,怎么办,我想到了接口,既然存在差异我就用接口统一

其差异在实现类表现。 所以这里有一个:DefaultResultInvocation的类实现这个ActionInvocation接口,这里不是命名不是很规范,这也是整体架构的难度。

下面请看 execute()所执行的方法:

public void execute() {
		//I want to the DefaultActionProxy to use a variety 
		//of situations then using the interface,can provide 
		//a unified method 
		actionInvocation.invoke();
	}

关键代码在invoke

package com.Invocation;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

import com.Interceptor.Interceptor;
import com.ireturn.IReBack;
import com.mapper.ActionMapping;
import com.proxy.ActionProxy;
import com.proxy.DefaultActionProxy;
import com.returnparam.ReturnParam;
import com.strust2.domain.ResultConfig;

public class DefaultActionInvocation implements ActionInvocation{
	private List<Interceptor> interceptors;
	private ActionMapping actionMapping;
	private Integer index = 0;
	
	public DefaultActionInvocation(List<Interceptor> interceptors,
			ActionMapping actionMapping) {
		this.interceptors = interceptors;
		this.actionMapping = actionMapping;
	}
	
	public String invoke() {
		//here we should get all the Interceptors and execute them
		String result = null;
		if(index < interceptors.size()){
			Interceptor iterceptor = interceptors.get(index++);
			result = iterceptor.interceptor(this);
		}else{
			//execute the the special class of action label
			result = executeActionMethod();
			//execute the result
			executeResultMethod(result);
		}
		return result;
	}
	public String executeActionMethod(){
		//here I need the class instance
		actionMapping.mapping();
		String classname = actionMapping.getClazz();
		String methodname = actionMapping.getMethod();
		String result = null;
		try {
			Class clazz = Class.forName(classname);
			Object obj = clazz.newInstance();
			Method method = clazz.getMethod(methodname, null);
			result = (String)method.invoke(obj, null);
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		//here I need the method instance
		return result;
	}
	public void executeResultMethod(String result){
		//I need the instance special by type attribute
		try {
			String type = searchMappingResultType(actionMapping.getResultConfigs(),result);
			String path = actionMapping.getParams().get(result);
			type = ReturnParam.getReturnValue(type);
			ActionProxy actionProxy = new DefaultActionProxy();
			IReBack reBack = (IReBack) Class.forName(type).newInstance();
			ActionInvocation resultInvocation = new DefaultResultInvocation(actionMapping,reBack,result,path);
			actionProxy.setActionInvocation(resultInvocation);
			actionProxy.execute();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	private String searchMappingResultType(List<ResultConfig> resultConfigs,String result){
		String type = null;
		for(int i = 0;i < resultConfigs.size(); i++){
			ResultConfig resultConfig = resultConfigs.get(i);
			if(resultConfig.getParams().containsKey(result)){
				type = resultConfig.getType();
				actionMapping.setParams(resultConfig.getParams());
			}
		}
		//if user fill out no type information
		//use the default type of "dispatcher"
		if(type == null){
			type = "dispatcher";
		}
		return type;
	}
	
}

这里有个链形式的递归,关于递归,之前我读struts2源码比较迷惑的地方,都在博客中做了了一些尝试性的探索记录。

这个递归的作用处理拦截器 和action之间的调用顺序。


关于action 如何执行就不多说了,从上边的方法可以看出执行ation method的方法,就异常处理代码多点。


下面讲讲result的处理

public void executeResultMethod(String result){
		//I need the instance special by type attribute
		try {
			String type = searchMappingResultType(actionMapping.getResultConfigs(),result);
			String path = actionMapping.getParams().get(result);
			type = ReturnParam.getReturnValue(type);
			ActionProxy actionProxy = new DefaultActionProxy();
			IReBack reBack = (IReBack) Class.forName(type).newInstance();
			ActionInvocation resultInvocation = new DefaultResultInvocation(actionMapping,reBack,result,path);
			actionProxy.setActionInvocation(resultInvocation);
			actionProxy.execute();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
actionMapping存储的只是当前action的result集,在这个actionMapping对象中定义一个Map<String,String> params

本来想在actionMapping()方法中将所有的result信息的存放到params中的,但是考虑到result有两种写法,其中一种写法不能讲name作为key,所以不得不写个搜索功能,在params中存储result的信息集合。

private String searchMappingResultType(List<ResultConfig> resultConfigs,String result){
		String type = null;
		for(int i = 0;i < resultConfigs.size(); i++){
			ResultConfig resultConfig = resultConfigs.get(i);
			if(resultConfig.getParams().containsKey(result)){
				type = resultConfig.getType();
				actionMapping.setParams(resultConfig.getParams());
			}
		}
		//if user fill out no type information
		//use the default type of "dispatcher"
		if(type == null){
			type = "dispatcher";
		}
		return type;
	}
下面看一下结果代理:

package com.proxy;

import com.Invocation.ActionInvocation;

public class DefaultActionProxy implements ActionProxy {
	
	private ActionInvocation actionInvocation;
	public void execute() {
		//I want to the DefaultActionProxy to use a variety 
		//of situations then using the interface,can provide 
		//a unified method 
		actionInvocation.invoke();
	}

	public ActionProxy getActionProxy() {
		ActionProxy actionProxy = new DefaultActionProxy();
		return null;
	}

	public ActionInvocation getActionInvocation() {
		return actionInvocation;
	}

	public void setActionInvocation(ActionInvocation actionInvocation) {
		this.actionInvocation = actionInvocation;
	}


	
	
}

please see DefaultResultInvocation class

package com.Invocation;

import java.util.List;

import com.Interceptor.Interceptor;
import com.ireturn.IReBack;
import com.mapper.ActionMapping;
import com.util.PathUtil;

/*
 * this class is implements the interface
 * so we can enforcement unified method
 * in the ActionProxy
 */
public class DefaultResultInvocation implements ActionInvocation{
	private ActionMapping actionMapping;
	private IReBack reBack;
	private String result;
	private String path;
	
	public DefaultResultInvocation(ActionMapping actionMapping, IReBack reBack,String result,String path) {
		this.actionMapping = actionMapping;
		this.reBack = reBack;
		this.result = result;
		this.path = path;
	}


	public String invoke() {
		path = "/"+path;
		reBack.reBack(path);
		return null;
	}


}

ReBack是redirect ,dispatcher功能类所实现的接口,这里也是为了统一才设置接口的。

这里我只实现了dispatcher功能的类。

package com.ireturn;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.dispatcher.Dispatcher;

public class Struts2Dispatcher implements IReBack {
	
	/** implements the interface method what you want to do*/
	/** in other way we can derive request class,but it seems to implements some method */
	public void reBack(String path) {
		try {
			//get the Request variable
			HttpServletRequest request = (HttpServletRequest) Dispatcher.getScopes().get("request");
			HttpServletResponse response = (HttpServletResponse) Dispatcher.getScopes().get("response");
			//forward the request 
			request.getRequestDispatcher(path).forward(request, response);
		} catch (ServletException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
}

这里就需要得到之前缓存的静态变量scope集合了。从集合中得到作用域。


好了,基本是这些了,上边拦截器只提供了接口,实现类还是要靠用户实现的。 还是那句话功能实现人人都会,如何处理复杂的关系,如何巧妙搭设整个框架,我想,这是源码吸引我的地方








评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值