Java web 2022跟学尚硅谷(四) 后端基础

MVC

当前模式

MVC

优化后的模式1.8

更改后的模式

FruitServlet

package com.atguigu.fruit.servlets;

import com.atguigu.fruit.myspringmvc.ViewBaseServlet;
import com.atguigu.fruit.pojo.Fruit;
import com.atguigu.fruit.service.FruitService;
import com.atguigu.uils.StringUtils;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;

/**
 * @ClassName: FruitServlet
 * @Description:
 * @Author: wty
 * @Date: 2022/12/6
 */
@WebServlet("/fruit.do")
public class FruitServlet extends ViewBaseServlet {
    private FruitService fruitService = new FruitService();

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

        String operate = request.getParameter("operate");
        if (StringUtils.isEmpty(operate)) {
            operate = "index";
        }

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

    private void index(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        List<Fruit> fruitList = null;
        // 分页查询(增加参数pageNumber)
        Integer pageNumber = 1;
        int sum = 0;
        HttpSession session = request.getSession();

        // 模糊查询
        String oper = request.getParameter("oper");
        String keyword = null;
        if (StringUtils.isNotEmpty(oper) && "search".equals(oper)) {
            // 相当于是模糊查询
            keyword = request.getParameter("keyword");
            if (StringUtils.isEmpty(keyword)) {
                keyword = "";
            }
            pageNumber = 1;
        } else {
            // 说明此处不是模糊查询,此时keyword应该从session作用域获取

            // 分页查询(增加参数pageNumber)
            String pageNumberStr = request.getParameter("pageNumber");
            if (StringUtils.isNotEmpty(pageNumberStr)) {
                pageNumber = Integer.parseInt(pageNumberStr);
            }
            Object keywordObj = session.getAttribute("keyword");
            if (null != keywordObj) {
                keyword = (String) keywordObj;
            } else {
                keyword = "";
            }
        }
        // 将keyword从session作用域获取
        session.setAttribute("keyword", keyword);

        fruitList = fruitService.getFruitList(pageNumber, keyword);


        // 非分页,显示全部,更新当前页的值
        session.setAttribute("pageNumber", pageNumber);

        // 获取总条数
        sum = fruitService.getFruitCount(keyword);
        // 获取总页数pageCount
        session.setAttribute("pageCount", ((sum + 5 - 1) / 5));

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

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

    }

    private void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        // 判断是doGet还是doPost
        if (StringUtils.isEmpty(request.getParameter("fname"))
                || StringUtils.isEmpty(request.getParameter("price"))
                || StringUtils.isEmpty(request.getParameter("fcount"))) {
            processTemplate("add", request, response);
            return;
        }
        // 获取参数
        String fname = request.getParameter("fname");

        String priceStr = request.getParameter("price");
        Integer price = Integer.parseInt(priceStr);

        String fcountStr = request.getParameter("fcount");
        Integer fcount = Integer.parseInt(fcountStr);

        String remark = request.getParameter("remark");
        fruitService.addFruit(new Fruit(0, fname, price, fcount, remark));
        response.sendRedirect("fruit.do");
    }

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

            //fruitService
            fruitService.delFruitByFid(fid);
            response.sendRedirect("fruit.do");
        }
    }

    private void edit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String fidStr = request.getParameter("fid");
        if (StringUtils.isNotEmpty(fidStr)) {
            Integer fid = Integer.parseInt(fidStr);

            Fruit fruit = fruitService.getFruitByFid(fid);
            request.setAttribute("fruit", fruit);
            processTemplate("edit", request, response);
        }

    }

    private void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        // 获取参数
        String fidStr = request.getParameter("fid");
        Integer fid = Integer.parseInt(fidStr);

        String fname = request.getParameter("fname");

        String priceStr = request.getParameter("price");
        Integer price = Integer.parseInt(priceStr);

        String fcountStr = request.getParameter("fcount");
        Integer fcount = Integer.parseInt(fcountStr);

        String remark = request.getParameter("remark");
        //  执行更新
        fruitService.updateFruitByFid(new Fruit(fid, fname, price, fcount, remark));
        // 资源跳转
        //processTemplate("index", request, response);
        // 此处需要重定向,目的是重新给indexServlet发请求,重新获取fruitList然后覆盖到session中的数据才是最新的
        response.sendRedirect("fruit.do");
    }

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

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

index.js

function delFruit(fid) {
    if (confirm("是否确认删除?")) {
        window.location.href = "fruit.do?fid=" + fid + "&operate=del";
    }
}

function page(pageNumber) {
    window.location.href = "fruit.do?pageNumber=" + pageNumber;
}

add.html

<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"></meta>
    <link rel="stylesheet" href="css/add.css" type="text/css"></link>
</head>
<body>
<div id="div_container">
    <div id="div_fruit_list">
        <p class="center_p f32">添加库存信息</p>
        <form th:action="@{/fruit.do}" method="post">
            <input type="hidden" name="operate" value="add"></input>
            <table id="table_fruit">
                <tr>
                    <th class="w20">名称:</th>
                    <td><input type="text" name="fname"/></td>
                </tr>
                <tr>
                    <th class="w20">单价:</th>
                    <td><input type="text" name="price"/></td>
                </tr>
                <tr>
                    <th class="w20">库存:</th>
                    <td><input type="text" name="fcount"/></td>
                </tr>
                <tr>
                    <th class="w20">备注:</th>
                    <td><input type="text" name="remark"/></td>
                </tr>
                <tr>
                    <th colspan="2">
                        <input type="submit" value="添加"/>
                    </th>
                </tr>
            </table>
        </form>
    </div>
</div>
</body>
</html>

index.html

<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="css/index.css"></link>
    <script language="JavaScript" src="js/index.js"></script>
</head>
<body>
<div id="div_container">
    <div id="div_fruit_list">
        <p class="center_p f32">欢迎使用水果库存后台管理系统</p>
        <div id="div_add">
            <form id="form_search" th:action="@{/fruit.do}" method="post">
                <input type="hidden" name="oper" value="search"></input>
                请输入查询关键字:<input type="text" name="keyword" th:value="${session.keyword}"></input>
                <input type="submit" value="查询"></input>
            </form>
            <a th:href="@{/fruit.do(operate = 'add')}" id="a_add">添加库存记录</a>
        </div>
        <table id="table_fruit">
            <tr>
                <th class="w20">名称</th>
                <th class="w20">单价</th>
                <th class="w20">库存</th>
                <th class="w20">操作</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><a th:text="${fruit.fname}" th:href="@{'/edit.do?fid='+${fruit.fid}}">苹果</a></td>-->
                <td><a th:text="${fruit.fname}" th:href="@{/fruit.do(fid=${fruit.fid},operate = 'edit')}">苹果</a></td>
                <td th:text="${fruit.price}">5</td>
                <td th:text="${fruit.fcount}">20</td>
                <!--<td><img src="imgs/del.jpeg" class="delImg" th:οnclick="'delFruit('+${fruit.fid}+')'"></img></td>-->
                <td><img src="imgs/del.jpeg" class="delImg" th:onclick="|delFruit(${fruit.fid})|"></img></td>
            </tr>

        </table>
        <div id="div_page">
            <div>
                <input type="button" value="首  页" th:onclick="page(1)" th:disabled="${session.pageNumber==1}"></input>
                <input type="button" value="上一页" th:onclick="|page(${session.pageNumber - 1})|"
                       th:disabled="${session.pageNumber==1}"></input>
                <input type="button" value="下一页" th:onclick="|page(${session.pageNumber + 1})|"
                       th:disabled="${session.pageNumber==session.pageCount}"></input>
                <input type="button" value="尾  页" th:onclick="|page(${session.pageCount})|"
                       th:disabled="${session.pageNumber==session.pageCount}"></input>
            </div>
        </div>
    </div>
</div>
</body>
</html>

edit.html

<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"></meta>
    <link rel="stylesheet" href="css/edit.css" type="text/css"></link>
</head>
<body>
<div id="div_container">
    <div id="div_fruit_list">
        <p class="center_p f32">编辑库存信息</p>
        <form th:action="@{/fruit.do}" method="post" th:object="${fruit}">
            <input type="hidden" name="operate" value="update"></input>
            <!--隐藏域:功能类似于文本框,它的值会随着表单的发送也会发送给服务器,但是界面上用户看不到-->
            <input type="hidden" name="fid" th:value="*{fid}"/>
            <table id="table_fruit">
                <tr>
                    <th class="w20">名称:</th>
                    <!--<td><input type="text" name="fname" th:value="${fruit.fname}"></td>-->
                    <td><input type="text" name="fname" th:value="*{fname}"/></td>
                </tr>
                <tr>
                    <th class="w20">单价</th>
                    <!--<td><input type="text" name="price" th:value="${fruit.price}"></td>-->
                    <td><input type="text" name="price" th:value="*{price}"/></td>
                </tr>
                <tr>
                    <th class="w20">库存</th>
                    <!--<td><input type="text" name="fcount" th:value="${fruit.fcount}"></td>-->
                    <td><input type="text" name="fcount" th:value="*{fcount}"/></td>
                </tr>
                <tr>
                    <th class="w20">备注</th>
                    <!--<td><input type="text" name="remark" th:value="${fruit.remark}"></td>-->
                    <td><input type="text" name="remark" th:value="*{remark}"/></td>
                </tr>
                <tr>
                    <th colspan="2">
                        <input type="submit" value="修改"/>
                    </th>
                </tr>
            </table>
        </form>
    </div>
</div>
</body>
</html>

继续优化:利用反射1.9

package com.atguigu.fruit.servlets;

import com.atguigu.fruit.myspringmvc.ViewBaseServlet;
import com.atguigu.fruit.pojo.Fruit;
import com.atguigu.fruit.service.FruitService;
import com.atguigu.uils.StringUtils;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

/**
 * @ClassName: FruitServlet
 * @Description:
 * @Author: wty
 * @Date: 2022/12/6
 */
@WebServlet("/fruit.do")
public class FruitServlet extends ViewBaseServlet {
    private FruitService fruitService = new FruitService();

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

        String operate = request.getParameter("operate");
        if (StringUtils.isEmpty(operate)) {
            operate = "index";
        }

        // 获取当前类中的所有方法
        Method[] methods = this.getClass().getDeclaredMethods();
        for (Method method : methods) {
            String name = method.getName();
            if (operate.equals(name)) {
                // 找到和operate一样名称的方法,用反射调用
                try {
                    method.invoke(this, request, response);
                    return;
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
        throw new RuntimeException("operate值非法!");
    }

    private void index(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        List<Fruit> fruitList = null;
        // 分页查询(增加参数pageNumber)
        Integer pageNumber = 1;
        int sum = 0;
        HttpSession session = request.getSession();

        // 模糊查询
        String oper = request.getParameter("oper");
        String keyword = null;
        if (StringUtils.isNotEmpty(oper) && "search".equals(oper)) {
            // 相当于是模糊查询
            keyword = request.getParameter("keyword");
            if (StringUtils.isEmpty(keyword)) {
                keyword = "";
            }
            pageNumber = 1;
        } else {
            // 说明此处不是模糊查询,此时keyword应该从session作用域获取

            // 分页查询(增加参数pageNumber)
            String pageNumberStr = request.getParameter("pageNumber");
            if (StringUtils.isNotEmpty(pageNumberStr)) {
                pageNumber = Integer.parseInt(pageNumberStr);
            }
            Object keywordObj = session.getAttribute("keyword");
            if (null != keywordObj) {
                keyword = (String) keywordObj;
            } else {
                keyword = "";
            }
        }
        // 将keyword从session作用域获取
        session.setAttribute("keyword", keyword);

        fruitList = fruitService.getFruitList(pageNumber, keyword);


        // 非分页,显示全部,更新当前页的值
        session.setAttribute("pageNumber", pageNumber);

        // 获取总条数
        sum = fruitService.getFruitCount(keyword);
        // 获取总页数pageCount
        session.setAttribute("pageCount", ((sum + 5 - 1) / 5));

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

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

    }

    private void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        // 判断是doGet还是doPost
        if (StringUtils.isEmpty(request.getParameter("fname"))
                || StringUtils.isEmpty(request.getParameter("price"))
                || StringUtils.isEmpty(request.getParameter("fcount"))) {
            processTemplate("add", request, response);
            return;
        }
        // 获取参数
        String fname = request.getParameter("fname");

        String priceStr = request.getParameter("price");
        Integer price = Integer.parseInt(priceStr);

        String fcountStr = request.getParameter("fcount");
        Integer fcount = Integer.parseInt(fcountStr);

        String remark = request.getParameter("remark");
        fruitService.addFruit(new Fruit(0, fname, price, fcount, remark));
        response.sendRedirect("fruit.do");
    }

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

            //fruitService
            fruitService.delFruitByFid(fid);
            response.sendRedirect("fruit.do");
        }
    }

    private void edit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String fidStr = request.getParameter("fid");
        if (StringUtils.isNotEmpty(fidStr)) {
            Integer fid = Integer.parseInt(fidStr);

            Fruit fruit = fruitService.getFruitByFid(fid);
            request.setAttribute("fruit", fruit);
            processTemplate("edit", request, response);
        }

    }

    private void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        // 获取参数
        String fidStr = request.getParameter("fid");
        Integer fid = Integer.parseInt(fidStr);

        String fname = request.getParameter("fname");

        String priceStr = request.getParameter("price");
        Integer price = Integer.parseInt(priceStr);

        String fcountStr = request.getParameter("fcount");
        Integer fcount = Integer.parseInt(fcountStr);

        String remark = request.getParameter("remark");
        //  执行更新
        fruitService.updateFruitByFid(new Fruit(fid, fname, price, fcount, remark));
        // 资源跳转
        //processTemplate("index", request, response);
        // 此处需要重定向,目的是重新给indexServlet发请求,重新获取fruitList然后覆盖到session中的数据才是最新的
        response.sendRedirect("fruit.do");
    }

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

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

优化2.0

dispatcher

架构图

架构图

DispatcherServlet

package com.atguigu.myssm.myspringmvc;

import com.atguigu.uils.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @ClassName: DispatcherServlet
 * @Description:
 * @Author: wty
 * @Date: 2022/12/7
 */
@WebServlet("*.do")
public class DispatcherServlet extends HttpServlet {
    private Map<String, Object> beanMap = new HashMap<>();

    /**
     * @param
     * @return
     * @description 解析配置文件
     * @date 2022/12/7 12:10
     * @author wty
     **/
    public DispatcherServlet() {

    }

    @Override
    public void init() throws ServletException {
        InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
        // 1.创建DocumentBuilderFactory
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        // 2.创建DocumentBuilder
        try {
            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<?> beanObj = Class.forName(className);
                    // 类对象
                    Object o = beanObj.newInstance();

                    // 加入servletContext
                    //Field servletContextField = beanObj.getDeclaredField("servletContext");
                    //servletContextField.setAccessible(true);
                    //servletContextField.set(o, this.getServletContext());

                    Method setServletContext = beanObj.getDeclaredMethod("setServletContext", ServletContext.class);
                    setServletContext.invoke(o, this.getServletContext());

                    beanMap.put(beanId, o);
                }
            }


        } catch (ParserConfigurationException | InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        } catch (IOException | InvocationTargetException e) {
            e.printStackTrace();
        } catch (SAXException | ClassNotFoundException | NoSuchMethodException 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

        String servletPath = request.getServletPath();
        /// hello.do
        System.out.println(servletPath);

        // 1.字符串截取 hello.do 得到 hello
        servletPath = servletPath.substring(1, servletPath.length() - 3);
        System.out.println(servletPath);

        // 2. hello 和 helloController对应上
        Object contorllerBeanObject = beanMap.get(servletPath);


        // 下面的逻辑来自于FruitController
        String operate = request.getParameter("operate");
        if (StringUtils.isEmpty(operate)) {
            operate = "index";
        }

        try {
            Method declaredMethod = contorllerBeanObject.getClass().getDeclaredMethod(operate, HttpServletRequest.class, HttpServletResponse.class);
            if (declaredMethod != null) {
                declaredMethod.setAccessible(true);
                declaredMethod.invoke(contorllerBeanObject, request, response);
            } else {
                throw new RuntimeException("operate值非法!");
            }
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

ViewBaseServlet

package com.atguigu.myssm.myspringmvc;

import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @ClassName: ViewBaseServlet
 * @Description:
 * @Author: wty
 * @Date: 2022/12/5
 */

public class ViewBaseServlet extends HttpServlet {

    private TemplateEngine templateEngine;
    private ServletContext servletContext;

    public void init(ServletContext servletContext) throws ServletException {

        // 1.获取ServletContext对象
        //ServletContext servletContext = this.getServletContext();
        //servletContext = this.getServletContext();
        this.servletContext = servletContext;

        // 2.创建Thymeleaf解析器对象
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);

        // 3.给解析器对象设置参数
        // ①HTML是默认模式,明确设置是为了代码更容易理解
        templateResolver.setTemplateMode(TemplateMode.HTML);

        // ②设置前缀
        String viewPrefix = servletContext.getInitParameter("view-prefix");

        templateResolver.setPrefix(viewPrefix);

        // ③设置后缀
        String viewSuffix = servletContext.getInitParameter("view-suffix");

        templateResolver.setSuffix(viewSuffix);

        // ④设置缓存过期时间(毫秒)
        templateResolver.setCacheTTLMs(60000L);

        // ⑤设置是否缓存
        templateResolver.setCacheable(true);

        // ⑥设置服务器端编码方式
        templateResolver.setCharacterEncoding("utf-8");

        // 4.创建模板引擎对象
        templateEngine = new TemplateEngine();

        // 5.给模板引擎对象设置模板解析器
        templateEngine.setTemplateResolver(templateResolver);

    }

    /**
     * @param
     * @return void
     * @description 完成资源的转发和视图的渲染
     * @param: templateName
     * @param: req
     * @param: resp
     * @date 2022/12/5 16:26
     * @author wty
     **/
    protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 1.设置响应体内容类型和字符集
        resp.setContentType("text/html;charset=UTF-8");

        // 2.创建WebContext对象
        WebContext webContext = new WebContext(req, resp, this.servletContext);

        // 3.处理模板数据
        templateEngine.process(templateName, webContext, resp.getWriter());
    }
}

FruitController

package com.atguigu.fruit.controllers;

import com.atguigu.fruit.pojo.Fruit;
import com.atguigu.fruit.service.FruitService;
import com.atguigu.myssm.myspringmvc.ViewBaseServlet;
import com.atguigu.uils.StringUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

/**
 * @ClassName: FruitServlet
 * @Description:
 * @Author: wty
 * @Date: 2022/12/6
 */
public class FruitController extends ViewBaseServlet {
    /**
     * 之前FruitController是一个Servlet组件,那么其中的init方法一定会被调用
     * 之前init方法的内部会调用super.init()
     */

    private ServletContext servletContext;

    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
        try {
            super.init(servletContext);
        } catch (ServletException e) {
            e.printStackTrace();
        }
    }

    private FruitService fruitService = new FruitService();

    private void index(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        List<Fruit> fruitList = null;
        // 分页查询(增加参数pageNumber)
        Integer pageNumber = 1;
        int sum = 0;
        HttpSession session = request.getSession();

        // 模糊查询
        String oper = request.getParameter("oper");
        String keyword = null;
        if (StringUtils.isNotEmpty(oper) && "search".equals(oper)) {
            // 相当于是模糊查询
            keyword = request.getParameter("keyword");
            if (StringUtils.isEmpty(keyword)) {
                keyword = "";
            }
            pageNumber = 1;
        } else {
            // 说明此处不是模糊查询,此时keyword应该从session作用域获取

            // 分页查询(增加参数pageNumber)
            String pageNumberStr = request.getParameter("pageNumber");
            if (StringUtils.isNotEmpty(pageNumberStr)) {
                pageNumber = Integer.parseInt(pageNumberStr);
            }
            Object keywordObj = session.getAttribute("keyword");
            if (null != keywordObj) {
                keyword = (String) keywordObj;
            } else {
                keyword = "";
            }
        }
        // 将keyword从session作用域获取
        session.setAttribute("keyword", keyword);

        fruitList = fruitService.getFruitList(pageNumber, keyword);


        // 非分页,显示全部,更新当前页的值
        session.setAttribute("pageNumber", pageNumber);

        // 获取总条数
        sum = fruitService.getFruitCount(keyword);
        // 获取总页数pageCount
        session.setAttribute("pageCount", ((sum + 5 - 1) / 5));

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

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

    }

    private void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        // 判断是doGet还是doPost
        if (StringUtils.isEmpty(request.getParameter("fname"))
                || StringUtils.isEmpty(request.getParameter("price"))
                || StringUtils.isEmpty(request.getParameter("fcount"))) {
            processTemplate("add", request, response);
            return;
        }
        // 获取参数
        String fname = request.getParameter("fname");

        String priceStr = request.getParameter("price");
        Integer price = Integer.parseInt(priceStr);

        String fcountStr = request.getParameter("fcount");
        Integer fcount = Integer.parseInt(fcountStr);

        String remark = request.getParameter("remark");
        fruitService.addFruit(new Fruit(0, fname, price, fcount, remark));
        response.sendRedirect("fruit.do");
    }

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

            //fruitService
            fruitService.delFruitByFid(fid);
            response.sendRedirect("fruit.do");
        }
    }

    private void edit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String fidStr = request.getParameter("fid");
        if (StringUtils.isNotEmpty(fidStr)) {
            Integer fid = Integer.parseInt(fidStr);

            Fruit fruit = fruitService.getFruitByFid(fid);
            request.setAttribute("fruit", fruit);
            processTemplate("edit", request, response);
        }

    }

    private void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        // 获取参数
        String fidStr = request.getParameter("fid");
        Integer fid = Integer.parseInt(fidStr);

        String fname = request.getParameter("fname");

        String priceStr = request.getParameter("price");
        Integer price = Integer.parseInt(priceStr);

        String fcountStr = request.getParameter("fcount");
        Integer fcount = Integer.parseInt(fcountStr);

        String remark = request.getParameter("remark");
        //  执行更新
        fruitService.updateFruitByFid(new Fruit(fid, fname, price, fcount, remark));
        // 资源跳转
        //processTemplate("index", request, response);
        // 此处需要重定向,目的是重新给indexServlet发请求,重新获取fruitList然后覆盖到session中的数据才是最新的
        response.sendRedirect("fruit.do");
    }

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

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

优化Controller2.1

新增配置

settings-Build,Execution,Deployment-Compiler-java Compiler
增加一句

-parameters

增加配置

配置完成后的效果

配置完成后的效果
可以发现参数中是可以获取到实际的名字

FruitController

package com.atguigu.fruit.controllers;

import com.atguigu.fruit.pojo.Fruit;
import com.atguigu.fruit.service.FruitService;
import com.atguigu.uils.StringUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;

/**
 * @ClassName: FruitServlet
 * @Description:
 * @Author: wty
 * @Date: 2022/12/6
 */
public class FruitController {

    private FruitService fruitService = new FruitService();

    private String index(String oper, String keyword, Integer pageNumber, HttpServletRequest request) {
        List<Fruit> fruitList = null;
        // 分页查询(增加参数pageNumber)
        int sum = 0;
        HttpSession session = request.getSession();

        if (null == pageNumber) {
            pageNumber = 1;
        }
        // 模糊查询
        if (StringUtils.isNotEmpty(oper) && "search".equals(oper)) {
            // 相当于是模糊查询
            if (StringUtils.isEmpty(keyword)) {
                keyword = "";
            }
            pageNumber = 1;
        } else {
            // 说明此处不是模糊查询,此时keyword应该从session作用域获取

            // 分页查询(增加参数pageNumber)
            Object keywordObj = session.getAttribute("keyword");
            if (null != keywordObj) {
                keyword = (String) keywordObj;
            } else {
                keyword = "";
            }
        }
        // 将keyword从session作用域获取
        session.setAttribute("keyword", keyword);

        fruitList = fruitService.getFruitList(pageNumber, keyword);


        // 非分页,显示全部,更新当前页的值
        session.setAttribute("pageNumber", pageNumber);

        // 获取总条数
        sum = fruitService.getFruitCount(keyword);
        // 获取总页数pageCount
        session.setAttribute("pageCount", ((sum + 5 - 1) / 5));

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

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

    private String add(String fname, Integer price, Integer fcount, String remark, HttpServletRequest request) throws IOException {
        request.setCharacterEncoding("UTF-8");
        // 判断是doGet还是doPost
        //if (StringUtils.isEmpty(request.getParameter("fname"))
        //        || StringUtils.isEmpty(request.getParameter("price"))
        //        || StringUtils.isEmpty(request.getParameter("fcount"))) {
        //    //processTemplate("add", request, response);
        //    return "add";
        //}
        if (StringUtils.isEmpty(fname)
                || null == price
                || null == fcount) {
            //processTemplate("add", request, response);
            return "add";
        }
        fruitService.addFruit(new Fruit(0, fname, price, fcount, remark));
        //response.sendRedirect("fruit.do");
        return "redirect:fruit.do";

    }

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

    private String edit(Integer fid, HttpServletRequest request) {
        if (null != fid) {
            Fruit fruit = fruitService.getFruitByFid(fid);
            request.setAttribute("fruit", fruit);
            //processTemplate("edit", request, response);
            return "edit";
        }
        return "error";
    }

    private String update(Integer fid, String fname, Integer price, Integer fcount, String remark) {
        //  执行更新
        fruitService.updateFruitByFid(new Fruit(fid, fname, price, fcount, remark));
        // 资源跳转
        //response.sendRedirect("fruit.do");
        return "redirect:fruit.do";
    }
}

DispatcherServlet

package com.atguigu.myssm.myspringmvc;

import com.atguigu.uils.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName: DispatcherServlet
 * @Description:
 * @Author: wty
 * @Date: 2022/12/7
 */
@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet {
    private Map<String, Object> beanMap = new HashMap<>();

    /**
     * @param
     * @return
     * @description 解析配置文件
     * @date 2022/12/7 12:10
     * @author wty
     **/
    public DispatcherServlet() {

    }

    @Override
    public void init() throws ServletException {
        super.init();
        InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
        // 1.创建DocumentBuilderFactory
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        // 2.创建DocumentBuilder
        try {
            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<?> beanObj = Class.forName(className);
                    // 类对象
                    Object o = beanObj.newInstance();

                    // 加入servletContext
                    //Field servletContextField = beanObj.getDeclaredField("servletContext");
                    //servletContextField.setAccessible(true);
                    //servletContextField.set(o, this.getServletContext());

                    //Method setServletContext = beanObj.getDeclaredMethod("setServletContext", ServletContext.class);
                    //setServletContext.invoke(o, this.getServletContext());

                    beanMap.put(beanId, o);
                }
            }


        } catch (ParserConfigurationException | InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SAXException | 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

        String servletPath = request.getServletPath();
        /// hello.do
        System.out.println(servletPath);

        // 1.字符串截取 hello.do 得到 hello
        servletPath = servletPath.substring(1, servletPath.length() - 3);
        System.out.println(servletPath);

        // 2. hello 和 helloController对应上
        Object contorllerBeanObject = beanMap.get(servletPath);


        // 下面的逻辑来自于FruitController
        String operate = request.getParameter("operate");
        if (StringUtils.isEmpty(operate)) {
            operate = "index";
        }

        try {
            Method declaredMethods[] = contorllerBeanObject.getClass().getDeclaredMethods();
            for (Method declaredMethod : declaredMethods) {
                if (operate.equals(declaredMethod.getName())) {
                    // 1.统一获取请求参数
                    // 获取当前方法的所有参数,返回参数数组
                    Parameter[] parameters = declaredMethod.getParameters();
                    // parametersobjectsValue用来存放参数的值
                    Object[] parametersobjectsValue = 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)) {
                            parametersobjectsValue[i] = request;
                        } else if ("response".equals(parameterName)) {
                            parametersobjectsValue[i] = response;
                        } else if ("session".equals(parameterName)) {
                            parametersobjectsValue[i] = request.getSession();
                        } else {
                            // 从请求中获取参数值
                            String parameterValue = request.getParameter(parameterName);

                            //当前页面http://localhost:8080/pro16/fruit.do?pageNumber=2
                            // 最后的2在parameterValue中是"2"会报错argument type mismatch
                            String typeName = parameter.getType().getName();
                            if ("java.lang.String".equals(typeName)) {
                                parametersobjectsValue[i] = parameterValue;
                            } else if (null != parameterValue && "java.lang.Integer".equals(typeName)) {
                                parametersobjectsValue[i] = Integer.parseInt(parameterValue);
                            } else {
                                parametersobjectsValue[i] = parameterValue;
                            }
                        }
                    }
                    // 2.controller组件中的方法调用
                    declaredMethod.setAccessible(true);
                    Object o = declaredMethod.invoke(contorllerBeanObject, parametersobjectsValue);

                    // 3.视图处理:
                    String methodReturnStr = (String) o;
                    if (methodReturnStr.startsWith("redirect")) {
                        // 比如 redirect:fruit.do
                        // 截取后只想要 fruit.do
                        String redirectStr = methodReturnStr.substring("redirect:".length());
                        response.sendRedirect(redirectStr);
                    } else {
                        // 比如 edit
                        super.processTemplate(methodReturnStr, request, response);
                    }
                } else {
                    //throw new RuntimeException("operate值非法!");
                }
            }
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
// 常间错误 argument type mismatch
// 当前页面http://localhost:8080/pro16/fruit.do?pageNumber=2

ViewBaseServlet

package com.atguigu.myssm.myspringmvc;

import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @ClassName: ViewBaseServlet
 * @Description:
 * @Author: wty
 * @Date: 2022/12/5
 */

public class ViewBaseServlet extends HttpServlet {

    private TemplateEngine templateEngine;

    @Override
    public void init() throws ServletException {

        // 1.获取ServletContext对象
        ServletContext servletContext = this.getServletContext();

        // 2.创建Thymeleaf解析器对象
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);

        // 3.给解析器对象设置参数
        // ①HTML是默认模式,明确设置是为了代码更容易理解
        templateResolver.setTemplateMode(TemplateMode.HTML);

        // ②设置前缀
        String viewPrefix = servletContext.getInitParameter("view-prefix");

        templateResolver.setPrefix(viewPrefix);

        // ③设置后缀
        String viewSuffix = servletContext.getInitParameter("view-suffix");

        templateResolver.setSuffix(viewSuffix);

        // ④设置缓存过期时间(毫秒)
        templateResolver.setCacheTTLMs(60000L);

        // ⑤设置是否缓存
        templateResolver.setCacheable(true);

        // ⑥设置服务器端编码方式
        templateResolver.setCharacterEncoding("utf-8");

        // 4.创建模板引擎对象
        templateEngine = new TemplateEngine();

        // 5.给模板引擎对象设置模板解析器
        templateEngine.setTemplateResolver(templateResolver);

    }

    /**
     * @param
     * @return void
     * @description 完成资源的转发和视图的渲染
     * @param: templateName
     * @param: req
     * @param: resp
     * @date 2022/12/5 16:26
     * @author wty
     **/
    protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 1.设置响应体内容类型和字符集
        resp.setContentType("text/html;charset=UTF-8");

        // 2.创建WebContext对象
        WebContext webContext = new WebContext(req, resp, getServletContext());

        // 3.处理模板数据
        templateEngine.process(templateName, webContext, resp.getWriter());
    }
}

总结

  1. 最初的做法是: 一个请求对应一个Servlet,这样存在的问题是servlet太多了
  2. 把一些列的请求都对应一个Servlet, IndexServlet/AddServlet/EditServlet/DelServlet/UpdateServlet -> 合并成FruitServlet
    通过一个operate的值来决定调用FruitServlet中的哪一个方法
    使用的是switch-case
  3. 在上一个版本中,Servlet中充斥着大量的switch-case,试想一下,随着我们的项目的业务规模扩大,那么会有很多的Servlet,也就意味着会有很多的switch-case,这是一种代码冗余
    因此,我们在servlet中使用了反射技术,我们规定operate的值和方法名一致,那么接收到operate的值是什么就表明我们需要调用对应的方法进行响应,如果找不到对应的方法,则抛异常
  4. 在上一个版本中我们使用了反射技术,但是其实还是存在一定的问题:每一个servlet中都有类似的反射技术的代码。因此继续抽取,设计了中央控制器类:DispatcherServlet
    DispatcherServlet这个类的工作分为两大部分:
    1.根据url定位到能够处理这个请求的controller组件:
    1)从url中提取servletPath : /fruit.do -> fruit
    2)根据fruit找到对应的组件:FruitController , 这个对应的依据我们存储在applicationContext.xml中
    <bean id=“fruit” class="com.atguigu.fruit.controllers.FruitController/>
    通过DOM技术我们去解析XML文件,在中央控制器中形成一个beanMap容器,用来存放所有的Controller组件
    3)根据获取到的operate的值定位到我们FruitController中需要调用的方法
    2.调用Controller组件中的方法:
    1. 获取参数
      获取即将要调用的方法的参数签名信息: Parameter[] parameters = method.getParameters();
      通过parameter.getName()获取参数的名称;
      准备了Object[] parameterValues 这个数组用来存放对应参数的参数值
      另外,我们需要考虑参数的类型问题,需要做类型转化的工作。通过parameter.getType()获取参数的类型
    2. 执行方法
      Object returnObj = method.invoke(controllerBean , parameterValues);
    3. 视图处理
      String returnStr = (String)returnObj;
      if(returnStr.startWith(“redirect:”)){

      }else if…
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心向阳光的天域

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值