JavaWeb学习笔记(六)——Servlet优化

6.1、Servlet优化

1.最初的做法:一个请求对应一个Servlet

存在的问题:servlet太多了

在这里插入图片描述

2.把一系列的请求对应一个Servlet

  • IndexServletAddServletEditServletDeleteServletUpdateServlet合并成FruitServlet
  • 通过一个operation值来决定调用FruitServlet中的哪个方法
  • 使用的switch-case语法来判断方法

在这里插入图片描述

FruitServlet.java

@WebServlet("/fruit.do")
public class FruitServlet extends ViewBaseServlet {
    private FruitDAO fruitDAO = new FruitDAOImpl();

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");

        String operation = request.getParameter("operation");
        if (StringUtil.isEmpty(operation)) {
            operation = "index";
        }

        switch (operation) {
            case "index":
                index(request,response);
                break;
            case "add":
                add(request,response);
                break;
            case "delete":
                delete(request,response);
                break;
            case "edit":
                edit(request,response);
                break;
            case "update":
                update(request,response);
                break;
            default:
                throw new RuntimeException("operation值非法!!");
        }
    }

    private void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.设置编码
       // request.setCharacterEncoding("UTF-8");

        //2.获取参数
        String fname = request.getParameter("fname");
        String priceStr = request.getParameter("price");
        int price = Integer.parseInt(priceStr);
        String countStr = request.getParameter("fcount");
        int fcount = Integer.parseInt(countStr);
        String remark = request.getParameter("remark");

        String FidStr = request.getParameter("fid");
        int fid = Integer.parseInt(FidStr);

        //3.执行更新
        Fruit fruit = new Fruit(fid, fname,price,fcount,remark);
        fruitDAO.updateFruit(fruit);

        //4.资源跳转
        response.sendRedirect("fruit.do");
    }

    private void edit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String strId = request.getParameter("fid");
        if (StringUtil.isNotEmpty(strId)) {
            int fid = Integer.parseInt(strId);
            Fruit fruit = fruitDAO.getFruitByFid(fid);
            request.setAttribute("fruit", fruit);
            super.processTemplate("edit", request,response);
        }
    }

    private void delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String fidStr = request.getParameter("fid");
        if (StringUtil.isNotEmpty(fidStr)) {
            int fid = Integer.parseInt(fidStr);
            fruitDAO.delFruit(fid);
            response.sendRedirect("fruit.do");
        }
    }

    private void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String fname = request.getParameter("fname");
        int price = Integer.parseInt(request.getParameter("price"));
        String remark = request.getParameter("remark");
        int fcount = Integer.parseInt(request.getParameter("fcount"));

        Fruit fruit = new Fruit(fname,price,fcount,remark);
        System.out.println(fruit);
        fruitDAO.addFruit(fruit);

        response.sendRedirect("fruit.do");
    }

    private void index(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        HttpSession session = request.getSession();

        //设置当前页:默认值为1
        int pageNum = 1;
        //
        String operate = request.getParameter("operate");
        //如果operate!=null,说明:通过表单的查询按钮点击过来的
        //如果operate==null,说明:不是通过表单的查询按钮点击过来的

        String keyword = null;
        if (StringUtil.isNotEmpty(operate) && "search".equals(operate)) {
            //说明是点击表单查询发送过来的请求
            //此时,pageNum应该还原为1,keyword应该从请求参数中获取
            pageNum = 1;
            keyword = request.getParameter("keyword");
            //如果keyword为null,需要设置为"",否则查询时会拼接成 %null%,我们期望的是 %%
            if (StringUtil.isEmpty(keyword)) {
                keyword = "";
            }
            //将keyword把偶才能(覆盖)到session中
            session.setAttribute("keyword",keyword);
        }else {
            //说明此处不是是点击表单查询发送过来的请求,比如点击上一页,下一页或者直接在地址栏输入网址
            //此时keyword 应该从session的作用域获取
            String pageNumStr = request.getParameter("pageNum");
            if(StringUtil.isNotEmpty(pageNumStr)) {
                //如果从请求中读取到pageNum,则类型转换,否则默认为1
                pageNum = Integer.parseInt(pageNumStr);
            }
            //如果不是点击的查询按钮,那么查询是基于session中保存的现有keyword进行查询
            Object keywordObj = session.getAttribute("keyword");
            if (keywordObj != null) {
                keyword = (String) keywordObj;
            }else {
                keyword = "";
            }
        }

        //重新更新当前页的值
        session.setAttribute("pageNum",pageNum);  
        List<Fruit> fruitList = fruitDAO.getFruitList(keyword,pageNum);

        //保存到session作用域
        session.setAttribute("fruitList", fruitList);

        int count = fruitDAO.getFruitCount(keyword);
        //总页数
        int pageCount = (count + 5 - 1) / 5;
       
        session.setAttribute("pageCount", pageCount);
    super.processTemplate("index",request,response);
    }
}

6.2、Servlet优化——使用反射

1.在上一个版本中,Servlet中充斥着大量的switch-case,随着项目业务扩大,那么会有很多的Servlet,也就意味着会有很多的switch-case。这是一种代码冗余。

2.因此,在Servlet中使用反射机制,规定operation的值和反方面一致,那么接收到operation的值是什么,就表明需要调用对应的方法进行响应,如果找不到对应的方法,则抛异常。

FruitServlet.java

@WebServlet("/fruit.do")
public class FruitController extends ViewBaseServlet {
    private FruitDAO fruitDAO = new FruitDAOImpl();

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");

        String operation = request.getParameter("operation");
        if (StringUtil.isEmpty(operation)) {
            operation = "index";
        }

        //获取当前类中的所有方法
        Method[] methods = this.getClass().getDeclaredMethods();
        for (Method m : methods) {
            //获取方法名称
            String methodName = m.getName();
            if (operation.equals(methodName)) {
                //找到和operation同名的方法,那么通过反射技术得到它
                try {
                    m.invoke(this,request,response);
                    return;
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
        throw new RuntimeException("operation值非法!!");

    }

    private void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.设置编码
       // request.setCharacterEncoding("UTF-8");

        //2.获取参数
        String fname = request.getParameter("fname");
        String priceStr = request.getParameter("price");
        int price = Integer.parseInt(priceStr);
        String countStr = request.getParameter("fcount");
        int fcount = Integer.parseInt(countStr);
        String remark = request.getParameter("remark");

        String FidStr = request.getParameter("fid");
        int fid = Integer.parseInt(FidStr);

        //3.执行更新
        Fruit fruit = new Fruit(fid, fname,price,fcount,remark);
        fruitDAO.updateFruit(fruit);

        //4.资源跳转
        response.sendRedirect("fruit.do");
    }

    private void edit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String strId = request.getParameter("fid");
        if (StringUtil.isNotEmpty(strId)) {
            int fid = Integer.parseInt(strId);
            Fruit fruit = fruitDAO.getFruitByFid(fid);
            request.setAttribute("fruit", fruit);
            super.processTemplate("edit", request,response);
        }
    }

    private void delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String fidStr = request.getParameter("fid");
        if (StringUtil.isNotEmpty(fidStr)) {
            int fid = Integer.parseInt(fidStr);
            fruitDAO.delFruit(fid);
            response.sendRedirect("fruit.do");
        }
    }

    private void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String fname = request.getParameter("fname");
        int price = Integer.parseInt(request.getParameter("price"));
        String remark = request.getParameter("remark");
        int fcount = Integer.parseInt(request.getParameter("fcount"));

        Fruit fruit = new Fruit(fname,price,fcount,remark);
        System.out.println(fruit);
        fruitDAO.addFruit(fruit);

        response.sendRedirect("fruit.do");
    }

    private void index(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        HttpSession session = request.getSession();

        //设置当前页:默认值为1
        int pageNum = 1;
        //
        String operate = request.getParameter("operate");
        //如果operate!=null,说明:通过表单的查询按钮点击过来的
        //如果operate==null,说明:不是通过表单的查询按钮点击过来的

        String keyword = null;
        if (StringUtil.isNotEmpty(operate) && "search".equals(operate)) {
            //说明是点击表单查询发送过来的请求
            //此时,pageNum应该还原为1,keyword应该从请求参数中获取
            pageNum = 1;
            keyword = request.getParameter("keyword");
            //如果keyword为null,需要设置为"",否则查询时会拼接成 %null%,我们期望的是 %%
            if (StringUtil.isEmpty(keyword)) {
                keyword = "";
            }
            //将keyword把偶才能(覆盖)到session中
            session.setAttribute("keyword",keyword);
        }else {
            //说明此处不是是点击表单查询发送过来的请求,比如点击上一页,下一页或者直接在地址栏输入网址
            //此时keyword 应该从session的作用域获取
            String pageNumStr = request.getParameter("pageNum");
            if(StringUtil.isNotEmpty(pageNumStr)) {
                //如果从请求中读取到pageNum,则类型转换,否则默认为1
                pageNum = Integer.parseInt(pageNumStr);
            }
            //如果不是点击的查询按钮,那么查询是基于session中保存的现有keyword进行查询
            Object keywordObj = session.getAttribute("keyword");
            if (keywordObj != null) {
                keyword = (String) keywordObj;
            }else {
                keyword = "";
            }
        }

        //重新更新当前页的值
        session.setAttribute("pageNum",pageNum);
        List<Fruit> fruitList = fruitDAO.getFruitList(keyword,pageNum);
        //保存到session作用域
        session.setAttribute("fruitList", fruitList);

        int count = fruitDAO.getFruitCount(keyword);
        int pageCount = (count + 5 - 1) / 5;
        session.setAttribute("pageCount", pageCount);
      super.processTemplate("index",request,response);
    }
}

6.3、DispatcherServlet的引入

6.3.1、XML

1.概念

HTML:超文本标记语言
XML:可扩展的标记语言
HTML是XML的一个子集

2.XML包含三个部分:

1)XML声明:而且声明这一行代码必须在XML文件的第一行

2)DTD 文档类型定义

3)XML正文

applicationContext.xml】(放在src下)

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

<beans>
    <!--这个bean标签的作用是:将来servletPath中涉及的名字对应打的是fruit,那么就要FruitController这个类来处理-->
    <bean id="fruit" class="com.mvc.fruit.controllers.FruitController"/>
</beans>

6.3.2、Servlet优化:引入DispatcherServlet

1.在上一个版本中使用了反射机制,但是其实还是存在一定的问题:每一个Servlet中都有类似的反射技术的代码。

2.因此,继续抽取设计了中央控制器类:DispatcherServlet类

在这里插入图片描述

3.DispatcherServlet类的工作分为两大部分:

1)根据url定位到能够处理这个请求的controller组件:

  • url中提取servletPath:/fruit.do -> fruit`

  • 根据fruit找到对应的组件:FruitController,这个对应的依据存储在applicationContext.xml中。

    <bean id="fruit" class="com.mvc.fruit.controllers.FruitController"/>
    

    通过DOM技术去解析XML文件,在中央控制器中形成一个beanMap容器,用来存放所有Controller组件。

  • 根据获取到的operation的值定位到FruitController中需要调用的方法。

2)调用Controller组件中的方法:

  • 获取参数

    • 获取即将要调用的方法的参数签名信息:

      Parameter[] parameters = method.getParameters();
      
    • 通过parameter.getName()获取参数的名称;

    • Object[] parameterValues用来存放对应参数的参数值。

    • 另外,需要考虑参数的类型问题,需要做类型转换的工作。通过parameter.getType()获取参数的类型。

  • 执行方法

    Object methodReturnObj = method.invoke(controllerBeanObj,parameterValues);
    
  • 视图处理

DispatcherServlet.java

@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 baenElement = (Element) beanNode;
                    String beanId = baenElement.getAttribute("id");
                    String className = baenElement.getAttribute("class");

                    Class controllerBeanClass = Class.forName(className);
                    Object beanObj = controllerBeanClass.newInstance();

                    beanMap.put(beanId, beanObj);
                }
            }
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置编码
        request.setCharacterEncoding("UTF-8");

        //假设URL:http://localhost:8080/03mvcDispatcher/hello.do
        //那么servletPath是:/hello.do
        //我的思路:
        // 第1步:  /hello.do ->  hello
        String servletPath = request.getServletPath();
        servletPath = servletPath.substring(1);
        int lastDotIndex = servletPath.lastIndexOf(".do");
        servletPath = servletPath.substring(0, lastDotIndex);
        System.out.println("servletPath=" + servletPath);

        // 第2步:  hello  -> HelloController
        Object controllerBeanObj = beanMap.get(servletPath);

        String operation = request.getParameter("operation");
        if (StringUtil.isEmpty(operation)) {
            operation = "index";
        }

        try {
            Method[] methods = controllerBeanObj.getClass().getDeclaredMethods();
            for (Method method : methods) {
                if (operation.equals(method.getName())){
                    //1.统一获取请求参数

                    //1-1.获取当前请求方法的参数,返回参数数组
                    Parameter[] parameters = method.getParameters();

                    //1-2.parameterValues用来存放参数的值
                    Object[] parameterValues = new Object[parameters.length];
                    for (int i = 0; i < parameters.length; i++) {
                        Parameter parameter = parameters[i];
                        //不考虑复选框的值,只考虑单选框的值
                        String parameterName = parameter.getName();
                        //如果参数名为request、response、session,那就不是通过请求中获取参数
                        if ("request".equals(parameterName)) {
                            parameterValues[i] = request;
                        } else if ("response".equals(parameterName)) {
                            parameterValues[i] = response;
                        } else if ("session".equals(parameterName)){
                            parameterValues[i] = request.getSession();
                        } else {
                            //从请求中获取参数值
                            String parameterValue = request.getParameter(parameterName);

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

                            parameterValues[i] = parameterObj;
                        }

                    }

                    //2.controller组件中的方法调用
                    method.setAccessible(true);
                    Object methodReturnObj = method.invoke(controllerBeanObj,parameterValues);

                    //3.视图处理
                    String methodReturnStr = (String) methodReturnObj;
                    if (methodReturnStr.startsWith("redirect:")) {//比如 :redirect:fruit.do
                        String redirectStr = methodReturnStr.substring("redirect:".length());
                        response.sendRedirect(redirectStr);
                    } else {
                        super.processTemplate(methodReturnStr,request,response);
                    }

                }
            }
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

FruitController.java

public class FruitController extends ViewBaseServlet {

    private FruitDAO fruitDAO = new FruitDAOImpl();

    private String update(Integer fid,String fname,Integer price,Integer fcount,String remark){

        //3.执行更新
        Fruit fruit = new Fruit(fid, fname,price,fcount,remark);
        fruitDAO.updateFruit(fruit);

        //4.资源跳转
        //response.sendRedirect("fruit.do");
        return "redirect:fruit.do";
    }

    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";
    }

    private String delete(Integer fid) {
        if (fid != null) {
            fruitDAO.delFruit(fid);
            //response.sendRedirect("fruit.do");
            return "redirect:fruit.do";
        }
        return "error";
    }

    private String add(String fname,Integer price,Integer fcount,String remark) {
        Fruit fruit = new Fruit(fname,price,fcount,remark);
        System.out.println(fruit);
        fruitDAO.addFruit(fruit);

        //response.sendRedirect("fruit.do");
        return "redirect:fruit.do";
    }

    private String index(String operate,String keyword,Integer pageNum,HttpServletRequest request) {

        HttpSession session = request.getSession();

        if (pageNum == null) {
            pageNum = 1;
        }

        if (StringUtil.isNotEmpty(operate) && "search".equals(operate)) {
            //说明是点击表单查询发送过来的请求
            //此时,pageNum应该还原为1,keyword应该从请求参数中获取
            pageNum = 1;
            //如果keyword为null,需要设置为"",否则查询时会拼接成 %null%,我们期望的是 %%
            if (StringUtil.isEmpty(keyword)) {
                keyword = "";
            }
            //将keyword保存(覆盖)到session中
            session.setAttribute("keyword",keyword);
        }else {
            //说明此处不是是点击表单查询发送过来的请求,比如点击上一页,下一页或者直接在地址栏输入网址
            //此时keyword 应该从session的作用域获取
            //如果不是点击的查询按钮,那么查询是基于session中保存的现有keyword进行查询
            Object keywordObj = session.getAttribute("keyword");
            if (keywordObj != null) {
                keyword = (String) keywordObj;
            }else {
                keyword = "";
            }
        }

        //重新更新当前页的值
        session.setAttribute("pageNum",pageNum);
        List<Fruit> fruitList = fruitDAO.getFruitList(keyword,pageNum);
        //保存到session作用域
        session.setAttribute("fruitList", fruitList);
        //总记录数
        int count = fruitDAO.getFruitCount(keyword);
        //总页数
        int pageCount = (count + 5 - 1) / 5;
        session.setAttribute("pageCount", pageCount);
        return "index";
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值