当前位置: 首页 > article >正文

JavaWeb Servlet的反射优化、Dispatcher优化、视图(重定向)优化、方法参数值获取优化

目录

  • 1. 背景
  • 2. 实现
    • 2.1 pom.xml
    • 2.2 FruitController.java
    • 2.3 DispatcherServlet.java
    • 2.4 applicationContext.xml
  • 3. 测试

1. 背景

前面我们做了Servlet的一个案例。但是存在很多问题,现在我们要做优化,优化的步骤如下:

  1. 每个Fruit请求都需要一个Servlet来处理,这样就会产生大量的Servlet。我们可以只用一个FruitServlet来处理,然后通过一个operate变量来区分请求FruitServlet的哪个方法
  2. 除了有Fruit的请求,可能还有很多其它类型的请求。可以用一个DispatcherServlet来处理所有的请求,然后定义一个applicationContext.xml来让一个请求和其处理的类对应
  3. 不在FruitController中做重定向,FruitController只返回要重定向的路径,统一由DispatcherServlet来做重定向
  4. 不在FruitController的方法中获取参数。由DispatcherServlet统一获取参数,然后传递给FruitController的方法

2. 实现

2.1 pom.xml

编译的时候保留方法的参数名,而不是擦除。注意删除target,不然不会生效

            <!-- 编译的时候保留方法的参数名,而不是擦除。注意删除target,不然不会生效 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.10.1</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                    <compilerArgument>-parameters</compilerArgument>
                </configuration>
            </plugin>

2.2 FruitController.java

只负责具体的业务逻辑处理。重定向、参数获取全部由DispatcherServlet处理

package com.hh.javaWebTest.servlet;

import com.hh.javaWebTest.bean.Fruit;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

// 只负责具体的业务逻辑处理。重定向、参数获取全部由DispatcherServlet处理
public class FruitController {


    protected String index(Integer paramId, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 不通过req.getParameter(paramName)获取参数值,而是通过在dispatcher统一获取,再传入进来
        // 测试是否能获取到参数
        System.out.println("paramId: " + paramId);

        System.out.println(req.getRequestURI());    // /javaWebTest/fruit.do
        System.out.println(req.getQueryString());   // paramId=1

        List<Fruit> fruitList = new ArrayList<Fruit>();
        fruitList.add(new Fruit("苹果", 5));
        fruitList.add(new Fruit("香蕉", 3));

        HttpSession session = req.getSession();
        session.setAttribute("fruitList", fruitList);

        // 由DispatcherServlet调用super.processTemplate("index", request, response);
        return "index";

    }

}

2.3 DispatcherServlet.java

接受所有的请求,然后进行分发

package com.hh.javaWebTest.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;

// 接受所有的请求,然后进行分发
@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet {

    private Map<String, Object> beanMap = new HashMap<>();

    @Override
    public void init() throws ServletException {
        // 手动进行ViewBaseServlet的初始化
        super.init();

        // 解析applicationContext.xml,形成id:class形式的beanMap
        try {
            InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            Document document = documentBuilder.parse(inputStream);

            NodeList beanNodeList = document.getElementsByTagName("bean");
            for (int i = 0; i < beanNodeList.getLength(); i++) {
                Node beanNode = beanNodeList.item(i);
                if (beanNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element beanElement = (Element) beanNode;
                    String beanId = beanElement.getAttribute("id");
                    String className = beanElement.getAttribute("class");
                    Class controllerBeanClass = Class.forName(className);
                    Object beanObj = controllerBeanClass.getDeclaredConstructor().newInstance();

                    beanMap.put(beanId, beanObj);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // servletPath: /fruit.do => fruit
        String servletPath = request.getServletPath();
        servletPath = servletPath.substring(1);
        int lastDotIndex = servletPath.lastIndexOf(".do");
        servletPath = servletPath.substring(0, lastDotIndex);

        // 获取fruit对应的class
        Object controllerBeanObj = beanMap.get(servletPath);

        // 获取operate
        String operate = request.getParameter("operate");
        if (StringUtils.isEmpty(operate)) {
            operate = "index";
        }

        try {
            Method[] methods = controllerBeanObj.getClass().getDeclaredMethods();
            for (Method method : methods) {
                // 匹配operate对应的类方法
                if (operate.equals(method.getName())) {
                    Parameter[] parameters = method.getParameters();
                    // 将类方法的值,保存到parameterValues
                    Object[] parameterValues = new Object[parameters.length];
                    for (int i = 0; i < parameters.length; i++) {
                        Parameter parameter = parameters[i];
                        String parameterName = parameter.getName();
                        if ("req".equals(parameterName)) {
                            parameterValues[i] = request;
                        } else if ("resp".equals(parameterName)) {
                            parameterValues[i] = response;
                        } else if ("session".equals(parameterName)) {
                            parameterValues[i] = request.getSession();
                        } else {
                            // 从请求中获取参数值
                            String parameterValue = request.getParameter(parameterName);
                            String typeName = parameter.getType().getName();

                            Object parameterObj = parameterValue;
                            if (parameterObj != null) {
                                if ("java.lang.Integer".equals(typeName)) {
                                    parameterObj = Integer.parseInt(parameterValue);
                                }
                            }

                            parameterValues[i] = parameterObj;
                        }
                    }

                    // 调用方法,返回值。根据返回值判断是否需要做重定向
                    method.setAccessible(true);
                    Object returnObj = method.invoke(controllerBeanObj, parameterValues);

                    // 视图处理(重定向处理)
                    String methodReturnStr = (String) returnObj;
                    if (methodReturnStr.startsWith("redirect:")) {  // 比如: redirect:fruit.do
                        String redirectStr = methodReturnStr.substring("redirect:".length());
                        response.sendRedirect(redirectStr);
                    } else if (methodReturnStr != "") {         // 比如: "index"
                        super.processTemplate(methodReturnStr, request, response);
                        return;
                    } else {
                        return;
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        throw new RuntimeException("operate值非法!");
    }
}

2.4 applicationContext.xml

定义java bean的id,和其对应的处理类

<?xml version="1.0" encoding="utf-8"?>

<!--
XML包含三个部分:
1. XML声明, 而且声明这一行代码必须在XML文件的第一行
2. DTD: 文档类型定义
3. XML正文
 -->

<!-- 该标签告知XML文档所使用的XML beans规范 -->
<!DOCTYPE beans [
        <!ELEMENT beans (bean*)>
        <!ELEMENT bean (property*)>
        <!ELEMENT property (#PCDATA)>

        <!ATTLIST bean id ID #REQUIRED>
        <!ATTLIST bean class CDATA #IMPLIED>
        <!ATTLIST property name CDATA #IMPLIED>
        <!ATTLIST property ref IDREF #IMPLIED>
        ]>

<beans>
    <!-- 说明这是一个java bean。id是fruit,其对应的处理类是FruitController -->
    <bean id="fruit" class="com.hh.javaWebTest.servlet.FruitController"/>
</beans>

3. 测试

请求http://localhost:8080/javaWebTest/fruit.do?paramId=1,web页面显示和之前的一样

web页面显示效果

控制台输出如下:

paramId: 1

http://www.kler.cn/a/449558.html

相关文章:

  • pyinstaller打包资源文件和ini配置文件怎么放
  • C#代码实现把中文录音文件(.mp3 .wav)转为文本文字内容
  • jsp中的四个域对象(Spring MVC)
  • 人工智能的未来:机遇、威胁与人类主导地位的挑战
  • 写给Pythoner的前端进阶指南(五):事件驱动模型
  • springboot中Jackson库和jsonpath库的区别和联系。
  • Qt for Python (PySide6)设置程序图标和任务栏图标
  • 【求职面试】大学转专业面试自我介绍模板7篇
  • 解决:websocket 1002 connection rejected 426upgrade required
  • 路径规划之启发式算法之二十:麻雀搜索算法(Sparrow Search Algorithm,SSA)
  • 搭建简易版本的git私有仓库--运用git和gitea
  • 灭屏情况下,飞行模式+静音模式+插耳,播放音乐,电流异常
  • 层序遍历练习
  • 重温设计模式--组合模式
  • 【FFmpeg】解封装 ① ( 封装与解封装流程 | 解封装函数简介 | 查找码流标号和码流参数信息 | 使用 MediaInfo 分析视频文件 )
  • 终章:DevOps实践总结报告
  • 鸿蒙人脸识别
  • RISC-V架构的压缩指令集介绍
  • 【Quartz】任务调度
  • Qt C++ 下网络通信与文件发送的实现
  • 黑马商城项目—服务注册、服务发现
  • C++ STL CookBook
  • 拥有人类情感的AI:未来还是幻想?
  • 蓝桥杯刷题——day9
  • AI可信论坛亮点:合合信息分享视觉内容安全技术前沿
  • K8S中的PV、PVC介绍和使用