Java web 中央控制器

发布时间 2023-10-11 19:41:32作者: harper886

Java web 中央控制器

mvc-servlet优化

03.MVC03

beanMap相当于一个容器

http://localhost:8080/pro15/fruit.do?operate=edit&fid=2

在上面的链接中使用fruit.do找到Controller控制器.然后再通过

operate找到edit方法

在原本的方法之中我们发现在FruitController的各种方法比如update(),edit(),del(),add(),index()方法里面都有一个 response.sendRedirect("fruit.do");重定向方法或者super.processTemplate("edit",request,response);获取视图模板技术.所以我们打算将这两个方法抽离到DispatcherServlet当中去让中央控制器来实现跳转与实现.

这一节主要的优化就是将上面的两个方法抽离到中央控制器当中去

  • 因为是中央控制器来调用这些方法所以我们可以将一个String返回给中央控制器.让中央控制器来接收.比如我们在update方法中返回redirect:fruit.do
   private String update(HttpServletRequest request) throws ServletException {
        //2.获取参数
        String fidStr = request.getParameter("fid");
        Integer fid = Integer.parseInt(fidStr);
        String fname = request.getParameter("fname");
        String priceStr = request.getParameter("price");
        int price = Integer.parseInt(priceStr);
        String fcountStr = request.getParameter("fcount");
        Integer fcount = Integer.parseInt(fcountStr);
        String remark = request.getParameter("remark");

        //3.执行更新
        fruitDAO.updateFruit(new Fruit(fid, fname, price, fcount, remark));
       //        response.sendRedirect("fruit.do");
        return "redirect:fruit.do";//只负责返回这个字符串
    }
  • 我们在edit()方法之中返回了edit
 private String edit(HttpServletRequest request) throws IOException, ServletException {
        String fidStr = request.getParameter("fid");
        if (StringUtil.isNotEmpty(fidStr)) {
            int fid = Integer.parseInt(fidStr);
            Fruit fruit = fruitDAO.getFruitByFid(fid);
            request.setAttribute("fruit", fruit);
//            super.processTemplate("edit", request, response);
            return "edit";
        }
        return "error";
    }

这样我们就将字符串返回给了中央控制器.同时如果我们都这样处理的话,这些类中的HttpServletResponse response,以及很多异常就不在需要了.所以是可以进行删除的

  • 让我们继续回到中央控制器,来进行进一步的抽取工作.我们在service()方法中找到了通过反射调用的方法.首先对代码Object returnObj = method.invoke(controllerBeanObj, request);的返回值接受为一个object对象,然后将这个对象强制转换为String类型.

  • 然后开始进行处理,首先判断该字符串是不是以redirect:为开头,如果是以redirect:为开头的话,这种情况就是要求重定向的方法,就截取redirect:后面的部分,然后通过response.sendRedirect(redirectStr);来调用截取的字符串.

  • 如果该字符串不是以redirect:为开头的话那么就要求调用视图模板技术,我们让DispatcherServlet 继承 ViewBaseServlet这样的话就可以直接通过uper.processTemplate(methodReturnStr, request, response);直接调用方法

    @WebServlet("*.do")
    public class DispatcherServlet extends ViewBaseServlet {
    
        private Map<String, Object> beanMap = new HashMap<>();
    
        public DispatcherServlet() {
        }
    
        public void init() throws ServletException {
            super.init();
            try {
                InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
                //1.创建DocumentBuilderFactory
                DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
                //2.创建DocumentBuilder对象
                DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
                //3.创建Document对象
                Document document = documentBuilder.parse(inputStream);
    
                //4.获取所有的bean节点
                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.newInstance();
                        beanMap.put(beanId, beanObj);
                    }
                }
            } catch (ParserConfigurationException e) {
                e.printStackTrace();
            } catch (SAXException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //设置编码
            request.setCharacterEncoding("UTF-8");
            //假设url是:  http://localhost:8080/pro15/hello.do
            //那么servletPath是:    /hello.do
            // 我的思路是:
            // 第1步: /hello.do ->   hello   或者  /fruit.do  -> fruit
            // 第2步: hello -> HelloController 或者 fruit -> FruitController
            String servletPath = request.getServletPath();
            servletPath = servletPath.substring(1);
            int lastDotIndex = servletPath.lastIndexOf(".do");
            servletPath = servletPath.substring(0, lastDotIndex);
    
            Object controllerBeanObj = beanMap.get(servletPath);
    
            String operate = request.getParameter("operate");
            if (StringUtil.isEmpty(operate)) {
                operate = "index";
            }
    
            try {
                Method method = controllerBeanObj.getClass().getDeclaredMethod(operate, HttpServletRequest.class);
                if (method != null) {
                    //2.controller组件中的方法调用
                    method.setAccessible(true);
                    Object returnObj = method.invoke(controllerBeanObj, request);
                    //3.视图处理
                    String methodReturnStr = (String) returnObj;
                    if (methodReturnStr.startsWith("redirect:")) {
                        String redirectStr = methodReturnStr.substring("redirect".length());//获取redirect后面的内容
                        response.sendRedirect(redirectStr);
                    } else {
                        //这种情况返回的就是edit
                        super.processTemplate(methodReturnStr, request, response);
                    }
                } else {
                    throw new RuntimeException("operate值非法!");
                }
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }