JavaWeb学习总结(四十九)——简单模拟Sping MVC
在Spring MVC中,将一个普通的java类标注上Controller注解之后,再将类中的方法使用RequestMapping注解标注,那么这个普通的java类就够处理Web请求,示例代码如下:
1 /**
2 * 使用Controller注解标注LoginUI类
3 */
4 @Controller
5 public class LoginUI {
6
7 //使用RequestMapping注解指明forward1方法的访问路径
8 @RequestMapping("LoginUI/Login2")
9 public View forward1(){
10 //执行完forward1方法之后返回的视图
11 return new View("/login2.jsp");
12 }
13
14 //使用RequestMapping注解指明forward2方法的访问路径
15 @RequestMapping("LoginUI/Login3")
16 public View forward2(){
17 //执行完forward2方法之后返回的视图
18 return new View("/login3.jsp");
19 }
20 }
spring通过java annotation就可以注释一个类为action ,在方法上添加上一个java annotation 就可以配置请求的路径了,那么这种机制是如何实现的呢,今天我们使用"自定义注解+Servlet"来简单模拟一下Spring MVC中的这种注解配置方式。
一、编写注解
1.1、Controller注解
开发Controller注解,这个注解只有一个value属性,默认值为空字符串,代码如下:
1 package me.gacl.annotation;
2
3 import java.lang.annotation.ElementType;
4 import java.lang.annotation.Retention;
5 import java.lang.annotation.RetentionPolicy;
6 import java.lang.annotation.Target;
7
8 /**
9 * @ClassName: Controller
10 * @Description: 自定义Controller注解
11 * @author: 孤傲苍狼
12 * @date: 2014-11-16 下午6:16:40
13 *
14 */
15 @Retention(RetentionPolicy.RUNTIME)
16 @Target(ElementType.TYPE)
17 public @interface Controller {
18
19 public String value() default "";
20 }
1.2、RequestMapping注解
开发RequestMapping注解,用于定义请求路径,这个注解只有一个value属性,默认值为空字符串,代码如下:
1 package me.gacl.annotation;
2
3 import java.lang.annotation.ElementType;
4 import java.lang.annotation.Retention;
5 import java.lang.annotation.RetentionPolicy;
6 import java.lang.annotation.Target;
7
8 /**
9 * 定义请求路径的java annotation
10 */
11 @Target(ElementType.METHOD)
12 @Retention(RetentionPolicy.RUNTIME)
13 public @interface RequestMapping {
14
15 public String value() default "";
16 }
以上就是我们自定义的两个注解,注解的开发工作就算是完成了,有了注解之后,那么就必须针对注解来编写处理器,否则我们开发的注解配置到类或者方法上面是不起作用的,这里我们使用Servlet来作为注解的处理器。
二、编写核心的注解处理器
2.1、开发AnnotationHandleServlet
这里使用一个Servlet来作为注解处理器,编写一个AnnotationHandleServlet,代码如下:
1 package me.gacl.web.controller;
2
3 import java.io.IOException;
4 import java.lang.reflect.InvocationTargetException;
5 import java.lang.reflect.Method;
6 import java.util.Set;
7 import javax.servlet.ServletConfig;
8 import javax.servlet.ServletException;
9 import javax.servlet.http.HttpServlet;
10 import javax.servlet.http.HttpServletRequest;
11 import javax.servlet.http.HttpServletResponse;
12 import me.gacl.annotation.Controller;
13 import me.gacl.annotation.RequestMapping;
14 import me.gacl.util.BeanUtils;
15 import me.gacl.util.RequestMapingMap;
16 import me.gacl.util.ScanClassUtil;
17 import me.gacl.web.context.WebContext;
18 import me.gacl.web.view.DispatchActionConstant;
19 import me.gacl.web.view.View;
20
21 /**
22 * <p>ClassName: AnnotationHandleServlet<p>
23 * <p>Description: AnnotationHandleServlet作为自定义注解的核心处理器以及负责调用目标业务方法处理用户请求<p>
24 * @author xudp
25 * @version 1.0 V
26 */
27 public class AnnotationHandleServlet extends HttpServlet {
28
29 private String pareRequestURI(HttpServletRequest request){
30 String path = request.getContextPath()+"/";
31 String requestUri = request.getRequestURI();
32 String midUrl = requestUri.replaceFirst(path, "");
33 String lasturl = midUrl.substring(0, midUrl.lastIndexOf("."));
34 return lasturl;
35 }
36
37 public void doGet(HttpServletRequest request, HttpServletResponse response)
38 throws ServletException, IOException {
39 this.excute(request, response);
40 }
41
42 public void doPost(HttpServletRequest request, HttpServletResponse response)
43 throws ServletException, IOException {
44 this.excute(request, response);
45 }
46
47 private void excute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
48 //将当前线程中HttpServletRequest对象存储到ThreadLocal中,以便在Controller类中使用
49 WebContext.requestHodler.set(request);
50 //将当前线程中HttpServletResponse对象存储到ThreadLocal中,以便在Controller类中使用
51 WebContext.responseHodler.set(response);
52 //解析url
53 String lasturl = pareRequestURI(request);
54 //获取要使用的类
55 Class<?> clazz = RequestMapingMap.getRequesetMap().get(lasturl);
56 //创建类的实例
57 Object classInstance = BeanUtils.instanceClass(clazz);
58 //获取类中定义的方法
59 Method [] methods = BeanUtils.findDeclaredMethods(clazz);
60 Method method = null;
61 for(Method m:methods){//循环方法,找匹配的方法进行执行
62 if(m.isAnnotationPresent(RequestMapping.class)){
63 String anoPath = m.getAnnotation(RequestMapping.class).value();
64 if(anoPath!=null && !"".equals(anoPath.trim()) && lasturl.equals(anoPath.trim())){
65 //找到要执行的目标方法
66 method = m;
67 break;
68 }
69 }
70 }
71 try {
72 if(method!=null){
73 //执行目标方法处理用户请求
74 Object retObject = method.invoke(classInstance);
75 //如果方法有返回值,那么就表示用户需要返回视图
76 if (retObject!=null) {
77 View view = (View)retObject;
78 //判断要使用的跳转方式
79 if(view.getDispathAction().equals(DispatchActionConstant.FORWARD)){
80 //使用服务器端跳转方式
81 request.getRequestDispatcher(view.getUrl()).forward(request, response);
82 }else if(view.getDispathAction().equals(DispatchActionConstant.REDIRECT)){
83 //使用客户端跳转方式
84 response.sendRedirect(request.getContextPath()+view.getUrl());
85 }else{
86 request.getRequestDispatcher(view.getUrl()).forward(request, response);
87 }
88 }
89 }
90 } catch (IllegalArgumentException e) {
91 e.printStackTrace();
92 } catch (IllegalAccessException e) {
93