由于Web应用开发繁琐,利用重构抽取公共的Servlet功能,使开发变成更加简便的过程。
2.开发控制器类
3.编写配置文件 conf/context.xml
ok.jsp:
test.jsp:
6.Test测试看看能不能用:
7.对象方法设置获取类:
8.解析context.xml文件类:
9.找注解方法类:
原型开发与测试:
访问user/ok.do或user/test.do或user/add.do或user/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);
}
}