在任务六中我们讲过,前后端跨域数据交互,有两种方式可以解决跨域请求,任务六我们使用了CorsConfig类配置跨域。本次任务,我们使用一个基于 Promise 的 HTTP 库,可以用在浏览器和 node.js 中的axios,实现前后端跨域数据交互。通过本次任务,大家能够:
(1)掌握axios的使用方法,包括全局设置;
(2)Element中
对话框使用,并实现数据增加;
(3)指定记录删除,以及批量数据删除;
(4)Element中
对话框使用,并实现指定记录修改。
目前我们的前端页面还没有变,仍然沿用最初的home页面,下一个任务中我们将进行VUE路由设计,主要对侧边栏进行维护,届时将对页面的逻辑进行调整。
axios首先需要安装,如果VUE项目正在运行,请使用CTRL+C,然后点击Y终止运行,然后的终端输入:
npm i axios -s
引入axios封装到request中。新建一个utils文件夹,新建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我们稍后经过对比之后在进行更改。
import request from '@/utils/request'//添加
Vue.prototype.request=request // 添加
在前端页面使用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
}
(1)搜索按钮添加一个@click="load"
点击事件,调用load方法。
(2)添加一个重置按钮,并为这个按钮添加一个@click="reset"
点击事件,调用reset方法。
代码为:
搜索
重置
reset方法的代码为:
reset(){
this.username="";
this.nickname="";
this.address="";
this.load();
}
增加数据需要打开用户信息编辑对话框,然后输入对象值,执行添加操作,实现数据记录增加。
中添加elementUI组件Dialog 对话框中的“嵌套表单的 Dialog”在 中添加一个对话框。对话框使用elementUI组件Dialog 对话框中的“嵌套表单的 Dialog”。
对话框这段代码放在 中的位置没有关系,一般情况,为了增加可读性,新添加的代码我们放到最后修改相关属性,代码如下:
data添加dialogFormVisible和form,并将dialogFormVisible初始化为不可见。
data(){
return {
tableData:[],
total:0,
pageNum:1,
pageSize:2,
username:"",
nickname:"",
address:"",
dialogFormVisible:false,
form:{}
}
},
“新增”按钮添加调用hanleAdd()方法。
新增
主要目的是打开“添加用户”对话框,代码如下。
hanleAdd(){
this.dialogFormVisible = true;
this.form={};//如果之前有填过值,可以置空
}
确 定
实现用户信息添加,代码如下。
insert(){
this.request.post("http://localhost:8084/user",this.form).then(res=>{
if(res){
this.$message.success("保存成功");
this.dialogFormVisible=false;
this.load();
}else{
this.$message.error("保存失败");
}
})
},
点击“新增”按钮,打开“用户信息”对话框。
添加用户信息,点击“确定”按钮,显示“保存成功”。
可以看到最后的数据已经添加。
数据表中的数据已经完成
这里有一个思考: 为什么密码那列为空!!!
这是因为,一般情况,系统会根据客户需求初始化一个通用密码,然后对密码进行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注册与登录,见专门撰写的博客。
因为前期增加用户信息已经基本搭好框架,我们在此基础上进行稍微完善就可以了,编辑用户信息比较简单。
编辑
添加handleEdit()方法,代码如下:
handleEdit(row){
console.log(row);
this.form=row;//把当前行的数据赋值给form
this.dialogFormVisible=true;
}
运行项目,点击“编辑”可以打开“用户信息”对话框,实现数据更新,修改信息,因为后台调用的是saveOrUpdate(user)所以,mybatis会自动判断,然后实现更新。
数据表中的记录:
删除
添加handleDelete()方法,代码如下:
handleDelete(id){
this.request.delete("http://localhost:8084/user/"+id+"").then(res=>{
if(res){
this.$message.success("删除成功");
this.load();
}else{
this.$message.error("删除失败");
}
})
},
此时会发现没有提示,直接删除数据,既不合理,对数据的安全性也没有保障。一般对“删除”按钮添加提示功能。
使用elementUI组件中的Popconfirm 气泡确认框,升级“删除”按钮如下。需要将原来在button中的handleDelete(scope.row.id)方法放到确认框中。
删除
(1)首先为表格添加可以多选的复选按钮,使用elementUI的table组件中的多选。
(2)添加了复选框列。
(3)为表格添加@selection-change="handleSelectionChange"事件。
编辑
删除
编写handleSelectionChange()方法,代码如下:
handleSelectionChange(val){
console.log(val);
this.multipleSelection =val;
},
在后端UserController类添加一个批量删除接口deleteBatch:
//使用mybtis-plus实现批量删除
@PostMapping("/del/batch/")
public boolean deleteBatch(@RequestBody List ids){
return userService.removeByIds(ids);
}
批量删除
编写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.success("批量删除成功");
this.load();
}else{
this.$message.error("批量删除失败");
}
})
},
同时选中多条记录,实现批量删除。
特别说明: 可以参考前面删除按钮,添加一个警告弹窗。
本次任务,主要完成并掌握以下内容:
(1)掌握前端axios前后端跨域数据连接的方法;
(2)熟练引用Element的各类组件
在整个增删改查的过程中,我们发现一直要与后端的这个服务地址交互。每次写很麻烦,而且容易做错,这时候request.js的baseURL设置就有用了。
我们修改axios.create,代码如下:
const request = axios.create({
baseURL: 'http://localhost:8084',
timeout: 5000
})
今天是农历兔年春节,祝大家一切顺意!!!