1、需求

  • 实现对品牌数据最基础的 CRUD 功能(文中仅演示了查询和添加)
  • 实现在所有数据页面对数据的批量删除功能
  • 实现分页展示功能
  • 实现条件查询功能

2、环境准备

2.1 工程准备

  • vue.js 和 element-ui 依赖

  • 引入 Axios.js 依赖

  • 包结构

  • Maven 依赖 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>priv.dandelion</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>
        <!-- junit单元测试依赖 -->
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.11</version>
          <scope>test</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>
        <!-- 添加slf4j日志api -->
        <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-api</artifactId>
          <version>1.7.20</version>
        </dependency>
        <!-- 添加logback-classic依赖 -->
        <dependency>
          <groupId>ch.qos.logback</groupId>
          <artifactId>logback-classic</artifactId>
          <version>1.2.3</version>
        </dependency>
        <!-- 添加logback-core依赖 -->
        <dependency>
          <groupId>ch.qos.logback</groupId>
          <artifactId>logback-core</artifactId>
          <version>1.2.3</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>
        <!-- JSTL标准标签库依赖 -->
        <dependency>
          <groupId>taglibs</groupId>
          <artifactId>standard</artifactId>
          <version>1.1.2</version>
        </dependency>
        <!-- JSON串和Java对象的相互转换 -->
        <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>fastjson</artifactId>
          <version>1.2.62</version>
        </dependency>
      </dependencies>
    
      <build>
        <plugins>
          <plugin>
            <!-- tomcat插件 -->
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <version>2.2</version>
          </plugin>
        </plugins>
      </build>
    </project>
    
  • MyBatis 核心配置文件

    <?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="priv.dandelion.entity"/>
        </typeAliases>
    
        <environments default="development">
            <environment id="development">
                <!-- 采用JDBC的事务管理方式 -->
                <transactionManager type="JDBC"/>
                <!-- 数据库连接信息 -->
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <!-- value的值一定不能换行,一定!一定!不能换行 -->
                    <property name="url" value="jdbc:mysql:///db1?useSSL=false&amp;useUnicode=true&amp;characterEncoding=utf-8&amp;useServerPrepStmts=true"/>
                    <property name="username" value="root"/>
                    <property name="password" value="123456"/>
                </dataSource>
            </environment>
        </environments>
        <!-- 扫描mapper,加载SQL映射文件 -->
        <mappers>
            <package name="priv.dandelion.dao"/>
        </mappers>
    </configuration>
    
  • 创建 SqlSession 工厂工具类

    package priv.dandelion.utils;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    public class SqlSessionFactoryUtils {
    
        // 提升作用域,用于再方法内进行返回
        private static SqlSessionFactory sqlSessionFactory;
    
        // 静态代码块会随着类的加载自动执行且只执行一次
        static {
            String resource = "mybatis-config.xml";
            InputStream inputStream = null;
            try {
                inputStream = Resources.getResourceAsStream(resource);
            } catch (IOException e) {
                e.printStackTrace();
            }
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        }
    
        public static SqlSessionFactory getSqlSessionFactory() {
            return sqlSessionFactory;
        }
    }
    
  • 实体类 Brand.java

    package priv.dandelion.entity;
    
    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, 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 +
                    ", brand_name='" + brandName + '\'' +
                    ", company_name='" + companyName + '\'' +
                    ", ordered=" + ordered +
                    ", description='" + description + '\'' +
                    ", status=" + status +
                    '}';
        }
    }
    
  • Mapper 映射文件和 Mapper 接口

    <?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="priv.dandelion.dao.BrandMapper">
    
        <!-- 解决数据库与实体类命名不一致问题 -->
        <resultMap id="brandResultMap" type="brand">
            <result column="brand_name" property="brandName"></result>
            <result column="company_name" property="companyName"></result>
        </resultMap>
    
    </mapper>
    
  • 前端页面 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">
        <!--搜索表单-->
        <el-form :inline="true" :model="brand" class="demo-form-inline">
            <el-form-item label="当前状态">
                <el-select v-model="brand.status" placeholder="当前状态">
                    <el-option label="启用" value="1"></el-option>
                    <el-option label="禁用" value="0"></el-option>
                </el-select>
            </el-form-item>
    
            <el-form-item label="企业名称">
                <el-input v-model="brand.companyName" placeholder="企业名称"></el-input>
            </el-form-item>
    
            <el-form-item label="品牌名称">
                <el-input v-model="brand.brandName" placeholder="品牌名称"></el-input>
            </el-form-item>
    
            <el-form-item>
                <el-button type="primary" @click="onSubmit">查询</el-button>
            </el-form-item>
        </el-form>
    
        <!--按钮-->
        <!--
            @click="dialogVisible = true"
            单击时将dialogVisible设置为true,展示对话框
        -->
        <el-row>
            <el-button type="danger" plain>批量删除</el-button>
            <el-button type="primary" plain @click="dialogVisible = true">新增</el-button>
        </el-row>
    
        <!--添加数据对话框表单-->
        <el-dialog
                title="编辑品牌"
                :visible.sync="dialogVisible"
                width="30%">
            <el-form ref="form" :model="brand" label-width="80px">
                <el-form-item label="品牌名称">
                    <el-input v-model="brand.brandName"></el-input>
                </el-form-item>
    
                <el-form-item label="企业名称">
                    <el-input v-model="brand.companyName"></el-input>
                </el-form-item>
    
                <el-form-item label="排序">
                    <el-input v-model="brand.ordered"></el-input>
                </el-form-item>
    
                <el-form-item label="备注">
                    <el-input type="textarea" v-model="brand.description"></el-input>
                </el-form-item>
    
                <el-form-item label="状态">
                    <el-switch v-model="brand.status"
                               active-value="1"
                               inactive-value="0"
                    ></el-switch>
                </el-form-item>
                <el-form-item>
                    <el-button type="primary" @click="addBrand">提交</el-button>
                    <el-button @click="dialogVisible = false">取消</el-button>
                </el-form-item>
            </el-form>
        </el-dialog>
    
        <!--表格-->
        <!--
    		其中<el-table-column></el-table-column>标签的prop属性值
    		需要和Vue核心对象返回tableData的对象属性名一致
    	-->
        <template>
            <!--
    			@selection-change="handleSelectionChange"
    			监听到复选框勾选时,获取行的记录
    			需要在Vue核心对象中实现handleSelectionChange函数
    		-->
            <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="企业名称"
                        align="center">
                </el-table-column>
                <el-table-column
                        prop="ordered"
                        align="center"
                        label="排序">
                </el-table-column>
                <el-table-column
                        prop="status"
                        align="center"
                        label="当前状态">
                </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>
    
        <!--分页工具条-->
        <el-pagination
                @size-change="handleSizeChange"
                @current-change="handleCurrentChange"
                :current-page="currentPage"
                :page-sizes="[5, 10, 15, 20]"
                :page-size="5"
                layout="total, sizes, prev, pager, next, jumper"
                :total="400">
        </el-pagination>
    
    </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",
            methods: {
                tableRowClassName({row, rowIndex}) {
                    if (rowIndex === 1) {
                        return 'warning-row';
                    } else if (rowIndex === 3) {
                        return 'success-row';
                    }
                    return '';
                },
                // 复选框选中后执行的方法
                handleSelectionChange(val) {
                    this.multipleSelection = val;
    
                    console.log(this.multipleSelection)
                },
                // 查询方法
                onSubmit() {
                    console.log(this.brand);
                },
                // 添加数据
                addBrand(){
                    console.log(this.brand);
                },
                //分页
                handleSizeChange(val) {
                    console.log(`每页 ${val} 条`);
                },
                handleCurrentChange(val) {
                    console.log(`当前页: ${val}`);
                }
            },
            data() {
                return {
                    // 当前页码
                    currentPage: 4,
                    // 添加数据对话框是否展示的标记
                    dialogVisible: false,
    
                    // 品牌模型数据
                    brand: {
                        status: '',
                        brandName: '',
                        companyName: '',
                        id:"",
                        ordered:"",
                        description:""
                    },
                    // 复选框选中数据集合
                    multipleSelection: [],
                    // 表格数据
                    tableData: [{
                        brandName: '华为',
                        companyName: '华为科技有限公司',
                        ordered: '100',
                        status: "1"
                    }, {
                        brandName: '华为',
                        companyName: '华为科技有限公司',
                        ordered: '100',
                        status: "1"
                    }, {
                        brandName: '华为',
                        companyName: '华为科技有限公司',
                        ordered: '100',
                        status: "1"
                    }, {
                        brandName: '华为',
                        companyName: '华为科技有限公司',
                        ordered: '100',
                        status: "1"
                    }]
                }
            }
        })
    </script>
    </body>
    </html>
    

2.2 创建表

  • SQL脚本

    -- 删除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 
           ('华为', '华为技术有限公司', 100, '万物互联', 1),
           ('小米', '小米科技有限公司', 50, 'are you ok', 1),
           ('格力', '格力电器股份有限公司', 30, '让世界爱上中国造', 1),
           ('阿里巴巴', '阿里巴巴集团控股有限公司', 10, '买买买', 1),
           ('腾讯', '腾讯计算机系统有限公司', 50, '玩玩玩', 0),
           ('百度', '百度在线网络技术公司', 5, '搜搜搜', 0),
           ('京东', '北京京东世纪贸易有限公司', 40, '就是快', 1),
           ('小米', '小米科技有限公司', 50, 'are you ok', 1),
           ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),
           ('华为', '华为技术有限公司', 100, '万物互联', 1),
           ('小米', '小米科技有限公司', 50, 'are you ok', 1),
           ('格力', '格力电器股份有限公司', 30, '让世界爱上中国造', 1),
           ('阿里巴巴', '阿里巴巴集团控股有限公司', 10, '买买买', 1),
           ('腾讯', '腾讯计算机系统有限公司', 50, '玩玩玩', 0),
           ('百度', '百度在线网络技术公司', 5, '搜搜搜', 0),
           ('京东', '北京京东世纪贸易有限公司', 40, '就是快', 1),
           ('华为', '华为技术有限公司', 100, '万物互联', 1),
           ('小米', '小米科技有限公司', 50, 'are you ok', 1),
           ('格力', '格力电器股份有限公司', 30, '让世界爱上中国造', 1),
           ('阿里巴巴', '阿里巴巴集团控股有限公司', 10, '买买买', 1),
           ('腾讯', '腾讯计算机系统有限公司', 50, '玩玩玩', 0),
           ('百度', '百度在线网络技术公司', 5, '搜搜搜', 0),
           ('京东', '北京京东世纪贸易有限公司', 40, '就是快', 1),
           ('小米', '小米科技有限公司', 50, 'are you ok', 1),
           ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),
           ('华为', '华为技术有限公司', 100, '万物互联', 1),
           ('小米', '小米科技有限公司', 50, 'are you ok', 1),
           ('格力', '格力电器股份有限公司', 30, '让世界爱上中国造', 1),
           ('阿里巴巴', '阿里巴巴集团控股有限公司', 10, '买买买', 1),
           ('腾讯', '腾讯计算机系统有限公司', 50, '玩玩玩', 0),
           ('百度', '百度在线网络技术公司', 5, '搜搜搜', 0),
           ('京东', '北京京东世纪贸易有限公司', 40, '就是快', 1),
           ('华为', '华为技术有限公司', 100, '万物互联', 1),
           ('小米', '小米科技有限公司', 50, 'are you ok', 1),
           ('格力', '格力电器股份有限公司', 30, '让世界爱上中国造', 1),
           ('阿里巴巴', '阿里巴巴集团控股有限公司', 10, '买买买', 1),
           ('腾讯', '腾讯计算机系统有限公司', 50, '玩玩玩', 0),
           ('百度', '百度在线网络技术公司', 5, '搜搜搜', 0),
           ('京东', '北京京东世纪贸易有限公司', 40, '就是快', 1),
           ('小米', '小米科技有限公司', 50, 'are you ok', 1),
           ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),
           ('华为', '华为技术有限公司', 100, '万物互联', 1),
           ('小米', '小米科技有限公司', 50, 'are you ok', 1),
           ('格力', '格力电器股份有限公司', 30, '让世界爱上中国造', 1),
           ('阿里巴巴', '阿里巴巴集团控股有限公司', 10, '买买买', 1),
           ('腾讯', '腾讯计算机系统有限公司', 50, '玩玩玩', 0),
           ('百度', '百度在线网络技术公司', 5, '搜搜搜', 0),
           ('京东', '北京京东世纪贸易有限公司', 40, '就是快', 1)
            ;
       
    
    SELECT * FROM tb_brand;
    

3、查询所有功能

3.1 后端实现

3.1.1 Dao层方法实现

package priv.dandelion.dao;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.ResultMap;
import org.apache.ibatis.annotations.Select;
import priv.dandelion.entity.Brand;

import java.util.List;


public interface BrandMapper {

    // 解决数据库与实体类明明不一致问题
    @ResultMap("brandResultMap")
    @Select("select * from tb_brand")
    List<Brand> selectAll();

}

3.1.2 Service层方法实现

  • 接口

    package priv.dandelion.service;
    
    import priv.dandelion.entity.Brand;
    
    import java.util.List;
    
    public interface BrandService {
        /**
         * 查询所有
         * @return
         */
        List<Brand> selectAll();
    }
    
  • 实现类

    package priv.dandelion.service.impl;
    
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import priv.dandelion.dao.BrandMapper;
    import priv.dandelion.entity.Brand;
    import priv.dandelion.service.BrandService;
    import priv.dandelion.utils.SqlSessionFactoryUtils;
    
    import java.util.List;
    
    public class BrandServiceImpl implements BrandService {
    
        SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
    
        @Override
        public List<Brand> selectAll() {
            SqlSession sqlSession = sqlSessionFactory.openSession();
            BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
            List<Brand> brands = mapper.selectAll();
            sqlSession.close();
            return brands;
        }
    }
    

3.1.3 Servlet实现与Servlet优化

  • BaseServlet 负责替换 HttpServlet ,根据请求的最后一段路径进行方法分发,是 Servlet的父类

    package priv.dandelion.controller.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    /**
     * 替换HttpServlet
     *
     * 根据请求的最后一段路径进行方法分发
     */
    public class BaseServlet extends HttpServlet {
        // 重写service,根据请求路径进行方法分发
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 1. 获取请求路径
            String requestURI = req.getRequestURI();    // /brand-case/brand/selectAll
            // 获取请求路径的最后一段,即方法名
            int index = requestURI.lastIndexOf('/');
            // substring(index)截取字符串为左闭右开区间,不需要斜杠,index需要+1
            String methodName = requestURI.substring(index + 1);
    
            // 2. 获取BrandServlet的字节码对象,并获取方法的Method对象
            // 此处的this为动态绑定(Servlet入口在子类中,子类调用父类方法,程序执行到此处时,this代表调用父类方法的子类对象)
            Class<? extends BaseServlet> cls = this.getClass();
            // 获取方法的Method对象
            try {
                Method method = cls.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
    
                // 3. 执行方法
                method.invoke(this, req, resp);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
    
  • BrandServlet 关于 Brand 的 Servlet 类,将多个 Servlet 写在一个类中

    package priv.dandelion.controller.servlet;
    
    import com.alibaba.fastjson.JSON;
    import priv.dandelion.entity.Brand;
    import priv.dandelion.service.BrandService;
    import priv.dandelion.service.impl.BrandServiceImpl;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.util.List;
    
    @WebServlet("/brand/*")
    public class BrandServlet extends BaseServlet{
    
        private BrandService brandService = new BrandServiceImpl();
    
        public void selectAll(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            List<Brand> brands = brandService.selectAll();
            // 将查询到的结果序列化为JSON
            String jsonString = JSON.toJSONString(brands);
            // 处理中文,使用utf-8
            resp.setContentType("text/json;charset=utf-8");
            // 写回数据
            resp.getWriter().write(jsonString);
        }
        
        // ...
        
    }
    

3.2 前端实现

  • 代码

    <!--
    	...
    -->
    <script src="js/axios-0.18.0.js"></script>
    
    <script>
        new Vue({
            el: "#app",
            // 当页面加载完成后发送异步请求来获取数据
            mounted(){
                // 原生的this不能在Axios中使用,提升其生命周期
                var _this = this;
                // 使用Axios发送异步请求
                axios({
                    method:"get",
                    url:"http://localhost:8080/brand-case/selectAll"
                }).then(function (resp) {
                    _this.tableData = resp.data;
                })
            },
            
            // ...
            // ...
            // ...
        })
    </script>
    </body>
    </html>
    

4、添加功能

4.1 后端实现

4.1.1 Dao层方法实现

4.1.2 Service层方法实现

  • 添加接口

    /**
     * 添加数据
     */
    boolean addBrand(Brand brand);
    
  • 实现接口

    @Override
    public boolean addBrand(Brand brand) {
        // 自动提交事务
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
    
        // 判断用户名是否不存在
        final boolean flag = (null == mapper.selectByBrandName(brand.getBrandName()));
        if (flag) mapper.addBrand(brand);
    
        sqlSession.close();
        return flag;
    }
    

4.1.3 Serlvet实现,在 BrandServlet 中添加方法

public void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
    // 接收前端提交的数据
    BufferedReader reader = req.getReader();
    String params = reader.readLine();
    // 反序列化为Brand对象
    Brand brand = JSON.parseObject(params, Brand.class);
    // 调用Service进行添加
    if (brandService.addBrand(brand)) resp.getWriter().write("success");
}

4.2 前端实现

  • 代码

        <!--
            ......
        -->
    
    	<!--按钮-->
        <!--
            @click="dialogVisible = true"
            单击时将dialogVisible设置为true,展示对话框
        -->
        <el-row>
            <el-button type="danger" plain>批量删除</el-button>
            <el-button type="primary" plain @click="dialogVisible = true">新增</el-button>
        </el-row>
    
        <!--添加数据对话框表单-->
        <el-dialog
                title="编辑品牌"
                :visible.sync="dialogVisible"
                width="30%">
            <el-form ref="form" :model="brand" label-width="80px">
                <el-form-item label="品牌名称">
                    <el-input v-model="brand.brandName"></el-input>
                </el-form-item>
    
                <el-form-item label="企业名称">
                    <el-input v-model="brand.companyName"></el-input>
                </el-form-item>
    
                <el-form-item label="排序">
                    <el-input v-model="brand.ordered"></el-input>
                </el-form-item>
    
                <el-form-item label="备注">
                    <el-input type="textarea" v-model="brand.description"></el-input>
                </el-form-item>
    
                <el-form-item label="状态">
                    <el-switch v-model="brand.status"
                               active-value="1"
                               inactive-value="0"
                    ></el-switch>
                </el-form-item>
                <el-form-item>
                    <el-button type="primary" @click="addBrand">提交</el-button>
                    <el-button @click="dialogVisible = false">取消</el-button>
                </el-form-item>
            </el-form>
        </el-dialog>
    
        <!--
            ......
        -->
    
    <script>
        new Vue({
            // ...
            // ...
            methods: {
                // 查询所有数据,抽出作为一个函数,降低耦合
                selectAll() {
                    // 原生的this不能在Axios中使用,提升其生命周期
                    var _this = this;
                    // 使用Axios发送异步请求
                    axios({
                        method:"get",
                        url:"http://localhost:8080/brand-case/selectAll"
                    }).then(function (resp) {
                        _this.tableData = resp.data;
                    })
                },
                
                // ...
                // ...
                // ...
                
                // 添加数据
                addBrand(){
                    //console.log(this.brand);
                    // 检验数据是否合法,判空细节不表
                    var flag = true;
                    // isNaN()函数 把空串 空格 以及NUll 按照0来处理,所以先去除。非数字类型返回true
                    if (this.brand.ordered == '' || this.brand.ordered == null || isNaN(this.brand.ordered)) {
                        flag = false;
                        this.$message({
                            message: '警告:排序不可为空且必须为一个数字',
                            type: 'warning'
                        });
                    }
                    // 原生的this不能在Axios中使用,提升其生命周期
                    var _this = this;
                    // 发送AJAX异步请求,添加数据
                    if (flag) {
                        axios({
                            method:"post",
                            url:"http://localhost:8080/brand-case/addBrand",
                            // Axios 内部不能使用原生的 this
                            data:_this.brand
                        }).then(function (resp){
                            if ("success" == resp.data) {
                                // 添加成功
                                // 关闭窗口
                                _this.dialogVisible = false;
                                // 重新查询数据
                                _this.selectAll();
                                // 显示成功提示
                                _this.$message({
                                    message: '品牌数据添加成功',
                                    type: 'success'
                                });
                            } else {
                                // 显示错误提示
                                _this.$message.error('该品牌已存在,添加失败');
                            }
                        })
                    }
                },
                // ...
                // ...
                // ...
    </script>
    </body>
    </html>
    

4、修改和删除功能

  • Dao

    @Update("update tb_brand " +
            "set brand_name = #{brandName}," +
            "company_name = #{companyName}," +
            "ordered = #{ordered}," +
            "description = #{description}," +
            "status = #{status} " +
            "where id = #{id};")
    void updateBrand(Brand brand);
    
    @Delete("delete from tb_brand where id = #{id};")
    void deleteBrand(@Param("id") String id);
    
  • Service 新增接口方法并实现

    @Override
    public boolean updateBrand(Brand brand) {
        // 自动提交事务
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
    
        // 判断用户名是否不存在
        boolean flag = (null == mapper.selectByBrandName(brand.getBrandName()));
        if (flag) mapper.updateBrand(brand);
    
        sqlSession.close();
        return flag;
    }
    
    @Override
    public void deleteBrand(String id) {
        // 自动提交事务
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
    
        mapper.deleteBrand(id);
    
        sqlSession.close();
    }
    
  • Servlet

    public void update(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
        // 接收前端提交的数据
        BufferedReader reader = req.getReader();
        String params = reader.readLine();
        // 反序列化为Brand对象
        Brand brand = JSON.parseObject(params, Brand.class);
        // 调用Service进行修改
        if (brandService.addBrand(brand)) resp.getWriter().write("success");
    }
    
    public void delete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
        // 接收前端提交的数据
        String id = req.getParameter("id");
        // 调用Service进行添加
        brandService.deleteBrand(id);
    }
    
  • 前端页面

    
    

5、批量删除功能

  • Dao

    • Mapper接口

      void deleteByIds(@Param("ids") int[] ids);
      
    • Mapper映射文件

      <!-- 批量删除,动态SQL -->
      <delete id="deleteByIds">
          <!-- delete from tb_brand where id in (?,?,...,?) -->
          delete from tb_brand where id in
          <foreach collection="ids" item="id" separator="," open="(" close=")">
              #{id}
          </foreach>
      </delete>
      
  • Service

    @Override
    public void deleteByIds(int[] ids) {
        // 自动提交事务
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
    
        mapper.deleteByIds(ids);
        sqlSession.close();
    }
    
  • Servlet

    public void deleteByIds(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
        // 接收前端提交的数据
        BufferedReader reader = req.getReader();
        String params = reader.readLine();
        // 反序列化为Brand对象
        int[] ids = JSON.parseObject(params, int[].class);
        brandService.deleteByIds(ids);
        resp.getWriter().write("success");
    }
    
  • 前端页面

    <!--
    	...
    -->
    
    <div id="app">
        
        <!--
    		...
    	-->
        
        <el-row>
            <el-button type="danger" plain @click="deleteByIds">批量删除</el-button>
            <el-button type="primary" plain @click="dialogVisible = true">新增</el-button>
        </el-row>
    
        <!--
    		...
    	-->
    
    </div>
    
    <!--
    	...
    -->
    
    <script>
        new Vue({
            el: "#app",
            // 当页面加载完成后发送异步请求来获取数据
            mounted(){
                this.selectAll();
            },
            methods: {
                // ...
                // ...
                // 批量删除
                deleteByIds() {
                    this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
                        confirmButtonText: '确定',
                        cancelButtonText: '取消',
                        type: 'warning'
                    }).then(() => {
                        this.$message({
                            type: 'success',
                            message: '正在删除...'
                        });
                        // 将id数据写入被选中的id数组模型
                        for (let i = 0; i < this.multipleSelection.length; i++) {
                            let selectionElem = this.multipleSelection[i];
                            this.selectedIds[i] = selectionElem.id;
                        }
                        console.log(this.multipleSelection);
                        console.log(this.selectedIds);
                        // 发送AJAX请求
                        var _this = this;
                        axios({
                            method:"post",
                            url:"http://localhost:8080/brand-case/brand/deleteByIds",
                            // Axios 内部不能使用原生的 this
                            data:_this.selectedIds
                        }).then(function (resp){
                            if ("success" == resp.data) {
                                // 重新查询数据
                                _this.selectAll();
                                // 显示成功提示
                                _this.$message({
                                    message: '删除成功',
                                    type: 'success'
                                });
                            } else {
                                // 显示错误提示
                                _this.$message.error('删除失败');
                            }
                        })
                    }).catch(() => {
                        this.$message({
                            type: 'info',
                            message: '已取消删除'
                        });
                    });
                }
            },
            data() {
                return {
                    // ...
                    // ...
                    // 被选中的数据库id数组
                    selectedIds:[]
                }
            }
        })
    </script>
    </body>
    </html>
    

6、分页功能

  • 用于分页查询的 JavaBean

    package priv.dandelion.entity;
    
    import java.util.List;
    
    /**
     * 分页查询的JavaBean
     */
    public class PageBean<T> {
        // 总记录数
        private int totalCount;
        // 当前页数据
        private List<T> rows;
    
        public int getTotalCount() {
            return totalCount;
        }
    
        public void setTotalCount(int totalCount) {
            this.totalCount = totalCount;
        }
    
        public List<T> getRows() {
            return rows;
        }
    
        public void setRows(List<T> rows) {
            this.rows = rows;
        }
    }
    
  • Dao

    // limit 开始索引, 查询的条目数
    // select * from tb limit 0, 5
    // 页面传递的参数为 起始条数和每一页显示的条数
    // 开始索引 = (当前页码 - 1) * 每一页显示的条数
    @Select("select * from tb_brand limit #{begin}, #{pageSize}")
    List<Brand> selectByPage(@Param("begin") int begin, @Param("pageSize") int pageSize);
    
    @Select("select count(*) from tb_brand")
    int selectTotalCount();
    
  • Service

    @Override
    public PageBean<Brand> selectByPage(int currentPage, int pageSize) {
    
        SqlSession sqlSession = sqlSessionFactory.openSession();
        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
    
        // 计算开始索引
        int begin = (currentPage - 1) * pageSize;
    
        // 查询数据
        List<Brand> rows = mapper.selectByPage(begin, pageSize);
        int totalCount = mapper.selectTotalCount();
    
        // 封装数据
        PageBean<Brand> brandPageBean = new PageBean<>();
        brandPageBean.setRows(rows);
        brandPageBean.setTotalCount(totalCount);
    
        sqlSession.close();
        return brandPageBean;
    }
    
  • Servlet

    public void selectByPage(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
        // 接收当前页码和每页展示条数
        int currentPage = Integer.parseInt(req.getParameter("currentPage"));
        int pageSize = Integer.parseInt(req.getParameter("pageSize"));
        // 调用对应的Service进行查询
        PageBean<Brand> brandPageBean = brandService.selectByPage(currentPage, pageSize);
        // 序列化为JSON
        String jsonString = JSON.toJSONString(brandPageBean);
        // 写回数据
        resp.setContentType("text/json;charset=utf-8");
        resp.getWriter().write(jsonString);
    }
    
  • 页面

    <!--
    	...
    -->
    
        <!--分页工具条,绑定Model-->
        <el-pagination
                @size-change="handleSizeChange"
                @current-change="handleCurrentChange"
                :current-page="currentPage"
                :page-sizes="[5, 10, 15, 20]"
                :page-size="pageSize"
                layout="total, sizes, prev, pager, next, jumper"
                :total="totalCount">
        </el-pagination>
    
    <!--
    	...
    -->
    
    <script>
        new Vue({
            el: "#app",
            // 当页面加载完成后发送异步请求来获取数据
            mounted(){
                this.selectAll();
            },
            methods: {
                // 查询所有数据,抽出作为一个函数,降低耦合
                selectAll() {
                    // 原生的this不能在Axios中使用,提升其生命周期
                    var _this = this;
                    // 使用Axios发送异步请求
                    axios({
                        method:"get",
                        // URL改为分页查询所需的URL
                        url:"http://localhost:8080/brand-case/brand/selectByPage?currentPage="+ _this.currentPage +"&pageSize="+ _this.pageSize
                    }).then(function (resp) {
                        _this.tableData = resp.data.rows;
                        _this.totalCount = resp.data.totalCount;
                    })
                },
                // ...
                // ...
                // ...
            },
            data() {
                return {
                    // 每页记录数
                    pageSize: 5,
                    // 当前页码
                    currentPage: 1,
                    // 总记录数
                    totalCount: 100,
                    // ...
                    // ...
                }
            }
        })
    </script>
    </body>
    </html>
    

7、条件查询

  • Dao

    • Mapper接口

      List<Brand> selectByPageAndCondition(@Param("begin") int begin, @Param("pageSize") int pageSize, @Param("brand") Brand brand);
      int selectTotalCount();
      
    • Mapper映射文件

      <!-- 条件查询 -->
      <select id="selectByPageAndCondition" resultMap="brandResultMap">
          select * from tb_brand
          <where>
              <if test="brand.brandName != null and brand.brandName != ''">
                  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}, #{pageSize}
      </select>
      
      <select id="selectTotalCountByCondition" resultType="java.lang.Integer">
          select count(*) from tb_brand
          <where>
              <if test="brand.brandName != null and brand.brandName != ''">
                  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>
      </select>
      
  • Service

    @Override
    public PageBean<Brand> selectByPageAndCondition(int currentPage, int pageSize, Brand brand) {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
    
        // 计算开始索引
        int begin = (currentPage - 1) * pageSize;
        // 模糊查询准备
        String brandName = brand.getBrandName();
        String companyName = brand.getCompanyName();
        if (brandName != null && brandName.length() > 0)
            brand.setBrandName("%"+ brandName +"%");
        if (companyName != null && companyName.length() > 0)
            brand.setCompanyName("%"+ companyName +"%");
    
        // 查询数据
        List<Brand> rows = mapper.selectByPageAndCondition(begin, pageSize, brand);
        int totalCountByCondition = mapper.selectTotalCountByCondition(brand);
    
        // 封装数据
        PageBean<Brand> brandPageBean = new PageBean<>();
        brandPageBean.setRows(rows);
        brandPageBean.setTotalCount(totalCountByCondition);
    
        sqlSession.close();
        return brandPageBean;
    }
    
  • Servlet

    public void selectByPageAndCondition(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
        // 接收当前页码和每页展示条数
        int currentPage = Integer.parseInt(req.getParameter("currentPage"));
        int pageSize = Integer.parseInt(req.getParameter("pageSize"));
        // 获取查询条件对象
        BufferedReader reader = req.getReader();
        String params = reader.readLine();
        Brand brand = JSON.parseObject(params, Brand.class);
    
        // 调用对应的Service进行查询
        PageBean<Brand> brandPageBean = brandService.selectByPageAndCondition(currentPage, pageSize, brand);
        // 序列化为JSON
        String jsonString = JSON.toJSONString(brandPageBean);
        // 写回数据
        resp.setContentType("text/json;charset=utf-8");
        resp.getWriter().write(jsonString);
    }
    
  • 页面

    <!--
    	...
    -->
    <div id="app">
        <!--搜索表单-->
        <el-form :inline="true" :model="brand" class="demo-form-inline">
            <!--
            	...
        	-->
    
            <el-form-item>
                <el-button type="primary" @click="onSubmit">查询</el-button>
            </el-form-item>
        </el-form>
    	<!--
            ...
        -->
        
    </div>
    <!--
    	...
    -->
    
    <script>
        new Vue({
            el: "#app",
            // 当页面加载完成后发送异步请求来获取数据
            mounted(){
                this.selectAll();
            },
            methods: {
                // 查询所有数据,抽出作为一个函数,降低耦合
                selectAll() {
                    // 原生的this不能在Axios中使用,提升其生命周期
                    var _this = this;
                    // 使用Axios发送异步请求
                    axios({
                        method:"post",
                        url:"http://localhost:8080/brand-case/brand/selectByPageAndCondition?currentPage="+ _this.currentPage +"&pageSize="+ _this.pageSize,
                        data:_this.brand
                    }).then(function (resp) {
                        _this.tableData = resp.data.rows;
                        _this.totalCount = resp.data.totalCount;
                    })
                },
                
                // ...
                // ...
                
                // 查询方法
                onSubmit() {
                    this.selectAll();
                },
                // ...
                // ...
            },
            // ...
        })
    </script>
    </body>
    </html>
    
11-19 12:26