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