WEB由浅入深-03篇

103 阅读13分钟

学习插图.jpg

前篇

分页-pagination

//    查询指定页码的列表信息,每页显示5条信息
    List<Fruit> getAll(Integer pageNo);
@Override
public List<Fruit> getAll(Integer pageNo) {
    String sql = "select * from t_fruit limit ?,5";
    List<Fruit> list = super.QueryList(sql,(pageNo - 1) * 5);
    return list;
}
Integer pageNo = 1;

String pageNoStr = req.getParameter("pageNo");
if (StringUtil.isNotEmpty(pageNoStr)){
    pageNo= Integer.parseInt(pageNoStr);
}

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

function page(pageNo){
    window.location.href = "fruit?pageNo="+pageNo;
}
//    获取所有的条数
    Integer getCount();
@Override
public Integer getCount() {
    String sql = "select count(*) from t_fruit";
    return ((Long)super.getValue(sql)).intValue();
}
    Integer pageCount = fruitService.getCount();
    Integer pageNum = (pageCount + 5 - 1) / 5;
    session.setAttribute("pageNum",pageNum);

        /*
        一页显示5条数据
        * 总记录条数    页数
        * 1           1
        * 5           1
        * 6           2
        * 10          2
        * 11          3
        * 15          3
        * 16          4
        * pageCount   (pageCount + 5 - 1) / 5
        * */

//        转发
        super.processTemplate("index",req,resp);
<table>
         <tr>
            <th>名称</th>
            <th>单价</th>
            <th>数量</th>
            <th>操作</th>
         </tr>
         <tr th:if="${#lists.isEmpty(session.fruitList)}">
            <td colspan="4">对不起,库存为空!</td>
         </tr>
         <tr th:unless="${#lists.isEmpty(session.fruitList)}" th:each="fruit : ${session.fruitList}">
            <td th:text="${fruit.fname}">苹果</td>
            <td th:text="${fruit.price}">12</td>
            <td th:text="${fruit.fcount}">3</td>
            <td>
               <div class="opBtn">
               <input type="button" value="删除"/>
               <input type="button" value="修改" >
               </div>
            </td>
         </tr>
      </table>
   </div>
<div class="pageBtn">
   <input type="button" value="首 页" th:onclick="page(1)" th:disabled="${session.pageNo==1}">
   <input type="button" value="上一页" th:onclick="|page(${session.pageNo-1})|" th:disabled="${session.pageNo==1}">
   <input type="button" value="下一页" th:onclick="|page(${session.pageNo+1})|" th:disabled="${session.pageNo==session.pageNum}">
   <input type="button" value="尾 页" th:onclick="|page(${session.pageNum})|" th:disabled="${session.pageNo==session.pageNum}">
</div>

关键字查询-keyword

<form th:action="@{/index.do}" method="post">
   <input type="hidden" name="oper" value="search">
   请输入关键字:<input type="text" name="keyword" th:value="${session.keyword}">
   <input type="submit" value="查询">
</form>
@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");

        String oper = req.getParameter("oper");

//        如果oper != null,则表示有关键字
//        如果oper == null,则表示没有关键字
        HttpSession session = req.getSession();
        String keyword = null;
        Integer pageNo = 1;
        if (StringUtil.isNotEmpty(oper) && "search".equals(oper)){
//            说明是点击表单过来的,要进行关键字查询
//            此时pageNo还原为1,keyword应该从请求参数中获取
            pageNo = 1;
            keyword = req.getParameter("keyword");
            if (keyword.isEmpty()){
                keyword = "";
            }
            session.setAttribute("keyword",keyword);
        }else{
//            说明此处不是点击表单查询发送过来的请求(比如点击下面的下一页,上一页,或者直接在地址栏输入网址)
//            此时keyword应该从session作用域获取
            String pageNoStr = req.getParameter("pageNo");
            if (StringUtil.isNotEmpty(pageNoStr)){
                pageNo= Integer.parseInt(pageNoStr);
            }
            Object keywordStr = session.getAttribute("keyword");
            if (keywordStr != null){
                keyword = (String) keywordStr;
            }else{
                keyword = "";
            }
        }
        session.setAttribute("pageNo",pageNo);

        List<Fruit> fruitList = fruitService.getAll(pageNo,keyword);
        fruitList.forEach(System.out::println);

        session.setAttribute("fruitList",fruitList);

        Integer pageCount = fruitService.getCount(keyword);
        Integer pageNum = (pageCount + 5 - 1) / 5;
        session.setAttribute("pageNum",pageNum);

        /*
        一页显示5条数据
        * 总记录条数    页数
        * 1           1
        * 5           1
        * 6           2
        * 10          2
        * 11          3
        * 15          3
        * 16          4
        * pageCount   (pageCount + 5 - 1) / 5
        * */

//        转发
        super.processTemplate("index",req,resp);
    }
//    查询指定页码的列表信息,每页显示5条信息
    List<Fruit> getAll(Integer pageNo,String keyword);
    
//    获取所有的条数
    Integer getCount(String keyword);
@Override
public List<Fruit> getAll(Integer pageNo,String keyword) {
    String sql = "select * from t_fruit where fname like ? or remark like ? limit ?,5";
    List<Fruit> list = super.QueryList(sql,"%"+keyword+"%","%"+keyword+"%",(pageNo - 1) * 5);
    return list;
}

@Override
public Integer getCount(String keyword) {
    String sql = "select count(*) from t_fruit where fname like ? or remark like ?";
    return ((Long)super.getValue(sql,"%"+keyword+"%","%"+keyword+"%")).intValue();
}

MVC的演变

Servlet的演变.png

优化一:

将多个Servlet根据前端参数operate合并为一个Servlet,根据分支结构选出参数对应的方法。

/**
 * @author crystal
 * @create 2023-01-12 18:36
 */
@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 operate = request.getParameter("operate");
        if (StringUtil.isEmpty(operate)){
            operate = "index";
        }

        switch (operate){
            case "index":
                index(request,response);
                break;
            case "add":
                add(request,response);
                break;
            case "del":
                del(request,response);
                break;
            default:
                throw new RuntimeException("operate值非法!");
        }
    }

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

            //super.processTemplate("index",request,response);
            response.sendRedirect("fruit.do");
        }
    }

    private void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");

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

        Fruit fruit = new Fruit(0,fname , price , fcount , remark ) ;

        fruitDAO.addFruit(fruit);

        response.sendRedirect("fruit.do");

    }

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

        HttpSession session = request.getSession() ;
        Integer pageNo = 1 ;

        String oper = request.getParameter("oper");
        //如果oper!=null 说明 通过表单的查询按钮点击过来的
        //如果oper是空的,说明 不是通过表单的查询按钮点击过来的

        String keyword = null ;
        if(StringUtil.isNotEmpty(oper) && "search".equals(oper)){
            //说明是点击表单查询发送过来的请求
            //此时,pageNo应该还原为1 , keyword应该从请求参数中获取
            pageNo = 1 ;
            keyword = request.getParameter("keyword");
            if(StringUtil.isEmpty(keyword)){
                keyword = "" ;
            }
            session.setAttribute("keyword",keyword);
        }else{
            //说明此处不是点击表单查询发送过来的请求(比如点击下面的上一页下一页或者直接在地址栏输入网址)
            //此时keyword应该从session作用域获取
            String pageNoStr = request.getParameter("pageNo");
            if(StringUtil.isNotEmpty(pageNoStr)){
                pageNo = Integer.parseInt(pageNoStr);
            }
            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 ;
        /*
        总记录条数       总页数
        1               1
        5               1
        6               2
        10              2
        11              3
        fruitCount      (fruitCount+5-1)/5
         */
        session.setAttribute("pageCount",pageCount);

        //此处的视图名称是 index
        //那么thymeleaf会将这个 逻辑视图名称 对应到 物理视图 名称上去
        //逻辑视图名称 :   index
        //物理视图名称 :   view-prefix + 逻辑视图名称 + view-suffix
        //所以真实的视图名称是:      /       index       .html
        super.processTemplate("index",request,response);
    }

}

前端请求 (代码片段):

<td><a th:text="${fruit.fname}" th:href="@{/fruit.do(fid=${fruit.fid},operate='edit')}">苹果</a></td>
<form th:action="@{/fruit.do}" method="post" style="float:left;width:60%;margin-left:20%;">
   <input type="hidden" name="oper" value="search"/>
function delFruit(fid){
    if(confirm('是否确认删除?')){
        window.location.href='fruit.do?fid='+fid+'&operate=del';
    }
}

function page(pageNo){
    window.location.href="fruit.do?pageNo="+pageNo;
}
<form th:action="@{/fruit.do}" method="post" th:object="${fruit}">
   <input type="hidden" name="operate" value="update">
<form action="fruit.do" method="post">
   <input type="hidden" name="operate" value="add">

优化二(reflect):

/**
 * @author crystal
 * @create 2023-01-12 18:36
 */
@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 operate = request.getParameter("operate");
        if (StringUtil.isEmpty(operate)){
            operate = "index";
        }

//        通过反射获取当前类中的所有方法
        Method[] methods = this.getClass().getDeclaredMethods();
        for(Method method : methods){
            String methodName = method.getName();
            if (operate.equals(methodName)){
                try {
                    method.invoke(this,request,response);
                    return;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        throw new RuntimeException("operate值非法!");
    }

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

        //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 ));

        //4.资源跳转
        //super.processTemplate("index",request,response);
        //request.getRequestDispatcher("index.html").forward(request,response);
        //此处需要重定向,目的是重新给IndexServlet发请求,重新获取furitList,然后覆盖到session中,这样index.html页面上显示的session中的数据才是最新的
        response.sendRedirect("fruit.do");
    }

    private void edit(HttpServletRequest request , HttpServletResponse response)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);
        }
    }
    private void del(HttpServletRequest request , HttpServletResponse response)throws IOException, ServletException {
        String fidStr = request.getParameter("fid");
        if(StringUtil.isNotEmpty(fidStr)){
            int fid = Integer.parseInt(fidStr);
            fruitDAO.delFruit(fid);

            //super.processTemplate("index",request,response);
            response.sendRedirect("fruit.do");
        }
    }

    private void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");

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

        Fruit fruit = new Fruit(0,fname , price , fcount , remark ) ;

        fruitDAO.addFruit(fruit);

        response.sendRedirect("fruit.do");

    }

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

        HttpSession session = request.getSession() ;
        Integer pageNo = 1 ;

        String oper = request.getParameter("oper");
        //如果oper!=null 说明 通过表单的查询按钮点击过来的
        //如果oper是空的,说明 不是通过表单的查询按钮点击过来的

        String keyword = null ;
        if(StringUtil.isNotEmpty(oper) && "search".equals(oper)){
            //说明是点击表单查询发送过来的请求
            //此时,pageNo应该还原为1 , keyword应该从请求参数中获取
            pageNo = 1 ;
            keyword = request.getParameter("keyword");
            if(StringUtil.isEmpty(keyword)){
                keyword = "" ;
            }
            session.setAttribute("keyword",keyword);
        }else{
            //说明此处不是点击表单查询发送过来的请求(比如点击下面的上一页下一页或者直接在地址栏输入网址)
            //此时keyword应该从session作用域获取
            String pageNoStr = request.getParameter("pageNo");
            if(StringUtil.isNotEmpty(pageNoStr)){
                pageNo = Integer.parseInt(pageNoStr);
            }
            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 ;
        /*
        总记录条数       总页数
        1               1
        5               1
        6               2
        10              2
        11              3
        fruitCount      (fruitCount+5-1)/5
         */
        session.setAttribute("pageCount",pageCount);

        //此处的视图名称是 index
        //那么thymeleaf会将这个 逻辑视图名称 对应到 物理视图 名称上去
        //逻辑视图名称 :   index
        //物理视图名称 :   view-prefix + 逻辑视图名称 + view-suffix
        //所以真实的视图名称是:      /       index       .html
        super.processTemplate("index",request,response);
    }

}

优化三(DispatcherServlet):

part 01

/**
 * @author crystal
 * @create 2023-01-12 22:33
 */
@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");

//        获取请求的url:http://localhost:8080/pro/hello.do
//        第一步:getServletPath()   获取/hello.do
        String servletPath = request.getServletPath();
//        第二步:从/hello.do获取hello.do
        servletPath = servletPath.substring(1);
//        获取.do的索引
        int lastDotIndexOf = servletPath.lastIndexOf(".do");
        servletPath = servletPath.substring(0,lastDotIndexOf);
//        第三步:将获取到的hello ——> HelloController



    }
}

applicationContext.xml

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

<beans>
    <bean id = "fruit" class = "com.atguigu.fruit.controllers.FruitController"></bean>
</beans>
/**
 * @author crystal
 * @create 2023-01-12 18:36
 */
//@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 operate = request.getParameter("operate");
        if (StringUtil.isEmpty(operate)){
            operate = "index";
        }

//        通过反射获取当前类中的所有方法
        Method[] methods = this.getClass().getDeclaredMethods();
        for(Method method : methods){
            String methodName = method.getName();
            if (operate.equals(methodName)){
                try {
                    method.invoke(this,request,response);
                    return;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        throw new RuntimeException("operate值非法!");
    }

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

        //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 ));

        //4.资源跳转
        //super.processTemplate("index",request,response);
        //request.getRequestDispatcher("index.html").forward(request,response);
        //此处需要重定向,目的是重新给IndexServlet发请求,重新获取furitList,然后覆盖到session中,这样index.html页面上显示的session中的数据才是最新的
        response.sendRedirect("fruit.do");
    }

    private void edit(HttpServletRequest request , HttpServletResponse response)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);
        }
    }
    private void del(HttpServletRequest request , HttpServletResponse response)throws IOException, ServletException {
        String fidStr = request.getParameter("fid");
        if(StringUtil.isNotEmpty(fidStr)){
            int fid = Integer.parseInt(fidStr);
            fruitDAO.delFruit(fid);

            //super.processTemplate("index",request,response);
            response.sendRedirect("fruit.do");
        }
    }

    private void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");

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

        Fruit fruit = new Fruit(0,fname , price , fcount , remark ) ;

        fruitDAO.addFruit(fruit);

        response.sendRedirect("fruit.do");

    }

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

        HttpSession session = request.getSession() ;
        Integer pageNo = 1 ;

        String oper = request.getParameter("oper");
        //如果oper!=null 说明 通过表单的查询按钮点击过来的
        //如果oper是空的,说明 不是通过表单的查询按钮点击过来的

        String keyword = null ;
        if(StringUtil.isNotEmpty(oper) && "search".equals(oper)){
            //说明是点击表单查询发送过来的请求
            //此时,pageNo应该还原为1 , keyword应该从请求参数中获取
            pageNo = 1 ;
            keyword = request.getParameter("keyword");
            if(StringUtil.isEmpty(keyword)){
                keyword = "" ;
            }
            session.setAttribute("keyword",keyword);
        }else{
            //说明此处不是点击表单查询发送过来的请求(比如点击下面的上一页下一页或者直接在地址栏输入网址)
            //此时keyword应该从session作用域获取
            String pageNoStr = request.getParameter("pageNo");
            if(StringUtil.isNotEmpty(pageNoStr)){
                pageNo = Integer.parseInt(pageNoStr);
            }
            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 ;
        /*
        总记录条数       总页数
        1               1
        5               1
        6               2
        10              2
        11              3
        fruitCount      (fruitCount+5-1)/5
         */
        session.setAttribute("pageCount",pageCount);

        //此处的视图名称是 index
        //那么thymeleaf会将这个 逻辑视图名称 对应到 物理视图 名称上去
        //逻辑视图名称 :   index
        //物理视图名称 :   view-prefix + 逻辑视图名称 + view-suffix
        //所以真实的视图名称是:      /       index       .html
        super.processTemplate("index",request,response);
    }

}

part02

/**
 * @author crystal
 * @create 2023-01-12 22:33
 */
@WebServlet("*.do")
public class DispatcherServlet extends HttpServlet {

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

    public void init(ServletConfig servletConfig){
        try {
//        读取配置文件,将实例装进map集合
            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 id = beanElement.getAttribute("id");
                    String className = beanElement.getAttribute("class");
                    Class<?> clazz = Class.forName(className);
                    Object classObj = clazz.newInstance();
                    beanMap.put(id,classObj);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


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

//        获取请求的url:http://localhost:8080/pro/hello.do
//        第一步:getServletPath()   获取/hello.do
        String servletPath = request.getServletPath();
//        第二步:从/hello.do获取hello.do
        servletPath = servletPath.substring(1);
//        获取.do的索引
        int lastDotIndexOf = servletPath.lastIndexOf(".do");
        servletPath = servletPath.substring(0,lastDotIndexOf);
//        第三步:将获取到的hello ——> HelloController

        Object beanObj = beanMap.get(servletPath);

//        获取前端的参数operate
        String operate = request.getParameter("operate");
        if (operate == null){
            operate = "index";
        }

//        根据反射调用方法
        try {
            Method method = beanObj.getClass().getDeclaredMethod(operate, HttpServletRequest.class, HttpServletResponse.class);
            if (method != null){
                method.setAccessible(true);
                method.invoke(beanObj,request,response);
            }else{
                throw new RuntimeException("operate的值非法!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
part03(视图处理)
/**
 * @author crystal
 * @create 2023-01-12 22:33
 */
@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet {

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

    public DispatcherServlet(){
    }

    public void init() throws ServletException {
        super.init();
        try {
//        读取配置文件,将实例装进map集合
            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 id = beanElement.getAttribute("id");
                    String className = beanElement.getAttribute("class");
                    Class<?> clazz = Class.forName(className);
                    Object classObj = clazz.newInstance();
                    beanMap.put(id,classObj);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


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

//        获取请求的url:http://localhost:8080/pro/hello.do
//        第一步:getServletPath()   获取/hello.do
        String servletPath = request.getServletPath();
//        第二步:从/hello.do获取hello.do
        servletPath = servletPath.substring(1);
//        获取.do的索引
        int lastDotIndexOf = servletPath.lastIndexOf(".do");
        servletPath = servletPath.substring(0,lastDotIndexOf);
//        第三步:将获取到的hello ——> HelloController

        Object beanObj = beanMap.get(servletPath);

//        获取前端的参数operate
        String operate = request.getParameter("operate");
        if (operate == null){
            operate = "index";
        }

//        根据反射调用方法
        try {
            Method method = beanObj.getClass().getDeclaredMethod(operate, HttpServletRequest.class);
            if (method != null){
//                调用controller中对应的方法
                method.setAccessible(true);
                Object ObjStr = method.invoke(beanObj,request);

//                视图处理
                String returnStr = (String) ObjStr;
                if (returnStr.startsWith("redirect:")){
                    String redirectVal = returnStr.substring("redirect:".length());
                    response.sendRedirect(redirectVal);
                }else{
                    super.processTemplate(returnStr,request,response);
                }
            }else{
                throw new RuntimeException("operate的值非法!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
/**
 * @author crystal
 * @create 2023-01-12 18:36
 */
public class FruitController{

    private FruitDAO fruitDAO = new FruitDAOImpl();

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

        //4.资源跳转
        //super.processTemplate("index",request,response);
        //request.getRequestDispatcher("index.html").forward(request,response);
        //此处需要重定向,目的是重新给IndexServlet发请求,重新获取furitList,然后覆盖到session中,这样index.html页面上显示的session中的数据才是最新的
//        response.sendRedirect("fruit.do");
        return "redirect:fruit.do";
    }

    private String edit(HttpServletRequest request )throws IOException {
        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";
    }
    private String del(HttpServletRequest request)throws IOException {
        String fidStr = request.getParameter("fid");
        if(StringUtil.isNotEmpty(fidStr)){
            int fid = Integer.parseInt(fidStr);
            fruitDAO.delFruit(fid);

            //super.processTemplate("index",request,response);
//            response.sendRedirect("fruit.do");
            return "redirect:fruit.do";
        }
        return "error";
    }

    private String add(HttpServletRequest request) throws ServletException {
        String fname = request.getParameter("fname");
        Integer price = Integer.parseInt(request.getParameter("price")) ;
        Integer fcount = Integer.parseInt(request.getParameter("fcount"));
        String remark = request.getParameter("remark");

        Fruit fruit = new Fruit(0,fname , price , fcount , remark ) ;

        fruitDAO.addFruit(fruit);

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

    private String index(HttpServletRequest request)throws IOException {

        HttpSession session = request.getSession() ;
        Integer pageNo = 1 ;

        String oper = request.getParameter("oper");
        //如果oper!=null 说明 通过表单的查询按钮点击过来的
        //如果oper是空的,说明 不是通过表单的查询按钮点击过来的

        String keyword = null ;
        if(StringUtil.isNotEmpty(oper) && "search".equals(oper)){
            //说明是点击表单查询发送过来的请求
            //此时,pageNo应该还原为1 , keyword应该从请求参数中获取
            pageNo = 1 ;
            keyword = request.getParameter("keyword");
            if(StringUtil.isEmpty(keyword)){
                keyword = "" ;
            }
            session.setAttribute("keyword",keyword);
        }else{
            //说明此处不是点击表单查询发送过来的请求(比如点击下面的上一页下一页或者直接在地址栏输入网址)
            //此时keyword应该从session作用域获取
            String pageNoStr = request.getParameter("pageNo");
            if(StringUtil.isNotEmpty(pageNoStr)){
                pageNo = Integer.parseInt(pageNoStr);
            }
            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 ;
        /*
        总记录条数       总页数
        1               1
        5               1
        6               2
        10              2
        11              3
        fruitCount      (fruitCount+5-1)/5
         */
        session.setAttribute("pageCount",pageCount);

        //此处的视图名称是 index
        //那么thymeleaf会将这个 逻辑视图名称 对应到 物理视图 名称上去
        //逻辑视图名称 :   index
        //物理视图名称 :   view-prefix + 逻辑视图名称 + view-suffix
        //所以真实的视图名称是:      /       index       .html
//        super.processTemplate("index",request,response);
        return "index";
    }
}
part04(参数提取)
/**
 * @author crystal
 * @create 2023-01-12 22:33
 */
@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet {

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

    public DispatcherServlet(){
    }

    public void init() throws ServletException {
        super.init();
        try {
//        读取配置文件,将实例装进map集合
            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 id = beanElement.getAttribute("id");
                    String className = beanElement.getAttribute("class");
                    Class<?> clazz = Class.forName(className);
                    Object classObj = clazz.newInstance();
                    beanMap.put(id,classObj);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


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

//        获取请求的url:http://localhost:8080/pro/hello.do
//        第一步:getServletPath()   获取/hello.do
        String servletPath = request.getServletPath();
//        第二步:从/hello.do获取hello.do
        servletPath = servletPath.substring(1);
//        获取.do的索引
        int lastDotIndexOf = servletPath.lastIndexOf(".do");
        servletPath = servletPath.substring(0,lastDotIndexOf);
//        第三步:将获取到的hello ——> HelloController

        Object beanObj = beanMap.get(servletPath);

//        获取前端的参数operate
        String operate = request.getParameter("operate");
        if (operate == null){
            operate = "index";
        }

//        根据反射调用方法
        try {
//            1. 统一获取请求参数
            Method[] methods = beanObj.getClass().getDeclaredMethods();
            for (Method method : methods){
                if(operate.equals(method.getName())){

                    Parameter[] parameters = method.getParameters();

//                创建数组,用来承载方法中参数的值
                    Object[] parameterVals = new Object[parameters.length];

                    for (int i = 0; i < parameters.length; i++) {
                        Parameter parameter = parameters[i];


                        String parameterName = parameter.getName();
                        if ("request".equals(parameterName)){
                            parameterVals[i] = "request";
                        }else if("response".equals(parameterName)){
                            parameterVals[i] = "response";
                        }else if ("session".equals(parameterName)){
                            parameterVals[i] = request.getSession();
                        }else{
                            String parameterValue = request.getParameter(parameterName);

                            Class<?> typeName = parameter.getType();
                            parameterVals[i] = parameterValue;
                            Object parameterObj = parameterVals[i];
                            if (parameterObj != null){
                                if ("iava.lang.Integer".equals(typeName)){
                                    parameterObj = Integer.parseInt(parameterValue);
                                }
                                parameterVals[i] = parameterObj;
                            }

                        }
                    }
//                调用controller中对应的方法
                    method.setAccessible(true);
                    Object ObjStr = method.invoke(beanObj,parameterVals);

//                视图处理
                    String returnStr = (String) ObjStr;
                    if (returnStr.startsWith("redirect:")){
                        String redirectVal = returnStr.substring("redirect:".length());
                        response.sendRedirect(redirectVal);
                    }else{
                        super.processTemplate(returnStr,request,response);
                    }
                }
            }
        } catch (Exception e) {
        e.printStackTrace();
    }
    }
}
/**
 * @author crystal
 * @create 2023-01-12 18:36
 */
public class FruitController{

    private FruitDAO fruitDAO = new FruitDAOImpl();

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

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

        //4.资源跳转
        //super.processTemplate("index",request,response);
        //request.getRequestDispatcher("index.html").forward(request,response);
        //此处需要重定向,目的是重新给IndexServlet发请求,重新获取furitList,然后覆盖到session中,这样index.html页面上显示的session中的数据才是最新的
//        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 del(Integer fid)throws IOException {
        if(fid != null){
            fruitDAO.delFruit(fid);
            //super.processTemplate("index",request,response);
//            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(0,fname , price , fcount , remark ) ;
        fruitDAO.addFruit(fruit);
//        response.sendRedirect("fruit.do");
        return "redirect:fruit.do";
    }

    private String index(String oper,String keyword,Integer pageNo,HttpServletRequest request) {

        HttpSession session = request.getSession() ;

        //如果oper!=null 说明 通过表单的查询按钮点击过来的
        //如果oper是空的,说明 不是通过表单的查询按钮点击过来的
        if (pageNo == null){
            pageNo = 1;
        }

        if(StringUtil.isNotEmpty(oper) && "search".equals(oper)){
            //说明是点击表单查询发送过来的请求
            //此时,pageNo应该还原为1 , keyword应该从请求参数中获取
            pageNo = 1 ;
            if(StringUtil.isEmpty(keyword)){
                keyword = "" ;
            }
            session.setAttribute("keyword",keyword);
        }else{
            //说明此处不是点击表单查询发送过来的请求(比如点击下面的上一页下一页或者直接在地址栏输入网址)
            //此时keyword应该从session作用域获取
            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 ;
        /*
        总记录条数       总页数
        1               1
        5               1
        6               2
        10              2
        11              3
        fruitCount      (fruitCount+5-1)/5
         */
        session.setAttribute("pageCount",pageCount);

        //此处的视图名称是 index
        //那么thymeleaf会将这个 逻辑视图名称 对应到 物理视图 名称上去
        //逻辑视图名称 :   index
        //物理视图名称 :   view-prefix + 逻辑视图名称 + view-suffix
        //所以真实的视图名称是:      /       index       .html
//        super.processTemplate("index",request,response);
        return "index";
    }
}