国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

17、基于Mybaits、Vue、axios、Element-ui的JavaWeb項(xiàng)目

這篇具有很好參考價(jià)值的文章主要介紹了17、基于Mybaits、Vue、axios、Element-ui的JavaWeb項(xiàng)目。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

目錄

1、項(xiàng)目功能介紹

?編輯

? ? ? ??

2、環(huán)境準(zhǔn)備

創(chuàng)建項(xiàng)目

準(zhǔn)備數(shù)據(jù)庫

準(zhǔn)備Mybatis核心配置文件

創(chuàng)建實(shí)體類與Mapper映射文件

補(bǔ)全項(xiàng)目結(jié)構(gòu)

1、在pom.xml中導(dǎo)入相關(guān)依賴

2、導(dǎo)入axios、vue的js文件

3、導(dǎo)入Element-ui

3、查詢所有功能的實(shí)現(xiàn)? ?

3.1、后端的實(shí)現(xiàn)

3.1.1、dao層方法的實(shí)現(xiàn):

3.1.2、service方法的實(shí)現(xiàn)

3.1.3、servlet實(shí)現(xiàn)

3.1.4、測(cè)試后端程序

3.2、前端實(shí)現(xiàn)

3.2.1、創(chuàng)建brand.html頁面

3.2.2、官網(wǎng)復(fù)制Element組件代碼

4、添加功能的實(shí)現(xiàn)

?4.1、后端的實(shí)現(xiàn)

4.1.1、dao層方法的實(shí)現(xiàn)

4.1.2、serivce方法的實(shí)現(xiàn)

4.1.3、servlet的實(shí)現(xiàn)

4.2、前端實(shí)現(xiàn)

5、Servlet代碼優(yōu)化

5.1、問題引入

5.2、代碼優(yōu)化

5.2.1、后端代碼的優(yōu)化

?5.2.2、前端代碼的優(yōu)化

6、批量刪除功能實(shí)現(xiàn)

6.1、后端實(shí)現(xiàn)

6.1.1、dao層代碼的實(shí)現(xiàn)

?編輯

6.1.2、service方法實(shí)現(xiàn)

6.1.2、servlet的實(shí)現(xiàn)

6.2、前端實(shí)現(xiàn)

6.2.1、獲取選擇的id值

6.2.2、發(fā)送異步請(qǐng)求

?6.2.3、確認(rèn)框提示

7、分頁查詢功能的實(shí)現(xiàn)

7.1、分析

7.1.1、分頁查詢sql

7.1.2、前后端數(shù)據(jù)的分析

7.1.3、流程分析

7.2、后端實(shí)現(xiàn)?

7.2.1、dao層方法的實(shí)現(xiàn)

7.2.2、service方法實(shí)現(xiàn)

7.2.3、servlet實(shí)現(xiàn)

7.2.4、測(cè)試

7.3、前端實(shí)現(xiàn)

7.3.1、selectAll()的改進(jìn)

?7.3.2、改變每頁條目數(shù)

7.3.3、 改變當(dāng)前頁碼

?8、條件查詢功能實(shí)現(xiàn)

8.1、后端實(shí)現(xiàn)

8.1.1、dao層實(shí)現(xiàn)

8.1.2、service的實(shí)現(xiàn)

8.1.3、servlet的實(shí)現(xiàn)

8.2、前端實(shí)現(xiàn)

?10、修改功能的實(shí)現(xiàn)

10.1、后端實(shí)現(xiàn)

10.1.1、dao層方法的實(shí)現(xiàn)

10.1.2、service方法的實(shí)現(xiàn)

10.1.3、servlet實(shí)現(xiàn)

10.2、前端實(shí)現(xiàn)


1、項(xiàng)目功能介紹

vue+mybatis idea,Javaweb,前端

以上是我們?cè)诰C合案例要實(shí)現(xiàn)的功能。對(duì)數(shù)據(jù)的除了對(duì)數(shù)據(jù)的增刪改查功能外,還有一些復(fù)雜的功能,如 批量刪除、分頁查詢、條件查詢 等功能

批量刪除 功能:每條數(shù)據(jù)前都有復(fù)選框,當(dāng)我選中多條數(shù)據(jù)并點(diǎn)擊 批量刪除 按鈕后,會(huì)發(fā)送請(qǐng)求到后端并刪除數(shù)據(jù)庫中指定的多條數(shù)據(jù)。

分頁查詢 功能:當(dāng)數(shù)據(jù)庫中有很多數(shù)據(jù)時(shí),我們不可能將所有的數(shù)據(jù)展示在一頁里,這個(gè)時(shí)候就需要分頁展示數(shù)據(jù)。

條件查詢 功能:數(shù)據(jù)庫量大的時(shí)候,我們就需要精確的查詢一些想看到的數(shù)據(jù),這個(gè)時(shí)候就需要通過條件查詢。

修改品牌:

刪除品牌

? ? ? ??

2、環(huán)境準(zhǔn)備

創(chuàng)建項(xiàng)目

1、創(chuàng)建Maven項(xiàng)目,如下

vue+mybatis idea,Javaweb,前端

?vue+mybatis idea,Javaweb,前端

為項(xiàng)目起名?

vue+mybatis idea,Javaweb,前端

?vue+mybatis idea,Javaweb,前端

?在pom.xml中加入如下,是這個(gè)模塊變?yōu)閣eb模塊

vue+mybatis idea,Javaweb,前端

vue+mybatis idea,Javaweb,前端

?vue+mybatis idea,Javaweb,前端

?vue+mybatis idea,Javaweb,前端

?vue+mybatis idea,Javaweb,前端

?然后依次點(diǎn)擊 Apply ,Ok

做完上述操作以后,項(xiàng)目結(jié)構(gòu)如下:

vue+mybatis idea,Javaweb,前端

準(zhǔn)備數(shù)據(jù)庫

創(chuàng)建一個(gè)名為 db2 的數(shù)據(jù)庫,建表語句如下:

create database db2;

在db2 下準(zhǔn)備數(shù)據(jù)庫表,如下

-- 刪除tb_brand表
drop table if exists tb_brand;
-- 創(chuàng)建tb_brand表
create table tb_brand (
    -- id 主鍵
    id           int primary key auto_increment,
    -- 品牌名稱
    brand_name   varchar(20),
    -- 企業(yè)名稱
    company_name varchar(20),
    -- 排序字段
    ordered      int,
    -- 描述信息
    description  varchar(100),
    -- 狀態(tài):0:禁用  1:?jiǎn)⒂?    status       int
);
-- 添加數(shù)據(jù)
insert into tb_brand (brand_name, company_name, ordered, description, status)
values 
       ('華為', '華為技術(shù)有限公司', 100, '萬物互聯(lián)', 1),
       ('小米', '小米科技有限公司', 50, 'are you ok', 1),
       ('格力', '格力電器股份有限公司', 30, '讓世界愛上中國(guó)造', 1),
       ('阿里巴巴', '阿里巴巴集團(tuán)控股有限公司', 10, '買買買', 1),
       ('騰訊', '騰訊計(jì)算機(jī)系統(tǒng)有限公司', 50, '玩玩玩', 0),
       ('百度', '百度在線網(wǎng)絡(luò)技術(shù)公司', 5, '搜搜搜', 0),
       ('京東', '北京京東世紀(jì)貿(mào)易有限公司', 40, '就是快', 1),
       ('小米', '小米科技有限公司', 50, 'are you ok', 1),
       ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),
       ('華為', '華為技術(shù)有限公司', 100, '萬物互聯(lián)', 1),
       ('小米', '小米科技有限公司', 50, 'are you ok', 1),
       ('格力', '格力電器股份有限公司', 30, '讓世界愛上中國(guó)造', 1),
       ('阿里巴巴', '阿里巴巴集團(tuán)控股有限公司', 10, '買買買', 1),
       ('騰訊', '騰訊計(jì)算機(jī)系統(tǒng)有限公司', 50, '玩玩玩', 0),
       ('百度', '百度在線網(wǎng)絡(luò)技術(shù)公司', 5, '搜搜搜', 0),
       ('京東', '北京京東世紀(jì)貿(mào)易有限公司', 40, '就是快', 1),
       ('華為', '華為技術(shù)有限公司', 100, '萬物互聯(lián)', 1),
       ('小米', '小米科技有限公司', 50, 'are you ok', 1),
       ('格力', '格力電器股份有限公司', 30, '讓世界愛上中國(guó)造', 1),
       ('阿里巴巴', '阿里巴巴集團(tuán)控股有限公司', 10, '買買買', 1),
       ('騰訊', '騰訊計(jì)算機(jī)系統(tǒng)有限公司', 50, '玩玩玩', 0),
       ('百度', '百度在線網(wǎng)絡(luò)技術(shù)公司', 5, '搜搜搜', 0),
       ('京東', '北京京東世紀(jì)貿(mào)易有限公司', 40, '就是快', 1),
       ('小米', '小米科技有限公司', 50, 'are you ok', 1),
       ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),
       ('華為', '華為技術(shù)有限公司', 100, '萬物互聯(lián)', 1),
       ('小米', '小米科技有限公司', 50, 'are you ok', 1),
       ('格力', '格力電器股份有限公司', 30, '讓世界愛上中國(guó)造', 1),
       ('阿里巴巴', '阿里巴巴集團(tuán)控股有限公司', 10, '買買買', 1),
       ('騰訊', '騰訊計(jì)算機(jī)系統(tǒng)有限公司', 50, '玩玩玩', 0),
       ('百度', '百度在線網(wǎng)絡(luò)技術(shù)公司', 5, '搜搜搜', 0),
       ('京東', '北京京東世紀(jì)貿(mào)易有限公司', 40, '就是快', 1),
       ('華為', '華為技術(shù)有限公司', 100, '萬物互聯(lián)', 1),
       ('小米', '小米科技有限公司', 50, 'are you ok', 1),
       ('格力', '格力電器股份有限公司', 30, '讓世界愛上中國(guó)造', 1),
       ('阿里巴巴', '阿里巴巴集團(tuán)控股有限公司', 10, '買買買', 1),
       ('騰訊', '騰訊計(jì)算機(jī)系統(tǒng)有限公司', 50, '玩玩玩', 0),
       ('百度', '百度在線網(wǎng)絡(luò)技術(shù)公司', 5, '搜搜搜', 0),
       ('京東', '北京京東世紀(jì)貿(mào)易有限公司', 40, '就是快', 1),
       ('小米', '小米科技有限公司', 50, 'are you ok', 1),
       ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),
       ('華為', '華為技術(shù)有限公司', 100, '萬物互聯(lián)', 1),
       ('小米', '小米科技有限公司', 50, 'are you ok', 1),
       ('格力', '格力電器股份有限公司', 30, '讓世界愛上中國(guó)造', 1),
       ('阿里巴巴', '阿里巴巴集團(tuán)控股有限公司', 10, '買買買', 1),
       ('騰訊', '騰訊計(jì)算機(jī)系統(tǒng)有限公司', 50, '玩玩玩', 0),
       ('百度', '百度在線網(wǎng)絡(luò)技術(shù)公司', 5, '搜搜搜', 0),
       ('京東', '北京京東世紀(jì)貿(mào)易有限公司', 40, '就是快', 1);

建好的的表如下:

vue+mybatis idea,Javaweb,前端

準(zhǔn)備Mybatis核心配置文件

1、在resources目錄下添加mybaits核心配置文件,去mybatis官方復(fù)制粘貼,然后修改即可,步驟如下:

1)創(chuàng)建 mybatis-config.xml

vue+mybatis idea,Javaweb,前端

vue+mybatis idea,Javaweb,前端

2)修改后的mybatis核心配置文件如下所示

vue+mybatis idea,Javaweb,前端

??

創(chuàng)建實(shí)體類與Mapper映射文件

因?yàn)橐粋€(gè)實(shí)體類對(duì)應(yīng)這一個(gè)mapper映射文件,因此需要先創(chuàng)建實(shí)體類

1、創(chuàng)建實(shí)體類

根據(jù)數(shù)據(jù)庫表tb_brand,我們創(chuàng)建一個(gè)Brand實(shí)體類

步驟:右擊java -> New -> Java Class

vue+mybatis idea,Javaweb,前端????????

根據(jù)數(shù)據(jù)庫表 tb_brand 在實(shí)體類Brand中創(chuàng)建對(duì)應(yīng)的屬性及get、set方法,如下所示

vue+mybatis idea,Javaweb,前端

代碼如下:

package com.clear.pojo;

public class Brand {
    private Integer id;
    private String brandName;
    private String companyName;
    private Integer ordered;
    private String description;
    private Integer 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 +
                '}';
    }
}

?2、創(chuàng)建mapper映射文件

在創(chuàng)建mapper映射文件之前,在創(chuàng)建一個(gè)mapper接口,如下所示

步驟:右擊java -> New -> Java Class -> 選擇Interface?

vue+mybatis idea,Javaweb,前端

?vue+mybatis idea,Javaweb,前端

?接下來在resources目錄下創(chuàng)建一個(gè)與BrandMapper接口在同一目錄下的映射文件(因?yàn)轫?xiàng)目部署時(shí)mapper接口生成的class字節(jié)碼文件需要與mapper映射文件xml在同一目錄下

步驟視圖如下:

vue+mybatis idea,Javaweb,前端

?vue+mybatis idea,Javaweb,前端

?接著我們與創(chuàng)建mybatis核心配置時(shí)一樣,依然去myabtis官網(wǎng)復(fù)制粘貼,然后修改,修改后的映射文件如下所示:

vue+mybatis idea,Javaweb,前端

?緊接著去修改mybatis核心配置文件中mapper標(biāo)簽 中 resource屬性的值,如下所示:

vue+mybatis idea,Javaweb,前端

補(bǔ)全項(xiàng)目結(jié)構(gòu)

如下所示

vue+mybatis idea,Javaweb,前端????????

1、在pom.xml中導(dǎo)入相關(guān)依賴

需要連接MySQL——導(dǎo)入MySQL相關(guān)依賴

使用了mybatis簡(jiǎn)化JDBC——導(dǎo)入mybatis依賴

需要使用JSON在前后端傳遞數(shù)據(jù)——導(dǎo)入fastjson

是Java的web項(xiàng)目——導(dǎo)入servlet(注意scope為provided)

為了方便啟動(dòng)服務(wù)器——導(dǎo)入tomcat7插件

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-case</artifactId>
    <version>1.0-SNAPSHOT</version>


    <packaging>war</packaging>

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

    <dependencies>
        <!--servlet-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <!--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.46</version>
        </dependency>
        <!--fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.62</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>

2、導(dǎo)入axios、vue的js文件

vue+mybatis idea,Javaweb,前端

3、導(dǎo)入Element-ui

vue+mybatis idea,Javaweb,前端

?至此,基本的環(huán)境就準(zhǔn)備的差不多了,如果還需要其他的,后續(xù)在補(bǔ)充

3、查詢所有功能的實(shí)現(xiàn)? ?

vue+mybatis idea,Javaweb,前端

如上圖所示是查詢所有品牌數(shù)據(jù)在頁面展示的效果。要實(shí)現(xiàn)這個(gè)功能,要先搞明白如下問題:

1)什么時(shí)候發(fā)送異步請(qǐng)求?

頁面加載完畢后就需要在頁面上看到所有的品牌數(shù)據(jù)。所以在 mounted() 這個(gè)構(gòu)造函數(shù)中寫發(fā)送異步請(qǐng)求的代碼。

2)請(qǐng)求需要攜帶參數(shù)嗎?

查詢所有功能不需要攜帶什么參數(shù)。

3)響應(yīng)的數(shù)據(jù)格式是什么樣?

后端是需要將 List<Brand> 對(duì)象轉(zhuǎn)換為 JSON 格式的數(shù)據(jù)并響應(yīng)回給瀏覽器。響應(yīng)數(shù)據(jù)格式如下:

vue+mybatis idea,Javaweb,前端

整體流程如下:

?vue+mybatis idea,Javaweb,前端

我們先實(shí)現(xiàn)后端程序,然后再實(shí)現(xiàn)前端程序。 ?

3.1、后端的實(shí)現(xiàn)

3.1.1、dao層方法的實(shí)現(xiàn):

在com.clear.mapper.BrandMapper接口中定義抽象方法,并使用注解來編寫SQL語句,如下所示

vue+mybatis idea,Javaweb,前端

但是這樣肯定會(huì)出問題的,因?yàn)槲覀儎傞_始創(chuàng)建實(shí)體類Brand時(shí),Brand中的屬性與數(shù)據(jù)庫表tb_brand中的字段名沒有一一對(duì)應(yīng),這樣mybatis無法幫我們完成自動(dòng)封裝,所以我們需要在BrandMapper映射文件中定義結(jié)果映射 ,使用resultMap標(biāo)簽。如下所示:

vue+mybatis idea,Javaweb,前端

定義完結(jié)果映射關(guān)系后,在接口selectAll()方法上引用該結(jié)構(gòu)映射。使用@ResultMap()注解來完成,如下所示:

vue+mybatis idea,Javaweb,前端

接著我們來優(yōu)化一下上面的配置:

我們發(fā)現(xiàn),在BrandMapper映射文件中resultMap標(biāo)簽中的type屬性需要填寫B(tài)rand實(shí)體類的全限定名,這顯然有點(diǎn)不簡(jiǎn)潔了,我們可以通過在mybatis核心配置文件中定義typeAliases標(biāo)簽來簡(jiǎn)化它,如下所示:

vue+mybatis idea,Javaweb,前端

接著修改BrandMapper映射文件,如下所示

vue+mybatis idea,Javaweb,前端?????

3.1.2、service方法的實(shí)現(xiàn)

在com.clear.service包下創(chuàng)建BrandService的接口,在該接口中定義查詢所有的抽象方法

vue+mybatis idea,Javaweb,前端

并在com.clear.service下再創(chuàng)建impl包;impl表示是放 service 層接口的實(shí)現(xiàn)類的包。 在該包下創(chuàng)建名為BrandServiceImpl類

vue+mybatis idea,Javaweb,前端

這時(shí)就要疑惑了,之前我們都是直接定義service類,然后在里面定義方法,此處為什么要給 service 定義接口呢?因?yàn)閟ervice定義了接口后,在 servlet 中就可以使用多態(tài)的形式創(chuàng)建Service實(shí)現(xiàn)類的對(duì)象,如下:

vue+mybatis idea,Javaweb,前端

這里使用多態(tài)是因?yàn)榉奖阄覀兒笃诮獬齋ervlet和service的耦合。從上面的代碼我們可以看到SelectAllServlet類和BrandServiceImpl類之間是耦合在一起的,如果后期 BrandService 有其它更好的實(shí)現(xiàn)類(例如叫 BrandServiceImpl),那就需要修改SelectAllServlet類中的代碼。后面我們學(xué)習(xí)了Spring框架后就可以解除SelectAllServlet類和紅色框括起來的代碼耦合。而現(xiàn)在咱們還做不到解除耦合,在這里只需要理解為什么定義接口即可。

BrandServiceImpl類代碼如下:

package com.clear.service.impl;

import com.clear.mapper.BrandMapper;
import com.clear.pojo.Brand;
import com.clear.service.BrandService;
import com.clear.util.SqlSessionFactoryUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import java.util.List;

public class BrandServiceImpl implements BrandService {
    //1. 創(chuàng)建SqlSessionFactory 工廠對(duì)象
    SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();

    /**
     * 查詢所有
     * @return
     */
    @Override
    public List<Brand> selectAll() {
        //2. 獲取SqlSession對(duì)象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //3. 獲取BrandMapper
        BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
        //4. 調(diào)用方法
        List<Brand> brands = brandMapper.selectAll();

        //5. 釋放資源
        sqlSession.close();

        return brands;
    }
}

上述中用到了一個(gè)工廠對(duì)象,在com.clear.util包下創(chuàng)建SqlSessionFactoryUtils類,工廠對(duì)象的代碼如下:

package com.clear.util;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.InputStream;

/**
 * 獲取SqlSessionFactory對(duì)象的工具類
 */
public class SqlSessionFactoryUtils {
    private static SqlSessionFactory sqlSessionFactory;

    //靜態(tài)代碼塊會(huì)隨著類的加載而自動(dòng)執(zhí)行,且只執(zhí)行一次
    static {
        InputStream inputStream = null;
        try {
            String resource = "mybatis-config.xml";
            inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

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

3.1.3、servlet實(shí)現(xiàn)

在 com.clear.web.servlet?包下定義名為SelectAllServlet的查詢所有的servlet。該servlet邏輯如下:

1)調(diào)用service的selectAll()方法查詢到所有的品牌數(shù)據(jù),并返回結(jié)果

2)將返回的結(jié)果封裝為json數(shù)據(jù)

3)響應(yīng)json數(shù)據(jù)至前端

servlet代碼如下:


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

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1、調(diào)用service查詢
        List<Brand> brands = brandService.selectAll();
        // 2、轉(zhuǎn)為json
        String jsonString =JSON.toJSONString(brands);
        // 3、寫數(shù)據(jù)
        response.setContentType("text/json;charset=utf-8"); //告知瀏覽器響應(yīng)的數(shù)據(jù)類型, 告知瀏覽器使用什么字符集進(jìn)行解碼
        PrintWriter writer = response.getWriter();
        // 響應(yīng)數(shù)據(jù)至瀏覽器
        writer.write(jsonString);
    }

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

3.1.4、測(cè)試后端程序

在瀏覽器輸入訪問 servlet 的資源路徑 http://localhost:8080/brand-case/selectAllServlet ,如果沒有報(bào)錯(cuò),并能看到如下信息表明后端程序沒有問題

vue+mybatis idea,Javaweb,前端

3.2、前端實(shí)現(xiàn)

3.2.1、創(chuàng)建brand.html頁面

在webapp目錄下創(chuàng)建brand.html頁面,如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>

</body>
</html>

在頁面引入Element 的css、js文件 和 Vue.js,如下:

一般是是在</body> 標(biāo)簽之前引入


<script src="js/vue.js"></script>
<script src="element-ui/lib/index.js"></script>
<link rel="stylesheet" href="element-ui/lib/theme-chalk/index.css"> 

創(chuàng)建Vue核心對(duì)象,如下所示:

vue+mybatis idea,Javaweb,前端

創(chuàng)建 Vue 對(duì)象時(shí),需要傳遞一個(gè) js 對(duì)象,而該對(duì)象中需要如下屬性:

1)el:?用來指定哪些標(biāo)簽受 Vue 管理。 該屬性取值 #app 中的 app 需要是受管理的標(biāo)簽的id屬性值

2)data:用來定義數(shù)據(jù)模型

3)methods:用來定義函數(shù)。

定義div標(biāo)簽,它有一個(gè)id屬性,值為app,如下:

vue+mybatis idea,Javaweb,前端

3.2.2、官網(wǎng)復(fù)制Element組件代碼

去Element官網(wǎng)復(fù)制組件代碼,然后進(jìn)行修改,步驟如下:

vue+mybatis idea,Javaweb,前端

將html標(biāo)簽拷貝到 <div id="app"></div> 中,如下:

vue+mybatis idea,Javaweb,前端

將css樣式拷貝到我們頁面的 head 標(biāo)簽中,如下

vue+mybatis idea,Javaweb,前端

?將方法和模型數(shù)據(jù)拷貝到 Vue 對(duì)象指定的位置

vue+mybatis idea,Javaweb,前端

?拷貝修改后的brand.html頁面如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <style>
        /*表格的樣式*/
        .el-table .warning-row {
            background: oldlace;
        }

        .el-table .success-row {
            background: #f0f9eb;
        }
    </style>
</head>
<body>
<div id="app">
    <template>
        <el-table
                :data="tableData"
                style="width: 100%"
                :row-class-name="tableRowClassName">
            <el-table-column
                    prop="brandName"
                    label="品牌名稱"
                    align="center">
            </el-table-column>
            <el-table-column
                    prop="companyName"
                    label="企業(yè)名稱"
                    align="center">
            </el-table-column>
            <el-table-column
                    prop="ordered"
                    label="排序"
                    align="center">
            </el-table-column>
            <el-table-column
                    prop="status"
                    label="當(dāng)前狀態(tài)"
                    align="center">
            </el-table-column>

        </el-table>
    </template>
</div>

<script src="js/vue.js"></script>
<script src="element-ui/lib/index.js"></script>
<link rel="stylesheet" href="element-ui/lib/theme-chalk/index.css">

<script>
    new Vue({
        el: "#app",
        data() {
            return {
                tableData: [{
                    brandName: '2016-05-02',
                    companyName: '王小虎',
                    ordered: '上海市普陀區(qū)金沙江路 1518 弄',
                    status:"100"
                }]
            }
        },
        methods: {
            tableRowClassName({row, rowIndex}) {
                if (rowIndex === 1) {
                    return 'warning-row';
                } else if (rowIndex === 3) {
                    return 'success-row';
                }
                return '';

            }
        }
    })
</script>
</body>
</html>

其中,解釋一下上述部分的含義:

vue+mybatis idea,Javaweb,前端

vue+mybatis idea,Javaweb,前端

?測(cè)試一下,上述brand.html頁面代碼,頁面如下:

vue+mybatis idea,Javaweb,前端

?接下來頁面添加按鈕,依然是去Element官網(wǎng)導(dǎo)入Element組件,如下所示:

vue+mybatis idea,Javaweb,前端

?測(cè)試一下,上述brand.html頁面代碼,頁面如下:

vue+mybatis idea,Javaweb,前端

?接下來為每行的最前面添加復(fù)選框,依然是去Element官網(wǎng)復(fù)制Element組件,然后修改,如下所示:

找到這個(gè)帶復(fù)選框的表格,去復(fù)制它的代碼?

vue+mybatis idea,Javaweb,前端

vue+mybatis idea,Javaweb,前端

思考一下,當(dāng)我們選擇了復(fù)選框以后,應(yīng)該要執(zhí)行某種方法來傳遞?選擇的這些行數(shù)據(jù),所以我們觀察Element組件代碼后發(fā)現(xiàn),在<el-table>標(biāo)簽中需要有一個(gè)事件 @selection-change="handleSelectionChange" ,如下

vue+mybatis idea,Javaweb,前端

?還如要他綁定的函數(shù),handleSelectionChange,如下所示:

vue+mybatis idea,Javaweb,前端

從該函數(shù)中又發(fā)現(xiàn)還需要一個(gè)模型數(shù)據(jù) multipleSelection ,所以還需要定義出該模型數(shù)據(jù)

標(biāo)號(hào)列也用同樣的方式進(jìn)行拷貝并修改。

修改后的brand.html頁面如下:

vue+mybatis idea,Javaweb,前端

?vue+mybatis idea,Javaweb,前端

?測(cè)試結(jié)果如下所示:

vue+mybatis idea,Javaweb,前端

接下來為每行最前面添加序號(hào),依然是去Element官網(wǎng)復(fù)制Element組件,然后再修改,如下

找到前面帶序號(hào)的表格,復(fù)制它的代碼

vue+mybatis idea,Javaweb,前端

?vue+mybatis idea,Javaweb,前端

修改后的brand.html代碼如下:

vue+mybatis idea,Javaweb,前端

?測(cè)試結(jié)果如下:

vue+mybatis idea,Javaweb,前端

下面就可以開始完成查詢所有的前端頁面了

前端需要在頁面加載完畢后發(fā)送 ajax 請(qǐng)求,所以發(fā)送請(qǐng)求的邏輯應(yīng)該放在 mounted() 鉤子函數(shù)中。而響應(yīng)回來的數(shù)據(jù)需要賦值給表格綁定的數(shù)據(jù)模型,從下圖可以看出表格綁定的數(shù)據(jù)模型是 tableData

vue+mybatis idea,Javaweb,前端

前端代碼如下

// 勾子函數(shù),頁面加載完畢后執(zhí)行
        method(){
            //當(dāng)頁面加載完成后,發(fā)送異步請(qǐng)求,獲取數(shù)據(jù)
            var _this = this;

            axios({
                method:"get",
                url:"http://localhost:8080/brand-case/selectAllServlet",
            }).then(function (resp) { // then回調(diào)函數(shù)
                _this.tableData = resp.data;
            });

啟動(dòng)服務(wù)器測(cè)試,如下

vue+mybatis idea,Javaweb,前端

發(fā)現(xiàn)達(dá)到我們想要的效果,我們想要的效果是將數(shù)據(jù)庫表tb_brand中所有記錄都展示出來,但是顯然沒有這樣效果,我們檢查我們的前端代碼,發(fā)現(xiàn)如下錯(cuò)誤:

vue+mybatis idea,Javaweb,前端繼續(xù)測(cè)試發(fā)現(xiàn)依然達(dá)不到想要的效果,經(jīng)檢查發(fā)現(xiàn),我們的勾子函數(shù)寫錯(cuò)了,如下:

vue+mybatis idea,Javaweb,前端

?繼續(xù)測(cè)試發(fā)現(xiàn)依然達(dá)不到想要的效果,經(jīng)檢查發(fā)現(xiàn)我們使用的是axios發(fā)送異步請(qǐng)求,但是我們并沒有導(dǎo)入axios,下面進(jìn)行導(dǎo)入

<script src="js/axios-0.18.0.js"></script>

?完整代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <style>
        /*表格的樣式*/
        .el-table .warning-row {
            background: oldlace;
        }

        .el-table .success-row {
            background: #f0f9eb;
        }
    </style>
</head>
<body>
<div id="app">
    <template>
        <el-table
                :data="tableData"
                style="width: 100%"
                :row-class-name="tableRowClassName"
                @selection-change="handleSelectionChange">
            <el-table-column
                    type="selection"
                    width="55">
            </el-table-column>

            <el-table-column
                    type="index"
                    width="50">
            </el-table-column>

            <el-table-column
                    prop="brandName"
                    label="品牌名稱"
                    align="center">
            </el-table-column>
            <el-table-column
                    prop="companyName"
                    label="企業(yè)名稱"
                    align="center">
            </el-table-column>
            <el-table-column
                    prop="ordered"
                    label="排序"
                    align="center">
            </el-table-column>
            <el-table-column
                    prop="status"
                    label="當(dāng)前狀態(tài)"
                    align="center">
            </el-table-column>
            <el-table-column
                    align="center"
                    label="操作">
                <el-row>
                    <el-button type="primary">修改</el-button>
                    <el-button type="danger">刪除</el-button>
                </el-row>
            </el-table-column>

        </el-table>
    </template>
</div>

<script src="js/vue.js"></script>
<script src="element-ui/lib/index.js"></script>
<link rel="stylesheet" href="element-ui/lib/theme-chalk/index.css">

<script src="js/axios-0.18.0.js"></script>
<script>
    new Vue({
        el: "#app",
        data() {
            return {
                multipleSelection: [],

                // 表格數(shù)據(jù)
                tableData: []
            }
        },
        methods: {
            tableRowClassName({row, rowIndex}) {
                if (rowIndex === 1) {
                    return 'warning-row';
                } else if (rowIndex === 3) {
                    return 'success-row';
                }
                return '';

            },
            // 選擇復(fù)選框后執(zhí)行的函數(shù)
            handleSelectionChange(val) {
                this.multipleSelection = val;
            }
        },
        // 勾子函數(shù),頁面加載完畢后執(zhí)行
        mounted(){
            //當(dāng)頁面加載完成后,發(fā)送異步請(qǐng)求,獲取數(shù)據(jù)
            var _this = this;

            axios({
                method:"get",
                url:"http://localhost:8080/brand-case/selectAllServlet",
            }).then(function (resp) { // then回調(diào)函數(shù)
                _this.tableData = resp.data;
            });
        }
    })
</script>
</body>
</html>

測(cè)試結(jié)果如下:

vue+mybatis idea,Javaweb,前端

?至此,查詢所有功能的前后端頁面均已完成

4、添加功能的實(shí)現(xiàn)

vue+mybatis idea,Javaweb,前端

上圖是添加數(shù)據(jù)的對(duì)話框,當(dāng)點(diǎn)擊 提交 按鈕后就需要將數(shù)據(jù)提交到后端,并將數(shù)據(jù)保存到數(shù)據(jù)庫中。下圖是整體的流程:

vue+mybatis idea,Javaweb,前端

頁面發(fā)送請(qǐng)求時(shí),需要將輸入框輸入的內(nèi)容提交給后端程序,而這里是以 json 格式進(jìn)行傳遞的。而具體的數(shù)據(jù)格式如下:

vue+mybatis idea,Javaweb,前端?注意:由于是添加數(shù)據(jù),所以上述json數(shù)據(jù)中id是沒有值的。

?4.1、后端的實(shí)現(xiàn)

4.1.1、dao層方法的實(shí)現(xiàn)

在BrandMapper接口中定義add()抽象的添加方法,并使用@Insert注解編寫SQL語句,代碼如下:

/**
     * 添加品牌
     * @param brand
     */
    @Insert("insert into tb_brand values(null, #{brandName}, #{companyName}, #{ordered}," +
            "#{description}, #{status})")
    void add(Brand brand);

4.1.2、serivce方法的實(shí)現(xiàn)

在BrandService接口中定義add(),添加品牌的業(yè)務(wù)邏輯方法?

    /**
     * 添加品牌
     * @param brand
     */
    void add(Brand brand);

在BrandServiceImpl類中重寫add()?方法,并進(jìn)行業(yè)務(wù)邏輯實(shí)現(xiàn)

    /**
     * 添加品牌
     * @param brand
     */
    public void add(Brand brand){
        //2. 獲取SqlSession對(duì)象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //3. 獲取BrandMapper
        BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
        //4. 調(diào)用方法
        brandMapper.add(brand);
        // 提交事務(wù)
        sqlSession.commit();
        
        //5. 釋放資源
        sqlSession.close();

    }

注意:增刪改操作一定要提交事務(wù)

4.1.3、servlet的實(shí)現(xiàn)

在com.clear.web.servlet包寫定義名為AddServlet的 Servlet。該 Servlet 的邏輯如下:

1)接收頁面提交的數(shù)據(jù)。頁面到時(shí)候提交的數(shù)據(jù)是 json 格式的數(shù)據(jù),所以此處需要使用輸入流讀取數(shù)據(jù)

2)將接收到的數(shù)據(jù)轉(zhuǎn)換為Brand對(duì)象

3)調(diào)用 service 的add方法進(jìn)行添加的業(yè)務(wù)邏輯處理

4)給瀏覽器響應(yīng)添加成功的標(biāo)識(shí),這里直接給瀏覽器響應(yīng) success 字符串表示成功


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

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1、接收品牌數(shù)據(jù)
        BufferedReader br = request.getReader();
        String jsonStr = br.readLine(); // 因?yàn)閖son字符串自有一行數(shù)據(jù)
        // 2、轉(zhuǎn)為Brand對(duì)象
        Brand brand = JSON.parseObject(jsonStr, Brand.class);
        // 3、調(diào)用service完成添加
        brandService.add(brand);

        // 4、響應(yīng)成功標(biāo)識(shí)
        PrintWriter writer = response.getWriter();
        writer.write("success");
    }

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

4.2、前端實(shí)現(xiàn)

vue+mybatis idea,Javaweb,前端

打開頁面,我們并沒有發(fā)現(xiàn)其有新增品牌的按鈕,現(xiàn)在我們就將新增品牌的按鈕做出來,因?yàn)榇龝?huì)還要批量刪除的操作,因此這里一并把新增按鈕、批量刪除按鈕都做出來

從 Element 官網(wǎng)找具有著色效果的按鈕,并將代碼拷貝到我們自己的頁面上

?vue+mybatis idea,Javaweb,前端

修改后的brand.html如下

vue+mybatis idea,Javaweb,前端

測(cè)試結(jié)果如下:

vue+mybatis idea,Javaweb,前端

接下來為新增品牌按鈕綁定一個(gè)對(duì)話框表單

去Element官網(wǎng)復(fù)制組件,如下

vue+mybatis idea,Javaweb,前端

vue+mybatis idea,Javaweb,前端

?修改的brand.html頁面如下:

vue+mybatis idea,Javaweb,前端

vue+mybatis idea,Javaweb,前端

vue+mybatis idea,Javaweb,前端

做完上述操作后,我們進(jìn)行測(cè)試,結(jié)果如下:

vue+mybatis idea,Javaweb,前端

我們發(fā)現(xiàn),當(dāng)點(diǎn)擊新增品牌按鈕是,確實(shí)可以彈出對(duì)話框,但是對(duì)話框里的內(nèi)容不是一個(gè)表單,接下來我們將把對(duì)話框里的內(nèi)容改變?yōu)橐粋€(gè)表單

去Element官網(wǎng)找到類似的組件,復(fù)制粘貼,如下

vue+mybatis idea,Javaweb,前端

?vue+mybatis idea,Javaweb,前端

vue+mybatis idea,Javaweb,前端

vue+mybatis idea,Javaweb,前端

將模型數(shù)據(jù)和方法復(fù)制去指定位置,如下所示

vue+mybatis idea,Javaweb,前端vue+mybatis idea,Javaweb,前端

?測(cè)試如下:

vue+mybatis idea,Javaweb,前端

?現(xiàn)在點(diǎn)擊新增品牌按鈕以后,可以彈出對(duì)話框表單,但他不是我們想要的,因此我們將繼續(xù)修改它,如下:

vue+mybatis idea,Javaweb,前端

測(cè)試,結(jié)果如下

vue+mybatis idea,Javaweb,前端

?已經(jīng)很接近我們要的效果了,觀察發(fā)現(xiàn),在備注下還缺少一個(gè)名為狀態(tài)的滑塊,還有右下角多了個(gè)兩個(gè)按鈕 取消與確定

現(xiàn)在為對(duì)話框表單添加一個(gè)滑塊,去Element官網(wǎng)復(fù)制,如下

vue+mybatis idea,Javaweb,前端

?vue+mybatis idea,Javaweb,前端

?vue+mybatis idea,Javaweb,前端

接著刪除右下角的兩個(gè)按鈕

vue+mybatis idea,Javaweb,前端

?測(cè)試如下

vue+mybatis idea,Javaweb,前端

已經(jīng)達(dá)到了我們想要的效果,但是我們點(diǎn)擊提交或者是取消按鈕沒反應(yīng)

思考一下,我們前面在創(chuàng)建對(duì)話框時(shí)為新增品牌按鈕綁定了@click="dialogVisible = true"

?如下所示

vue+mybatis idea,Javaweb,前端

在data()定義了如下模型數(shù)據(jù)

?vue+mybatis idea,Javaweb,前端

?意思就是說當(dāng) dialogVisible == false 時(shí),對(duì)話框就會(huì)關(guān)閉,因此我們可以為取消按鈕綁定一個(gè)單擊事件 @click="dialogVisible =?false",如下所示

vue+mybatis idea,Javaweb,前端

接下來將提交按鈕 綁定的單擊事件改名,如下

vue+mybatis idea,Javaweb,前端

vue+mybatis idea,Javaweb,前端

接下來我們將修改對(duì)話框表中的綁定的模型數(shù)據(jù)

vue+mybatis idea,Javaweb,前端

?修改模型數(shù)據(jù)

vue+mybatis idea,Javaweb,前端

?修改后

vue+mybatis idea,Javaweb,前端

??

?完成上述操作后,我們就可以在addBrand方法中編寫代碼來完成添加功能的前端了

vue+mybatis idea,Javaweb,前端

上圖左邊是頁面效果,里面的提交按鈕可以通過上圖右邊看出綁定了一個(gè) 單擊事件,而該事件綁定的是addBrand函數(shù),所以添加品牌功能的邏輯代碼應(yīng)該寫在addBrand()函數(shù)中。在此方法中需要發(fā)送異步請(qǐng)求并將表單中輸入的數(shù)據(jù)作為參數(shù)進(jìn)行傳遞。如下:

vue+mybatis idea,Javaweb,前端

在then函數(shù)中的匿名函數(shù)是成功后的回調(diào)函數(shù),而resp.data就可以獲取到響應(yīng)回來的數(shù)據(jù),如果值是 success 表示數(shù)據(jù)添加成功。成功后我們需要做一下邏輯處理:

1、?關(guān)閉新增對(duì)話窗口

如下圖所示是添加數(shù)據(jù)的對(duì)話框代碼,從代碼中可以看到此對(duì)話框綁定了 dialogVisible 數(shù)據(jù)模型,只需要將該數(shù)據(jù)模型的值設(shè)置為 false,就可以關(guān)閉新增對(duì)話框窗口了。

vue+mybatis idea,Javaweb,前端

?這一步操作我們?cè)谇懊嬉呀?jīng)做過了

2、重新查詢數(shù)據(jù)

無論品牌數(shù)據(jù)添加成功與否,用戶只要能在頁面上查看到數(shù)據(jù)說明添加成功。而此處需要重新發(fā)送異步請(qǐng)求獲取所有的品牌數(shù)據(jù),而這段代碼在查詢所有功能中已經(jīng)實(shí)現(xiàn),所以我們可以將此功能代碼進(jìn)行抽取,抽取到一個(gè)selectAll()?函數(shù)中

接下來創(chuàng)建一個(gè)selectAll函數(shù),將mounted()勾子函數(shù)中的代碼復(fù)制過來,下面是勾子函數(shù)

vue+mybatis idea,Javaweb,前端

selectAll函數(shù)如下:

vue+mybatis idea,Javaweb,前端

3、彈出消息給用戶提示添加成功

vue+mybatis idea,Javaweb,前端

上圖左邊就是 elementUI 官網(wǎng)提供的成功提示代碼,而上圖右邊是具體的效果。

注意:上面的this需要的是表示 VUE 對(duì)象的this ??

綜上所述,addBrand函數(shù)代碼如下:

    // 添加品牌對(duì)話框表單點(diǎn)擊提交按鈕后執(zhí)行的函數(shù)
            addBrand() {
                var _this = this;

                // 發(fā)送ajax請(qǐng)求,添加數(shù)據(jù)
                axios({
                    method: "post",
                    url: "http://localhost:8080/brand-case/addServlet",
                    data: _this.brand
                }).then(function (resp) {
                    //響應(yīng)數(shù)據(jù)的處理邏輯
                    if (resp.data == "success") {
                        // 品牌添加成功,關(guān)閉對(duì)話框表單窗口
                        _this.dialogVisible = false;
                        // 查詢查詢數(shù)據(jù)
                        _this.selectAll();
                        // 彈出消息提示
                        _this.$message({
                            message: '恭喜你,品牌數(shù)據(jù)添加成功',
                            type: 'success'
                        });
                    }
                })

            },

完成了上面查詢功能和添加品牌功能,接下來我們就來優(yōu)化一下servlet目錄下的代碼

5、Servlet代碼優(yōu)化

5.1、問題引入

Web層中servlet的個(gè)數(shù)太多時(shí),不便于管理和編寫

將Servlet進(jìn)行歸類,對(duì)于同一個(gè)實(shí)體的操作方法,寫到一個(gè)Servlet中。比如:BrandServlet、UserServlet,如下:

vue+mybatis idea,Javaweb,前端

通過之前的兩個(gè)功能,我們發(fā)現(xiàn)每一個(gè)功能都需要定義一個(gè) servlet,一個(gè)模塊需要實(shí)現(xiàn)增刪改查功能,就需要4個(gè) servlet,模塊一多就會(huì)造成servlet 泛濫。

此時(shí)我們就想 servlet 能不能像 service 一樣,一個(gè)模塊只定義一個(gè) servlet,而每一個(gè)功能只需要在該 servlet 中定義對(duì)應(yīng)的方法。例如下面代碼:

@WebServlet("/brand/*")
public class BrandServlet {
    //查詢所有
	public void selectAll(...) {}
    
    //添加品牌
    public void add(...) {}
    
     //修改數(shù)據(jù)
    public void update(...) {}
    
    //刪除
    public void delete(...) {}
}

而我們知道發(fā)送請(qǐng)求 servlet,tomcat 會(huì)自動(dòng)的調(diào)用 service() 方法,之前我們?cè)谧远x的 servlet 中重寫 doGet() 方法和 doPost() 方法,當(dāng)我們?cè)L問該 servlet 時(shí)會(huì)根據(jù)請(qǐng)求方式將請(qǐng)求分發(fā)給 doGet() 或者 doPost() 方法,如下圖

vue+mybatis idea,Javaweb,前端

那么我們也可以仿照這樣請(qǐng)求分發(fā)的思想,在 service() 方法中根據(jù)具體的操作調(diào)用對(duì)應(yīng)的方法,如:查詢所有就調(diào)用 selectAll() 方法,添加企業(yè)信息就調(diào)用 add() 方法。

為了做到通用,我們定義一個(gè)通用的 servlet 類,在定義其他的 servlet 是不需要繼承 HttpServlet,而繼承我們定義的 BaseServlet,在BaseServlet 中調(diào)用具體 servlet(如BrandServlet)中的對(duì)應(yīng)方法。

public class BaseServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //進(jìn)行請(qǐng)求的分發(fā)
    }
}

BrandServlet定義就需要修改為如下:

@WebServlet("/brand/*")
public class BrandServlet extends BaseServlet {
    //用戶實(shí)現(xiàn)分頁查詢
	public void selectAll(...) {} 
    
    //添加品牌信息
    public void add(...) {}
    
    //修改品牌信息
    public void update(...) {}
    
    //刪除品牌信息
    public void delete(...) {}
}

那么如何在BaseServlet中調(diào)用對(duì)應(yīng)的方法呢?比如查詢所有就調(diào)用 selectAll() 方法。

可以規(guī)定在發(fā)送請(qǐng)求時(shí),請(qǐng)求資源的二級(jí)路徑(/brandServlet/selectAll)和需要調(diào)用的方法名相同,如:

查詢所有數(shù)據(jù)的路徑以后就需要寫成:http://localhost:8080/brand-case/brandServlet/selectAll

添加品牌數(shù)據(jù)的路徑以后就需要寫成:http://localhost:8080/brand-case/brandServlet/add?

修改品牌數(shù)據(jù)的路徑以后就需要寫成:http://localhost:8080/brand-case/brandServlet/update

刪除品牌數(shù)據(jù)的路徑以后就需要寫成:http://localhost:8080/brand-case/brandServlet/delete

這樣的話,BaseServlet 中就需要獲取到資源的二級(jí)路徑作為方法名,然后調(diào)用該方法,代碼如下:


public class BaseServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1、獲取請(qǐng)求路徑
        String uri = req.getRequestURI();  // 例如路徑為:/brand-case/brand/selectAll
        // 2、獲取最后一段路徑(方法名)
        int index = uri.lastIndexOf("/");
        String methodName = uri.substring(index + 1);

        // 2、執(zhí)行方法
        // 獲取BrandServlet字節(jié)碼對(duì)象 Class
        Class<? extends BaseServlet> cls = this.getClass();
        // 2.1、獲取方法 Method對(duì)象
        try {
            Method method = cls.getMethod(methodName,HttpServletRequest.class,HttpServletResponse.class);
            // 2.2、調(diào)用方法
            method.invoke(this,req,resp);

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

通過上面代碼發(fā)現(xiàn)根據(jù)方法名獲取對(duì)應(yīng)方法的 Method 對(duì)象時(shí)需要指定方法參數(shù)的字節(jié)碼對(duì)象。解決這個(gè)問題,可以將方法的參數(shù)類型規(guī)定死,而方法中可能需要用到 request 對(duì)象和 response 對(duì)象,所以指定方法的參數(shù)為 HttpServletRequestHttpServletResponse,那么 BrandServlet 代碼就可以改進(jìn)為:

@WebServlet("/brand/*")
public class BrandServlet extends BaseServlet {
    //用戶實(shí)現(xiàn)分頁查詢
	public void selectAll(HttpServletRequest req, HttpServletResponse resp) {}
    
    //添加品牌信息
    public void add(HttpServletRequest req, HttpServletResponse resp) {}
    
    //修改品牌信息
    public void update(HttpServletRequest req, HttpServletResponse resp) {}
    
    //刪除品牌信息
    public void delete(HttpServletRequest req, HttpServletResponse resp) {}
}

5.2、代碼優(yōu)化

5.2.1、后端代碼的優(yōu)化

定義了 BaseServlet 后,針對(duì)品牌模塊我們定義一個(gè) BrandServlet 的 Servlet,并使其繼承 BaseServlet 。在BrandServlet中定義 以下功能的方法:

1)查詢功能:方法名聲明為 selectAll ,并將之前的 SelectAllServlet 中的邏輯代碼拷貝到該方法中

2)添加品牌功能:方法名聲明為 add ,并將之前的 AddServlet 中的邏輯代碼拷貝到該方法中

代碼如下所示:


@WebServlet("/brand/*")
public class BrandServlet extends BaseServlet{
    private BrandService brandService = new BrandServiceImpl();

    public void selectAll(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1、調(diào)用service查詢
        List<Brand> brands = brandService.selectAll();
        System.out.println(brands);
        // 2、轉(zhuǎn)為json
        String jsonString = JSON.toJSONString(brands);
        // 3、寫數(shù)據(jù)
        response.setContentType("text/json;charset=utf-8"); //告知瀏覽器響應(yīng)的數(shù)據(jù)類型, 告知瀏覽器使用什么字符集進(jìn)行解碼
        PrintWriter writer = response.getWriter();
        // 響應(yīng)數(shù)據(jù)至瀏覽器
        writer.write(jsonString);
    }

    public void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1、接收品牌數(shù)據(jù)
        BufferedReader br = request.getReader();
        String jsonStr = br.readLine(); // 因?yàn)閖son字符串自有一行數(shù)據(jù)
        // 2、轉(zhuǎn)為Brand對(duì)象
        Brand brand = JSON.parseObject(jsonStr, Brand.class);
        // 3、調(diào)用service完成添加
        brandService.add(brand);

        // 4、響應(yīng)成功標(biāo)識(shí)
        PrintWriter writer = response.getWriter();
        writer.write("success");
    }
}

接著刪除之前創(chuàng)建的兩個(gè)Serlvet,如下

vue+mybatis idea,Javaweb,前端

?5.2.2、前端代碼的優(yōu)化

頁面中之前發(fā)送的請(qǐng)求的路徑都需要進(jìn)行修改,selectAll()函數(shù)中發(fā)送異步請(qǐng)求的 url 應(yīng)該改為 http://localhost:8080/brand-case/brand/selectAll 。具體如下

vue+mybatis idea,Javaweb,前端

addBrand()函數(shù)中發(fā)送異步請(qǐng)求的 url 應(yīng)該改為 http://localhost:8080/brand-case/brand/add 。具體如下

vue+mybatis idea,Javaweb,前端

?經(jīng)測(cè)試,上面優(yōu)化后的代碼可以正常運(yùn)行

6、批量刪除功能實(shí)現(xiàn)

vue+mybatis idea,Javaweb,前端

如上圖所示點(diǎn)擊選擇多條數(shù)據(jù)前的復(fù)選框就意味著要?jiǎng)h除這些數(shù)據(jù),而點(diǎn)擊了 批量刪除 按鈕后,需要讓用戶確認(rèn)一下,因?yàn)橛锌赡苁怯脩粽`操作的,當(dāng)用戶確定后需要給后端發(fā)送請(qǐng)求并攜帶者需要?jiǎng)h除數(shù)據(jù)的多個(gè)id值,后端程序刪除數(shù)據(jù)庫中的數(shù)據(jù)。具體的流程如下:

vue+mybatis idea,Javaweb,前端

注意: ?

????????前端發(fā)送請(qǐng)求時(shí)需要將要?jiǎng)h除的多個(gè)id值是以json格式提交給后端,而該json格式數(shù)據(jù)如下:

[1,2,3,4]

6.1、后端實(shí)現(xiàn)

6.1.1、dao層代碼的實(shí)現(xiàn)

在BrandMapper接口中定義抽象方法deleteByIds(int[] ids),由于這里需要使用到動(dòng)態(tài)SQL,屬于比較復(fù)雜的SQL操作,因此我們不采用注解的方式實(shí)現(xiàn),轉(zhuǎn)而采用SQL映射文件配置

接口方法聲明如下:

 /**
     * 批量刪除
     * @param ids
     */
    void deleteByIds(@Param("ids") int[] ids);

在BrandMapper.xml映射配置文件中添加 statement,如下所示

vue+mybatis idea,Javaweb,前端

6.1.2、service方法實(shí)現(xiàn)

在BrandService接口中定義抽象方法deleteByIds(int[] ids),批量刪除的業(yè)務(wù)邏輯方法


    /**
     * 批量刪除
     * @param ids
     */
    void deleteByIds(int[] ids);

BrandServiceImpl類中重寫deleteByIds(int[] ids)方法,并進(jìn)行業(yè)務(wù)邏輯實(shí)現(xiàn),代碼如下:

 /**
     * 批量刪除
     * @param ids
     */
    public void deleteByIds(int[] ids){
        // 2、獲取SqlSession對(duì)象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 3、獲取BrandMapper
        BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
        // 4、調(diào)用方法
        brandMapper.deleteByIds(ids);
        // 提交事務(wù)
        sqlSession.commit();
        
        // 5、釋放資源
        sqlSession.close();
        
    }

6.1.2、servlet的實(shí)現(xiàn)

因?yàn)槲覀冊(cè)谇懊鎯?yōu)化過servlet,因此我們創(chuàng)建的servlet不再繼承HttpServlet,在前面我們定義了BrandServlet,繼承自BaseServlet,而BaseServlet繼承自HttpServlet,相當(dāng)于我們間接繼承了HttpServlet

現(xiàn)在我們?cè)贐randServlet中定義deleteByIds()這個(gè)方法,該方法代碼邏輯如下:

1)接收頁面提交的數(shù)據(jù)。頁面到時(shí)候提交的數(shù)據(jù)是 json 格式的數(shù)據(jù),所以此處需要使用輸入流讀取數(shù)據(jù)

2)將接收到的數(shù)據(jù)轉(zhuǎn)換為 int[] 數(shù)組

3)調(diào)用 service 的 deleteByIds() 方法進(jìn)行批量刪除的業(yè)務(wù)邏輯處理

4)給瀏覽器響應(yīng)添加成功的標(biāo)識(shí),這里直接給瀏覽器響應(yīng) success 字符串表示成功

代碼如下:

/**
     * 批量刪除
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    public void deleteByIds(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1、接收數(shù)據(jù)(json串)
        BufferedReader br = request.getReader();
        String jsonStr = br.readLine();

        // 2、將接收到的數(shù)據(jù)轉(zhuǎn)為數(shù)組
        int[] ids = JSON.parseObject(jsonStr, int[].class);

        // 3、調(diào)用service完成批量刪除
        brandService.deleteByIds(ids);
        // 4、響應(yīng)成功標(biāo)識(shí)
        PrintWriter writer = response.getWriter();
        writer.write("success");

    }

6.2、前端實(shí)現(xiàn)

此功能的前端代碼實(shí)現(xiàn)稍微有點(diǎn)麻煩,分為以下幾步實(shí)現(xiàn)

6.2.1、獲取選擇的id值

我們前面做頁面表格的時(shí)候代碼如下:

vue+mybatis idea,Javaweb,前端

?vue+mybatis idea,Javaweb,前端

從上圖可以看出表格復(fù)選框綁定了一個(gè) selection-change 事件,該事件是當(dāng)選擇項(xiàng)發(fā)生變化時(shí)會(huì)觸發(fā)。該事件綁定了 handleSelectionChange 函數(shù),而該函數(shù)有一個(gè)參數(shù) val ,該參數(shù)是獲取選中行的數(shù)據(jù),如下:

?vue+mybatis idea,Javaweb,前端

而我們只需要將所有選中數(shù)據(jù)的id值提交給服務(wù)端即可,獲取id的邏輯我們書寫在批量刪除?按鈕綁定的函數(shù)中。

批量刪除?按鈕綁定單擊事件,并給綁定觸發(fā)時(shí)調(diào)用的函數(shù),如下

vue+mybatis idea,Javaweb,前端

并在Vue對(duì)象中的 methods 中定義 deleteByIds() 函數(shù),在該函數(shù)中從 multipleSelection 數(shù)據(jù)模型中獲取所選數(shù)據(jù)的id值。要完成這個(gè)功能需要在 Vue 對(duì)象中定義一個(gè)數(shù)據(jù)模型 selectedIds:[],在 deleteByIds() 函數(shù)中遍歷 multipleSelection 數(shù)組,并獲取到每一個(gè)所選數(shù)據(jù)的id值存儲(chǔ)到 selectedIds 數(shù)組中,代碼實(shí)現(xiàn)如下:

vue+mybatis idea,Javaweb,前端

vue+mybatis idea,Javaweb,前端

6.2.2、發(fā)送異步請(qǐng)求

使用 axios 發(fā)送異步請(qǐng)求并經(jīng)上一步獲取到的存儲(chǔ)所有的 id 數(shù)組作為請(qǐng)求參數(shù)

vue+mybatis idea,Javaweb,前端

?6.2.3、確認(rèn)框提示

由于刪除操作是比較危險(xiǎn)的;有時(shí)候可能是由于用戶的誤操作點(diǎn)擊了 批量刪除 按鈕,所以在點(diǎn)擊了按鈕后需要先給用戶確認(rèn)提示。而確認(rèn)框在 elementUI 中也提供了,如下圖

vue+mybatis idea,Javaweb,前端

而在點(diǎn)擊 確定 按鈕后需要執(zhí)行之前刪除的邏輯。將前面兩步操作整合在一起,確保用戶點(diǎn)擊了確定按鈕在執(zhí)行,優(yōu)化后前端代碼實(shí)現(xiàn)如下:

   // 批量刪除按鈕綁定的函數(shù)
        deleteByIds() {
            // 彈出提示框,詢問用戶是否確認(rèn)刪除
            this.$confirm("該操作將永久刪除這些數(shù)據(jù),是否繼續(xù)?", "警告", {
                confirmButtonText: '確定',
                cancelButtonText: '取消',
                type: 'warning'
            }).then(() => {
                // 用戶點(diǎn)擊確定后的邏輯

                // 1、遍歷從 multipleSelection 中 獲取id
                for (let i = 0; i < this.multipleSelection.length; i++) {
                    let selectElement = this.multipleSelection[i];
                    this.selectedIds[i] = selectElement.id;  // 將id存入數(shù)組
                }
                // 2、發(fā)送Ajax請(qǐng)求
                var _this = this;
                axios({
                    method: "post",  // 增刪改都用post請(qǐng)求
                    url: "http://localhost:8080/brand-case/brand/deleteByIds",
                    data: _this.selectedIds
                }).then(function (resp) {
                    if (resp.data == "success") {
                        // 刪除成功,重新查詢所有數(shù)據(jù)
                        _this.selectAll();
                        // 并彈出消息提示
                        _this.$message({
                            message: '恭喜你,品牌批量刪除成功',
                            type: 'success'
                        });
                    }
                })
            }).catch(() =>{
                // 用戶點(diǎn)擊取消后的邏輯
                this.$message({
                    type:'info',
                    message:'已取消刪除'
                });
            });
        },

測(cè)試批量刪除功能

啟動(dòng)服務(wù)器,選擇復(fù)選框,點(diǎn)擊批量刪除按鈕

vue+mybatis idea,Javaweb,前端

?刪除成功

7、分頁查詢功能的實(shí)現(xiàn)

7.1、分析

7.1.1、分頁查詢sql

分頁查詢也是從數(shù)據(jù)庫進(jìn)行查詢的,,所以我們要分頁對(duì)應(yīng)的SQL語句應(yīng)該怎么寫。分頁查詢使用 LIMIT 關(guān)鍵字,格式為:LIMIT 開始索引 每頁顯示的條數(shù)?。以后前端頁面在發(fā)送請(qǐng)求攜帶參數(shù)時(shí),它并不明確開始索引是什么,但是它知道查詢第幾頁。所以 開始索引 需要在后端進(jìn)行計(jì)算,計(jì)算的公式是 :開始索引 = (當(dāng)前頁碼 - 1)* 每頁顯示條數(shù)

比如說查詢第一頁的數(shù)據(jù)的SQL語句是:

select * from tb_brand limit 0,5;

查詢第二頁的數(shù)據(jù)的SQL語句是:

select * from tb_brand limit 5,5;

查詢第三頁的數(shù)據(jù)的 SQL 語句是:

select * from tb_brand limit 10,5;

以此類推

7.1.2、前后端數(shù)據(jù)的分析

分頁查詢功能時(shí)候比較復(fù)雜的,所以我們要先分析清楚以下兩個(gè)問題:

前端需要傳遞什么參數(shù)給后端

根據(jù)上一步對(duì)分頁查詢 SQL 語句分析得出,前端需要給后端兩個(gè)參數(shù)

1)當(dāng)前頁碼 : currentPage

2)每頁顯示條數(shù):pageSize

后端需要響應(yīng)什么數(shù)據(jù)給前端

vue+mybatis idea,Javaweb,前端

上圖是分頁查詢頁面展示的效果,從上面我們可以看出需要響應(yīng)以下相關(guān)聯(lián)數(shù)據(jù)

1)當(dāng)前頁需要展示的數(shù)據(jù)。我們?cè)诤蠖艘话銜?huì)存儲(chǔ)到 List 集合中

2)總共記錄數(shù)。在上圖頁面中需要展示總的記錄數(shù),所以這部分?jǐn)?shù)據(jù)也需要??偟捻撁?elementUI 的分頁組件會(huì)自動(dòng)計(jì)算,我們不需要關(guān)心

而這兩部分需要封裝到 PageBean 對(duì)象中,并將該對(duì)象轉(zhuǎn)換為 json 格式的數(shù)據(jù)響應(yīng)回給瀏覽器

vue+mybatis idea,Javaweb,前端

通過上面的分析我們需要先在 pojo 包下創(chuàng)建 PageBean 類,為了做到通過會(huì)將其定義成泛型類,代碼如下:

package com.clear.pojo;

import java.util.List;

/**
 * 分頁查詢JavaBean
 */
public class PageBean<T> {

    private Integer totalCount;  // 總記錄數(shù)
    private List<T> rows;  // 當(dāng)前頁數(shù)據(jù)

    public Integer getTotalCount() {
        return totalCount;
    }

    public void setTotalCount(Integer totalCount) {
        this.totalCount = totalCount;
    }

    public List<T> getRows() {
        return rows;
    }

    public void setRows(List<T> rows) {
        this.rows = rows;
    }
}

7.1.3、流程分析

后端需要響應(yīng)總記錄數(shù)和當(dāng)前頁的數(shù)據(jù) 兩部分?jǐn)?shù)據(jù)給前端。所以在BrandMapper接口中需要定義兩個(gè)方法:

? ? ? ? selectByPage():查詢當(dāng)前頁的數(shù)據(jù)的方法

? ? ? ? selectTotalCount():查詢總記錄的方法

整體流程如下:

vue+mybatis idea,Javaweb,前端

7.2、后端實(shí)現(xiàn)?

7.2.1、dao層方法的實(shí)現(xiàn)

在BrandMapper接口中定義selectByPage()方法進(jìn)行分頁查詢,代碼如下:

    /**
     * 分頁查詢
     * @param begin
     * @param size
     * @return
     */
    @Select("select * from tb_brand limit #{begin}, #{size}")
    @ResultMap("brandResultMap")
    List<Brand> selectByPage(@Param("begin") int begin,@Param("size") int size);

在BrandMapper接口中定義selectTotalCount()方法進(jìn)行統(tǒng)計(jì)記錄數(shù),代碼如下:

    /**
     * 查詢總記錄數(shù)
     * @return
     */
    @Select("select count(*) from tb_brand")
    int selectTotalCount();

7.2.2、service方法實(shí)現(xiàn)

在BrandService接口中定義selectBypage() 分頁查詢數(shù)據(jù)的業(yè)務(wù)邏輯方法

    /**
     * 分頁查詢
     * @param currentPage  當(dāng)前頁碼
     * @param pageSize  每頁展示條數(shù)
     * @return
     */
    PageBean<Brand> selectByPage(int currentPage, int pageSize);
 

在BrandServiceImpl?類中重寫 selectByPage() 方法,并進(jìn)行業(yè)務(wù)邏輯實(shí)現(xiàn)

@Override
    public PageBean<Brand> selectByPage(int currentPage, int pageSize) {
        //2. 獲取SqlSession對(duì)象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //3. 獲取BrandMapper
        BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
        //4. 計(jì)算開始索引
        int begin = (currentPage - 1) * pageSize;
        // 計(jì)算查詢條目數(shù)
        int size = pageSize;
        //5. 查詢當(dāng)前頁數(shù)據(jù)
        List<Brand> brands = brandMapper.selectByPage(currentPage, pageSize);
        //6. 查詢總記錄數(shù)
        int totalCount = brandMapper.selectTotalCount();

        //7. 封裝PageBean對(duì)象
        PageBean<Brand> pageBean = new PageBean<>();
        pageBean.setRows(brands);
        pageBean.setTotalCount(totalCount);
        //8. 釋放資源
        sqlSession.commit();

        return pageBean;
    }

7.2.3、servlet實(shí)現(xiàn)

在BrandSerlet類中定義selectByPage()方法。該方法的邏輯如下:

1)獲取頁面提交的 當(dāng)前頁碼每頁顯示條目數(shù) 兩個(gè)數(shù)據(jù)。這兩個(gè)參數(shù)是在url后進(jìn)行拼接的,格式是 url?currentPage=1&pageSize=5。獲取這樣的參數(shù)需要使用 requet.getparameter() 方法獲取。

2)調(diào)用 service 的 selectByPage() 方法進(jìn)行分頁查詢的業(yè)務(wù)邏輯處理

3)將查詢到的數(shù)據(jù)轉(zhuǎn)換為 json 格式的數(shù)據(jù)

4)響應(yīng) json 數(shù)據(jù)至前端

BrandServlet中selectByPage()方法代碼實(shí)現(xiàn)如下:


    /**
     * 分頁查詢功能
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    public void selectByPage(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1. 接收 當(dāng)前頁碼 和 每頁展示條數(shù)    url?currentPage=1&pageSize=5
        String _currentPage = request.getParameter("currentPage");
        String _pageSize = request.getParameter("pageSize");

        int currentPage = Integer.parseInt(_currentPage);
        int pageSize = Integer.parseInt(_pageSize);

        //2. 調(diào)用service查詢
        PageBean<Brand> pageBean = brandService.selectByPage(currentPage, pageSize);

        //2. 轉(zhuǎn)為JSON
        String jsonString = JSON.toJSONString(pageBean);
        //3. 寫數(shù)據(jù)
        response.setContentType("text/json;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.write(jsonString);
    }

7.2.4、測(cè)試

在瀏覽器上地址欄輸入 http://localhost:8080/brand-case/brand/selectByPage?currentPage=1&pageSize=5 ,查詢到以下數(shù)據(jù)

vue+mybatis idea,Javaweb,前端

7.3、前端實(shí)現(xiàn)

7.3.1、selectAll()的改進(jìn)

selectAll()函數(shù)之前是查詢所有數(shù)據(jù),現(xiàn)需要改成分頁查詢。 請(qǐng)求路徑應(yīng)改為 http://localhost:8080/brand-case/brand/selectByPage?currentPage=1&pageSize=5 ,而 currentPagepageSize 是需要攜帶的參數(shù),分別是 當(dāng)前頁碼 和 每頁顯示的條目數(shù)。

剛才我們對(duì)后端代碼進(jìn)行測(cè)試可以看出響應(yīng)回來的數(shù)據(jù),所以在異步請(qǐng)求的成功回調(diào)函數(shù)(then 中的匿名函數(shù))中給頁面表格的數(shù)據(jù)模型賦值 _this.tableData = resp.data.rows;。整體代碼如下

    var _this = this;

                axios({
                    method: "get",
                    url: "http://localhost:8080/brand-case/brand/selectByPage?currentPage=1&pageSize=5",
                }).then(function (resp) {
                    // 設(shè)置表格數(shù)據(jù)
                    _this.tableData = resp.data.rows;  // {rows:[],totalCount:100}
                });

響應(yīng)的數(shù)據(jù)中還有總記錄數(shù),要進(jìn)行總記錄數(shù)展示需要在頁面綁定數(shù)據(jù)模型

vue+mybatis idea,Javaweb,前端

而頁面中分頁組件給 當(dāng)前頁碼每頁顯示的條目數(shù) 都綁定了數(shù)據(jù)模型

vue+mybatis idea,Javaweb,前端

所以 selectAll() 函數(shù)中發(fā)送異步請(qǐng)求的資源路徑中不能將當(dāng)前頁碼和 每頁顯示條目數(shù)寫死,代碼就可以優(yōu)化為

vue+mybatis idea,Javaweb,前端

?7.3.2、改變每頁條目數(shù)

????vue+mybatis idea,Javaweb,前端????

當(dāng)我們改變每頁顯示的條目數(shù)后,需要重新發(fā)送異步請(qǐng)求。而下圖是分頁組件代碼,@size-change 就是每頁顯示的條目數(shù)發(fā)生變化時(shí)會(huì)觸發(fā)的事件

vue+mybatis idea,Javaweb,前端?而該事件綁定了一個(gè) handleSizeChange 函數(shù),整個(gè)邏輯如下:

vue+mybatis idea,Javaweb,前端

7.3.3、 改變當(dāng)前頁碼

當(dāng)我們改變頁碼時(shí),需要重新發(fā)送異步請(qǐng)求。而下圖是分頁組件代碼,@current-change 就是頁碼發(fā)生變化時(shí)會(huì)觸發(fā)的事件

vue+mybatis idea,Javaweb,前端

?而該事件綁定了一個(gè) handleCurrentChange 函數(shù),整個(gè)邏輯如下

vue+mybatis idea,Javaweb,前端

?測(cè)試

經(jīng)測(cè)試,頁面上啥也沒有,我們檢查代碼,檢查后發(fā)現(xiàn)分頁工具條中的模型數(shù)據(jù)沒有在Vue對(duì)象中聲明出來,如下所示:

vue+mybatis idea,Javaweb,前端

再次測(cè)試,分頁工具條就可以使用了,如下

vue+mybatis idea,Javaweb,前端

?8、條件查詢功能實(shí)現(xiàn)

vue+mybatis idea,Javaweb,前端

?上圖就是用來輸入條件查詢的條件數(shù)據(jù)的。要做條件查詢功能,先明確以下三個(gè)問題

1)三個(gè)條件之間滿足什么關(guān)系?

同時(shí)滿足,所用 SQL 中多個(gè)條件需要使用 and 關(guān)鍵字連接

2)3個(gè)條件必須全部填寫嗎?

不需要。想根據(jù)哪兒個(gè)條件查詢就寫那個(gè),所以這里需要使用動(dòng)態(tài) sql 語句

3)條件查詢需要分頁嗎?

需要

整個(gè)條件分頁查詢流程如下:

vue+mybatis idea,Javaweb,前端

8.1、后端實(shí)現(xiàn)

8.1.1、dao層實(shí)現(xiàn)

在BrandMapper接口中定義selectByPageAndCondition()?方法 和selectTotalCountByCondtion()方法?,用來進(jìn)行條件分頁查詢功能,方法如下:

/**
     * 分頁條件查詢
     *
     * @param begin
     * @param size
     * @param brand
     * @return
     */
    List<Brand> selectByPageAndCondition(@Param("begin") int begin,
                                         @Param("size") int size, @Param("brand") Brand brand);


    /**
     * 根據(jù)條件查詢總記錄數(shù)
     *
     * @return
     */
    int selectTotalCountByCondition(Brand brand);

參數(shù):

begin 分頁查詢的起始索引

size 分頁查詢的每頁條目數(shù)

brand 用來封裝條件的對(duì)象

由于這是一個(gè)復(fù)雜的查詢語句,需要使用動(dòng)態(tài)sql;所以我們?cè)谟成渑渲梦募袝鴮?sql 語句。brand_name 字段和 company_name 字段需要進(jìn)行模糊查詢,所以需要使用 % 占位符。映射配置文件中 statement 書寫如下:

 <!--查詢滿足條件的數(shù)據(jù)并進(jìn)行分頁-->
    <select id="selectByPageAndCondition" resultMap="brandResultMap">
        select *
        from tb_brand
        <where>
            <if test="brand.brandName != null and brand.brandName != '' ">
                and brand_name like #{brand.brandName}
            </if>
            <if test="brand.companyName != null and brand.companyName != '' ">
                and company_name like #{brand.companyName}
            </if>
            <if test="brand.status != null ">
                and status = #{brand.status}
            </if>
        </where>
        limit #{begin},#{size}
    </select>


   <!--查詢滿足條件的數(shù)據(jù)條目數(shù)-->
    <select id="selectTotalCountByCondition" resultType="java.lang.Integer">
        select count(*)
        from tb_brand
        <where>
            <if test="brandName != null and brandName != '' ">
                and brand_name like #{brandName}
            </if>

            <if test="companyName != null and companyName != '' ">
                and company_name like #{companyName}
            </if>

            <if test="status != null">
                and status = #{status}
            </if>
        </where>
    </select>

8.1.2、service的實(shí)現(xiàn)

BrandService 接口中定義 selectByPageAndCondition() 分頁查詢數(shù)據(jù)的業(yè)務(wù)邏輯方法

/**
     * 分頁條件查詢
     * @param currentPage
     * @param pageSize
     * @param brand
     * @return
     */
    PageBean<Brand> selectByPageAndCondition(int currentPage, int pageSize, Brand brand);

BrandServiceImpl 類中重寫 selectByPageAndCondition() 方法,并進(jìn)行業(yè)務(wù)邏輯實(shí)現(xiàn)


    /**
     * 分頁條件查詢
     * @param currentPage
     * @param pageSize
     * @param brand
     * @return
     */
    public PageBean<Brand> selectByPageAndCondition(int currentPage, int pageSize, Brand brand){
        //2. 獲取SqlSession對(duì)象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //3. 獲取BrandMapper
        BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);

        //4. 計(jì)算開始索引
        int begin = (currentPage - 1) * pageSize;
        // 計(jì)算查詢條目數(shù)
        int size = pageSize;

        // 處理brand條件,模糊表達(dá)式
        String brandName = brand.getBrandName();
        if (brandName != null && brandName.length() > 0) {
            brand.setBrandName("%" + brandName + "%");
        }

        String companyName = brand.getCompanyName();
        if (companyName != null && companyName.length() > 0) {
            brand.setCompanyName("%" + companyName + "%");
        }

        //5. 查詢當(dāng)前頁數(shù)據(jù)
        List<Brand> rows = brandMapper.selectByPageAndCondition(begin, size, brand);

        //6. 查詢總記錄數(shù)
        int totalCount = brandMapper.selectTotalCountByCondition(brand);

        //7. 封裝PageBean對(duì)象
        PageBean<Brand> pageBean = new PageBean<>();
        pageBean.setRows(rows);
        pageBean.setTotalCount(totalCount);

        //8. 釋放資源
        sqlSession.close();

        return pageBean;
    }

8.1.3、servlet的實(shí)現(xiàn)

BrandServlet 類中定義 selectByPageAndCondition() 方法。而該方法的邏輯如下:

1)獲取頁面提交的 當(dāng)前頁碼每頁顯示條目數(shù) 兩個(gè)數(shù)據(jù)。這兩個(gè)參數(shù)是在url后進(jìn)行拼接的,格式是 url?currentPage=1&pageSize=5。獲取這樣的參數(shù)需要使用 requet.getparameter() 方法獲取。

2)獲取頁面提交的 條件數(shù)據(jù) ,并將數(shù)據(jù)封裝到一個(gè)Brand對(duì)象中。由于這部分?jǐn)?shù)據(jù)到時(shí)候是需要以 json 格式進(jìn)行提交的,所以我們需要通過流獲取數(shù)據(jù),具體代碼如下:

// 獲取查詢條件對(duì)象
BufferedReader br = request.getReader();
String params = br.readLine();//json字符串

//轉(zhuǎn)為 Brand
Brand brand = JSON.parseObject(params, Brand.class);

3)調(diào)用 service 的 selectByPageAndCondition() 方法進(jìn)行分頁查詢的業(yè)務(wù)邏輯處理

4)將查詢到的數(shù)據(jù)轉(zhuǎn)換為 json 格式的數(shù)據(jù)

5)響應(yīng) json 數(shù)據(jù)

Brandservlet 中 selectByPageAndCondition() 方法代碼實(shí)現(xiàn)如下:

 /**
     * 分頁條件查詢
     *
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    public void selectByPageAndCondition(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1. 接收 當(dāng)前頁碼 和 每頁展示條數(shù)    url?currentPage=1&pageSize=5
        String _currentPage = request.getParameter("currentPage");
        String _pageSize = request.getParameter("pageSize");

        int currentPage = Integer.parseInt(_currentPage);
        int pageSize = Integer.parseInt(_pageSize);

        // 獲取查詢條件對(duì)象
        BufferedReader br = request.getReader();
        String params = br.readLine();

        // 轉(zhuǎn)為Brand對(duì)象
        Brand brand = JSON.parseObject(params, Brand.class);

        //2. 調(diào)用service查詢
        PageBean<Brand> pageBean = brandService.selectByPageAndCondition(currentPage, pageSize, brand);

        //2. 轉(zhuǎn)為JSON
        String jsonString = JSON.toJSONString(pageBean);
        //3. 寫數(shù)據(jù)
        response.setContentType("text/json;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.write(jsonString);
    }

8.2、前端實(shí)現(xiàn)

前端代碼我們從以下幾方面實(shí)現(xiàn):

1、查詢表單綁定查詢條件對(duì)象模型

如下所示:

vue+mybatis idea,Javaweb,前端

2、?點(diǎn)擊查詢按鈕查詢數(shù)據(jù)

vue+mybatis idea,Javaweb,前端

從上面頁面可以看到給 查詢 按鈕綁定了 query()?函數(shù),而在query()?函數(shù)中只需要調(diào)用 selectAll() 函數(shù)進(jìn)行條件分頁查詢,如下:

vue+mybatis idea,Javaweb,前端

3、改進(jìn) selectAll() 函數(shù)

子頁面加載完成后發(fā)送異步請(qǐng)求,需要攜帶當(dāng)前頁碼、每頁顯示條數(shù)、查詢條件對(duì)象。接下來先對(duì)攜帶的數(shù)據(jù)進(jìn)行說明:

1)當(dāng)前頁碼每頁顯示條數(shù) 這兩個(gè)參數(shù)我們會(huì)拼接到 URL 的后面

2)查詢條件對(duì)象 這個(gè)參數(shù)需要以 json 格式提交給后端程序

修改 selectAll() 函數(shù)邏輯為

vue+mybatis idea,Javaweb,前端

?9、前端代碼優(yōu)化

咱們已經(jīng)將所有的功能實(shí)現(xiàn)完畢。而針對(duì)前端代碼中的發(fā)送異步請(qǐng)求的代碼,如下

vue+mybatis idea,Javaweb,前端

需要在成功的回調(diào)函數(shù)(也就是then 函數(shù)中的匿名函數(shù))中使用this,都需要在外邊使用 _this 記錄一下 this 所指向的對(duì)象;因?yàn)樵谕膺叺?this 表示的是 Vue 對(duì)象,而回調(diào)函數(shù)中的 this 表示的不是 vue 對(duì)象。這里我們可以使用 ECMAScript6 中的新語法(箭頭函數(shù))來簡(jiǎn)化這部分代碼,如上面的代碼可以簡(jiǎn)化為:

vue+mybatis idea,Javaweb,前端

?箭頭函數(shù)語法?:

(參數(shù)) => {
?? ?邏輯代碼
}

箭頭函數(shù)的作用:

替換(簡(jiǎn)化)匿名函數(shù)。

測(cè)試

啟動(dòng)服務(wù)器測(cè)試發(fā)現(xiàn),如下問題

vue+mybatis idea,Javaweb,前端

當(dāng)前狀態(tài)這列并不是我們想要的 啟用或禁用

現(xiàn)在我們優(yōu)化一下代碼,先去Brand實(shí)體類中進(jìn)行如下修改?

?vue+mybatis idea,Javaweb,前端

?修改brand.html頁面

vue+mybatis idea,Javaweb,前端

修改后測(cè)試,效果如下:

vue+mybatis idea,Javaweb,前端

?10、修改功能的實(shí)現(xiàn)

當(dāng)用戶點(diǎn)擊修改按鈕以后,會(huì)彈出對(duì)話框表單(表單中有回顯數(shù)據(jù)),當(dāng)點(diǎn)擊 提交 按鈕后就需要將數(shù)據(jù)提交到后端,并將數(shù)據(jù)保存到數(shù)據(jù)庫中。

10.1、后端實(shí)現(xiàn)

10.1.1、dao層方法的實(shí)現(xiàn)

在BrandMapper接口中定義一個(gè)update()抽象方法,并使用@Update注解編寫SQL語句

 /**
     * 修改品牌
     * @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);

10.1.2、service方法的實(shí)現(xiàn)

BrandService 接口中定義 update() 添加數(shù)據(jù)的業(yè)務(wù)邏輯方法

    /**
     * 修改品牌
     * @param brand
     */
    void update(Brand brand);

BrandServiceImpl 類中重寫 update() 方法,并進(jìn)行業(yè)務(wù)邏輯實(shí)現(xiàn)

/**
     * 添加品牌
     *
     * @param brand
     */
    public void add(Brand brand) {
        //2. 獲取SqlSession對(duì)象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //3. 獲取BrandMapper
        BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
        //4. 調(diào)用方法
        brandMapper.add(brand);
        // 提交事務(wù)
        sqlSession.commit();

        //5. 釋放資源
        sqlSession.close();

    }

10.1.3、servlet實(shí)現(xiàn)

在BrandServlet定義update()方法,代碼如下:


    /**
     * 修改品牌
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    public void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1、接收品牌數(shù)據(jù)
        BufferedReader br = request.getReader();
        String jsonStr = br.readLine(); // 因?yàn)閖son字符串自有一行數(shù)據(jù)
        // 2、轉(zhuǎn)為Brand對(duì)象
        Brand brand = JSON.parseObject(jsonStr, Brand.class);
        // 3、調(diào)用service完成添加
        brandService.update(brand);

        // 4、響應(yīng)成功標(biāo)識(shí)
        PrintWriter writer = response.getWriter();
        writer.write("success");
    }

10.2、前端實(shí)現(xiàn)

當(dāng)點(diǎn)擊修改按鈕時(shí),彈出對(duì)話框表單進(jìn)行修改

vue+mybatis idea,Javaweb,前端

vue+mybatis idea,Javaweb,前端

11、刪除功能的實(shí)現(xiàn)文章來源地址http://www.zghlxwxcb.cn/news/detail-619171.html

到了這里,關(guān)于17、基于Mybaits、Vue、axios、Element-ui的JavaWeb項(xiàng)目的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 2022.9.17 vue、element-ui實(shí)現(xiàn)登錄獲取手機(jī)驗(yàn)證碼,進(jìn)行手機(jī)號(hào)校驗(yàn)、驗(yàn)證碼CD60秒

    2022.9.17 vue、element-ui實(shí)現(xiàn)登錄獲取手機(jī)驗(yàn)證碼,進(jìn)行手機(jī)號(hào)校驗(yàn)、驗(yàn)證碼CD60秒

    1、直接點(diǎn)擊,不為空校驗(yàn) 2、輸入手機(jī)號(hào)格式不正確時(shí) 3、獲取完驗(yàn)證碼進(jìn)行讀秒 三、vue 1、進(jìn)行手機(jī)號(hào)校驗(yàn)關(guān)鍵在對(duì)單個(gè)手機(jī)號(hào)輸入框進(jìn)行校驗(yàn),需要使用到validateField對(duì)部分表單字段進(jìn)行校驗(yàn),valid是校驗(yàn)完的提示信息,當(dāng)valid為空時(shí)代表校驗(yàn)成功 2、讀秒和設(shè)置禁用,在校

    2024年02月11日
    瀏覽(32)
  • 基于vue+element-ui實(shí)現(xiàn)上傳進(jìn)度條

    基于vue+element-ui實(shí)現(xiàn)上傳進(jìn)度條

    目錄 基于el-upload組件實(shí)現(xiàn)進(jìn)度條的編寫 后臺(tái)進(jìn)度前臺(tái)進(jìn)度條顯示 基于el-upload組件實(shí)現(xiàn)進(jìn)度條的編寫 ①編寫文件上傳時(shí)的鉤子函數(shù) ②監(jiān)聽進(jìn)度百分比 后臺(tái)進(jìn)度前臺(tái)進(jìn)度條顯示 參考文章: 后臺(tái)進(jìn)度前臺(tái)顯示進(jìn)度條_weixin_30646505的博客-CSDN博客 后端思路: ①創(chuàng)建一個(gè)類,封裝進(jìn)

    2023年04月08日
    瀏覽(22)
  • npm ERR! Could not resolve dependency:npm ERR! peer vue@“^2.5.17“ from element-ui@2.15.12

    npm ERR! Could not resolve dependency:npm ERR! peer vue@“^2.5.17“ from element-ui@2.15.12

    在IDEA的控制臺(tái)輸入指令 npm i element-ui -S 報(bào)錯(cuò): npm ERR! Could not resolve dependency:npm ERR! peer vue@\\\"^2.5.17\\\" from element-ui@2.15.12 vue3.0 不兼容 element-ui ,于是推出了element-plus 1.下載 element-plus npm install element-plus --save 2. 在main.js中引用

    2024年02月12日
    瀏覽(24)
  • 基于vue+element-ui的H5可視化編輯器

    基于vue+element-ui的H5可視化編輯器

    h5ve-design是一款專注低代碼平臺(tái)工具,功能強(qiáng)大,高可擴(kuò)展的HTML5可視化編輯器,致力于提供一套簡(jiǎn)單易用、高效創(chuàng)新、無限可能的解決方案。技術(shù)棧采用vue和javascript開發(fā), 專注研發(fā)創(chuàng)新工具。 Vue2.x+Javascript+Element-ui H5可視化編輯器包括的核心功能區(qū)有:組件區(qū)、畫布區(qū)、頂部

    2024年02月07日
    瀏覽(23)
  • 【vue后臺(tái)管理系統(tǒng)】基于Vue+Element-UI+ECharts開發(fā)通用管理后臺(tái)(中)

    【vue后臺(tái)管理系統(tǒng)】基于Vue+Element-UI+ECharts開發(fā)通用管理后臺(tái)(中)

    點(diǎn)擊菜單圖標(biāo)之前: 點(diǎn)擊菜單圖標(biāo)之后: 首先我們要知道菜單欄的收縮,由el-menu的collapse屬性控制: 我們通過分析可以知道: 菜單按鈕的點(diǎn)擊是在CommonHeader.vue組件中,而我們修改的collapse屬性卻在CommonAside.vue中,這是兩個(gè)不同的組件。很明顯這涉及到了組件間的通信問題,

    2024年02月03日
    瀏覽(62)
  • vue-element-admin:基于element-ui 的一套后臺(tái)管理系統(tǒng)集成方案

    vue-element-admin:基于element-ui 的一套后臺(tái)管理系統(tǒng)集成方案

    1.1簡(jiǎn)介 vue-element-admin是基于element-ui 的一套后臺(tái)管理系統(tǒng)集成方案。 GitHub地址:https://github.com/PanJiaChen/vue-element-admin 項(xiàng)目在線預(yù)覽:https://panjiachen.gitee.io/vue-element-admin 1.2安裝 如果上面的install報(bào)錯(cuò) 則先執(zhí)行下面的命令,再install 2.1簡(jiǎn)介 vueAdmin-template是基于vue-element-admin的一套

    2023年04月16日
    瀏覽(31)
  • Vue3初學(xué)者詳細(xì)教程之zip安裝Node.js版本v16.6.0、vue/cli版本4.5.13、element-ui版本2.15.6、axios版本0.25.0

    Vue3初學(xué)者詳細(xì)教程之zip安裝Node.js版本v16.6.0、vue/cli版本4.5.13、element-ui版本2.15.6、axios版本0.25.0

    《Node.js v16.6.0官網(wǎng)下載》 在node文件夾里面創(chuàng)建2個(gè)文件夾分別是node_cache和node_global 在解壓路徑文件夾cmd輸入以下命令創(chuàng)建2個(gè)文件夾 新建系統(tǒng)變量NODE_HOME 編輯Path系統(tǒng)變量 測(cè)試nodejs環(huán)境變量是否生效 cmd運(yùn)行 node -v 命令,輸出版本號(hào)說明成功 以系統(tǒng)管理員的身份打開cmd命令提

    2024年02月07日
    瀏覽(119)
  • 基于Vue和Element-UI自定義分組以及分組全選Select 選擇器

    基于Vue和Element-UI自定義分組以及分組全選Select 選擇器

    上一篇博文我們已經(jīng)實(shí)現(xiàn)了基于Vue和Element-UI中Select 選擇器的分組全選以及樣式修改問題, 但是在分組方面我們是用了element-ui 自帶的 使用el-option-group對(duì)備選項(xiàng)進(jìn)行分組,它的label屬性為分組名 的功能,但是出來的效果樣式很難自定義,就算是魔改element的樣式也有一些改不了

    2023年04月08日
    瀏覽(28)
  • 基于Vue+Element-Ui開發(fā)的月日組件,可以選擇月份和天數(shù)小插件(新版本)

    基于Vue+Element-Ui開發(fā)的月日組件,可以選擇月份和天數(shù)小插件(新版本)

    最近有粉絲在使用的過程中發(fā)現(xiàn)不能滿足自己項(xiàng)目上的需求,評(píng)論說不支持 placeholder 以及更改輸入框大小 size ,所以又趕緊更新了一個(gè)版本,之前是1.0.7,現(xiàn)在新版本為1.1.0,點(diǎn)擊查看之前的老版本 本組件是基于Vue和Element-ui,因Element官方組件庫沒有可以選擇月份和天數(shù)的組

    2023年04月19日
    瀏覽(25)
  • 如何搭建一個(gè)基于vue2和element-ui的項(xiàng)目框架模板(兩萬四千字長(zhǎng)文)

    如何搭建一個(gè)基于vue2和element-ui的項(xiàng)目框架模板(兩萬四千字長(zhǎng)文)

    使用vue script標(biāo)簽引入 如果只是單純的使用vue,可以使用 script src=\\\"https://cdn.jsdelivr.net/npm/vue/dist/vue.js\\\"/script 直接引入 npm安裝vue 使用npm安裝vue需要先安裝node.js,如果你的電腦未安裝node,可以參考我的個(gè)人碰到的前端問題總結(jié)及解決方案2第15個(gè)問題先安裝nvm(node version manager)

    2024年02月13日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包