Java web 中央控制器

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();
            }
        }
    }
    
    

    抽取获取参数到中心控制器

    • 现在我们将获取参数的方式放到中央控制器当中去

      这是我们原本的update()代码

       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));
            return "redirect:fruit.do";//只负责返回这个字符串
        }
    

    我们将把所以的获取参数的方式从这里面删除.只保留业务代码

    private String update(Integer fid, String fname, Integer price, Integer fcount, String remark) throws ServletException {
            //3.执行更新
            fruitDAO.updateFruit(new Fruit(fid, fname, price, fcount, remark));
            //4.资源跳转
            return "redirect:fruit.do";//只负责返回这个字符串
        }
    
  • 将edit()代码也修改为相同的形式

  private String edit(Integer fid, HttpServletRequest request) {
        if (fid != null) {
            Fruit fruit = fruitDAO.getFruitByFid(fid);
            request.setAttribute("fruit", fruit);
//            super.processTemplate("edit", request, response);
            return "edit";
        }
        return "error";
    }
  • 将del()代码也这样修改
  private String del(Integer fid)  {
        if (fid!=null) {
            fruitDAO.delFruit(fid);//删除
            //super.processTemplate("index",request,response);
//            response.sendRedirect("fruit.do");
            return "redirect:fruit.do";//只负责返回这个字符串
        }
        return "error";
    }
  • 将add()代码也这样修改

     private String add(String fname,Integer price,Integer fcount,String remark) {
            Fruit fruit = new Fruit(0, fname, price, fcount, remark);
            fruitDAO.addFruit(fruit);
    //        response.sendRedirect("fruit.do");
            return "redirect:fruit.do";//只负责返回这个字符串
        }
    
  • 下面来修改index()方法

 private String index(String oper, String keyword, Integer pageNo, HttpServletRequest request) {
        HttpSession session = request.getSession();
        if (StringUtil.isNotEmpty(oper) && "search".equals(oper)) {
            pageNo = 1;
            if (StringUtil.isEmpty(keyword)) {
                keyword = "";
            }
            session.setAttribute("keyword", keyword);
        } else {
            Object keywordObj = session.getAttribute("keyword");
            if (keywordObj != null) {
                keyword = (String) keywordObj;
            } else {
                keyword = "";
            }
        }
        // 重新更新当前页的值
        session.setAttribute("pageNo", pageNo);
        FruitDAO fruitDAO = new FruitDAOImpl();
        List<Fruit> fruitList = fruitDAO.getFruitList(keyword, pageNo);
        session.setAttribute("fruitList", fruitList);
        //总记录条数
        int fruitCount = fruitDAO.getFruitCount(keyword);
        //总页数
        int pageCount = (fruitCount + 5 - 1) / 5;
        session.setAttribute("pageCount", pageCount);
        return "index";
    }
  • FruitController类修改完了,我们要开始进行修改中央控制器了

  • 首先我们需要先通过这条反射语句Method[] methods = controllerBeanObj.getClass().getDeclaredMethods();//通过反射获取该类的全部方法获取所有的类当中的方法的参数名称.

posted @ 2023-10-11 19:37  harper886  阅读(21)  评论(0编辑  收藏  举报