技术栈及相关参考资料:

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优化

每个Servlet写一个类非常杂乱,不利于编写和管理

可以将其写到同一个类中,URL将更变为如http://localhost:8080/brand-case/brand/selectAll的形式

  1. 获取最后一段路径,即方法名称
  2. 通过反射获取方法对象,执行方法

注:

  • 不继承HttpServlet而进行自定义,并手动实现使用请求路径进行方法分发
  • 注意代码中this的使用方法(动态绑定)
  • 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 前端实现

  1. 页面加载完成后发送异步请求,获取列表数据(需要引入 Axios 的 JS 文件)
  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 前端实现

  1. 点击提交按钮时,发送AJAX请求携带表单数据
  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>

JavaWeb实战:基础CRUD+批量删除+分页+条件的更多相关文章

  1. stark组件的分页,模糊查询,批量删除

    1.分页组件高阶 2.整合展示数据showlist类 3.stark组件之分页 3.stark组件之search模糊查询 4.action批量处理数据 4.总结 1.分页组件高阶 1.分页的class ...

  2. Magicodes.WeiChat——ASP.NET Scaffolding生成增删改查、分页、搜索、删除确认、批量操作、批量删除等业务代码

    关于T4代码生成这块,我之前写过几篇帖子,如:<Magicodes.NET框架之路——让代码再飞一会(ASP.NET Scaffolding)>(http://www.cnblogs.co ...

  3. php部分---对数据的多条件查询,批量删除

    1.给多条件查询,添加条件 <h1>新闻信息查看</h1> <?php $tiaojian1=" 1=1"; $tiaojian2=" 1= ...

  4. JAVAEE——BOS物流项目04:学习计划、datagrid、分页查询、批量删除、修改功能

    1 学习计划 1.datagrid使用方法(重要) n 将静态HTML渲染为datagrid样式 n 发送ajax请求获取json数据创建datagrid n 使用easyUI提供的API创建data ...

  5. SQL存储过程将符合条件的大量记录批量删除脚本

    -- ============================================= -- Author: James Fu -- Create date: 2015/10/27 -- D ...

  6. django实战(三)--删除和批量删除

    上一节我们完成了带分页的模糊查询,本节我们继续删除操作. 同样的,先给出各个模块的代码(上一节的就不在贴出了):urls.py path('curd/delete/',views.curd_delet ...

  7. mteclipse中运行的分页,搜索,列表批量删除的界面,它的源代码

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <hea ...

  8. Linux基础教程 linux系统中的批量删除文件与空文件删除的命令介绍

    linux下面删除文件或者目录命令rm(remove): 兄弟连Linux培训 功能说明:删除文件或目录. 语 法:rm[-dfirv][--help][--version][文件或目录...] 补充 ...

  9. mybatis(二)接口编程 、动态sql 、批量删除 、动态更新、连表查询

    原理等不在赘述,这里主要通过代码展现. 在mybatis(一)基础上,新建一个dao包,并在里面编写接口,然后再在xml文件中引入接口路径,其他不变,在运用阶段将比原始方法更节约时间,因为不用再去手动 ...

  10. EasyUI-DataGrid之批量删除

    简单介绍一下,涉及到的几个知识点: 1.checkbox,多选 2.前台到后台传值,我用的是字符串拼接,到了后台在拆分的方式 3.批量删除的底层实现 效果图 前台view <table id=& ...

随机推荐

  1. KingabseES 锁机制

    KingabseES的锁机制 目录 KingabseES的锁机制 一.前言 二.锁机制 三.表级锁 ( Table-Level Locks ) 1.访问共享(ACCESS SHARE) 2.行共享(R ...

  2. linux中cd后自动 ls的设置

    根据不同的shell设置不太一样.常见的有bash csh两种.可以用echo $SHELL来查询当前是哪一种. bash设置是在用户的home下打开.bashrc在里面加上如下: cd() { bu ...

  3. Linux系统编程001--系统IO

    1. 文件系统:用来存储.组织.管理文件的一套方式.协议 2. 文件 文件的属性:i-node唯一表示一个文件的存在与否 文件的内容 3. Linux系统如何实现文件的操作? 点击查看代码 硬件层: ...

  4. k8s驱逐篇(4)-kube-scheduler抢占调度驱逐

    介绍kube-scheduler抢占调度驱逐之前,先简单的介绍下kube-scheduler组件: kube-scheduler简介 kube-scheduler组件是kubernetes中的核心组件 ...

  5. Svelte Ui Admin后台管理系统|svelte3+svelteUI中后台前端解决方案

    基于svelte3.x+svelteKit+svelte-ui网页后台管理系统SvelteAdmin. Svelte-Ui-Admin 基于svelte3.x+svelteKit+vite3+echa ...

  6. Spring Boot 整合Hibernate Validator

    Spring Boot 整合Hibernate Validator 依赖 <dependencies> <dependency> <groupId>org.spri ...

  7. getch()之隐藏输入密码

    getch() :读取字符且不会回显(不会显示):不从输入缓冲区读取:在getch中,把回车按键输入, 识别为回车符'\r':在getchar中,把回车按键输入,识别为回车符'\n'. getch() ...

  8. Flink基础概念入门

    Flink 概述 什么是 Flink Apache Apache Flink 是一个开源的流处理框架,应用于分布式.高性能.高可用的数据流应用程序.可以处理有限数据流和无限数据,即能够处理有边界和无边 ...

  9. HCNP Routing&Switching之ARP安全

    前文我们了解了IP安全相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/16652367.html:今天我们来聊一聊ARP安全相关话题: 什么是ARP? ...

  10. 使用 Docker 安装 Elastic Stack 8.0 并开始使用

    文章转载自:https://mp.weixin.qq.com/s/fLnIzbbqYfILS6uCvGctXw 运行 Elasticsearch docker network create elast ...