文章目录
1.Axios介绍
1.1 概述
axios时目前最流行的ajax封装库之一,用于很方便地实现ajax请求的发送。其主要支持以下功能:
- 从浏览器发出 XMLHttpRequests请求;
- 从 node.js 发出 http 请求;
- 支持 Promise API;
- 能拦截请求和响应;
- 能转换请求和响应数据;
- 取消请求;
- 实现JSON数据的自动转换;
- 客户端支持防止 XSRF攻击
2. Axios-Post请求
2.1 编辑页面JS
我们常见新的前端html文件,完成下列的代码:
<script src="../js/axios.js"></script>
<script>
/**
* 完成用户入库操作
* 用法: axios.post(url地址,对象名称)
* axios.put(url地址, 对象名称)
*
* axios.get(url地址,{params: 对象名称})
* axios.delete(url地址,{params: 对象名称})
*/
let url1 = "http://localhost:8090/axios/saveUser"
let user1 = {name: "tomcat",age: 18, sex: "女"}
axios.post(url1,user1)
.then(function(promise){
console.log(promise.data)
})
</script>
worestfull风格一般只在查询业务中使用,新增入库涉及到用户敏感信息,所以我们选择封装对象进行数据传递。对于post请求,一般都发送俩次,一次解决跨域问题的,一次传递数据的请求。
2.2 页面参数说明
说明: 用户在js中写的是JS对象,经过浏览器解析发起Ajax请求时,js对象被解析为JSON串.
交互的媒介: HTTP协议 协议中要求传递字符串
2.3 打印Sql语句
说明: 编辑YML文件,增加SQL的日志输出,方便我们观察方法运行时执行的SQL情况。
#配置端口号
server:
port: 8090
#管理数据源
spring:
datasource:
#高版本驱动使用
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/jt?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
#设定用户名和密码
username: root
password: root
#SpringBoot整合Mybatis
mybatis:
#指定别名包
type-aliases-package: com.jt.pojo
#扫描指定路径下的映射文件
mapper-locations: classpath:/mybatis/mappers/*.xml
#开启驼峰映射
configuration:
map-underscore-to-camel-case: true
# 一二级缓存默认开始 所以可以简化
#打印mysql日志
logging:
level:
com.jt.mapper: debug
2.4 编辑AxiosController
我们在当前后端项目下,新创建AxiosController完成后端代码;
@RestController
@CrossOrigin
@RequestMapping("/axios") //抽取请求路径中公共部分的前缀
public class AxiosController {
@Autowired
private AxiosService axiosService;
/**
* 实现用户入库操作
* url地址: http://localhost:8090/axios/saveUser
* 参数: JSON串 {"name":"tomcat","age":18,"sex":"女"}
* 返回值: 成功消息
* 难点: 前端传递的是JSON,后端不可以直接使用User对象接收.
* 解决方案:
* 1.对象可以转化为JSON串 @ResponseBody
* 2.JSON串转化为对象 @RequestBody
*/
@PostMapping("/saveUser")
public String saveUser(@RequestBody User user){
axiosService.saveUser(user);
return "用户新增成功!!";
}
}
前端页面将对象转换为json串传递到后端服务器上,后端服务器在使用对象接收时,需要将json串转化为java对象进行使用,@ResponseBody
注解可以将对象转化为JSON串,而@RequestBody
注解可以将JSON串转化为对象。
2.5 编辑AxiosService
我们在当前后端项目下,新创建AxiosService完成后端代码;
@Service
public class AxiosServiceImpl implements AxiosService{
@Autowired
private AxiosMapper axiosMapper;
@Override
public void saveUser(User user) {
axiosMapper.saveUser(user);
}
}
2.6 编辑AxiosMapper
我们在当前后端项目下,新创建AxiosMapper完成后端代码;
public interface AxiosMapper {
@Insert("insert into demo_user(id,name,age,sex) value (null,#{name},#{age},#{sex})")
void saveUser(User user);
}
3 Ajax常见问题处理
3.1 简化Ajax前缀
我们可以通过 axios.defaults.baseURL = “http://localhost:8090”
来定义axios请求的前缀,从而简化我们在代码中的url路径信息输入:
//定义axios请求的前缀
axios.defaults.baseURL = "http://localhost:8090"
//let url1 = "/axios/saveUser"
let user1 = {name: "tomcat",age: 18, sex: "女"}
axios.post("/axios/saveUser",user1)
.then(function(promise){
console.log(promise.data)
})
3.2 关于promise对象的说明
概念: ajax发起请求之后,服务器返回信息,将返回的信息封装到了promise对象中。
引入promise对象,使得ajax调用 在交互中变得简化.
下面的截图中列举了promise对象中常用的一些封装信息:
- config:请求的网址信息,请求的方法,请求的中传递的参数;
- data:服务器返回值的结果
- status:当前请求的状态信息
3.3 Ajax "回调地狱"问题
是指Ajax 的嵌套调用问题,嵌套层级太深,不便于维护,而且容易产生死循环调用。
3.3.1 回调地狱说明
像下方的代码案例一样,我们发起Ajax 请求后,后端服务器返回了一个结果,我们接收结果后,将结果当作参数接收,再次发起请求:
分析:为了解决地狱回调问题,我们需要考虑 将ajax的2层方法,想办法封装到一层中.
3.3.2 解决回调地狱-async-await
/**
* 1.定义一个方法
* 关键字:
* 1. async 标识函数
* 2. await
*/
async function saveUser(){
let user2 = {name: "axios",age: 18, sex: "男"}
let promise = await axios.post("/axios/saveUser",user2)
console.log(promise.data)
}
//2.调用方法
saveUser()
我们首先定义一个saveUser方法,并用async 关键字标注它,方法中实现接收接收服务器返回值的结果;接收返回值结果时,使用await 关键字,其可以替代.then方法,更简便的实现返回值结果的接收。
3.3.3 简化promise对象写法
/**
* 1.定义一个方法
* 关键字:
* 1. async 标识函数
* 2. await 标识ajax请求
*/
async function saveUser(){
let user2 = {name: "axios",age: 18, sex: "男"}
//let {conf: confv,data: datav,status: statusv} = await axios.post("/axios/saveUser",user2)
let {data: result} = await axios.post("/axios/saveUser",user2)
console.log(result)
}
这里我们将返回的 promise
对象,进行指定格式的转换,转换为:{conf: confv,data: datav,status: statusv}
的key:valuse
的结构,这样的话,我们就可以直接使用 promise
对象中存储的内容,我们一般只关心其返回的状态码,所以可以简化为data: result
的结构内容,这样直接使用result
便可以得到其对象中存储的状态码的值。
4.用户CURD操作
接下来,我们使用一个比较完成的页面,来完成前后端调用的相关案例,首先我们粘贴下面的前端代码到开发工具中,在此模板基础上进行相关的开发工作:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户模块案例</title>
</head>
<body>
<div id="app">
<div alignt="center">
<h3 alignt="center">用户新增</h3><br>
<p>
用户名称: <input type="text" name="name" />
用户年龄: <input type="text" name="age" />
用户性别: <input type="text" name="sex" />
<button >新增</button>
</p>
</div>
<hr />
<div alignt="center">
<h3 alignt="center">用户修改操作</h3><br>
<p>
用户ID号: <input type="text" name="id" disabled/>
用户名称: <input type="text" name="name" />
用户年龄: <input type="text" name="age" />
用户性别: <input type="text" name="sex" />
<button >修改</button>
</p>
</div>
<h1 alignt="center">用户列表展现案例</h1>
<table alignt="center" border="1px" width="80%">
<tr alignt="center">
<td>ID编号</td>
<td>姓名</td>
<td>年龄</td>
<td>性别</td>
<td>操作</td>
</tr>
<!-- 遍历tr标签 展现数据 -->
<tr alignt="center" >
<td ></td>
<td ></td>
<td ></td>
<td ></td>
<td>
<button >修改</button>
<button >删除</button>
</td>
</tr>
</table>
</div>
<script src="../js/axios.js"></script>
<script src="../js/vue.js"></script>
<script>
</script>
</body>
</html>
4.1 实现用户列表展现
4.1.1 需求说明
要求用户访问页面的时候, 初始化的时候 就要求访问后台服务器.,发起Ajax请求. 实现用户列表页面的渲染.
解决方案: 使用mounted 函数
4.1.2 编辑页面JS
<script src="../js/axios.js"></script>
<script src="../js/vue.js"></script>
<script>
//指定公共的前缀
axios.defaults.baseURL = "http://localhost:8090"
const app = new Vue({
el: "#app",
data: {
userList: []
},
methods: {
async findUserList(){
let {data: result} = await axios.get("/axios/findUserList")
//如果需要将ajax请求与vue JS进行关联,则必须实现数据传递
this.userList = result
}
},
mounted(){
//页面初始化完成之后调用
this.findUserList()
}
})
</script>
4.1.3 编辑AxiosController
/**
* 需求: 查询所有的用户信息
* URL: /axios/findUserList
* 返回值: List<User>
*/
@GetMapping("/findUserList")
public List<User> findUserList(){
return axiosService.findUserList();
}
4.1.4 编辑AxiosService
@Override
public List<User> findUserList() {
return axiosMapper.findUserList();
}
4.1.5 编辑AxiosMapper
@Select("select * from demo_user")
List<User> findUserList();
4.1.6 页面中回显数据
<!-- 遍历tr标签 展现数据 -->
<tr align="center" v-for="user in userList">
<td v-text="user.id"></td>
<td v-text="user.name"></td>
<td v-text="user.age"></td>
<td v-text="user.sex"></td>
<td>
<button>修改</button>
<button>删除</button>
</td>
</tr>
4.1.7 页面效果展现
4.2 用户新增操作
4.2.1 双向数据绑定
规则: 看到文本框,首先想到使用双向数据绑定.
用户输入框 双向数据绑定:
- 页面名称
<div align="center">
<h3 align="center">用户新增</h3><br>
<p>
用户名称: <input type="text" name="name" v-model="addUser.name"/>
用户年龄: <input type="text" name="age" v-model="addUser.age" />
用户性别: <input type="text" name="sex" v-model="addUser.sex" />
<button @click="addUserBtn">新增</button>
</p>
</div>
- 编辑页面JS
data: {
userList: [],
//定义新增的user对象
addUser: {
id: null,
name: '',
age: '',
sex: ''
}
}
- 编辑提交函数
//实现用户数据的入库操作 this.addUser 传递封装的对象
async addUserBtn(){
let {data: result,status: status}
= await axios.post("/axios/saveUser",this.addUser)
if(status === 200){
alert(result)
//1.清空用户文本输入框
this.addUser = {}
//2.刷新用户列表
this.findUserList()
}else{
alert("用户新增失败!!!!")
}
}
后端的代码此前已经完成,直接使用即可;
4.3 用户修改操作
4.3.1 数据回显
-
在表格中按钮添加点击事件
-
定义点击事件函数
//用户修改事件
updateClick(user){
//将user对象传递给updateUser的属性
this.updateUser = user
}
- 定义页面数据双向数据绑定
<div align="center">
<h3 align="center">用户修改操作</h3><br>
<p>
用户ID号: <input type="text" name="id" v-model="updateUser.id" disabled/>
用户名称: <input type="text" name="name" v-model="updateUser.name"/>
用户年龄: <input type="text" name="age" v-model="updateUser.age"/>
用户性别: <input type="text" name="sex" v-model="updateUser.sex"/>
<button>修改</button>
</p>
</div>
4.3.2 实现用户修改操作
- 编辑修改按钮
- 编辑修改页面JS
//定义修改操作函数 数据封装之后提交
async updateUserBtn(){
let {data: result} = await axios.put("/axios/updateUser",this.updateUser)
alert(result)
this.updateUser = {}
this.findUserList()
}
4.3.3 编辑AxiosController
/**
* 用户修改操作
* URL: /axios/updateUser
* 参数: JSON串
* 返回值: String
*/
@PutMapping("/updateUser")
public String updateUser(@RequestBody User user){
axiosService.updateUser(user);
return "用户修改成功!!!";
}
4.3.4 编辑AxiosService
@Override
public void updateUser(User user) {
axiosMapper.updateUser(user);
}
4.3.5 编辑AxiosMapper
@Update("update demo_user set name=#{name},age=#{age},sex=#{sex} where id=#{id}")
void updateUser(User user);
4.4 用户删除操作
4.4.1 编辑修改按钮
<!-- 遍历tr标签 展现数据 -->
<tr align="center" v-for="user in userList">
<td v-text="user.id"></td>
<td v-text="user.name"></td>
<td v-text="user.age"></td>
<td v-text="user.sex"></td>
<td>
<button @click="updateClick(user)">修改</button>
<button @click="deleteUser(user)">删除</button>
</td>
</tr>
4.4.2 实现用户删除操作
async deleteUser(user){
//根据主键删除
//await axios.delete("/axios/deleteUser",{params: {id: user.id}});
let {data: result} = await axios.delete("/axios/deleteUser?id="+user.id);
alert(result)
//重新查询列表数据
this.findUserList()
}
},
4.4.3 编辑AxiosService
@Override
public void deleteUserById(Integer id) {
axiosMapper.deleteUserById(id);
}
4.4.4 编辑AxiosController
@DeleteMapping("deleteUser") //delete / get
public String deleteUser(Integer id){
axiosService.deleteUserById(id);
return "用户删除成功!!!";
}
4.4.5 编辑AxiosMapper
@Delete("delete from demo_user where id = #{id}")
void deleteUserById(Integer id);
5.完整代码展示
5.1 前端完整代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>用户列表展现案例</title>
</head>
<body>
<div id="app">
<div align="center">
<h3 align="center">用户新增</h3><br>
<p>
用户名称: <input type="text" name="name" v-model="addUser.name"/>
用户年龄: <input type="text" name="age" v-model="addUser.age" />
用户性别: <input type="text" name="sex" v-model="addUser.sex" />
<button @click="addUserBtn">新增</button>
</p>
</div>
<hr />
<div align="center">
<h3 align="center">用户修改操作</h3><br>
<p>
用户ID号: <input type="text" name="id" v-model="updateUser.id" disabled/>
用户名称: <input type="text" name="name" v-model="updateUser.name"/>
用户年龄: <input type="text" name="age" v-model="updateUser.age"/>
用户性别: <input type="text" name="sex" v-model="updateUser.sex"/>
<button @click="updateUserBtn">修改</button>
</p>
</div>
<h1 align="center">用户列表展现案例</h1>
<table align="center" border="1px" width="80%">
<tr align="center">
<td>ID编号</td>
<td>姓名</td>
<td>年龄</td>
<td>性别</td>
<td>操作</td>
</tr>
<!-- 遍历tr标签 展现数据 -->
<tr align="center" v-for="user in userList">
<td v-text="user.id"></td>
<td v-text="user.name"></td>
<td v-text="user.age"></td>
<td v-text="user.sex"></td>
<td>
<button @click="updateClick(user)">修改</button>
<button @click="deleteUser(user)">删除</button>
</td>
</tr>
</table>
</div>
<script src="../js/axios.js"></script>
<script src="../js/vue.js"></script>
<script>
//指定公共的前缀
axios.defaults.baseURL = "http://localhost:8090"
const app = new Vue({
el: "#app",
data: {
userList: [],
//定义新增的user对象
addUser: {
id: null,
name: '',
age: '',
sex: ''
},
updateUser: {
id: '',
name: '',
age: '',
sex: ''
}
},
methods: {
async findUserList(){
let {data: result} = await axios.get("/axios/findUserList")
//如果需要将ajax请求与vue JS进行关联,则必须实现数据传递
this.userList = result
},
//实现用户数据的入库操作 this.addUser 传递封装的对象
async addUserBtn(){
let {data: result,status: status}
= await axios.post("/axios/saveUser",this.addUser)
if(status === 200){
alert(result)
//1.清空用户文本输入框
this.addUser = {}
//2.刷新用户列表
this.findUserList()
}else{
alert("用户新增失败!!!!")
}
},
//用户修改事件
updateClick(user){
//将user对象传递给updateUser的属性
this.updateUser = user
},
//定义修改操作函数 数据封装之后提交
async updateUserBtn(){
let {data: result} = await axios.put("/axios/updateUser",this.updateUser)
alert(result)
this.updateUser = {}
this.findUserList()
},
//用户删除事件
async deleteUser(user){
//根据主键删除
//await axios.delete("/axios/deleteUser",{params: {id: user.id}});
let {data: result} = await axios.delete("/axios/deleteUser?id="+user.id);
alert(result)
//重新查询列表数据
this.findUserList()
}
},
mounted(){
//页面初始化完成之后调用
this.findUserList()
}
})
</script>
</body>
</html>
5.2 后端完整代码展示
5.2.1 AxiosController
package com.jt.controller;
import com.jt.pojo.User;
import com.jt.service.AxiosService;
import com.jt.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@CrossOrigin
@RequestMapping("/axios") //抽取前缀
public class AxiosController {
@Autowired
private AxiosService axiosService;
/**
* 实现用户入库操作
* url地址: http://localhost:8090/axios/saveUser
* 参数: JSON串 {"name":"tomcat","age":18,"sex":"女"}
* 返回值: 成功消息
* 难点: 前端传递的是JSON,后端不可以直接使用User对象接收.
* 解决方案:
* 1.对象可以转化为JSON串 @ResponseBody
* 2.JSON串转化为对象 @RequestBody
*/
@PostMapping("/saveUser")
public String saveUser(@RequestBody User user){
axiosService.saveUser(user);
return "用户新增成功!!";
}
/**
* 需求: 查询所有的用户信息
* URL: /axios/findUserList
* 返回值: List<User>
*/
@GetMapping("/findUserList")
public List<User> findUserList(){
return axiosService.findUserList();
}
/*
*用户修改操作
* url:/axios/updateUser
* 参数:json串
* 返回值:String
*/
@PutMapping("/updateUser")
public String updateUser(@RequestBody User user){
axiosService.updateUser(user);
return "用户修改成功";
}
/*
*用户删除操作
* url:/axios/deleteUser
* 参数:
* 返回值:
*/
@DeleteMapping("deleteUser")
public String deleteUser(Integer id){
axiosService.deleteUserById(id);
return "用户删除成功!!!";
}
}
5.2.2 AxiosService
package com.jt.service;
import com.jt.pojo.User;
import java.util.List;
public interface AxiosService {
//url地址:http://localhost:8090/axios/saveUser
void saveUser(User user);
//查找
List<User> findUserList();
//修改
void updateUser(User user);
//删除
void deleteUserById(Integer id);
}
package com.jt.service;
import com.jt.mapper.AxiosMapper;
import com.jt.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
class AxiosServiceImpl implements AxiosService{
@Autowired
private AxiosMapper axiosMapper;
@Override
public void saveUser(User user) {
axiosMapper.saveUser(user);
}
@Override
public List<User> findUserList() {
return axiosMapper.findUserList();
}
@Override
public void updateUser(User user) {
axiosMapper.updateUser(user);
}
@Override
public void deleteUserById(Integer id) {
axiosMapper.deleteUserById(id);
}
}
5.2.3 AxiosMapper
package com.jt.mapper;
import com.jt.pojo.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface AxiosMapper {
@Insert("insert into demo_user(id,name,age,sex) value (null,#{name},#{age},#{sex})")
void saveUser(User user);
@Select("select * from demo_user")
List<User> findUserList();
@Update("update demo_user set name=#{name},age=#{age},sex=#{sex} where id = #{id}")
void updateUser(User user);
@Delete("delete from demo_user where id = #{id}")
void deleteUserById(Integer id);
}
5.2.4 application
#配置端口号
server:
port: 8090
servlet:
context-path: /
#管理数据源
spring:
datasource:
#低版本驱动需要使用com.mysql.jdbc.Driver
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/jt?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
username: root
password: root
#springboot整合mybatis
mybatis:
#指定别名包
type-aliases-package: com.jt.pojo
#扫描指定路径下的映射文件
mapper-locations: classpath:/mybatis/mappers/*.xml
#开启驼峰映射
configuration:
map-underscore-to-camel-case: true
# 一二级缓存默认开始 所以可以简化
#打印mysql日志
logging:
level:
com.jt.mapper: debug