java-模拟struts2跳转

发表于 2016-08-24 12:55 显示全部楼层 16 2685

本工程仅模拟struts2页面跳转功能。各位看看就好。

工程目录:

blob.png

约定:

配置文件,必须是actions.xml

红框内的java类是测试用。


struts跳转原理:

1、xml中配置逻辑处理类,跳转的页面及页面跳转类型

2、过滤器拦截请求,doFileter 解析xml中配置信息,反射处理类执行配置方法,根据结果及跳转类型去到不同页面

3、通过ThreadLocal 共享及传递请求数据


对应思路:

1、使用ActionXMLParse 模拟struts2 xml文件解析

2、使用ActionContext 模拟 struts2中参数的传递

3、使用ActionFilter 模拟struts2 的StrutsPrepareAndExecuteFilter,实现页面的跳转



第一步:actions.xml解析

<?xml version="1.0" encoding="UTF-8"?>
<actions>
	<!-- 
		action 表示一domain实体一系列逻辑处理信息包装
		name:请求映射路径 eg: /student
		class: 全限类名
		method: 默认进入方法(类似 servlet 中的service)
		
		restult		请求处理结果策略
			name	处理结果返回识别名称
			type	处理结果类型, redirect 是重定向  dispatch 是转发
			value	请求路径(页面或者映射路径)
			
		上面2个配置封装成2个实体类
		ActionConfig  ResultConfig
		
	 -->
	<action name="student" class="com.langfei.web.action.StudentAction" method="execute">
		<result name="toList" type="redirect">/student?cmd=list</result>
		<result name="list" type="dispatch">/WEB-INF/views/list.jsp</result>
	</action>
	
	<action name="user" class="com.langfei.web.action.UserAction" method="list">
	</action>
</actions>


配置包装类

/**
 * Action 配置包装类
 * @author yexingfei
 *
 */
public class ActionConfig {
	private String name;
	private String className;
	private String method;
	
	//一个action中有多个ResultConfig, 使用map相比 list根据方便
	private Map<String, ResultConfig> resultMap = new HashMap<>();
	
	public ActionConfig(String name, String className, String method) {
		this.name = name;
		this.className = className;
		this.method = method;
	}
	public ActionConfig() {
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getClassName() {
		return className;
	}
	public void setClassName(String className) {
		this.className = className;
	}
	public String getMethod() {
		return method;
	}
	public void setMethod(String method) {
		this.method = method;
	}
	
	public Map<String, ResultConfig> getResultMap() {
		return resultMap;
	}
	public void setResultMap(Map<String, ResultConfig> resultMap) {
		this.resultMap = resultMap;
	}
	@Override
	public String toString() {
		return "ActionConfig [name=" + name + ", className=" + className + ", method=" + method + "]";
	}
}
/**
 * action 处理结果包装类
 * @author yexingfei
 *
 */
public class ResultConfig {
	private String name;
	private String type; // dispatcher redirect
	private String path;
	
	public ResultConfig(String name, String type, String path) {
		super();
		this.name = name;
		this.type = type;
		this.path = path;
	}

	public String getName() {
		return name;
	}

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

	public String getType() {
		return type;
	}

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

	public String getPath() {
		return path;
	}

	public void setPath(String path) {
		this.path = path;
	}

	public ResultConfig() {
		super();
	}

	@Override
	public String toString() {
		return "ResultConfig [name=" + name + ", type=" + type + ", path=" + path + "]";
	}
}


xml解析:

/**
 * actions.xml 配置文件解析
 * @author yexingfei
 *
 */
public class ActionXMLParse {
	private ActionXMLParse() {
	}

	private static InputStream in;
	//使用map比list更加容易操作
	private static Map<String, ActionConfig> actionsMap = new HashMap<>();
	static {
		//固定actions.xml
		in = Thread.currentThread().getContextClassLoader().getResourceAsStream("actions.xml");
		Document document = getDocument();

		Element root = document.getDocumentElement();
		NodeList list = root.getElementsByTagName("action");
		ActionConfig config = null;
		//多个action解析
		for (int i = 0; i < list.getLength(); i++) {
			config = new ActionConfig();
			Element element = (Element) list.item(i);
			config.setMethod(element.getAttribute("method"));
			config.setClassName(element.getAttribute("class"));
			config.setName(element.getAttribute("name"));
			actionsMap.put(config.getName(), config);
			
			//解析result
			NodeList resultList = element.getElementsByTagName("result");
			
			ResultConfig resultConfig = null;
			Map<String, ResultConfig> map = new HashMap<>();
			for(int j = 0; j < resultList.getLength(); j++){
				Element ele = (Element) resultList.item(j);
				resultConfig = new ResultConfig();
				resultConfig.setName(ele.getAttribute("name"));
				resultConfig.setPath(ele.getTextContent());
				resultConfig.setType(ele.getAttribute("type"));
				map.put(resultConfig.getName(), resultConfig);
				config.setResultMap(map);
			}
		}
	}

	private static Document getDocument() {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder;
		try {
			builder = factory.newDocumentBuilder();
			return builder.parse(in);
		} catch (Exception e) {
			e.printStackTrace();
		}
		throw new RuntimeException("加载action.xml文件出错");
	}

	//通过action名字获取actionConfig配置信息
	public static ActionConfig getActionConfig(String action) {
		return actionsMap.get(action);
	}
}
/**
 * Action 统一处理工具类
 * @author yexingfei
 *
 */
public class ActionUtil {
	private ActionUtil(){}
	//通过action名字获取actionConfig配置信息
	public static  ActionConfig getActionConfig(String action){
		return ActionXMLParse.getActionConfig(action);
	}
	//通过action名字及结果名字获取ResultConfig配置信息
	public static  ResultConfig getResultConfig(String action, String result){
		return getActionConfig(action).getResultMap().get(result);
	}
}


第二步:使用ActionContext 模拟 struts2中参数的传递

/**
 * 上下文环境包装类
 * @author yexingfei
 *
 */
public class ActionContext {
	private HttpServletRequest request;
	private HttpServletResponse response;
	//确保每次请求都是不同的上下文环境
	private static ThreadLocal<ActionContext> threadLocal = new ThreadLocal<>();
	
	public ActionContext(HttpServletRequest request, HttpServletResponse response) {
		super();
		this.request = request;
		this.response = response;
	}
	public HttpServletRequest getRequest() {
		return request;
	}
	public void setRequest(HttpServletRequest request) {
		this.request = request;
	}
	public HttpServletResponse getResponse() {
		return response;
	}
	public void setResponse(HttpServletResponse response) {
		this.response = response;
	}
	public static ActionContext getContext() {
		return threadLocal.get();
	}
	public static void setContext(ActionContext mContext) {
		threadLocal.set(mContext);
	}
}

第三步:使用ActionFilter 模拟struts2 的StrutsPrepareAndExecuteFilter,实现页面的跳转

/**
 *  模拟struts2 的StrutsPrepareAndExecuteFilter,实现页面的跳转
 * @author yexingfei
 *
 */
public class ActionFilter implements Filter{
	
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		
	}
	
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		
		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse resp = (HttpServletResponse) response;
		//设置参数
		ActionContext context = new ActionContext(req, resp);
		ActionContext.setContext(context);
		
		//通过url获取ActonConfig信息
		String requestUri = req.getRequestURI().substring(1);
		ActionConfig actionConfig = ActionUtil.getActionConfig(requestUri);
		if(actionConfig != null){
			try {
				//解析ActionConfig, 反射执行逻辑
				Class<?> clz = Class.forName(actionConfig.getClassName());
				Object object = clz.newInstance();
				Method method = clz.getMethod(actionConfig.getMethod());
				//处理结果
				String ret = (String) method.invoke(object);
				
				//根据处理结果或者结果配置信息
				ResultConfig config = ActionUtil.getResultConfig(actionConfig.getName(), ret);
				String type = config.getType();
				String path = config.getPath();
				System.out.println(config);
				//根据类型实现跳转或转发
				if("dispatch".equals(type)){
					req.getRequestDispatcher(path).forward(req, resp);
					return;
				}else if("redirect".equals(type)){
					resp.sendRedirect(path);
					return;
				}
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
		//不匹配直接放行
		chain.doFilter(request, response);
	}
	
	@Override
	public void destroy() {
	}
}

第四步:测试

public class StudentAction {
	
	//统一入口,默认入口
	public String execute(){
		String cmd = ActionContext.getContext().getRequest().getParameter("cmd");
		if("edit".equals(cmd)){
			return edit();
		}else{
			return list();
		}
	}
	
	// 注意: 返回值跟actions.xml中配置的result name必须一一对应
	public String edit(){
		System.out.println("StudentAction.edit()");
		
		return "toList";
	}
	
	public String list(){
		System.out.println("StudentAction.list()");
		return "list";
	}
}


总结:

    没有总结。

评分

参与人数 1学币 +2 收起 理由
seemygo + 2 总结的很详细

查看全部评分

回复 使用道具
举报
崇拜

发表于 2017-02-15 12:42 显示全部楼层

围观楼主

回复 支持 反对 使用道具
举报
沟里郭嘉身似椅

发表于 2017-02-15 07:12 显示全部楼层

回复 支持 反对 使用道具
举报
ttplayboy

发表于 2017-02-15 04:03 显示全部楼层

回复 支持 反对 使用道具
举报
大道至简

发表于 2017-02-14 15:58 显示全部楼层

回复 支持 反对 使用道具
举报
今夜为你想

发表于 2017-02-14 02:05 显示全部楼层

回复 支持 反对 使用道具
举报
diming520

发表于 2017-02-13 23:47 显示全部楼层

回复 支持 反对 使用道具
举报
馨四君

发表于 2017-02-13 20:15 显示全部楼层

好文章,必须帮顶!!!

回复 支持 反对 使用道具
举报
东北兰蔻

发表于 2017-02-13 19:34 显示全部楼层

回复 支持 反对 使用道具
举报
荣婳

发表于 2017-02-13 18:47 显示全部楼层

回复 支持 反对 使用道具
举报
12下一页

发表新文章
叶星飞

叩丁狼骨干成员

0

学分

982

学币

1035

积分

叩丁狼骨干成员

Rank: 6Rank: 6

积分
1035
Ta的主页 发消息
精华帖排行榜

精彩推荐

  • 关注叩丁狼教育