Java学习不走弯路教程(18 Web框架)

Web框架

一. 前言
在前上一章教程中,我们实现了程序在Tomcat上的部署。
本章将在上一章的基础上,进一步扩展程序。

注:
1.本文针对初学Java的同学训练学习思路,请不要太纠结于细节问题。
2.本文旨在达到抛砖引玉的效果,希望大家扩展本例子,以学到更多知识的精髓。

学习本章需要准备的知识:
1.读完本系列教程的前面章节。
2.理解Java注解

二. 步入正题
话不多说,大家自己理解,下面步入正题:

我们来做一个简单的Web框架如下:
修改前:

修改后:

工程结构如下:

我们希望用一个普通的Java类而不是Servlet来处理Web请求,
比如如下的代码:

 1 /**
 2  * 
 3  * @author http://www.java123.vip
 4  *
 5  */
 6 @Controller // 用@Controller注解表示这个类可以处理web请求
 7 public class PersonController {
 8 
 9     @Request(path="/person.do")  // 请求路径
10     public String query(@Parameter(name="personid")String personId) { //参数名
11         
12         MyContainer container = MyContainer.getInstance();
13         PersonService personService = (PersonService)container.getObject(PersonService.class);
14         
15         Person personResult = personService.getPerson(personId);
16         
17         StringBuffer result = new StringBuffer();
18         result.append("id:"+personResult.id);
19         result.append("<br/>username:"+personResult.username);
20         result.append("<br/>password:"+personResult.passwd);
21         
22         return result.toString();
23     }
24 
25 }

引用的注解定义如下:

 1 /**
 2  * 
 3  * @author http://www.java123.vip
 4  *
 5  */
 6 @Target(value = { ElementType.TYPE })
 7 @Retention(value = RetentionPolicy.RUNTIME)
 8 public @interface Controller {
 9 
10 }
 1 /**
 2  * 
 3  * @author http://www.java123.vip
 4  *
 5  */
 6 @Target(value = { ElementType.PARAMETER })
 7 @Retention(value = RetentionPolicy.RUNTIME)
 8 public @interface Parameter {
 9 
10     String name();
11 
12 }
 1 /**
 2  * 
 3  * @author http://www.java123.vip
 4  *
 5  */
 6 @Target(value = { ElementType.METHOD })
 7 @Retention(value = RetentionPolicy.RUNTIME)
 8 public @interface Request {
 9 
10     String path();
11 
12 }

要把请求分发到这个普通的Java类上,我们需要在框架层处理这个映射:
首先,我们把所有的请求都放到一个Servlet中,然后通过这个Servlet来根据请求的路径,去调用具体的业务逻辑方法。
修改web.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>fileview_web05</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  
  <servlet>
      <servlet-name>dispacherServlet</servlet-name>
      <servlet-class>vip.java123.fileview.fw.web.DispacherServlet</servlet-class>
      <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
      <servlet-name>dispacherServlet</servlet-name>
      <url-pattern>*.do</url-pattern>
  </servlet-mapping>
</web-app>

然后做一个DispacherServlet来做请求分发:

  1 /**
  2  * 
  3  * @author http://www.java123.vip
  4  *
  5  */
  6 public class DispacherServlet extends HttpServlet{
  7 
  8     private Map<String,ControllerInvoker> controllerMap = new HashMap<String,ControllerInvoker>();
  9     
 10     public DispacherServlet() {
 11         // load all controller
 12         String controllerPackage = "vip.java123.fileview.app.web";
 13         
 14         try {
 15             // 扫描controller包下面的所有类,并加载包含注解@Controller的类
 16             Class[] controllerClasses = ClassScaner.getClasses(controllerPackage);
 17             for(int i = 0; i < controllerClasses.length; i ++) {
 18                 Class controller = controllerClasses[i];
 19                 
 20                 // 判断是否含有注解@Controller
 21                 if(controller.getAnnotation(Controller.class) != null) {
 22                     
 23                     // 生成新的Controller实例
 24                     Object obj = controller.newInstance();
 25                     
 26                     // 扫描所有的方法
 27                     Method[] methods = controller.getMethods();
 28                     for(int j = 0; j < methods.length; j ++) {
 29                         Method method = methods[j];
 30                         
 31                         // 加载含有@Request注解的方法
 32                         Request requestAnnotation = method.getAnnotation(Request.class);
 33                         if(requestAnnotation != null) {
 34                             
 35                             // 注解声明的请求路径
 36                             String path = requestAnnotation.path();
 37                             
 38                             // 做一个invoker,以便请求过来时调用
 39                             ControllerInvoker invoker = new ControllerInvoker();
 40                             invoker.path = path;
 41                             invoker.obj = obj;
 42                             invoker.method = method;
 43                             
 44                             // 处理@Parameter注解
 45                             List<String> parameterNameList = new ArrayList<String>();
 46                             Annotation[][] annotations = method.getParameterAnnotations();
 47                             for(int k = 0; k < annotations.length; k ++) {
 48                                 if(annotations[k].length > 0) {
 49                                     Parameter parameterAnnotaion = (Parameter)annotations[k][0];
 50                                     String parameterName = parameterAnnotaion.name();
 51                                     parameterNameList.add(parameterName);
 52                                 }
 53                             }
 54                             invoker.paramNames = new String[parameterNameList.size()];
 55                             for(int m = 0; m < parameterNameList.size(); m ++) {
 56                                 invoker.paramNames[m] = parameterNameList.get(m);
 57                             }
 58                             
 59                             // 将做好的invoker放入Map中,key为请求路径
 60                             System.out.println("load controller:"+path);
 61                             controllerMap.put(path, invoker);
 62                         }
 63                     }
 64                 }
 65             }
 66             
 67         } catch (ClassNotFoundException e) {
 68             e.printStackTrace();
 69         } catch (IOException e) {
 70             e.printStackTrace();
 71         } catch (InstantiationException e) {
 72             e.printStackTrace();
 73         } catch (IllegalAccessException e) {
 74             e.printStackTrace();
 75         }
 76         
 77     }
 78     
 79     /**
 80      * 处理Get请求
 81      */
 82     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 83         // 获得请求路径
 84         String contextPath = request.getContextPath();
 85         String requestPath = request.getRequestURI();
 86         String path = requestPath.replace(contextPath, "");
 87         
 88         System.out.println("request:"+path);
 89         
 90         // 根据请求路径获得做好的invoker
 91         ControllerInvoker invoker = controllerMap.get(path);
 92         
 93         if(invoker != null) {
 94             // 根据请求的参数值设置invoker
 95             invoker.paramValues = new String[invoker.paramNames.length];
 96             for(int i = 0; i < invoker.paramNames.length; i ++) {
 97                 invoker.paramValues[i] = request.getParameter(invoker.paramNames[i]);
 98             }
 99             
100             // 调用invoker,并将结果写到response中
101             String result = invoker.invokMethod();
102             response.getWriter().println(result);
103         }
104     }
105 
106 }

需要一个辅助类ControllerInvoker来支持:

 1 /**
 2  * 
 3  * @author http://www.java123.vip
 4  *
 5  */
 6 public class ControllerInvoker {
 7 
 8     public String path;
 9     public Object obj;
10     public Method method;
11     public String[] paramNames;
12     public String[] paramValues;
13     
14     // 调用制定的方法
15     public String invokMethod() {
16         try {
17             return (String)method.invoke(obj, paramValues);
18         } catch (IllegalArgumentException e) {
19             e.printStackTrace();
20         } catch (IllegalAccessException e) {
21             e.printStackTrace();
22         } catch (InvocationTargetException e) {
23             e.printStackTrace();
24         }
25         
26         return null;
27     }
28 }

三. 测试

启动服务器:

 

向服务器请求person.html文件,在浏览器端输入1,点query按钮:

显示查询结果:

完整程序请大家从[这里]下载

如有问题,大家来我的网站进行提问。
https://www.java123.vip/qa

版权声明:本教程版权归java123.vip所有,禁止任何形式的转载与引用。

猜你喜欢

转载自www.cnblogs.com/java123-vip/p/9771083.html