重构Web框架

由于Web应用开发繁琐,利用重构抽取公共的Servlet功能,使开发变成更加简便的过程。

原型开发与测试:

访问user/ok.douser/test.douser/add.douser/doc.do


1.开发注解:

package cn.tedu.base.web;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
	String value();
}

2.开发控制器类

package cn.tedu.demo.web;

import cn.tedu.base.web.RequestMapping;

@RequestMapping("/user")
public class DemoController {
	@RequestMapping("/ok.do")
	public String hello() {
		System.out.println("Hello World!");
		return "ok";
	}
	@RequestMapping("/test.do")
	public String test() {
		System.out.println("Test");
		return "test";
	}
	@RequestMapping("/add.do")
	public String add() {
		//重定向分为两种情况
		//1: http 协议开始的URL
		//2: 当前应用的URL
		
		//如果是http 开始的就直接重定向
		//否则就 重定向到 contextPath + /user/ok.do
		 return "redirect:/user/ok.do";
	}
	@RequestMapping("/doc.do")
	public String doc() {
		return "redirect:http://doc.tedu.cn";
	}
}

3.编写配置文件 conf/context.xml

<?xml version="1.0" encoding="UTF-8"?>
 <beans>
     <!-- 声明控制器组件 -->
     <bean class="cn.tedu.demo.web.DemoController"/>
 </beans>

4.web.xml配置文件

<servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>cn.tedu.base.web.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>config</param-name>
        <param-value>conf/context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>
5.WEB-INF下建一个文件夹jsp,里建文件ok.jsp和test.jsp

ok.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>OK</h1>
</body>
</html>

test.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>Test</h1>
</body>
</html>

6.Test测试看看能不能用:

package cn.tedu.test;

import java.util.ArrayList;
import java.util.Collection;

import org.junit.Test;

import cn.tedu.base.web.ApplicationContext;
import cn.tedu.base.web.HandlerMapping;
import cn.tedu.base.web.UrlHandler;
import cn.tedu.demo.web.DemoController;

public class TestCase {
	@Test
	public void testApplicationContext() {
		String file = "conf/context.xml";
		ApplicationContext ctx = new ApplicationContext(file);
		System.out.println(ctx);
	}
	@Test
	public void testHandlerMapping() {
		Collection controllers = new ArrayList();
		controllers.add(new DemoController());
		HandlerMapping mapping = new HandlerMapping();
		mapping.init(controllers);
		System.out.println(mapping);
		//测试查找
		String url = "/user/ok.do";
		UrlHandler handler = mapping.getUrlHandler(url);
		System.out.println(handler);
	}
		
}

7.对象方法设置获取类:

package cn.tedu.base.web;

import java.lang.reflect.Method;

public class UrlHandler {
	private Object obj;
	private Method method;
	public UrlHandler() {
		
	}
	public UrlHandler(Object obj, Method method) {
		super();
		this.obj = obj;
		this.method = method;
	}
	public Object getObj() {
		return obj;
	}
	public void setObj(Object obj) {
		this.obj = obj;
	}
	public Method getMethod() {
		return method;
	}
	public void setMethod(Method method) {
		this.method = method;
	}
	
}

8.解析context.xml文件类:
package cn.tedu.base.web;

import java.io.InputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

/**
 * Application 应用
 * Context 上下文,管家
 * @author soft01
 *
 */
public class ApplicationContext {
	private Map<String, Object> beans=new HashMap<String, Object>();
	public ApplicationContext() {
		
	}
	/**
	 * 根据配置文件初始化全部对象
	 * @param cfg xml配置文件
	 */
	public ApplicationContext(String cfg) {
		init(cfg);
	}
	public void init(String cfg) {
		try {
			InputStream in = getClass().getClassLoader().getResourceAsStream(cfg);
			SAXReader reader = new SAXReader();
			Document doc = reader.read(in);
			Element root = doc.getRootElement();
			List<Element> list = root.elements("bean");
			for(Element e : list) {
				String className = e.attributeValue("class");
				Class cls = Class.forName(className);
				Object obj = cls.newInstance();
				String name = cls.getName();
				//name = "cn.tedu.DemoBean"
				name = name.substring(name.lastIndexOf(".")+1);
				String key = name.substring(0,1).toLowerCase()+name.substring(1);
				//key = "demoBean"
				System.out.println(key);
				beans.put(key, obj);
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}
	
	public Collection<Object> getBeans(){
		//Map 类型上有一个方法values() 用于返回
		//Map 中全部的value对象
		return beans.values();
	}
	
	public String toString() {
		return "ApplicationContext [beans=" + beans + "]";
	}
}

9.找注解方法类:

package cn.tedu.base.web;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * 根据用户请求的路径,获取对应的控制器对象和方法
 * 并且执行这个方法
 * @author soft01
 *
 */
public class HandlerMapping {
	//map 中的key是用户请求的url,map中的value是
	//对象和控制方法组成的一个实例
	private Map<String,UrlHandler> urlMap = new HashMap<String,UrlHandler>();
	
	//init方法用于根据控制器对象初始化map集合
	public void init(Collection<Object> controllers) {
		for(Object object : controllers) {
			//object = DemoController
			//利用反射API获取类上注解
			// cls = DemoController
			Class cls = object.getClass();
			//获取类上标注的注解
			RequestMapping rm = (RequestMapping)cls.getAnnotation(RequestMapping.class);
			String path1 = "";
			//获取注解上标注的值
			if(rm!=null) {
				path1 = rm.value();
			}
			System.out.println(path1);
			
			//解析方法上的注解
			//找到全部方法信息
			Method[] methods = cls.getDeclaredMethods();
			for(Method method : methods) {
				//找到方法上声明的注解
				RequestMapping rm2 = method.getAnnotation(RequestMapping.class);
				System.out.println("rm2");
				//如果没有找到注解的方法就跳过这个方法
				if(rm2==null) {
					continue;
				}
				String sub = rm2.value();
				System.out.println(sub);
				String path = path1+sub;
				//添加到map
				urlMap.put(path, new UrlHandler(object,method));
			}
		}
	}
	//根据用户提交的URL路径获取(对象和方法)UrlHandler
	public UrlHandler getUrlHandler(String path) {
		return urlMap.get(path);
	}
	
	public String toString() {
		return "HandlerMapping [urlMap=" + urlMap + "]";
	}
	
}
10.编写Servlet
package cn.tedu.base.web;

import java.io.IOException;
import java.lang.reflect.Method;

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


/**
 * Servlet implementation class DispatcherServlet
 */
public class DispatcherServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private ApplicationContext applicationContext;
	private HandlerMapping handlerMapping;
	/**
	 * Servlet初始化方法,加载控制器类
	 */
	public void init() throws ServletException {
		//读取context.xml
		//解析出类名
		String filename = getServletConfig().getInitParameter("config");
		applicationContext = new ApplicationContext(filename);
		System.out.println(applicationContext);
		handlerMapping = new HandlerMapping();
		//getBeans 方法获取 applicationContext 中
		//创建的全部控制器对象
		handlerMapping.init(applicationContext.getBeans());
	}
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doPost(request,response);
	}


	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("Hello World!");
		
		try {
			//获得用户请求时候的URL路径
			String url = request.getRequestURI();
			//删除url中开头的Context Path
			String contextPath = request.getContextPath();
			if(url.startsWith(contextPath)) {
				url=url.substring(contextPath.length());
			}                                                                                                                  
			
			//查找需要执行的对象和方法
			UrlHandler handler = handlerMapping.getUrlHandler(url);
			System.out.println("1111111111111");
			//利用反射执行执行控制器对象的方法
			Object obj = handler.getObj();
			System.out.println("1111111111111");
			Method method = handler.getMethod();
			//执行目标方法
			Object val = method.invoke(obj);
			String target = val.toString();
			processView(request,response,target);
			
		} catch (Exception e) {
			e.printStackTrace();
			throw new ServletException(e);
		} 
		
//		response.setContentType("text/html");
//		response.getWriter().print("OK"); 
	}

	/**
	 * 处理视图(显示)结果,根据target
	 * 来决定如何处理
	 * 1. 如果以redirect 为开头就进行重定向处理
	 * 		如果是http开始就绝对路径重定向
	 * 		如果不是http开始的就补上 contextPath再重定向
	 * 2. 如果不是以 redirect 就直转发
	 * @param request
	 * @param response
	 * @param target
	 */
	private void processView(HttpServletRequest request,HttpServletResponse response,String target) throws ServletException,IOException{
		if(target==null) {
			throw new ServletException("没有结果");
		}
		if(target.startsWith("redirect:")) {
			//重定向
			String path = target.substring("redirect:".length());
			if(!path.startsWith("http")) {
				path = request.getContextPath()+path;
			}
			response.sendRedirect(path);
		}else {
			//转发
			String path = "/WEB-INF/jsp/"+target+".jsp";
			forward(request,response,path);
		}
	}
	
	private void forward(HttpServletRequest request, HttpServletResponse response, String path) throws ServletException, IOException {
		RequestDispatcher rd = request.getRequestDispatcher(path);
		rd.forward(request, response);
	}
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

linsa_pursuer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值