前言
在早期的浏览器中,由于浏览器向服务器端请求数据时,服务器响应数据都是跳转到一个新的页面,而不是在原有页面上的刷新,因此对于用户来说这种操作不是很友好.同时,诸如注册用户以及用户登录等操作,我们只是让页面显示一行文字"注册成功","登录成功"修改页面的部分内容,但却要刷新整个页面,非常消耗网络资源.因此,异步请求则应运而生.
AJAX(Asynchronous JavaScript and XML):异步网络请求.AJAX能够让页面局部刷新的请求数据.实现AJAX的方法有:
- jQuery封装的AJAX(jQuery的ajax相对于原生的ajax更加方便使用,但是也没必要用到ajax异步请求时引入jQuery框架)
- 原生的XML HttpRequest (PS:原生的XML HttpRequest的配置和调用方式都很繁琐,实现异步请求很麻烦)
- axios.
1.AXIOS异步请求
axios,可以理解为ajax i/o system,这不是一种新技术,本质上还是对原生XMLHttpRequest的封装,可用于浏览器和nodejs的HTTP客户端,只不过它是基于Promise的,符合最新的ES规范。具备以下特点:
- 在浏览器中创建XML HttpRequest请求
- 在node.js中发送http请求
- 支持PromiseAPI
- 拦截请求和响应
- 转换请求和响应数据
- 取消要求
- 自动转换JSON数据
- 客户端支持防止CSRF/XSRF(跨域请求伪造)
2.前后端分离
- 为什么使用前后端分离?为什么以后不再使用同步请求?
如果不使用前后端分离的设计方式, 服务器开发人员需要准备两套Controller,分别应对浏览器客户端 和手机客户端, 因为浏览器客户端需要的内容是页面+数据, 而手机客户端只需要数据, 这样Java程序员需要准备一个Controller提供页面+数据,再准备一个Controller只提供数据, 这样的话同样的工作相当于做了两遍,比较影响开发效率,使用前后端分离后, 在Controller中不再写页面相关内容, 不管前端是浏览器还是手机 都只提供数据, 浏览器需要的页面必须咋请求数据之前先发一次请求获得一个静态页面,然后在页面中发出异步请求获取到数据, 把数据展示到页面中(这个过程称为页面的局部刷新), 只有通过异步请求才能实现局部刷新, 这样的话 如果考虑实现前后端分离, 则只能使用异步请求, 因为同步请求不能实现页面的局部刷新.
3.JSON
- 轻量级的数据交换格式(数据封装格式)
- 客户端和服务器之间进行复杂的数据交换时, 如果每次数据传输都自己定义传输数据的格式的话,太繁琐影响开发效率, JSON是一种通用的数据交换格式,使用JSON可以大大提高开发效率.
4.用户注册登录(异步请求版本)
- 前端页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<h1>注册页面</h1>
<input type="text" placeholder="用户名" v-model="user.username">
<input type="text" placeholder="密码" v-model="user.password">
<input type="text" placeholder="昵称" v-model="user.nickname">
<input type="button" value="注册" @click="reg()">
</div>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js "></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<script>
let v = new Vue({
el:"body>div",
data:{
user:{username:"",password:"",nickname:""},
info:""
},
methods:{
reg(){
//发出异步请求
//发出post请求:1.有敏感信息2.参数比较多需要封装到对象里面传输
axios.post("/reg",v.user).then(function (response) {
//alert(response.data);
if(response.data ==1){
alert("注册成功!返回首页");
location.href="/";
}else{//用户名已存在
alert("用户名已存在!");
}
})
}
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<h1>用户登录</h1>
<input type="text" placeholder="用户名" name="username" v-model="user.username">
<input type="password" placeholder="密码" name="password" v-model="user.password">
<input type="button" value="登录" @click="login()">
</div>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js "></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<script>
let v = new Vue({
el:"body>div",
data:{
user:{username:"",password:""},
info:""
},
methods:{
login(){
axios.post("/login",v.user).then(function (response) {
switch (response.data){
case 1:
alert("登录成功!,返回首页");
location.href="/";
break;
case 2:
alert("登录失败!,用户名不存在!");
break;
case 3:
alert("登录失败!,密码错误");
}
})
}
}
})
</script>
</body>
</html>
- 后端页面
package cn.tedu.boot07.controller;
import cn.tedu.boot07.entity.User;
import cn.tedu.boot07.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@Autowired
UserMapper mapper;
@RequestMapping("/reg")
public int reg(@RequestBody User user){
User u = mapper.selectByUsername(user.getUsername());
if(u != null){
return 2;
}
mapper.insert(user);
//请求返回数据1或2,相比于返回字符串,数据量更小,在用户访问量很大时,消耗的网络资源相对于字符串更少
return 1;
}
@RequestMapping("/login")
public int login(@RequestBody User user){
System.out.println("user = " + user);
User u = mapper.selectByUsername(user.getUsername());
if(u !=null){
if(u.getPassword().equals(user.getPassword())){
return 1;
}
return 3;
}
return 2;
}
}
5.商品管理系统(异步请求版本)
- 前端页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<h1>添加商品</h1>
<input type="text" placeholder="商品标题" v-model="product.title">
<input type="text" placeholder="商品价格" v-model="product.price">
<input type="text" placeholder="商品库存" v-model="product.num">
<input type="button" value="添加" @click="insert()">
</div>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js "></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<script>
let v = new Vue({
el:"body>div",
data:{
product:{title:"",price:"",num:""}
},
methods:{
insert(){
axios.post("/insert",v.product).then(function (response) {
alert("商品添加成功!返回首页")
location.href="/";
})
}
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<table border="1">
<caption>商品列表</caption>
<tr>
<th>id</th>
<th>标题</th>
<th>价格</th>
<th>库存</th>
<th>操作</th>
</tr>
<tr v-for="p in arr">
<td>{{p.id}}</td>
<td>{{p.title}}</td>
<td>{{p.price}}</td>
<td>{{p.num}}</td>
<!--废掉超链接跳转功能-->
<!--看点完超链接是否离开该页面 若是离开需要属性绑定 否则不需要则使用@click-->
<td><a :href="'/update.html?id='+p.id">修改</a>
<a href="javascript:void(0)" @click="del(p.id)">删除</a></td>
</tr>
</table>
</div>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js "></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<script>
let v = new Vue({
el: "body>div",
data: {
arr: []
},
methods: {
del(id) {//delete为关键字不能用作方法名
if (confirm("您确定删除此商品么?")) {
//发出异步get请求,如果传递一个参数并且不是敏感信息 使用get
axios.get("/delete?id=" + id).then(function (response) {
alert("删除完成!");
//刷新页面
location.reload();
})
}
}
},
created: function () {
//created在创建Vue对象,即初始化过程中执行的方法,一般Vue管理的范围
//需要进入页面的同时发请求获取数据时,获取数据的代码写在此处
axios.get("/select").then(function (response) {
//把查询到的商品数据 赋值给数组,页面会自动显示出商品信息
//当axios框架发现服务器响应的是JSON格式字符串时,会自动
//将字符串转成数组或js对象
v.arr = response.data;
})
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<h1>修改商品页面</h1>
<input type="text" placeholder="商品id" v-model="p.id" readonly>
<input type="text" placeholder="商品标题" v-model="p.title">
<input type="text" placeholder="商品价格" v-model="p.price">
<input type="text" placeholder="商品库存" v-model="p.num">
<input type="button" value="修改" @click="update()">
</div>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js "></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<script>
let v = new Vue({
el: "body>div",
data: {
p:{id:"",title:"",price:"",num:""}
},
methods: {
update(){
axios.post("/update",v.p).then(function (response) {
alert("修改成功!");
location.href="/list.html";
})
}
},
created:function () {
//进入页面就要发请求的代码写在此处
// /selectById?id=5
//location.search= ?id=5
//通过修改商品的id查询商品的详细信息
axios.get("/selectById"+location.search).then(function (response) {
//服务器返回的是装着商品详细信息的JSON字符串,axios框架会自动
//将JSON字符串转成js对象
v.p = response.data;
})
}
})
</script>
</body>
</html>
- 后端页面
package cn.tedu.boot08.controller;
import cn.tedu.boot08.entity.Product;
import cn.tedu.boot08.mapper.ProductMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class ProductController {
@Autowired
ProductMapper mapper;
@RequestMapping("/insert")
public void insert(@RequestBody Product p){
System.out.println("p = " + p);
mapper.insert(p);
}
@RequestMapping("/select")
public List<Product> select(){
List<Product> list = mapper.select();
//把装着Product对象的list集合直接响应给客户端
//当返回值为List集合或自定义对象时,SpringMVC框架会自动
//将集合或对象转成JSON格式的字符串再进行网络传输
return list;
}
@RequestMapping("/delete")
public void delete( int id){
mapper.delete(id);
}
@RequestMapping("/selectById")
public Product selectById(int id){
//通过id查询商品的所有信息
//SpringMVC框架发现返回值为自定义对象的时候会自动
//将对象转成JSON格式字符串后再进行传输
return mapper.selectById(id);
}
@RequestMapping("/update")
public void update(@RequestBody Product product){
mapper.update(product);
}
}
昨天练习时,在JavaScript中delete是不能用作方法名和变量名的,因为delete的关键字,而在JavaScript中的关键字有:
break、case、catch、continue、default、 delete、do、else、finally、for、 function、if、in、instanceof、new、 return、switch、this、throw、try、 typeof、var、void、while、 with.
而在JavaScript中,还有保留字也就是预留的关键字,指的是现在还不是关键字,之后可能会变成关键字的,同样也是不能用作方法名和变量名,JavaScript中的保留字有:
abstract、boolean、byte、char、class、 const、debugger、double、enum、export、 extends、fimal、float、goto、implements、 import、int、interface、long、mative、 package、private、protected、public、 short、static、super、synchronized、 throws、transient、volatile