基于配置的自定义的简单struts(了解struts原理)

             struts的基于配置的action跳转方式使用起来特别方便,对此我也模仿struts的action,实现一个自己定义的通过配置文件配置action进行简单的操作:

       首先,可以知道sturts是通过过滤器来拦截浏览器发送的请求,再在过滤器里进行操作,实现这个流程。

       那么,我们也定义一个filter在我们的程序中:

      

public class StrutsFilter implements Filter{
     public void doFilter(ServletRequest arg0, ServletResponse arg1,FilterChain arg2) throws 
      IOException, ServletException {
     {
       
     }
}


       同样,对所有请求进行拦截,在web.xml中进行配置:

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <display-name>Struts Blank</display-name>

    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>com.yc.frame.filter.StrutsFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>*</url-pattern>
    </filter-mapping>

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>


</web-app>
      当然,struts中最重要的就是struts.xml的这个配置文件,在这里分析配置文件可以知道,struts必然是先解析出xml,然后将解析的xml以一个数据结构储存,利用反射找到相应的Action子类,再用反射激活里面的配置的方法或者默认的execute方法,既然逻辑出来了,那么要如何设置数据结构对xml解析出来的文件进行存储呢?

struts.xml如下:

<?xml version="1.0" encoding="UTF-8" ?>
<struts>
  <!-- 自定义的Struts -->
    <package name="default" namespace="/"  >
	     <action name="user.action" class="com.yc.frame.actions.UserAction" method="add">
	            <result name="success"  type="direct">a.jsp</result>
	             <result name="fail" type="direct">a.jsp</result>
	     </action>
	    <!--多个action-->
    </package>
</struts>


在这里,每个节点对应一个类, 由于xml中有对应的层级关系,所以在设计这些类时,也要将这些类的层级关系体现出来,才能准确的对数据进行处理和操作:


//package节点对应的节点类,它应该有一个actioin节点类的集合<pre name="code" class="java">自然要提供getset方法(get,set省略)

public class PackageWrapper implements Serializable{/** * */private static final long serialVersionUID = -7700027765680530207L;private String namespace;private Map<String,ActionWrapper> actionMap=new HashMap<String,ActionWrapper>();
}
//action节点类,同时也要有result类的节点集合,
<pre name="code" class="java">(get,set省略)

 

public class ActionWrapper implements Serializable{
    /**
     *
     */
    private static final long serialVersionUID = -4176005261524671229L;
    private String className;
    private String methodName;
    private Map<String,ResultWrapper> resultMap=new HashMap<String,ResultWrapper>();
}
package com.yc.frame.wrapper;

//result节点的节点类

public class ResultWrapper implements Serializable {

    private String type;
    private String value;
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }
      那么,自然要先将他们解析存好,再进行操作,所以,在filter的init方法里进行初始化存好。这里用的是dom4j对他解析:(解析就省略了,有需要的请留言给源码哦!) 

    最核心的环节就是将数据读取出来后取出action的实体类,利用反射找到对应的方法,执行action的方法得到返回值,最后判断result的type,执行跳转页面,是不是清晰了一点?

   

		//1.解析请求
			HttpServletRequest request=(HttpServletRequest)arg0;
			HttpServletResponse response=(HttpServletResponse)arg1;
			String servletPath=request.getServletPath();//这个是请求的资源路径名
			//判断请求的路径名是否action
			if(servletPath.lastIndexOf(".action")==-1){
					arg2.doFilter(request, response);
			}else{
						try {
									//地址格式为:cccc/user.action     /user.action
									int lastSlashIndex = servletPath.lastIndexOf("/");
									String requestActionName = servletPath
											.substring(lastSlashIndex + 1);
									String nameSpaceName = servletPath.substring(0,
											lastSlashIndex);//这个是总项目后面那个文件夹地址
									//2.到map中找到这个action
									PackageWrapper packageWrapper = null;
									//TODO:
									//这里为什么要用这个entry?
									for (Map.Entry<String, PackageWrapper> entry : packagesMap
											.entrySet()) {
										PackageWrapper pw = entry.getValue();
										pw.getNamespace().equals(nameSpaceName);
										packageWrapper = pw;
										break;
									}
								
									//3.反射生成action的对象
									//4.激活这个action的execute方法
									//5.得到这个execute返回的String
									ActionWrapper actionWrapper = packageWrapper.getActionMap()
											.get(requestActionName);
									String actionClassName = actionWrapper.getClassName();
									Class c = Class.forName(actionClassName);
									Object obj1=c.newInstance();
									//TODO:
									//这里通过packageWrapper获得拦截器的集合
									List<Interceptor> interceptors=new ArrayList<Interceptor>();
									List<InterceptorWrapper> iw=packageWrapper.getInterceptorList();
									if(iw.size()>0){
										for(int i=0;i<iw.size();i++){
											InterceptorWrapper interceptorWrapper=iw.get(i);
											String inname=interceptorWrapper.getName();
											String inclassName=interceptorWrapper.getClassName();
											if(inclassName.toLowerCase().endsWith(inname.toLowerCase()+"interceptor")){
												Class interceptor = Class.forName(inclassName);
												Object obj=interceptor.newInstance();
												interceptors.add(((Interceptor)obj));
											}
										}
										actionInvokation=new ActionInvokation(interceptors,((Action)obj1));
									}
									String result = invokeActionMethod(request,c, requestActionName,
											actionWrapper);
									//6.到map中找到这个String对应的result;
									ResultWrapper resultWrapper=actionWrapper.getResultMap().get(result);
									//7.转发到这个result上
									String dispatcherType=resultWrapper.getType();
									String page=resultWrapper.getValue();
									if(dispatcherType!=null&&!"".equals(dispatcherType)){
												if("direct".equals(dispatcherType)){
													String path = request.getContextPath();
													String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
														response.sendRedirect(basePath+page);
												}
									}else{
										request.getRequestDispatcher(page).forward(request, response);
									}
						} catch (Exception e) {
							e.printStackTrace();
							request.getSession().setAttribute("ycexeption", e.getMessage());
						}
			}
		
	}
	/**
	 * 这个方法是对result中的方法进行激活,通过传过来的反射实例和action的名字以及拿到的method名字
	 * @param c
	 * @param requestActionName
	 * @param actionWrapper
	 * @return
	 * @throws SecurityException 
	 * @throws NoSuchMethodException 
	 */
	private String invokeActionMethod(HttpServletRequest request,Class c,String requestActionName,ActionWrapper actionWrapper) throws Exception{
		String requestResult="";
		Object obj=c.newInstance();
		//这里完成注入参数的工作
		injectParameterToAction(request, obj, c);
		//如果methodname为空,则执行action中的execute方法
		if(actionWrapper.getMethodName()==null||"".equals(actionWrapper.getMethodName())){
			requestResult=((Action)obj).execute();
		}else{ //否则执行action中的配置的方法
			String methodName=actionWrapper.getMethodName();
			Method m=c.getMethod(methodName, null);
			requestResult=(String) m.invoke(obj, null);
		}
		return requestResult;
	}
	//注入参数
	private void injectParameterToAction(HttpServletRequest request,Object obj,Class c) throws Exception, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
			//基本类型的注入
			//1.从request中取出所有的健值对,转成Map setName 
			Map<String,String[]> map=parseRequest(request);
			//2.从c中找出各个要注入的方法 getMthod方法名
			Method [] ms=c.getMethods();
			//3.反向激活方法,注入参数
			for(Method m:ms){
					String methodName=m.getName();
					if(map.containsKey(methodName)){
							String[] values=map.get(methodName);
							if(values.length==1){
									String s=values[0];
									String type=m.getParameterTypes()[0].getName();
									if (m.getParameterTypes()[0].getName().equals(
											"java.lang.Integer")
											|| m.getParameterTypes()[0].getName().equals(
													"int")) {
										// 激活方法,传进去值
										m.invoke(obj, Integer.parseInt(s));
										continue;
									} else if (m.getParameterTypes()[0].getName().equals(
											"java.lang.Double")
											|| m.getParameterTypes()[0].getName().equals(
													"double")) {
										m.invoke(obj, Double.parseDouble(s));
										continue;
									} else if (m.getParameterTypes()[0].getName().equals(
											"java.lang.Float")
											|| m.getParameterTypes()[0].getName().equals(
													"float")) {
										m.invoke(obj, Float.parseFloat(s));
										continue;
									} else if (m.getParameterTypes()[0].getName().equals(
											"java.lang.String")
											|| m.getParameterTypes()[0].getName().equals(
													"String")) {
										m.invoke(obj, s);
										continue;
									} 
							}
					}
			}
		
	}
	private Map<String, String[]> parseRequest(HttpServletRequest request) {
		Map<String,String[]> map=new HashMap<String,String[]>();
		Enumeration<String> enu=request.getParameterNames();
		while(enu.hasMoreElements()){
				String name=enu.nextElement();
				String methodName="set"+name.substring(0,1).toUpperCase()+name.substring(1);
				map.put(methodName, request.getParameterValues(name));
		}
		return map;
	
	}
	public void init(FilterConfig config) throws ServletException {
		//读取配置文件   Struts.xml  =》Map
		realpath=config.getServletContext().getRealPath("/");
		packagesMap=parseStrutsXml();
	}
解析xml文件省略了,这是我自己实现的一个最简单的struts,当然强大的struts我只是模仿了皮毛中的皮毛,欢迎来讨论和相互学习。


  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值