2.8.3 基于AJAX实现用户的CRUD操作



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 双向数据绑定

规则: 看到文本框,首先想到使用双向数据绑定.
用户输入框 双向数据绑定:

  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>

  1. 编辑页面JS
data: {
	userList: [],
	//定义新增的user对象
	addUser: {
		id: null,
		name: '',
		age: '',
		sex: ''
	}
}

  1. 编辑提交函数
//实现用户数据的入库操作  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 数据回显

  1. 在表格中按钮添加点击事件请添加图片描述

  2. 定义点击事件函数

	//用户修改事件
	updateClick(user){
		//将user对象传递给updateUser的属性
		this.updateUser = user
	}

  1. 定义页面数据双向数据绑定
<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 实现用户修改操作

  1. 编辑修改按钮

请添加图片描述

  1. 编辑修改页面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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值