JavaWeb实战:基础CRUD+批量删除+分页+条件
技术栈及相关参考资料:
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&useUnicode=true&characterEncoding=utf-8&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的形式
- 获取最后一段路径,即方法名称
- 通过反射获取方法对象,执行方法
注:
- 不继承
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 前端实现
- 页面加载完成后发送异步请求,获取列表数据(需要引入 Axios 的 JS 文件)
- 将数据设置到模型上
代码
<!--
...
-->
<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 前端实现
- 点击提交按钮时,发送AJAX请求携带表单数据
- 获取数据,判断添加是否成功,关闭窗口,重新加载数据
代码
<!--
......
--> <!--按钮-->
<!--
@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+批量删除+分页+条件的更多相关文章
- stark组件的分页,模糊查询,批量删除
1.分页组件高阶 2.整合展示数据showlist类 3.stark组件之分页 3.stark组件之search模糊查询 4.action批量处理数据 4.总结 1.分页组件高阶 1.分页的class ...
- Magicodes.WeiChat——ASP.NET Scaffolding生成增删改查、分页、搜索、删除确认、批量操作、批量删除等业务代码
关于T4代码生成这块,我之前写过几篇帖子,如:<Magicodes.NET框架之路——让代码再飞一会(ASP.NET Scaffolding)>(http://www.cnblogs.co ...
- php部分---对数据的多条件查询,批量删除
1.给多条件查询,添加条件 <h1>新闻信息查看</h1> <?php $tiaojian1=" 1=1"; $tiaojian2=" 1= ...
- JAVAEE——BOS物流项目04:学习计划、datagrid、分页查询、批量删除、修改功能
1 学习计划 1.datagrid使用方法(重要) n 将静态HTML渲染为datagrid样式 n 发送ajax请求获取json数据创建datagrid n 使用easyUI提供的API创建data ...
- SQL存储过程将符合条件的大量记录批量删除脚本
-- ============================================= -- Author: James Fu -- Create date: 2015/10/27 -- D ...
- django实战(三)--删除和批量删除
上一节我们完成了带分页的模糊查询,本节我们继续删除操作. 同样的,先给出各个模块的代码(上一节的就不在贴出了):urls.py path('curd/delete/',views.curd_delet ...
- mteclipse中运行的分页,搜索,列表批量删除的界面,它的源代码
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <hea ...
- Linux基础教程 linux系统中的批量删除文件与空文件删除的命令介绍
linux下面删除文件或者目录命令rm(remove): 兄弟连Linux培训 功能说明:删除文件或目录. 语 法:rm[-dfirv][--help][--version][文件或目录...] 补充 ...
- mybatis(二)接口编程 、动态sql 、批量删除 、动态更新、连表查询
原理等不在赘述,这里主要通过代码展现. 在mybatis(一)基础上,新建一个dao包,并在里面编写接口,然后再在xml文件中引入接口路径,其他不变,在运用阶段将比原始方法更节约时间,因为不用再去手动 ...
- EasyUI-DataGrid之批量删除
简单介绍一下,涉及到的几个知识点: 1.checkbox,多选 2.前台到后台传值,我用的是字符串拼接,到了后台在拆分的方式 3.批量删除的底层实现 效果图 前台view <table id=& ...
随机推荐
- 教大家怎么看monaco-editor的官方文档
最近业务中有用到浏览器在线编辑器,用的是monaco-editor,官网文档只在首页介绍了npm安装方式. 但其实还有另外一种<script>的引入方式,但是这种方式体现在API文档中,由 ...
- KingbaseES 多列分区的方法与性能
前言 对于多列分区,可以选择单级多列的范围分区,也可以选择范围加子分区的方式.但二者在不同场景下对于性能是有差异的,这里的性能差异主要是分区裁剪引起的差异. 例子 创建两张分区表,采取不同的分区策略: ...
- windows下 Rust 环境配置
搭建 Visual Studio Code 开发环境 首先,需要安装最新版的 Rust 编译工具和 Visual Studio Code. Rust 编译工具:https://www.rust-lan ...
- Django 使用Pycharm 创建工程
一.Pycharm 创建Django 工程 事实上,我们一般不使用命令行,而是直接在Pycharm 中创建Django 项目. Pycharm 是进行Django 开发的最佳 IDE,请大家自行安装, ...
- 修复 Elasticsearch 集群的常见错误和问题
文章转载自:https://mp.weixin.qq.com/s/8nWV5b8bJyTLqSv62JdcAw 第一篇:Elasticsearch 磁盘使用率超过警戒水位线 从磁盘常见错误说下去 当客 ...
- MinIO对接k8s使用
文档地址:https://github.com/minio/operator/blob/master/README.md https://docs.min.io/minio/k8s/deploymen ...
- 使用tomcat部署java的war包操作
修改tomcat配置文件server.xml 修改端口号,别跟其他已经被使用的端口号起冲突 修改项目所在路径 <?xml version="1.0" encoding=&qu ...
- Kibana: 运用Data Visualizer来分析CSV数据
- shell脚本中执行source命令不生效的解决办法
一个shell脚本文件中有一个source命令,使用bash a.sh命令执行后source命令进行验证没有生效. 这是因为在shell脚本中执行source会看到效果,但是shell脚本执行完后再次 ...
- loam详细代码解析与公式推导
loam详细代码解析与公式推导(基础理论知识) 一.基础坐标变换 loam中欧拉角解算都采用R P Y 的解算方式,即先左乘R, 再左乘P, 最后左乘Y,用矩阵表示为: R = Ry * Rp * R ...