JSP 學習筆記 | 五、MVC模式和三層架構 & JSP 案例實戰


前文:JSP 學習筆記 | 四、JSP標准標簽庫(JSTL)個人使用指南

前文:JSP 學習筆記 | 三、EL 表達式簡述

前文:JSP 學習筆記 | 二、JSP 腳本 & 案例實現 & 缺點分析

前文:JSP 學習筆記 | 一、JSP 原理理解

MVC模式和三層架構

MVC 模式和三層架構是一些理論的知識,將來我們使用了它們進行代碼開發會讓我們代碼維護性和擴展性更好。

MVC模式

MVC 是一種分層開發的模式,其中:

  • M:Model,業務模型,處理業務

  • V:View,視圖,界面展示

  • C:Controller,控制器,處理請求,調用模型和視圖

image-20210818163348642

控制器(serlvlet)用來接收瀏覽器發送過來的請求,控制器調用模型(JavaBean)來獲取數據,比如從數據庫查詢數據;控制器獲取到數據后再交由視圖(JSP)進行數據展示。

MVC 好處:

  • 職責單一,互不影響。每個角色做它自己的事,各司其職。

  • 有利於分工協作。

  • 有利於組件重用

三層架構

三層架構是將我們的項目分成了三個層面,分別是 表現層業務邏輯層數據訪問層

image-20210818164301154
  • 數據訪問層:對數據庫的CRUD基本操作
  • 業務邏輯層:對業務邏輯進行封裝,組合數據訪問層層中基本功能,形成復雜的業務邏輯功能。例如 注冊業務功能 ,我們會先調用 數據訪問層selectByName() 方法判斷該用戶名是否存在,如果不存在再調用 數據訪問層insert() 方法進行數據的添加操作
  • 表現層:接收請求,封裝數據,調用業務邏輯層,響應數據

而整個流程是,瀏覽器發送請求,表現層的Servlet接收請求並調用業務邏輯層的方法進行業務邏輯處理,而業務邏輯層方法調用數據訪問層方法進行數據的操作,依次返回到servlet,然后servlet將數據交由 JSP 進行展示。

三層架構的每一層都有特有的包名稱:(表現在項目的包名)

  • 表現層: com.riotian.controller 或者 com.riotian.web
  • 業務邏輯層:com.riotian.service
  • 數據訪問層:com.riotian.dao 或者 com.riotian.mapper

注意:不同的框架是對不同層進行封裝的

image-20210818165439826

MVC 和 三層架構

通過 MVC 和 三層架構 的學習,有些人肯定混淆了。那他們有什么區別和聯系?

image-20210818165808589

如上圖上半部分是 MVC 模式,上圖下半部分是三層架構。 MVC 模式 中的 C(控制器)和 V(視圖)就是 三層架構 中的表現層,而 MVC 模式 中的 M(模型)就是 三層架構 中的 業務邏輯層 和 數據訪問層。

可以將 MVC 模式 理解成是一個大的概念,而 三層架構 是對 MVC 模式 實現架構的思想。 那么我們以后按照要求將不同層的代碼寫在不同的包下,每一層里功能職責做到單一,將來如果將表現層的技術換掉,而業務邏輯層和數據訪問層的代碼不需要發生變化。

案例

需求:完成品牌數據的增刪改查操作

img

這個功能我們之前一直在做,而這個案例是將目前學習的所有的內容(包含 MVC模式 和 三層架構)進行應用,並將整個流程貫穿起來。

環境准備

環境准備工作,我們分以下步驟實現:

  • 創建新的項目模塊 brand_demo,引入坐標

  • 創建三層架構的包結構

  • 數據庫表 tb_brand

  • 實體類 Brand

  • MyBatis 基礎環境

    • Mybatis-config.xml
    • BrandMapper.xml
    • BrandMapper接口

創建工程

創建新的模塊 brand_demo,引入坐標。我們只要分析出要用到哪兒些技術,那么需要哪兒些坐標也就明確了

  • 需要操作數據庫。mysql的驅動包
  • 要使用mybatis框架。mybaits的依賴包
  • web項目需要用到servlet和jsp。servlet和jsp的依賴包
  • 需要使用 jstl 進行數據展示。jstl的依賴包

pom.xml 內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.example</groupId>
    <artifactId>brand-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.5</version>
        </dependency>

        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.34</version>
        </dependency>

        <!--servlet-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>

        <!--jsp-->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.2</version>
            <scope>provided</scope>
        </dependency>

        <!--jstl-->
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
            </plugin>
        </plugins>
    </build>
</project>

創建包

創建表

-- 刪除tb_brand表
drop table if exists tb_brand;
-- 創建tb_brand表
create table tb_brand
(
    -- id 主鍵
    id           int primary key auto_increment,
    -- 品牌名稱
    brand_name   varchar(20),
    -- 企業名稱
    company_name varchar(20),
    -- 排序字段
    ordered      int,
    -- 描述信息
    description  varchar(100),
    -- 狀態:0:禁用  1:啟用
    status       int
);
-- 添加數據
insert into tb_brand (brand_name, company_name, ordered, description, status)
values ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),
       ('華為', '華為技術有限公司', 100, '華為致力於把數字世界帶入每個人、每個家庭、每個組織,構建萬物互聯的智能世界', 1),
       ('小米', '小米科技有限公司', 50, 'are you ok', 1);

創建實體類

pojo 包下創建名為 Brand 的類。

public class Brand {
    // id 主鍵
    private Integer id;
    // 品牌名稱
    private String brandName;
    // 企業名稱
    private String companyName;
    // 排序字段
    private Integer ordered;
    // 描述信息
    private String description;
    // 狀態:0:禁用  1:啟用
    private Integer status;


    public Brand() {
    }

    public Brand(Integer id, String brandName, String companyName, String description) {
        this.id = id;
        this.brandName = brandName;
        this.companyName = companyName;
        this.description = description;
    }

    public Brand(Integer id, String brandName, String companyName, Integer ordered, String description, Integer status) {
        this.id = id;
        this.brandName = brandName;
        this.companyName = companyName;
        this.ordered = ordered;
        this.description = description;
        this.status = status;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getBrandName() {
        return brandName;
    }

    public void setBrandName(String brandName) {
        this.brandName = brandName;
    }

    public String getCompanyName() {
        return companyName;
    }

    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }

    public Integer getOrdered() {
        return ordered;
    }

    public void setOrdered(Integer ordered) {
        this.ordered = ordered;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    @Override
    public String toString() {
        return "Brand{" +
                "id=" + id +
                ", brandName='" + brandName + '\'' +
                ", companyName='" + companyName + '\'' +
                ", ordered=" + ordered +
                ", description='" + description + '\'' +
                ", status=" + status +
                '}';
    }
}

准備mybatis環境

定義核心配置文件 Mybatis-config.xml ,並將該文件放置在 resources

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--起別名-->
    <typeAliases>
        <package name="com.riotian.pojo"/>
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mybatis?useSSL=false&amp;useServerPrepStmts=true"/>
                <property name="username" value="root"/>
                <property name="password" value="xxx"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--掃描mapper-->
        <package name="com.riotian.mapper"/>
    </mappers>
</configuration>

resources 下創建放置映射配置文件的目錄結構 com/itheima/mapper,並在該目錄下創建映射配置文件 BrandMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.riotian.mapper.BrandMapper">
    
</mapper>

查詢所有

image-20210818174441917

當我們點擊 index.html 頁面中的 查詢所有 這個超鏈接時,就能查詢到上圖右半部分的數據。

對於上述的功能,點擊 查詢所有 超鏈接是需要先請后端的 servlet ,由 servlet 跳轉到對應的頁面進行數據的動態展示。而整個流程如下圖:

image-20210818174800783

編寫BrandMapper

mapper 包下創建創建 BrandMapper 接口,在接口中定義 selectAll() 方法

/**
  * 查詢所有
  * @return
  */
@Select("select * from tb_brand")
List<Brand> selectAll();

編寫工具類

com.itheima 包下創建 utils 包,並在該包下創建名為 SqlSessionFactoryUtils 工具類

public class SqlSessionFactoryUtils {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        //靜態代碼塊會隨着類的加載而自動執行,且只執行一次
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static SqlSessionFactory getSqlSessionFactory(){
        return sqlSessionFactory;
    }
}

編寫BrandService

service 包下創建 BrandService

public class BrandService {
    SqlSessionFactory factory = SqlSessionFactoryUtils.getSqlSessionFactory();

    /**
     * 查詢所有
     * @return
     */
    public List<Brand> selectAll(){
        //調用BrandMapper.selectAll()

        //2. 獲取SqlSession
        SqlSession sqlSession = factory.openSession();
        //3. 獲取BrandMapper
        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);

        //4. 調用方法
        List<Brand> brands = mapper.selectAll();

        sqlSession.close();

        return brands;
    }
}

編寫Servlet

web 包下創建名為 SelectAllServletservlet,該 servlet 的邏輯如下:

  • 調用 BrandServiceselectAll() 方法進行業務邏輯處理,並接收返回的結果
  • 將上一步返回的結果存儲到 request 域對象中
  • 跳轉到 brand.jsp 頁面進行數據的展示

具體的代碼如下:

@WebServlet("/selectAllServlet")
public class SelectAllServlet extends HttpServlet {
    private  BrandService service = new BrandService();

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

        //1. 調用BrandService完成查詢
        List<Brand> brands = service.selectAll();
        //2. 存入request域中
        request.setAttribute("brands",brands);
        //3. 轉發到brand.jsp
        request.getRequestDispatcher("/brand.jsp").forward(request,response);
    }

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

編寫brand.jsp頁面

brand.jsp 代碼如下,而 brand.jsp 頁面在表格中使用 JSTLEL表達式 從request域對象中獲取名為 brands 的集合數據並展示出來。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<hr>
<table border="1" cellspacing="0" width="80%">
    <tr>
        <th>序號</th>
        <th>品牌名稱</th>
        <th>企業名稱</th>
        <th>排序</th>
        <th>品牌介紹</th>
        <th>狀態</th>
        <th>操作</th>
    </tr>

    <c:forEach items="${brands}" var="brand" varStatus="status">
        <tr align="center">
            <%--<td>${brand.id}</td>--%>
            <td>${status.count}</td>
            <td>${brand.brandName}</td>
            <td>${brand.companyName}</td>
            <td>${brand.ordered}</td>
            <td>${brand.description}</td>
            <c:if test="${brand.status == 1}">
                <td>啟用</td>
            </c:if>
            <c:if test="${brand.status != 1}">
                <td>禁用</td>
            </c:if>
            <td><a href="/brand-demo/selectByIdServlet?id=${brand.id}">修改</a> <a href="#">刪除</a></td>
        </tr>
    </c:forEach>
</table>
</body>
</html>

測試

啟動服務器,並在瀏覽器輸入 http://localhost:8080/brand-demo/index.html,看到如下 查詢所有 的超鏈接,點擊該鏈接就可以查詢出所有的品牌數據

為什么出現這個問題呢?是因為查詢到的字段名和實體類對象的屬性名沒有一一對應。相比看到這大家一定會解決了(如果學了Mybatis映射關系的話),就是在映射配置文件中使用 resultMap 標簽定義映射關系。映射配置文件內容如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.riotian.mapper.BrandMapper">

    <resultMap id="brandResultMap" type="brand">
        <result column="brand_name" property="brandName"></result>
        <result column="company_name" property="companyName"></result>
    </resultMap>
</mapper>

並且在 BrandMapper 接口中的 selectAll() 上使用 @ResuleMap 注解指定使用該映射

/**
  * 查詢所有
  * @return
  */
@Select("select * from tb_brand")
@ResultMap("brandResultMap")
List<Brand> selectAll();

重啟服務器,再次訪問就能看到我們想要的數據了

添加

上圖是做 添加 功能流程。點擊 新增 按鈕后,會先跳轉到 addBrand.jsp 新增頁面,在該頁面輸入要添加的數據,輸入完畢后點擊 提交 按鈕,需要將數據提交到后端,而后端進行數據添加操作,並重新將所有的數據查詢出來。整個流程如下:

接下來我們根據流程來實現功能:

編寫BrandMapper方法

BrandMapper 接口,在接口中定義 add(Brand brand) 方法

@Insert("insert into tb_brand values(null,#{brandName},#{companyName},#{ordered},#{description},#{status})")
void add(Brand brand);

編寫BrandService方法

BrandService 類中定義添加品牌數據方法 add(Brand brand)

 	/**
     * 添加
     * @param brand
     */
    public void add(Brand brand){

        //2. 獲取SqlSession
        SqlSession sqlSession = factory.openSession();
        //3. 獲取BrandMapper
        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);

        //4. 調用方法
        mapper.add(brand);

        //提交事務
        sqlSession.commit();
        //釋放資源
        sqlSession.close();
    }

改進brand.jsp頁面

我們需要在該頁面表格的上面添加 新增 按鈕

<input type="button" value="新增" id="add"><br>

並給該按鈕綁定單擊事件,當點擊了該按鈕需要跳轉到 brand.jsp 添加品牌數據的頁面

<script>
    document.getElementById("add").onclick = function (){
        location.href = "/brand-demo/addBrand.jsp";
    }
</script>

注意:script 標簽建議放在 body 結束標簽前面。

編寫addBrand.jsp頁面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>添加品牌</title>
</head>
<body>
<h3>添加品牌</h3>
<form action="/brand-demo/addServlet" method="post">
    品牌名稱:<input name="brandName"><br>
    企業名稱:<input name="companyName"><br>
    排序:<input name="ordered"><br>
    描述信息:<textarea rows="5" cols="20" name="description"></textarea><br>
    狀態:
    <input type="radio" name="status" value="0">禁用
    <input type="radio" name="status" value="1">啟用<br>

    <input type="submit" value="提交">
</form>
</body>
</html>

編寫servlet

web 包下創建 AddServletservlet,該 servlet 的邏輯如下:

  • 設置處理post請求亂碼的字符集
  • 接收客戶端提交的數據
  • 將接收到的數據封裝到 Brand 對象中
  • 調用 BrandServiceadd() 方法進行添加的業務邏輯處理
  • 跳轉到 selectAllServlet 資源重新查詢數據

具體的代碼如下:

@WebServlet("/addServlet")
public class AddServlet extends HttpServlet {
    private BrandService service = new BrandService();


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

        //處理POST請求的亂碼問題
        request.setCharacterEncoding("utf-8");

        //1. 接收表單提交的數據,封裝為一個Brand對象
        String brandName = request.getParameter("brandName");
        String companyName = request.getParameter("companyName");
        String ordered = request.getParameter("ordered");
        String description = request.getParameter("description");
        String status = request.getParameter("status");

        //封裝為一個Brand對象
        Brand brand = new Brand();
        brand.setBrandName(brandName);
        brand.setCompanyName(companyName);
        brand.setOrdered(Integer.parseInt(ordered));
        brand.setDescription(description);
        brand.setStatus(Integer.parseInt(status));

        //2. 調用service 完成添加
        service.add(brand);

        //3. 轉發到查詢所有Servlet
        request.getRequestDispatcher("/selectAllServlet").forward(request,response);
    }

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

測試

點擊 brand.jsp 頁面的 新增 按鈕,會跳轉到 addBrand.jsp頁面

image-20210819220701121

點擊 提交 按鈕,就能看到如下頁面,里面就包含我們剛添加的數據

修改

通常點擊每條數據后面的 編輯 按鈕會跳轉到修改頁面,

在該修改頁面我們可以看到將 編輯 按鈕所在行的數據 回顯 到表單,然后需要修改那個數據在表單中進行修改,然后點擊 提交 的按鈕將數據提交到后端,后端再將數據存儲到數據庫中。

從上面的例子我們知道 修改 功能需要從兩方面進行實現,數據回顯和修改操作。

回顯數據

上圖就是回顯數據的效果。要實現這個效果,那當點擊 修改 按鈕時不能直接跳轉到 update.jsp 頁面,而是需要先帶着當前行數據的 id 請求后端程序,后端程序根據 id 查詢數據,將數據存儲到域對象中跳轉到 update.jsp 頁面進行數據展示。整體流程如下

image-20210819224243778
編寫BrandMapper方法

BrandMapper 接口,在接口中定義 selectById(int id) 方法

/**
 * 根據id查詢
 * @param id
 * @return
 */
@Select("select * from tb_brand where id = #{id}")
@ResultMap("brandResultMap")
Brand selectById(int id);
編寫BrandService方法

BrandService 類中定義根據id查詢數據方法 selectById(int id)

/**
 * 根據id查詢
 * @return
 */
public Brand selectById(int id){
    //調用BrandMapper.selectAll()
    //2. 獲取SqlSession
    SqlSession sqlSession = factory.openSession();
    //3. 獲取BrandMapper
    BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
    //4. 調用方法
    Brand brand = mapper.selectById(id);
    sqlSession.close();
    return brand;
}
編寫servlet

web 包下創建 SelectByIdServletservlet,該 servlet 的邏輯如下:

  • 獲取請求數據 id
  • 調用 BrandServiceselectById() 方法進行數據查詢的業務邏輯
  • 將查詢到的數據存儲到 request 域對象中
  • 跳轉到 update.jsp 頁面進行數據真實

具體代碼如下:

@WebServlet("/selectByIdServlet")
public class SelectByIdServlet extends HttpServlet {
    private  BrandService service = new BrandService();

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1. 接收id
        String id = request.getParameter("id");
        //2. 調用service查詢
        Brand brand = service.selectById(Integer.parseInt(id));
        //3. 存儲到request中
        request.setAttribute("brand",brand);
        //4. 轉發到update.jsp
        request.getRequestDispatcher("/update.jsp").forward(request,response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}
編寫update.jsp頁面

拷貝 addBrand.jsp 頁面,改名為 update.jsp 並做出以下修改:

  • title 標簽內容改為 修改品牌

  • form 標簽的 action 屬性值改為 /brand-demo/updateServlet

  • input 標簽要進行數據回顯,需要設置 value 屬性

    品牌名稱:<input name="brandName" value="${brand.brandName}"><br>
    企業名稱:<input name="companyName" value="${brand.companyName}"><br>
    排序:<input name="ordered" value="${brand.ordered}"><br>
    
  • textarea 標簽要進行數據回顯,需要在標簽體中使用 EL表達式

    描述信息:<textarea rows="5" cols="20" name="description">${brand.description} </textarea><br>
    
  • 單選框使用 if 標簽需要判斷 brand.status 的值是 1 還是 0 在指定的單選框上使用 checked 屬性,表示被選中狀態

    狀態:
    <c:if test="${brand.status == 0}">
        <input type="radio" name="status" value="0" checked>禁用
        <input type="radio" name="status" value="1">啟用<br>
    </c:if>
    
    <c:if test="${brand.status == 1}">
        <input type="radio" name="status" value="0" >禁用
        <input type="radio" name="status" value="1" checked>啟用<br>
    </c:if>
    

綜上,update.jsp 代碼如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>修改品牌</title>
</head>
<body>
<h3>修改品牌</h3>
<form action="/brand-demo/updateServlet" method="post">

    品牌名稱:<input name="brandName" value="${brand.brandName}"><br>
    企業名稱:<input name="companyName" value="${brand.companyName}"><br>
    排序:<input name="ordered" value="${brand.ordered}"><br>
    描述信息:<textarea rows="5" cols="20" name="description">${brand.description} </textarea><br>
    狀態:
    <c:if test="${brand.status == 0}">
        <input type="radio" name="status" value="0" checked>禁用
        <input type="radio" name="status" value="1">啟用<br>
    </c:if>

    <c:if test="${brand.status == 1}">
        <input type="radio" name="status" value="0" >禁用
        <input type="radio" name="status" value="1" checked>啟用<br>
    </c:if>

    <input type="submit" value="提交">
</form>
</body>
</html>

修改數據

做完回顯數據后,接下來我們要做修改數據了,而下圖是修改數據的效果:

在修改頁面進行數據修改,點擊 提交 按鈕,會將數據提交到后端程序,后端程序會對表中的數據進行修改操作,然后重新進行數據的查詢操作。整體流程如下:

image-20210819230242938
編寫BrandMapper方法

BrandMapper 接口,在接口中定義 update(Brand brand) 方法

/**
  * 修改
  * @param brand
  */
@Update("update tb_brand set brand_name = #{brandName},company_name = #{companyName},ordered = #{ordered},description = #{description},status = #{status} where id = #{id}")
void update(Brand brand);
編寫BrandService方法

BrandService 類中定義根據id查詢數據方法 update(Brand brand)

/**
 * 修改
 * @param brand
 */
public void update(Brand brand){
    //2. 獲取SqlSession
    SqlSession sqlSession = factory.openSession();
    //3. 獲取BrandMapper
    BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
    //4. 調用方法
    mapper.update(brand);
    //提交事務
    sqlSession.commit();
    //釋放資源
    sqlSession.close();
}
編寫servlet

web 包下創建 AddServletservlet,該 servlet 的邏輯如下:

  • 設置處理post請求亂碼的字符集
  • 接收客戶端提交的數據
  • 將接收到的數據封裝到 Brand 對象中
  • 調用 BrandServiceupdate() 方法進行添加的業務邏輯處理
  • 跳轉到 selectAllServlet 資源重新查詢數據

具體的代碼如下:

@WebServlet("/updateServlet")
public class UpdateServlet extends HttpServlet {
    private BrandService service = new BrandService();

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

        //處理POST請求的亂碼問題
        request.setCharacterEncoding("utf-8");
        //1. 接收表單提交的數據,封裝為一個Brand對象
        String id = request.getParameter("id");
        String brandName = request.getParameter("brandName");
        String companyName = request.getParameter("companyName");
        String ordered = request.getParameter("ordered");
        String description = request.getParameter("description");
        String status = request.getParameter("status");

        //封裝為一個Brand對象
        Brand brand = new Brand();
        brand.setId(Integer.parseInt(id));
        brand.setBrandName(brandName);
        brand.setCompanyName(companyName);
        brand.setOrdered(Integer.parseInt(ordered));
        brand.setDescription(description);
        brand.setStatus(Integer.parseInt(status));

        //2. 調用service 完成修改
        service.update(brand);

        //3. 轉發到查詢所有Servlet
        request.getRequestDispatcher("/selectAllServlet").forward(request,response);
    }

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

存在問題:update.jsp 頁面提交數據時是沒有攜帶主鍵數據的,而后台修改數據需要根據主鍵進行修改。

針對這個問題,我們不希望頁面將主鍵id展示給用戶看,但是又希望在提交數據時能將主鍵id提交到后端。此時我們就想到了在學習 HTML 時學習的隱藏域,在 update.jsp 頁面的表單中添加如下代碼:

<%--隱藏域,提交id--%>
<input type="hidden" name="id" value="${brand.id}">

update.jsp 頁面的最終代碼如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>修改品牌</title>
</head>
<body>
<h3>修改品牌</h3>
<form action="/brand-demo/updateServlet" method="post">

    <%--隱藏域,提交id--%>
    <input type="hidden" name="id" value="${brand.id}">

    品牌名稱:<input name="brandName" value="${brand.brandName}"><br>
    企業名稱:<input name="companyName" value="${brand.companyName}"><br>
    排序:<input name="ordered" value="${brand.ordered}"><br>
    描述信息:<textarea rows="5" cols="20" name="description">${brand.description} </textarea><br>
    狀態:
    <c:if test="${brand.status == 0}">
        <input type="radio" name="status" value="0" checked>禁用
        <input type="radio" name="status" value="1">啟用<br>
    </c:if>

    <c:if test="${brand.status == 1}">
        <input type="radio" name="status" value="0" >禁用
        <input type="radio" name="status" value="1" checked>啟用<br>
    </c:if>
    <input type="submit" value="提交">
</form>
</body>
</html>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM