1. 程式人生 > 其它 >JSP 學習筆記 | 五、MVC模式和三層架構 & JSP 案例實戰

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

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

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

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

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

MVC模式和三層架構

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

MVC模式

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

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

  • V:View,檢視,介面展示

  • C:Controller,控制器,處理請求,呼叫模型和檢視

控制器(serlvlet)用來接收瀏覽器傳送過來的請求,控制器呼叫模型(JavaBean)來獲取資料,比如從資料庫查詢資料;控制器獲取到資料後再交由檢視(JSP)進行資料展示。

MVC 好處:

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

  • 有利於分工協作。

  • 有利於元件重用

三層架構

三層架構是將我們的專案分成了三個層面,分別是 表現層業務邏輯層資料訪問層

  • 資料訪問層:對資料庫的CRUD基本操作
  • 業務邏輯層:對業務邏輯進行封裝,組合資料訪問層層中基本功能,形成複雜的業務邏輯功能。例如 註冊業務功能 ,我們會先呼叫 資料訪問層selectByName() 方法判斷該使用者名稱是否存在,如果不存在再呼叫 資料訪問層insert() 方法進行資料的新增操作
  • 表現層:接收請求,封裝資料,呼叫業務邏輯層,響應資料

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

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

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

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

MVC 和 三層架構

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

如上圖上半部分是 MVC 模式,上圖下半部分是三層架構。 MVC 模式 中的 C(控制器)和 V(檢視)就是 三層架構 中的表現層,而 MVC 模式 中的 M(模型)就是 三層架構

中的 業務邏輯層 和 資料訪問層。

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

案例

需求:完成品牌資料的增刪改查操作

這個功能我們之前一直在做,而這個案例是將目前學習的所有的內容(包含 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>

查詢所有

當我們點選 index.html 頁面中的 查詢所有 這個超連結時,就能查詢到上圖右半部分的資料。

對於上述的功能,點選 查詢所有 超連結是需要先請後端的 servlet ,由 servlet 跳轉到對應的頁面進行資料的動態展示。而整個流程如下圖:

編寫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頁面

點選 提交 按鈕,就能看到如下頁面,裡面就包含我們剛新增的資料

修改

通常點選每條資料後面的 編輯 按鈕會跳轉到修改頁面,

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

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

回顯資料

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

編寫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>

修改資料

做完回顯資料後,接下來我們要做修改資料了,而下圖是修改資料的效果:

在修改頁面進行資料修改,點選 提交 按鈕,會將資料提交到後端程式,後端程式會對錶中的資料進行修改操作,然後重新進行資料的查詢操作。整體流程如下:

編寫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>

The desire of his soul is the prophecy of his fate
你靈魂的慾望,是你命運的先知。