自定义struts框架

很多人在刚开始学习struts的时候,都搞不清struts的执行流程和底层的原理,本人开始也是,但是通过深入的学习,也试着自己来写一个模拟struts的框架,下面是我自己写的一个模拟struts2的框架。
首先先写一个登陆页面:
login.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <title>login</title>
    </head>

    <body>
         <form action="login.action" method="post">
         用户名:<input type="text" name="username"/><br/>
         密 码:<input type="password" name="password"/><br/>
                  <input type="submit" value="提交"/>
         </form>
     </body>
</html>
 

然后我们编写一个Servlet来处理所有以.action结尾的请求,因为这是一个MVC框架,我们的请求action以及结果视图都应在配置文件中配置,以达到解耦的目的,配置文件mystruts.xml在后面给出:
在读取配置文件时,我们需要对读取的配置信息进行保存,所以我们需要创建保存配置文件的两个实体类ActionMapping和Result类,在这里我们还需要导入dom4j这个jar包以读取配置文件:
Result.java

package org.wp.action;

/**
* 定义Result
* 保存配置的Result节点的信息
*/
public final class Result {
   private String name ;//result的名称
   private String url ; //result的跳转页面
   private Boolean redirect ;//是否重定向
   public Result(){}
   public Result(String name, String url, Boolean redirect) {
       this.name = name;
       this.url = url;
       this.redirect = redirect;
  }
  public String getName() {
       return name;
  }
  public void setName(String name) {
       this.name = name;
  }
  public String getUrl() {
      return url;
  }
  public void setUrl(String url) {
      this.url = url;
  }
  public Boolean getRedirect() {
      return redirect;
  }
  public void setRedirect(Boolean redirect) {
      this.redirect = redirect;
  }
}
 

ActionMapping.java

package org.wp.action;

import java.util.HashMap;
import java.util.Map;

/**
 * 定义ActionMapping
 * 保存配置文件中的信息
 */
public final class ActionMapping {
	private String name ; //action名称
	private String className ; //权限定类名
	//action对应的Result
	private Map<String,Result> results = new HashMap<String, Result>();
	public String getName() {
		return name;
	}
	public ActionMapping() {
	}
	public ActionMapping(String name, String className) {
		this.name = name;
		this.className = className;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getClassName() {
		return className;
	}
	public void setClassName(String className) {
		this.className = className;
	}
	public Map<String, Result> getResults() {
		return results;
	}
	public void setResults(Map<String, Result> results) {
		this.results = results;
	}
}

ActionServlet.java

package org.wp.servlet;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

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

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.wp.action.ActionMapping;
import org.wp.action.Result;

/** 核心控制器 拦截所有以.action结尾的请求 **/
public class ActionServlet extends HttpServlet {
	// mappings保存所有从配置文件mystruts.xml读取的信息 key:提交的请求名,value:请求名对应的action信息
	private Map<String,ActionMapping> mappings = new HashMap<String, ActionMapping>();
	@SuppressWarnings("unchecked")
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//获得表单提交的所有请求参数名
		Enumeration<String> en = request.getParameterNames();
		//获得请求的uri 如:/MyStruts/login.action
		String uri = request.getRequestURI();
		//获得上下文路径 /MyStruts
		String contextPath = request.getContextPath();
		//通过字符串截取获得请求的action名称 即:login
		String actionName = uri.substring(contextPath.length()+1,uri.lastIndexOf("."));
		//通过请求的action名,获得对应的映射信息
		ActionMapping mapping = mappings.get(actionName);
		String className = null ;
		try {
			//获得对应的
			className = mapping.getClassName();
		} catch (Exception e) {
			throw new RuntimeException("请求的action找不到");
		}

		Object obj = instance(className);
		//获得该类的所有方法
		Method[] methods = obj.getClass().getMethods();

		setValue(en,methods,obj,request);
		Method m = null ;
		try {
			m = obj.getClass().getMethod("execute",null);
			String s = (String) m.invoke(obj, null);

			if(s!=null){
				//取得结果试图
				Result r = mapping.getResults().get(s);
				//判断是否是重定向
				if(r.getRedirect()){
					response.sendRedirect(request.getContextPath()+r.getUrl());
				}else{
					request.getRequestDispatcher(r.getUrl()).forward(request, response);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**
	 * 通过反射为对应的Action中的属性赋值
	 * @param en
	 * @param methods
	 * @param obj
	 * @param req
	 */
	private void setValue(Enumeration<String> en, Method[] methods,Object obj,HttpServletRequest req) {

		while (en.hasMoreElements()) {
			String name = en.nextElement();

			String name_ = name.substring(0,1).toUpperCase().concat(name.substring(1));
			for (Method m : methods) {
				if(m.getName().startsWith("set")){
					String n = m.getName().substring(3);
					if(n.equals(name_)){
						try {
							String value = req.getParameter(name);
							m.invoke(obj,value);
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}
			}
		}
	}
	/**
	 * 通过反射初始化对应的处理类
	 * @param className
	 * @return Object
	 */
	private Object instance(String className) {
		try {
			return Class.forName(className).newInstance();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		this.doGet(request, response);
	}

	/**
	 * 初始化ActionServlet时,就读取指定的配置文件
	 */
	public void init(ServletConfig config) throws ServletException {
		//获得配置文件的名字
		String configName = config.getInitParameter("configName");
		String[] names = configName.split(",");
		for (String name : names) {
			readXML(name);
		}
	}

	/**
	 * 读取指定的配置文件
	 * @param name
	 */
	@SuppressWarnings("unchecked")
	private void readXML(String name) {
		//加载配置文件
		InputStream is = this.getClass().getClassLoader().getResourceAsStream(name);
		SAXReader read = new SAXReader();
		try {
			//通过dom4j读取配置文件
			Document document = read.read(is);
			//得到根元素
			Element root = document.getRootElement();
			//得到actions元素
			Element actions = root.element("actions");
			//迭代action元素
			Iterator<Element> it = actions.elementIterator("action");
			while(it.hasNext()){
				Element action = it.next();
				//封装action属性
				ActionMapping mapping = new ActionMapping(
						action.attributeValue("name"),action.attributeValue("class"));
				//迭代result元素
				Iterator<Element> results = action.elementIterator("result");
				while(results.hasNext()){
					Element result = results.next();
					//封装result属性
					Result res = new Result(result.attributeValue("name"),
							result.getText(),Boolean.valueOf(result.attributeValue("redirect")));
					mapping.getResults().put(res.getName(),res);
				}
				//保存配置信息
				mappings.put(mapping.getName(),mapping);
			}
		} catch (DocumentException e) {
			e.printStackTrace();
		}
	}
}
 


写好核心控制器之后,在web.xml中部署该ActionServlet:

<?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 ">
<servlet>
    <servlet-name>ActionServlet</servlet-name>
    <servlet-class>org.wp.servlet.ActionServlet</servlet-class>
    <init-param>
           <param-name>configName</param-name>
           <param-value>mystruts.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
           <servlet-name>ActionServlet</servlet-name>
           <url-pattern>*.action</url-pattern>
    </servlet-mapping>
</web-app>
 

然后定义Action接口:

package org.wp.action;
/**
 * 定义Action接口
 */
public interface Action {
	//定义结果试图常量
	public static final String SUCCESS = "success" ;
	public static final String INPUT = "input" ;
	public static final String ERROR = "error" ;
	public static final String LOGIN = "login" ;
	/**
	 * 定义execute方法
	 * @return String
	 * @throws Exception
	 */
	public String execute() throws Exception;
}
 

提供一个实现了Action接口的实现类ActionSupport:

package org.wp.action;

/**
 * 定义ActionSupport并实现Action接口
 *
 */
public class ActionSupport implements Action {
	/**
	 * 实现execute方法,并返回SUCCESS试图
	 */
	public String execute() throws Exception {
		return SUCCESS;
	}
}
 

然后编写自己的Action类LoginAction来处理登陆:

package entity;

package org.wp.action;

public class LoginAction extends ActionSupport {
	private String username ;//接收与表单域名称相同的参数值
	private String password ;
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String execute() throws Exception {
		if(username.equals("admin")&&password.equals("admin"))
			return SUCCESS;
		else
			return INPUT ;
	}
}

    然后在mystruts.xml对请求和视图进行配置:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mystruts[
<!ELEMENT mystruts (actions*)>
<!ELEMENT actions (action*)>
<!ELEMENT action (result*)>
<!ATTLIST action name CDATA #REQUIRED class CDATA #REQUIRED>
<!ATTLIST result name CDATA #REQUIRED redirect (true|false) "true">
]>

<mystruts>
    <actions>
        <action name="login" class="org.wp.action.LoginAction">
             <result name="success">/register.jsp</result>
             <result name="input">/index.jsp</result>
        </action>
    </actions>
</mystruts>
 

这样一个自定义的struts框架就完成了,看看也不是很复杂吧!然后我们通过访问http://localhost:8080/MyStruts/login.jsp 提交后ActionServlet就会进行拦截,然后就会去mystruts.xml中去找到与提交的action名相同的对应的Action处理类,通过执行execute方法来跳转到相应的视图。

猜你喜欢

转载自wupeng397.iteye.com/blog/1560251