目录
1、 创建BaseServlet继承HttpServlet重写service方法
2、创建不同对象的Servlet将不同的Servlet封装成方法
一、环境搭建
参照 Web案例
在pom.xml中再导入fastjson坐标
<!--导入fastjson坐标-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
二、编写前端页面
通过Element官网的代码编写基于Vue的前端页面
三、连接后端代码实现具体功能
1、查询所有
注意在Vue中使前后端信息交互使用axios异步请求实现
在Vue的data数据中创建数据模型,使后端的数据传递到前端模型中
data() {
return {
//当前页码
currentPage: 1,
//对话框默认为false隐藏
dialogVisible: false,
//品牌模型数据
brand: {
status: '',
brandName: '',
companyName:'',
id:'',
ordered:'',
description:''
},
//表格数据模型
tableData: [{
brandName: '三只松鼠',
companyName: '三只松鼠',
description: 'dsds',
ordered: '10',
status: '1',
}],
/*复选框选中的数据集合*/
multipleSelection: []
}
}
再通过遍历将数据库中的结果展示
<!--表格数据-->
<el-table
:data="tableData"
style="width: 100%"
@Selection-change="handleSelectionChange"
:row-class-name="tableRowClassName">
<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="description"
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>
前端页面向后端发送axios异步请求,使用Vue的生命周期mounted 使在页面加载完成后发送异步请求获取数据,将查询所有封装成方法,内部使用axios异步请求
mounted(){
//页面加载完成后发送异步请求获取数据
this.selectAll();
},
methods: {
//查询所有数据
selectAll(){
var _this=this
//页面加载完成后发送异步请求获取数据
axios({
method:"get",
url:"http://localhost:8080/webcore_case_war/brand/selectAll"
}).then(function (resp){
//将后端数据传递给前端模型
_this.tableData = resp.data;
})
},
这里需要注意:在axios中的this为undefined,他不能代表Vue中的数据,而Vue中的this始终指向Vue,所以要使用this做回调函数,需要在axios外部对this进行处理。
后端Servlet的逻辑
//通过service方法返回sql结果
List<Brand> brandList = brandService.selectAll();
//将返回的结果响应到页面
//将List集合转换为JSON
String brands = JSON.toJSONString(brandList);
//将结果相应到页面
resp.setContentType("text/json;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.write(brands);
后端需要注意的是:在service层中要使用接口规范Brand对象的方法,然后再service下创建包impl存放实现类。
2、新增
前端代码
前端创建表单通过axios异步请求携带表单数据提交到后端进行处理
<!--对话框-->
<el-dialog
title="添加品牌"
:visible.sync="dialogVisible"
width="30%"
:before-close="handleClose">
<!--内部加入表单-->
<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"
//按钮的switch逻辑,开启按钮表示status为1
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>
</span>
</el-dialog>
使用addBrand方法通过axios携带表单数据提交到后台数据库,再调用查询所有的方法
//提交新增数据
addBrand() {
var _this = this;
//发送异步请求,携带表单数据
axios({
method:"post",
url:"http://localhost:8080/webcore_case_war/brand/addBrand",
//携带表单数据
data:_this.brand
}).then(function (resp){
//判断后端返回的是否是success字符串
if (resp.data == "success"){
//添加成功关闭窗口
_this.dialogVisible = false;
//再次查询数据
_this.selectAll();
//添加成功弹出消息
_this.$message({
message: '恭喜你,添加成功',
type: 'success'
})
}
})
},
后端逻辑
前端的JSON数据要使用流读取
//获取前端数据,前端数据是以JSON格式提交的,使用流读取
BufferedReader reader = req.getReader();
String s = reader.readLine(); //对应的JSON字符串
//将对应的JSON字符串转为java对象
Brand brand = JSON.parseObject(s, Brand.class);
//将获取的数据封装到数据库
brandService.addBrand(brand);
//响应成功的标识
resp.getWriter().write("success");
3、代码优化
由于每实现一个功能就要创建一个Servlet,会使得Servlet的文件越来越多,因此对后端Servlet进行代码优化
可以发现所有的Servlet都使用了doGet和doPost方法实现数据转发,而doGet、doPost是Servlet内部写好的方法,所以我们可以重写HttpServlet中的方法分发的方法,来实现一个对象对应一个Servlet的操作代码,将所有的Servlet代码都写在一个Servlet中,通过其他的Servlet封装成方法进行调用即可。
1、 创建BaseServlet继承HttpServlet重写service方法
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.Method;
public class BaseServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、获取请求路径
String uri = req.getRequestURI(); // webcore_case_war/brand/selectAll
//2、获取最后一段路径--方法名
int index = uri.lastIndexOf('/');
//获取方法名
//直接使用index会包含/
String methodName = uri.substring(index + 1);
//3、执行方法
//3.1、获取方法的class类文件
//哪个方法调用这个service,这个this就代表哪个方法的对象
//例如BrandServlet和UserServlet,两个Servlet对象,这两个Servlet继承BaseServlet,都会调用这个service方法
//如果是BrandServlet中的selectAll方法调用service方法,那么这个this就代表BrandServlet对象
Class<? extends BaseServlet> cls = this.getClass();
try {
//3.2、通过class文件反射,获取方法
//(方法名称,方法携带的参数)方法携带的参数HttpServletRequest、HttpServletResponse也要加进去
//每个方法都会携带参数HttpServletRequest、HttpServletResponse
Method method = cls.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
//3.3、获取方法后执行方法
//方法反射告诉对象调用这个方法 方法名.invoke(对象名,携带的参数)
method.invoke(this,req,resp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
2、创建不同对象的Servlet将不同的Servlet封装成方法
通过/brand/* *号通配符,需要访问那个功能就将方法名替换*号
import com.alibaba.fastjson.JSON;
import com.itheima.pojo.Brand;
import com.itheima.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.io.PrintWriter;
import java.util.List;
@WebServlet("/brand/*")
public class BrandServlet extends BaseServlet{
//实现类要创建对象才能调用
private BrandServiceImpl brandService = new BrandServiceImpl();
public void selectAll(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
//通过service方法返回sql结果
List<Brand> brandList = brandService.selectAll();
//将返回的结果响应到页面
//将List集合转换为JSON
String brands = JSON.toJSONString(brandList);
//将结果相应到页面
resp.setContentType("text/json;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.write(brands);
}
public void addBrand(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
//获取前端数据,前端数据是以JSON格式提交的,使用流读取
BufferedReader reader = req.getReader();
String s = reader.readLine(); //对应的JSON字符串
//将对应的JSON字符串转为java对象
Brand brand = JSON.parseObject(s, Brand.class);
//将获取的数据封装到数据库
brandService.addBrand(brand);
//响应成功的标识
resp.getWriter().write("success");
}
}
4、删除品牌
前端逻辑
//删除按钮
handleDelete(row) {
this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
cancelButtonText: '取消',
confirmButtonText: '确定',
type: 'warning'
}).then(() => {
//异步请求后端删除数据
var _this = this;
axios({
method:"post",
url:"http://localhost:8080/webEndingCase_war/brand/deleteBrandById",
//将一行数据的数据携带传给后端
//在html中声明了携带的是id值
data:row
}).then(function (resp) {
//删除逻辑
if (resp.data == "success") {
//删除成功,自动关闭窗口
//刷新数据,重新查询
_this.selectAll();
}
}),
this.$message({
type: 'success',
message: '删除成功!'
});
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
后端逻辑
public void selectBrandById(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
//获取前端数据,前端数据是以JSON格式提交的,使用流读取
BufferedReader reader = req.getReader();
String id = reader.readLine(); //对应的JSON字符串
//调用service方法
Brand brand = brandService.selectBrandById(Integer.parseInt(id));
//将brand对象转成JSON字符串
String s = JSON.toJSONString(brand);
//将JSON字符串发送给前端
//相应给前端的字符串也要设置编码否则会乱码
resp.setContentType("text/json;charset=utf-8");
resp.getWriter().write(s);
}
技术难点:
如何获取页面id并将id传递给后端
<!--将一行数据的id藏在操作栏中,通过id就能获取到该行数据-->
<el-table-column
prop="id"
align="center"
label="操作">
<!--标签内写按钮-->
<template slot-scope="scope">
<!--根据id查询数据,将数据回调回页面-->
<el-button type="primary" @click="handleSelect(scope.row.id),updatedialogVisible = true">修改</el-button>
<el-button type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
</template>
</el-table-column>
在当前的操作栏隐藏对应的id值
再在对应单元格标签中添加属性 slot-scope="scope",在按钮的点击方法中声明参数scope.row.id,就可以获取该行数据的id值,也可以获取其他值。
![]()
在vue框架中
5、修改品牌
点击修改后进行数据回显,通过id获取数据响应给前端,修改数据后再点击提交修改,后端实现修改逻辑
前端逻辑
//提交修改逻辑
handleUpdate(){
var _this = this;
//发送异步请求,携带表单数据
axios({
method: "post",
url: "http://localhost:8080/webEndingCase_war/brand/updateBrand",
//携带表单数据
data:_this.updatebrand
}).then(function (resp) {
//判断后端返回的是否是success字符串
if (resp.data == "success") {
//添加成功关闭窗口
_this.updatedialogVisible = false;
//再次查询数据
_this.selectAll();
//添加成功弹出消息
_this.$message({
message: '恭喜你,修改成功',
type: 'success'
})
}
})
},
//点击修改后数据回调给页面
handleSelect(row){
var _this = this
//提交异步请求
//将一行数据的id值传递给后端
axios({
method:"post",
url:"http://localhost:8080/webEndingCase_war/brand/selectBrandById",
data:row
}).then(function (resp) {
//将回调的数据传给updateBrand模型
_this.updatebrand = resp.data;
})
},
后端逻辑
public void selectBrandById(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
//获取前端数据,前端数据是以JSON格式提交的,使用流读取
BufferedReader reader = req.getReader();
String id = reader.readLine(); //对应的JSON字符串
//调用service方法
Brand brand = brandService.selectBrandById(Integer.parseInt(id));
//将brand对象转成JSON字符串
String s = JSON.toJSONString(brand);
//将JSON字符串发送给前端
//相应给前端的字符串也要设置编码否则会乱码
resp.setContentType("text/json;charset=utf-8");
resp.getWriter().write(s);
}
public void updateBrand(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
//解决前端发送数据乱码问题
req.setCharacterEncoding("UTF-8");
//获取前端数据,前端数据是以JSON格式提交的,使用流读取
BufferedReader reader = req.getReader();
String s = reader.readLine(); //对应的JSON字符串
System.out.println(s);
//将对应的JSON字符串转为java对象
Brand brand = JSON.parseObject(s, Brand.class);
System.out.println(brand);
//调用service
brandService.updateBrand(brand);
//修改成功向前端响应标识
resp.getWriter().write("success");
}
技术难点:
数据回调传递到前端并展示
遇到的难题:
前端页面返回给后端的JSON中文格式乱码问题
对前端返回的字符串进行输出发现中文格式乱码
解决方法:
在servlet中添加如下代码解决中文乱码问题
req.setCharacterEncoding("UTF-8");
后端返回给前端中文乱码问题
6、批量删除
前端逻辑
//删除逻辑
for (let i = 0; i < this.multipleSelection.length; i++) {
let selectionbrand = this.multipleSelection[i];
//将选中的id传入deleteIds模型中
this.deleteIds[i] = selectionbrand.id;
}
var _this = this;
//发送异步请求,携带表单数据
axios({
method: "post",
url: "http://localhost:8080/webEndingCase_war/brand/deleteBrandByIds",
//携带表单数据
data: _this.deleteIds
}).then(function (resp) {
//判断后端返回的是否是success字符串
if (resp.data == "success") {
//再次查询数据
_this.selectAll();
}
})
后端逻辑
public void deleteBrandByIds(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
//接收前端数据 id数组[1,2,8]
BufferedReader reader = req.getReader();
String params = reader.readLine();
//将得到的JSON格式的id数组转为int型数组
int[] ids = JSON.parseObject(params, int[].class);
//调用service方法
brandService.deleteBrandByIds(ids);
//响应给前端结果
resp.getWriter().write("success");
}
技术难点:
获取前端页面复选框选中的id数组,传递给后端
7、分页查询
前端逻辑
//查询分页数据
selectByPage() {
var _this = this;
axios({
method:"get",
url:"http://localhost:8080/webEndingCase_war/brand/selectByPage?currentPage="+_this.currentPage+"&pageSize="+_this.pageSize
}).then(function (resp) {
//_this.tableData = resp.data; 当前后端传递的数据是{"pageData":[{"brandName":"联想","companyName":"联想有限公司"}
//JSON字符串格式,不能直接放入表格
//通过resp.data. 来获取不同的数据
_this.tableData = resp.data.pageData;
_this.totalCount = resp.data.totalCount;
})
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`);
//点击切换当前页,赋值给当前页模型
this.currentPage = val;
this.selectByPage();
},
//分页方法
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
this.pageSize = val;
this.selectByPage();
},
后端逻辑
public void selectByPage(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException{
//前端通过get请求 使用url将当前页码和当前页数据传到后端 url?currentPage=1&pageSize=10
String currentPage = req.getParameter("currentPage");
String pageSize = req.getParameter("pageSize");
//调用service方法
PageBean<Brand> pageBean = brandService.selectByPage(Integer.parseInt(currentPage), Integer.parseInt(pageSize));
//将java对象转成JSON格式
String jsonString = JSON.toJSONString(pageBean);
//将JSON数据发送给前端
resp.setContentType("text/json;charset=utf-8");
resp.getWriter().write(jsonString);
}
技术难点:
需要将当前分页页面数据和总数据条数封装成对象一起传递到前端
8、多条件分页查询
将查询全部、分页查询和多条件查询进行整合,使他们都使用同一个方法
前端逻辑
修改selectAll方法的查询逻辑,在url后面拼字符串,并且以post请求方式将多条件查询的参数传给后端,参数封装成了selectBrand模型,将来一访问页面就会进行默认的分页查询
//查询分页数据
selectByPage() {
axios({
//在then的外面可以直接使用this
method:"post",
url:"http://localhost:8080/webEndingCase_war/brand/selectByPageAndCondition?currentPage="+this.currentPage+"&pageSize="+this.pageSize,
data:this.selectBrand
}).then(resp => {
//_this.tableData = resp.data; 当前后端传递的数据是{"pageData":[{"brandName":"联想","companyName":"联想有限公司"}
//JSON字符串格式,不能直接放入表格
//通过resp.data. 来获取不同的数据
this.tableData = resp.data.pageData;
this.totalCount = resp.data.totalCount;
})
},
后端逻辑
public void selectByPageAndCondition(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException{
req.setCharacterEncoding("UTF-8");
//前端通过get请求 使用url将当前页码和当前页数据传到后端 url?currentPage=1&pageSize=10
String currentPage = req.getParameter("currentPage");
String pageSize = req.getParameter("pageSize");
System.out.println(currentPage);
//获取前端对应的查询条件对象
//接收前端数据
BufferedReader reader = req.getReader();
String params = reader.readLine();
System.out.println(params);
//将得到的JSON格式转为brand对象
Brand brand = JSON.parseObject(params,Brand.class);
System.out.println(brand);
//调用service方法
PageBean<Brand> pageBean = brandService.selectByPageAndCondition(Integer.parseInt(currentPage), Integer.parseInt(pageSize),brand);
System.out.println(pageBean);
//将java对象转成JSON格式
String jsonString = JSON.toJSONString(pageBean);
//将JSON数据发送给前端
resp.setContentType("text/json;charset=utf-8");
resp.getWriter().write(jsonString);
}
技术难点:
多条件查询后还要通过分页查询展示数据