首页 > 其他分享 >Servlet18 - DispatcherController

Servlet18 - DispatcherController

时间:2023-01-20 16:11:49浏览次数:45  
标签:do 请求 url xxx Servlet18 对象 operate DispatcherController

DispatcherServlet - 设置中央控制器

创建核心控制器,拦截所有请求进行处理,然后将请求发送给相应 xxController = 调用 xxController 方法处理请求
将原本的 xxServlet 改为 xxController,不拦截请求,只处理转发到控制器的请求 = 通过控制器方法处理请求
  • @WebServlet("*.do")  //拦截所有以 .do 结尾的请求 /xxx.do
    public class DispatcherServlet extends ViewBaseServlet{
        @Override
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //设置编码
            request.setCharacterEncoding("UTF-8");
    
            //获取请求的 url 即 /xxx.do
            String url = request.getServletPath(); // url = /xxx.do
            //字符串截取 获取 *的值
            url = url.substring(1); // 去除 /
            int lastDotIndex = url.lastIndexOf(".do"); // 获取最后一个 .do 中 . 的索引
            url = url.substring(0,lastDotIndex); // 去除 .do
            // 最后 url = xxx
    
            System.out.println(url);
        }
    }
    
配置 applicationContext.xml 文件,设置相应 url:/xxx.do 的请求由对应的 xxxController 来处理
  • <?xml version="1.0" encoding="utf-8" ?>
    <beans>
        <!-- 设置 servletpath 的名字是 fruit 的请求由 FruitController 来处理 -->
        <bean id="fruit" class="com.atguigu.fruit.controllers.FruitController"/>
    </beans>
    
在 DispatcherServlet 的构造方法中解析 applicationContext.xml 文件
将 bean 标签中的 id 和 class 取出,形成一一对应的键值对,key = id,value = 反射获取的class对应的类对象
  • //创造键值对存储对象,存放 url:/xxx.do 与 xxxController 的类对象一一对应关系
    private Map<String,Object> beanMap = new HashMap<String,Object>();
    
    //在构造方法中解析 applicationContext.xml 文件
    public DispatcherServlet() {
        //创建 InputStream 输入流对象 读取文件
        InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
        //创建 DocumentBuilderFactory 对象
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        //创建 DocumentBuilder 对象
        DocumentBuilder documentBuilder = null;
        try {
            documentBuilder = documentBuilderFactory.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        }
        //创建 Document 对象
        try {
            Document document = documentBuilder.parse(inputStream);
    
            //按标签读取文件中的内容 获取所有的 bean 节点
            NodeList beanNodeList = document.getElementsByTagName("bean");
    
            for (int i = 0; i < beanNodeList.getLength(); i++) {
                //遍历所有节点
                Node beanNode = beanNodeList.item(i);
                //判断节点的类型,将元素类型的节点强转为元素节点
                //从而可以调用元素节点的方法,获取节点中的 Attribute
                if(beanNode.getNodeType() == Node.ELEMENT_NODE){
                    Element beanElement = (Element) beanNode;
    
                    String beanId = beanElement.getAttribute("id");
                    String className = beanElement.getAttribute("class");
                    //根据获取到的 className 创建类实例对象,id 与类实例对象一一对应
                    Object beanObj = Class.forName(className).newInstance();
                    //作为键值对存储, key=beanId,value=beanOjb
                    beanMap.put(beanId,beanObj);
                }
            }
        } catch(...){...}
    }
    
  • 解析一个文件的固定步骤

    • 创建 InputStream 输入流对象 读取文件
    • 创建 DocumentBuilderFactory 对象
    • 创建 DocumentBuilder 对象
    • 创建 Document 对象
    • 使用 Document 对象读取文件内容
然后就可以在 Map 中通过 key 获取对应的 value,value 是 url 对应的 controller 类对象
  • Object controllerBeanObj = beanMap.get(url);
    
  • 如此一来,我们就得到了请求需要调用的 controller 类,再通过 operate 调用 controller类中需要调用的方法

在 DispatcherController 中 判断请求传入的 operate 参数值
  • Object controllerBeanObj = beanMap.get(url);
    
    String operate = request.getParameter("operate");
    if(StringUtil.isEmpty(operate)){
        operate = "index";
    }
    
    try {
        // 直接通过 operate 获取指定方法 method
        Method method = controllerBeanObj.getClass().getDeclaredMethod(operate, HttpServletRequest.class, HttpServletResponse.class);
        if(method != null){
            // .invoke 
            method.invoke(controllerBeanObj, request, response);
        }else{
            throw new RuntimeException("operate值非法!");
        }
    } catch (...) {...}
    
  • 整个过程通过反射实现,controllerBeanObj 是类对象,operate 是方法的 className,通过反射得到类中的相应方法,通过 Method 对象的 .invoke(obj,...params) 方法调用 method 方法,传入参数是 方法所在的类的实例对象 和 调用方法需要传入的参数,

标签:do,请求,url,xxx,Servlet18,对象,operate,DispatcherController
From: https://www.cnblogs.com/Ashen-/p/17062836.html

相关文章