任务八 应用mybatis-plus框架https://blog.csdn.***/wdyan297/article/details/128736234
任务九 axios前后端跨域数据交互
在任务六中我们讲过,前后端跨域数据交互,有两种方式可以解决跨域请求,任务六我们使用了CorsConfig类配置跨域。本次任务,我们使用一个基于 Promise 的 HTTP 库,可以用在浏览器和 node.js 中的axios,实现前后端跨域数据交互。通过本次任务,大家能够:
(1)掌握axios的使用方法,包括全局设置;
(2)Element中<el-dialog>
对话框使用,并实现数据增加;
(3)指定记录删除,以及批量数据删除;
(4)Element中<el-dialog>
对话框使用,并实现指定记录修改。
目前我们的前端页面还没有变,仍然沿用最初的home页面,下一个任务中我们将进行VUE路由设计,主要对侧边栏进行维护,届时将对页面的逻辑进行调整。
一、基础axios配置
1.Vue安装axios
axios首先需要安装,如果VUE项目正在运行,请使用CTRL+C,然后点击Y终止运行,然后的终端输入:
npm i axios -s
安装成功后,大家可以看到axios的版本
2.引入axios封装到request中
引入axios封装到request中。新建一个utils文件夹,新建request.js。
3.配置文件request.js
配置文件request.js代码如下。
import axios from 'axios'
const request = axios.create({
baseURL: '/api', // 注意!! 这里是全局统一加上了 '/api' 前缀,也就是说所有接口都会加上'/api'前缀在,页面里面写接口的时候就不要加 '/api'了,否则会出现2个'/api',类似 '/api/api/user'这样的报错,切记!!!
timeout: 5000
})
// request 拦截器
// 可以自请求发送前对请求做一些处理
// 比如统一加token,对请求参数统一加密
request.interceptors.request.use(config => {
config.headers['Content-Type'] = 'application/json;charset=utf-8';
// config.headers['token'] = user.token; // 设置请求头
return config
}, error => {
return Promise.reject(error)
});
// response 拦截器
// 可以在接口响应后统一处理结果
request.interceptors.response.use(
response => {
let res = response.data;
// 如果是返回的文件
if (response.config.responseType === 'blob') {
return res
}
// 兼容服务端返回的字符串数据
if (typeof res === 'string') {
res = res ? JSON.parse(res) : res
}
return res;
},
error => {
console.log('err' + error) // for debug
return Promise.reject(error)
}
)
export default request
说明: 关于baseURL我们稍后经过对比之后在进行更改。
4. 在main.js中引入request对象
两行代码为:
import request from '@/utils/request'//添加
Vue.prototype.request=request // 添加
5.使用request,修改load方法
在前端页面使用request,修改load方法。
load() {
//请求分页查询数据
//fetch("http://localhost:8084/user/page?pageNum="+this.pageNum+"&pageSize="+this.pageSize+"").then(res=>res.json()).then(res=>{
//使用axios封装的request
this.request.get("http://localhost:8084/user/page",{
params:{
pageNum: this.pageNum,
pageSize: this.pageSize,
username: this.username,
nickname:this.nickname,
address:this.address
}
}).then(res=>{
console.log(res)
this.tableData=res.data
this.total=res.total
})
}
这里有几个地方需要说明:
(1)如果出现这种没有数据的情况。
打开“开发者工具”我们会发现,现在数据放到records以及total中,这里是一个对象,所以我们的表格数据和总条目数据需要修改取值方式。
后端接口是这样的:
后端代码及解析详见任务八。
我们在任务六中的接口是这样的:
所以
console.log(res);
this.tableData=res.records;
this.total=res.total;
(2)使用 params整合传值
这样让前端传值比较整齐。
params:{
pageNum: this.pageNum,
pageSize: this.pageSize,
username: this.username,
nickname:this.nickname,
address:this.address
}
6.运行测试
二、“搜索”实现模糊查询
(1)搜索按钮添加一个@click="load"
点击事件,调用load方法。
(2)添加一个重置按钮,并为这个按钮添加一个@click="reset"
点击事件,调用reset方法。
代码为:
<el-button style="margin-left:5px" type="primary" @click="load">搜索</el-button>
<el-button style="margin-left:5px" type="warning" @click="reset">重置</el-button>
reset方法的代码为:
reset(){
this.username="";
this.nickname="";
this.address="";
this.load();
}
运行项目,实现模糊查询。
三、增加数据
增加数据需要打开用户信息编辑对话框,然后输入对象值,执行添加操作,实现数据记录增加。
1. </el-main>
中添加elementUI组件Dialog 对话框中的“嵌套表单的 Dialog”
在 </el-main>
中添加一个对话框。对话框使用elementUI组件Dialog 对话框中的“嵌套表单的 Dialog”。
对话框这段代码放在 </el-main>
中的位置没有关系,一般情况,为了增加可读性,新添加的代码我们放到最后修改相关属性,代码如下:
<el-dialog title="用户信息" :visible.sync="dialogFormVisible" width="30%">
<el-form label-width="80px" size="small">
<el-form-item label="用户名">
<el-input v-model="form.username" auto***plete="off"></el-input>
</el-form-item>
<el-form-item label="昵称">
<el-input v-model="form.nickname" auto***plete="off"></el-input>
</el-form-item>
<el-form-item label="邮箱">
<el-input v-model="form.email" auto***plete="off"></el-input>
</el-form-item>
<el-form-item label="电话">
<el-input v-model="form.phone" auto***plete="off"></el-input>
</el-form-item>
<el-form-item label="地址">
<el-input v-model="form.address" auto***plete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" >确 定</el-button>
</div>
</el-dialog>
2.data添加dialogFormVisible和form
data添加dialogFormVisible和form,并将dialogFormVisible初始化为不可见。
data(){
return {
tableData:[],
total:0,
pageNum:1,
pageSize:2,
username:"",
nickname:"",
address:"",
dialogFormVisible:false,
form:{}
}
},
3.“新增”按钮添加调用hanleAdd()方法
“新增”按钮添加调用hanleAdd()方法。
<el-button type="primary" @click="hanleAdd">新增<i class="el-icon-circle-plus"></i></el-button>
4.添加hanleAdd方法
主要目的是打开“添加用户”对话框,代码如下。
hanleAdd(){
this.dialogFormVisible = true;
this.form={};//如果之前有填过值,可以置空
}
5.“确定”按钮填调用insert()方法
<el-button type="primary" @click="insert">确 定</el-button>
6.添加insert方法
实现用户信息添加,代码如下。
insert(){
this.request.post("http://localhost:8084/user",this.form).then(res=>{
if(res){
this.$message.su***ess("保存成功");
this.dialogFormVisible=false;
this.load();
}else{
this.$message.error("保存失败");
}
})
},
7.运行项目
点击“新增”按钮,打开“用户信息”对话框。
添加用户信息,点击“确定”按钮,显示“保存成功”。
可以看到最后的数据已经添加。
数据表中的数据已经完成
这里有一个思考: 为什么密码那列为空!!!
这是因为,一般情况,系统会根据客户需求初始化一个通用密码,然后对密码进行MD5加密;
详细讲解为:
密码的安全问题:密码简单,明文密码
密码:1234 -------》 数据库:1234
这种方式一般安全性太低。
故要对密码进行加密,一般采用MD5加密,具体方法为:
MD5加密:1234+字符串(盐) 加密后生成32位的密码存到数据库中
登录的时候,对于密码则要进行解密,当原文(原密码)与盐一致,密文一致,才允许下一步操作。
MD5加密一般都需要在前端进行第一次加密,这样为了防止传递的是明文密码,然后再在后端进行二次加密。
以下方法仅供参考。
MD5加密,需要在用户表中再加一个salt字段,存放盐值。
注册时:
后端加密的方法
String salt = UUID.randomUUID().toString();
String password = user.getUserPassword();//取到前端传递的密码初始值
user.setUserPassword(getMD5Pwd(password, salt)).setUserSalt(salt);//对初始密码加盐,并存放盐值,然后继续后续操作即可
加密的方法getMD5Pwd 代码为:
/**
* 封装一个方法 对密码进行加密
*/
private String getMD5Pwd(String password, String salt) {
String md5Pwd = password + salt;
return DigestUtils.md5DigestAsHex(md5Pwd.getBytes());
}
登录时:
........
User selectUser = getUser("user_email", userEmail);
if (selectUser == null) {
return Result.error(405, "该邮箱不存在");
}
String userSalt = selectUser.getUserSalt();
String userPassword = selectUser.getUserPassword();
if (userPassword.equals(getMD5Pwd(user.getUserPassword(), userSalt))) {//解密,并与盐值做比较
........
为了项目连续性,这里就暂时不修改sys_user数据表结构,与本项目相关的MD5注册与登录,见专门撰写的博客。
四、编辑用户信息
因为前期增加用户信息已经基本搭好框架,我们在此基础上进行稍微完善就可以了,编辑用户信息比较简单。
1.给“编辑”按钮添加handleEdit()方法将当前行作为参数进行传递
<el-button type="su***ess" size="small" icon="el-icon-edit" @click="handleEdit(scope.row)">编辑</el-button>
2.添加handleEdit()方法
添加handleEdit()方法,代码如下:
handleEdit(row){
console.log(row);
this.form=row;//把当前行的数据赋值给form
this.dialogFormVisible=true;
}
3.运行项目
运行项目,点击“编辑”可以打开“用户信息”对话框,实现数据更新,修改信息,因为后台调用的是saveOrUpdate(user)所以,mybatis会自动判断,然后实现更新。
数据表中的记录:
五、删除用户
1.给“删除”按钮添加handleDelete()方法,将当前行的id作为参数进行传递。
<el-button type="danger" size="small" icon="el-icon-delete" @click="handleDelete(scope.row.id)">删除</el-button>
2. 添加handleDelete()方法
添加handleDelete()方法,代码如下:
handleDelete(id){
this.request.delete("http://localhost:8084/user/"+id+"").then(res=>{
if(res){
this.$message.su***ess("删除成功");
this.load();
}else{
this.$message.error("删除失败");
}
})
},
3.运行项目
选中一条记录,点击"删除"。
提示删除成功。
数据表中已删除相关记录。
4. 删除按钮升级提示功能
此时会发现没有提示,直接删除数据,既不合理,对数据的安全性也没有保障。一般对“删除”按钮添加提示功能。
使用elementUI组件中的Popconfirm 气泡确认框,升级“删除”按钮如下。需要将原来在button中的handleDelete(scope.row.id)方法放到确认框中。
<el-popconfirm style="margin-left:5px"
confirm-button-text='确定'
cancel-button-text='再想想'
icon="el-icon-info"
icon-color="red"
title="您确定删除吗?"
@confirm="handleDelete(scope.row.id)"
>
<el-button type="danger" size="small" slot="reference" icon="el-icon-delete" >删除</el-button>
六、数据批量删除
1. 升级数据表格为有复选框列的表格
(1)首先为表格添加可以多选的复选按钮,使用elementUI的table组件中的多选。
(2)添加了复选框列。
<el-table-column type="selection" width="55"></el-table-column>
(3)为表格添加@selection-change="handleSelectionChange"事件。
<el-table :data="tableData" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="id" label="ID " width="80">
</el-table-column>
<el-table-column prop="username" label="姓名 " width="80">
</el-table-column>
<el-table-column prop="email" label="邮箱" width="120">
</el-table-column>
<el-table-column prop="phone" label="电话">
</el-table-column>
<el-table-column prop="nickname" label="昵称">
</el-table-column>
<el-table-column prop="address" label="地址">
</el-table-column>
<el-table-column fixed="right" label="操作" width="240">
<template slot-scope="scope">
<el-button type="su***ess" size="small" icon="el-icon-edit" @click="handleEdit(scope.row)">编辑</el-button>
<el-popconfirm style="margin-left:5px"
confirm-button-text='确定'
cancel-button-text='再想想'
icon="el-icon-info"
icon-color="red"
title="您确定删除吗?"
@confirm="handleDelete(scope.row.id)"
>
<el-button type="danger" size="small" slot="reference" icon="el-icon-delete" >删除</el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
(4)运行
运行结果是这样的:
2.编写handleSelectionChange()方法
编写handleSelectionChange()方法,代码如下:
handleSelectionChange(val){
console.log(val);
this.multipleSelection =val;
},
3.后端添加一个批量删除方法
在后端UserController类添加一个批量删除接口deleteBatch:
//使用mybtis-plus实现批量删除
@PostMapping("/del/batch/")
public boolean deleteBatch(@RequestBody List<Integer> ids){
return userService.removeByIds(ids);
}
4. “批量删除”按钮添加delBatch单击事件
<el-button type="danger" @click="delBatch">批量删除<i class="el-icon-remove"></i></el-button>
5.编写delBatch方法
编写delBatch方法。
注意: 传递IDS批量数据时,使用post请求。
delBatch(){
let ids=this.multipleSelection.map(v=>v.id);//map这个方法可以实现将multipleSelection中的对象扁平化处理。
console.log(ids);
this.request.post("http://localhost:8084/user/del/batch/",ids).then(res=>{
if(res){
this.$message.su***ess("批量删除成功");
this.load();
}else{
this.$message.error("批量删除失败");
}
})
},
6.运行项目
同时选中多条记录,实现批量删除。
特别说明: 可以参考前面删除按钮,添加一个警告弹窗。
任务总结
本次任务,主要完成并掌握以下内容:
(1)掌握前端axios前后端跨域数据连接的方法;
(2)熟练引用Element的各类组件
彩蛋 request.js的baseURL完善
在整个增删改查的过程中,我们发现一直要与后端的这个服务地址交互。每次写很麻烦,而且容易做错,这时候request.js的baseURL设置就有用了。
我们修改axios.create,代码如下:
const request = axios.create({
baseURL: 'http://localhost:8084',
timeout: 5000
})
页面中做如下修改:
以后都可以不用写服务器地址啦!!!
再一个彩蛋
今天是农历兔年春节,祝大家一切顺意!!!