From Coffee to Data

技术需要善加利用:让弱小者的声音得到倾听,让每个人都有参与的机会,让世界免于灾难之苦。 ——Martin Kleppmann

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

在Servlet开发的工程实践中,为了减少过多的业务Servlet编写,会采用构建公共Servlet的方式,通过反射来搭建轻量级的MVC框架,从而加快应用开发。

关于Servlet开发的基础知识,请看:JavaWeb开发之详解Servlet及Servlet容器

前后端交互的基本形式

一般来说,前端提交数据请求有三种基本方式,分别是表单、链接和Ajax

1. 按钮

1 <form action="/BaseServlet/ServletDemo02?method=addStu" method="post">
2     用户<input type="text" name="username"/><br/>
3     <button>提交</button>
4 </form>

2. 链接

<a href="/BaseServlet/ServletDemo02?method=delStu">删除学生</a><br/>

3. Ajax

1 <button onclick="fn()">按钮</button>
2 <script>
3 function fn(){
4     $.post("/BaseServlet/ServletDemo02",{"method":"checkStu","user":"tom"},function(data){
5         alert(data);
6     });
7 }

在Servlet开发的语境中,它们的共同点都是:指定处理的Servlet类路径(在web.xml中指定)以及附带在请求中的“method”参数

通过调用request参数匹配业务处理逻辑

前端按照以上方法发起请求,Servlet容器就会把请求交给对应的Servlet处理,并且附带上形如 method=delStu 的参数,利用这个原理,就可以构建一个基础Servlet类,用来优化开发:

 1 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 2         //获取客户端提交到服务端的method对应的值
 3                 String md=request.getParameter("method");
 4                 //定义变量,存放功能执行完毕之后要转发的路径
 5                 String path=null;
 6                 
 7                 //通过判断md中不同的内容来决定本次功能
 8                 if("addStu".equals(md)){
 9                     path=addStu(request, response);
10                 }else if("delStu".equals(md)){
11                     path=delStu(request, response);
12                 }else if("checkStu".equals(md)){
13                     path=checkStu(request, response);
14                 }else if("".equals(md)){
15                     
16                 }
17                 if(null!=path){
18                     //服务端的请求转发
19                     request.getRequestDispatcher(path).forward(request, response);
20                 }
21     }
22 
23     
24     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
25         doGet(request, response);
26     }
27     
28     protected String addStu(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
29         System.out.println("添加学生");
30         return "/test.html";
31         
32     }
33     protected String delStu(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
34         System.out.println("删除学生");
35         return "/test.html";
36         
37     }
38     protected String checkStu(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
39         System.out.println("检查学生");
40         response.getWriter().println("DDDDDD");
41         return null;
42     }

以上的Servlet对请求进行了处理,通过获取index.html的请求,最后请求转发至目标页面,其核心思想是:

1. 提取request的method参数的值;

2. 定义变量,存储请求转发的路径;

3. 通过判断method参数中的值的内容,来决定调用哪个业务功能。

4. 完成业务功能后,使用请求转发处理

通过反射匹配业务处理逻辑

当业务量多的时候,以上实践仍是不够,此时比较好的方式就是采用反射。

 1 public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 2         doGet(request, response);
 3     }
 4     
 5     public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 6         //获取客户端提交到服务端的method对应的值
 7         String md=request.getParameter("method");
 8         //定义变量,存放功能执行完毕之后要转发的路径
 9         String path=null;
10         //获取到当前字节码对象(ServletDemo02.class在内存中对象)
11         Class<? extends ServletDemo02> clazz = this.getClass();
12         try {
13             //获取clazz上名称为md, 参数为HttpServletRequest和HttpServletResponse的方法
14             Method method=clazz.getMethod(md, HttpServletRequest.class,HttpServletResponse.class);
15             if(null!=method){
16                 //调用找到的方法
17                 path=(String)method.invoke(this, request,response);
18             }
19             if(null!=path){
20                 //服务端的转发
21                 request.getRequestDispatcher(path).forward(request, response);
22             }
23         } catch (Exception e) {
24             e.printStackTrace();
25         }     
26         
27     }
28 
29     public String addStu(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
30         System.out.println("添加学生");
31         return "/test.html";
32         
33     }
34     public String delStu(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
35         System.out.println("删除学生");
36         return "/test.html";
37         
38     }
39     public String checkStu(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
40         System.out.println("检查学生");
41         response.getWriter().println("DDDDDD");
42         return null;
43     }

1. 提取request的method参数的值;

2. 定义变量,存储请求转发的路径;

3. 获取到当前Servlet对象在内存中的Class对象

4. 获取Class对象上名称为md, 参数为HttpServletRequest和HttpServletResponse的方法

5. 根据是否返回方法对象,调用业务功能并使用请求转发处理

Java HttpServlet的父类GenericServlet,就是通过这个方法来调取HttpServlet的doGet或doPost方法的。

最佳实践

在实践开发中,一般会搭建一个BaseServlet,继承了HttpServlet并重写其Service方法,通过反射来找到业务功能子类对应的业务方法。

 1 public class BaseServlet extends HttpServlet {
 2     private static final long serialVersionUID = 12197442526341123L;
 3        
 4     @Override
 5     protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 6         System.out.println("service.....");
 7         //获取客户端提交到服务端的method对应的值
 8         String md=request.getParameter("method");
 9         //定义变量,存放功能执行完毕之后要转发的路径
10         String path=null;
11         //获取到当前字节码对象(ServletDemo02.class在内存中对象)
12         Class<? extends BaseServlet> clazz = this.getClass();
13         try {
14             //获取clazz上名称为md方法
15             Method method=clazz.getMethod(md, HttpServletRequest.class,HttpServletResponse.class);
16             if(null!=method){
17                 //调用找到的方法
18                 path=(String)method.invoke(this, request,response);
19             }
20             if(null!=path){
21                 //服务端的转发
22                 request.getRequestDispatcher(path).forward(request, response);
23             }
24         } catch (Exception e) {
25             e.printStackTrace();
26         }
27     }
28 
29 }

而业务功能子类,则继承BaseServlet,专注于业务逻辑的开发

 1 public class ServletDemo03 extends BaseServlet {
 2 
 3     private static final long serialVersionUID = 11248215356242123L;
 4     
 5     public ServletDemo03() {
 6         System.out.println("没有参数的构造函数");
 7     }
 8     
 9     public String addStu(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
10         System.out.println("添加学生");
11         return "/test.html";
12         
13     }
14     public String delStu(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
15         System.out.println("删除学生");
16         return "/test.html";
17         
18     }
19     public String checkStu(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
20         System.out.println("检查学生");
21         response.getWriter().println("DDDDDD");
22         return null;
23     }
24 
25 }

 

posted on 2018-11-20 09:54  Leoliu168  阅读(934)  评论(0编辑  收藏  举报