JavaWeb----mvc--servlet优化

资源地点:https://blog.csdn.net/jsdoulaoula/article/details/125648785

《优化1》

 

 平时我们都是写多个Servlet来对于每一个前端的操作,但是这样很麻烦

我想要一个Servlet来操作,将多个servlet转化成方法,通过前端操作的名称来调用这些方法

 

 

 

 

 《优化2》

上面的用Switch当方法一多会写死人

所以我们可以用反射和循环来优化

 1 package com.cilinmengy.Servlets;
 2 
 3 import javax.servlet.http.HttpServlet;
 4 import javax.servlet.http.HttpServletRequest;
 5 import javax.servlet.http.HttpServletResponse;
 6 import java.lang.reflect.InvocationTargetException;
 7 import java.lang.reflect.Method;
 8 
 9 public class IndexServlet extends HttpServlet {
10     @Override
11     public void service(HttpServletRequest request, HttpServletResponse resonse) {
12         Method[] methods = this.getClass().getDeclaredMethods();
13         String operate = request.getParameter("operate");
14         if (operate == null) {
15             operate = "index";
16         }
17         for (Method m : methods) {
18             if (m.getName().equals(operate)) {
19                 try {
20                     m.invoke(this, request, resonse);
21                     return;
22                 } catch (IllegalAccessException | InvocationTargetException e) {
23                     e.printStackTrace();
24                 }
25             }
26         }
27         throw new RuntimeException("operate值非法!");
28     }
29 
30     private void add(HttpServletRequest request, HttpServletResponse resonse) {
31     }
32 
33     private void delete(HttpServletRequest request, HttpServletResponse resonse) {
34     }
35 }

《优化三》

当xxxServlet多起来时,也要一个管理的类,否则在这么多的xxxServlet中会有很多的重复的反射代码

 

 

 接下来的问题是:如何将前端要访问的信息传到DispatcherServlet中然后让这个类去精确调用其他Servlet?

(这里我们要将Servlet改个名了,叫做xxxController更加符合语意)

1.首先是通过地址:地址中的名称一般指明了要访问的内容:

 

 

 

 

 2.

 

 让要访问的Hello与HelloController关联上

 

 1 package com.cilinmengy.Servlets;
 2 
 3 import org.w3c.dom.Document;
 4 import org.w3c.dom.Element;
 5 import org.w3c.dom.Node;
 6 import org.w3c.dom.NodeList;
 7 import org.xml.sax.SAXException;
 8 
 9 import javax.servlet.ServletException;
10 import javax.servlet.http.HttpServlet;
11 import javax.servlet.http.HttpServletRequest;
12 import javax.servlet.http.HttpServletResponse;
13 import javax.xml.parsers.DocumentBuilder;
14 import javax.xml.parsers.DocumentBuilderFactory;
15 import javax.xml.parsers.ParserConfigurationException;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.lang.annotation.Documented;
19 import java.lang.reflect.InvocationTargetException;
20 import java.lang.reflect.Method;
21 import java.util.HashMap;
22 
23 public class DispatchServlet extends HttpServlet {
24     private HashMap<String,Object> hashMap=new HashMap<>();
25     //与配置文件产生联系,获取其中的配置,将操作与操作对象用hashMap关联起来
26     public DispatchServlet() throws ParserConfigurationException, IOException, SAXException, ClassNotFoundException, IllegalAccessException, InstantiationException {
27         //通过类加载器获取与配置文件交流的流
28         InputStream inputStream=getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
29         //接下来是java读取.xml文件的操作
30         DocumentBuilderFactory documentBuilderFactory=DocumentBuilderFactory.newInstance();
31         DocumentBuilder documentBuilder=documentBuilderFactory.newDocumentBuilder();
32         Document document=documentBuilder.parse(inputStream);
33         //获取全部bean节点
34         NodeList beanNodeList=document.getElementsByTagName("bean");
35         for (int i=0;i<beanNodeList.getLength();i++)
36         {
37             Node beanNode = beanNodeList.item(i);
38             if (beanNode.getNodeType()==Node.ELEMENT_NODE){
39                 Element beanElement =(Element) beanNode;
40                 String beanId=beanElement.getAttribute("id");
41                 String className=beanElement.getAttribute("class");
42                 hashMap.put(beanId,Class.forName(className).newInstance());
43             }
44         }
45     }
46     @Override
47     public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
48         //得到要进行操作的名称
49         String servletPath=req.getServletPath();
50         servletPath=servletPath.substring(1);
51         int lastDoIndex =servletPath.lastIndexOf(".do");
52         servletPath=servletPath.substring(0,lastDoIndex);
53 
54         //从hashMap中取出操作对象
55         Object controller=hashMap.get(servletPath);
56         String operator=req.getParameter("operator");
57         try {
58             Method method=controller.getClass().getMethod(operator,req.getClass(),resp.getClass());
59             if (method!=null){
60                 method.invoke(controller,req,resp);
61             }
62         } catch (NoSuchMethodException e) {
63             e.printStackTrace();
64         } catch (IllegalAccessException e) {
65             e.printStackTrace();
66         } catch (InvocationTargetException e) {
67             e.printStackTrace();
68         }
69     }
70 }

 《优化四》

这一次优化的目的是

 

 如图可以看到在FruitController中的方法有很多这样请求参数的操作,但是这些操作相似,只是请求的参数不同而已,同时我们也希望尽量减少Servlet与Controller组件的联系

 

 我们希望这些参数通过传参的形式来获得如:

 

 这就说明我们要通过在中央控制器DispatchServlet来传入,可以通过反射获得方法的参数名称,同一传入

《总结》

下面是大佬的总结+我的理解:

最终实现,在Controller我们只用考虑业务操作,不需要考虑跳转,获取参数等等。

至此修改完成,总结一下

  1.最初的做法是: 一个请求对应一个Servlet,这样存在的问题是servlet太多了

改进
  2.把一些列的请求都对应一个Servlet, IndexServlet/AddServlet/EditServlet/DelServlet/UpdateServlet -> 合并成FruitServlet
  通过一个operate的值来决定调用FruitServlet中的哪一个方法
  使用的是switch-case

改进
  3.在上一个版本中,Servlet中充斥着大量的switch-case,试想一下,随着我们的项目的业务规模扩大,那么会有很多的Servlet,也就意味着会有很多的switch-case,这是一种代码冗余。
  因此,我们在servlet中使用了反射技术,我们规定operate的值和方法名一致,那么接收到operate的值是什么就表明我们需要调用对应的方法进行响应,如果找不到对应的方法,则抛异常

改进
  4.在上一个版本中我们使用了反射技术,但是其实还是存在一定的问题:每一个servlet中都有类似的反射技术的代码。因此继续抽取,设计了中央控制器类:DispatcherServlet
  DispatcherServlet这个类的工作分为两大部分:
  首先,根据url定位到能够处理这个请求的controller组件:
  1)从url中提取servletPath : /fruit.do -> fruit
  2)根据fruit找到对应的组件:FruitController , 这个对应的依据我们存储在applicationContext.xml中
  <bean id=“fruit” class="com.atguigu.fruit.controllers.FruitController/>
  通过DOM技术我们去解析XML文件,在中央控制器中形成一个beanMap容器,用来存放所有的Controller组件
  3)根据获取到的operate的值定位到我们FruitController中需要调用的方法
  其次,调用Controller组件中的方法

改进

  5.因为尽量减少Controller组件与Servlet以及优化重复获取参数的操作

  我们将方法要用到的参数从DispathServlet中通过反射得知并传入
————————————————
版权声明:本文为CSDN博主「蓦然回首却已人去楼空」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/jsdoulaoula/article/details/125648785

 

posted @ 2022-09-13 22:01  次林梦叶  阅读(36)  评论(0)    收藏  举报