前端的快速发展导致现在的开发模式发生改变。前后台分离开发在开发中应用日趋广泛。那么如何能够让前后端程序员能够更好的配合,数据交互方式是我们必须要掌握的内容。本案例使用springboot作为后端开发环境,前端分别使用form,jquery.ajax ,axios来完成与后端的数据交互。
1. http协议
在浏览器上进行的数据交互实际上应用的http协议。具体的大家可以参照文档:https://developer.mozilla.org...
2. 同步数据交互
我们先从同步数据交互开始说起,这种方式会导致表单的完全提交,页面的整体刷新。form元素中的action表示后台处理接口,method表示提交方式,浏览器支持的的方式get,post。当然协议中还规定了一些其他的提交方式,比如head,put,但是需要通过post方式进行模拟才可应用,这里不做过多讲解。enctype表示表单数据的编码方式,其取值有三种,分别为'application/x-www-form-urlencoded','multipart/form-data','text/plain',默认方式为application/x-www-form-urlencoded。
- application/x-www-form-urlencoded
将表单数据编码为 key1=val1@key2=val2,如果值为非字符数字的其他格式将会被使用百分数进行编码,所以这种方式不适用于表单数据中有二进制文件的表单
- multipart/form-data
主要用于表单数据中有二进制文件的表单也就是有附件上传的提交
- text/plain
不对表单数据进行编码
下面是一段前端代码。注意input必须要包含name属性,否则无法为协议数据提供key。另,如果input可以为用户提供直接输入的区域,如单行文本输入框<input type="text">那么就不用为其提供value,如果提供了value,这个value值将是默认值。如果input不可以为用户提供直接输入的区域,而是通过点击来选择,如下拉菜单,单选按钮,复选按钮,那么必须为input元素提供value值。
<form action="http://localhost:8888/users/saveOrUpdate" method="POST" enctype="application/x-www-form-urlencoded">
<table>
<tbody>
<tr>
<td>姓名</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密码</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td>性别</td>
<td>
<label for="gender_male">
<input type="radio" name="gender" id="gender_male">男
</label>
<label for="gender_female">
<input type="radio" name="gender" id="gender_female">女
</label>
</td>
</tr>
<tr>
<td colspan="2" align="right">
<input type="submit" value="保存">
</td>
</tr>
</tbody>
</table>
</form>
下面是相对应的后台代码,由于使用的是springboot,该controller默认返回的json格式数据:
/**
* 保存或修改用户信息
* */
@PostMapping(value="/saveOrUpdate",consumes= "application/x-www-form-urlencoded")
public User saveOrUpdate(@ModelAttribute User user) {
if(user.getId()!=null) {
//修改操作
} else {
//保存操作
}
return user;
}
这样即可完成数据的同步交互,数据交互完成后页面全局刷新,会将springmvc返回的user信息显示到浏览器页面中。
。
另外一种情况也比较常见,批量数据删除的时候,我们需要向后台传递多个id值。前端代码如下,注意,由于是一个类型的值,所有三个input的name值是一样的。
<form action="http://localhost:8888/users/batchDelete" method="post" enctype="application/x-www-form-urlencoded">
<table>
<tr>
<td><input type="checkbox" value="1001" name="ids"></td>
<td>张三</td>
</tr>
<tr>
<td><input type="checkbox" value="1002" name="ids"></td>
<td>李四</td>
</tr>
<tr>
<td><input type="checkbox" value="1003" name="ids"></td>
<td>王五</td>
</tr>
<tr>
<td colspan="2" align="right">
<input type="submit" value="确认删除">
</td>
</tr>
</table>
</form>
后台代码如下:
/**
* 批量删除用户信息
* */
@PostMapping(value="/batchDelete",consumes= "application/x-www-form-urlencoded")
public String batchDelete(Long[] ids) {
if(ids!=null){
for(Long id : ids) {
System.out.println(id);
}
}
return "删除成功";
}
实际上值被编码为 【ids=1001&ids=1002】
3. 数据的异步提交
前后台分离的开发模式中,数据异步提交更多一些。
3.1 jQuery提供的ajax API
使用jquery的ajax技术完成与后台之间的数据交互
下面是前端代码
$(function(){
//1. 为表单绑定提交事件,当点击提交按钮进行表单提交的时候触发
$('#userForm').on('submit',function(){
//3. 获取表单数据
var username = $('input[name=username]').val();
var password = $('input[name=password]').val();
var gender = $('input[name=gender]').val();
//4. 异步提交
$.post('http://localhost:8888/users/saveOrUpdate',{
username:username,
password:password,
gender:gender
},function(){
alert('保存成功!');
})
//2. 使用return false阻止表单的默认行为
return false;
});
});
目前后台还没做什么改变,我们打开页面,输入表单信息,单击提交。出现了跨域异常。但是如果查看请求信息,发现请求是已经发出去了,并且jquery中的post函数对我们的数据进行了编码,并且是按照表单数据格式(POST默认提交编码格式application/x-www-form-urlencoded)进行编码。
接下来我们就解决后台跨域的问题。其实很简单,只需要为当前类或者当前函数添加@CrossOrigin注解即可。其余代码不变。
/**
* 保存或修改用户信息
* */
@CrossOrigin
@ApiOperation(value="保存或修改用户信息",
response=User.class)
//@PostMapping(value="/saveOrUpdate",consumes= "application/x-www-form-urlencoded")
@PostMapping(value="/saveOrUpdate",consumes= "application/x-www-form-urlencoded")
public User saveOrUpdate(@ModelAttribute User user) {
if(user.getId()!=null) {
//修改操作
} else {
//保存操作
}
return user;
}
我们在这里分析一下,如果使用jquery,默认ajax函数会将参数按照application/x-www-form-urlencoded进行编码。这是为什么呢?
那么我们如何发送一个json格式的数据呢(到底发送什么格式的数据需要前后台开发者商定好,为了满足需求,我们尽量学会每种格式都会用)以下部分是前端代码:
// 1. 调用底层的ajax函数
$.ajax('http://localhost:8888/users/saveOrUpdate',{
method:'POST',
// 2. 手动对要发送的数据进行JSON格式的序列化
data:JSON.stringify({
username:username,
password:password,
gender:gender
}),
// 3. 指定参数类型为 json格式,但是注意,并不是说我指定了浏览器就会帮我们将数据转换为json,而是需要向第二步一样,我们自己对数据进行转化
contentType:'application/json',
success:function(){
alert('success');
}
});
由于数据格式已经发生变化,所以后台代码也要跟着发生变化。如下
@PostMapping(value="/saveOrUpdate",consumes= "application/json")
public User saveOrUpdate(@RequestBody User user) {
if(user.getId()!=null) {
//修改操作
} else {
//保存操作
}
return user;
}
测试发现传递的值为json格式,并且后台可以获取值。
但是要注意,由于发送的数据格式为application/json,所以浏览器向后台发送了两个请求,一个OPTION类型的,一个POST类型的,后者才是真正的请求。
好,继续往下讨论,如果是提交一个数组的话应该如何实现,这种需求在开发中也很常见。
前端代码如下
<form id="deleteForm" >
<table>
<tr>
<td><input type="checkbox" value="1001" name="ids"></td>
<td>张三</td>
</tr>
<tr>
<td><input type="checkbox" value="1002" name="ids"></td>
<td>李四</td>
</tr>
<tr>
<td><input type="checkbox" value="1003" name="ids"></td>
<td>王五</td>
</tr>
<tr>
<td colspan="2" align="right">
<input type="submit" value="确认删除">
</td>
</tr>
</table>
</form>
//1. 绑定事件
$('#deleteForm').on('submit',function(){
//2. 获取要删除元素的ID,以数组的方式进行保存,例如 [1001,1002]
var ids = $('#deleteForm input[name=ids]:checked').map(function(index,item){
return $(item).val();
}).toArray();
//3. 通过删除
$.post('http://localhost:8888/users/batchDelete',{ids:ids},function(data){
console.log(data);
alert('success');
});
return false;
});
后台保持不变
/**
* 批量删除用户信息
* */
@ApiOperation(value="批量删除用户信息",
response=String.class)
@PostMapping("/batchDelete")
public String batchDelete(Long[] ids) {
if(ids!=null){
for(Long id : ids) {
System.out.println(id);
}
} else {
System.out.println("ids:"+ids);
}
return "删除成功";
}
但是尝试之后发现代码没有报错,但是后台无法获取值
这是因为ids为一个数组,ajax会对数组进行编码,为原先的key添加了中括号,成为了ids[],但是后台却是用ids作为参数来接受,这时肯定无法获取。
查看jquery文档我们发现可以通过设定traditional来阻止上述行为
注意!这种方式是要慎用,因为traditional一旦设置为true,jquery将不会采用递归的方式序列化数据,这时如果我们传递数组中嵌入对象的这种数据将会出问题。这里还有其他更好的方式
- 修改后台接受参数的方式
设置注解@RequestParam(value="ids[]"),表明要接受的参数的key就是'ids[]'
/**
* 批量删除用户信息
* */
@ApiOperation(value="批量删除用户信息",
response=String.class)
@PostMapping("/batchDelete")
public String batchDelete(@RequestParam(value="ids[]") Long[] ids) {
if(ids!=null){
for(Long id : ids) {
System.out.println(id);
}
} else {
System.out.println("ids:"+ids);
}
return "删除成功";
}
- 通过json来获取数据
在前端中声明参数类型为json,并且使用JSON.stringify()进行编码
//1. 绑定事件
$('#deleteForm').on('submit',function(){
//2. 获取要删除元素的ID,以数组的方式进行保存,例如 [1001,1002]
var ids = $('#deleteForm input[name=ids]:checked').map(function(index,item){
return $(item).val();
}).toArray();
//3. 通过删除
//$.ajaxSettings.traditional = true;
$.ajaxSetup({
contentType:'application/json'
})
$.post('http://localhost:8888/users/batchDelete',JSON.stringify(ids),function(data){
console.log(data);
alert('success');
});
return false;
});
在后台代码中使用@requestBody来接受JSON格式参数
/**
* 批量删除用户信息
* */
@ApiOperation(value="批量删除用户信息",
response=String.class)
@PostMapping("/batchDelete")
public String batchDelete(@RequestBody Long[] ids) {
if(ids!=null){
for(Long id : ids) {
System.out.println(id);
}
} else {
System.out.println("ids:"+ids);
}
return "删除成功";
}
还有一种比较复杂的情况,当传递的数据是数组包含对象的话应该如何处理,数据格式如下:
[{id:1001,name:'terry'},{id:1002,name:'larry'}]
这里建议使用json来传递数据,前端代码如下:
<form id="batchSaveForm" >
<table>
<tr>
<td>username:<input type="text" name="username"></td>
<td>realname:<input type="text" name="realname"></td>
</tr>
<tr>
<td>username:<input type="text" name="username"></td>
<td>realname:<input type="text" name="realname"></td>
</tr>
<tr>
<td>username:<input type="text" name="username"></td>
<td>realname:<input type="text" name="realname"></td>
</tr>
<tr>
<td colspan="2" align="right">
<input type="submit" value="确认保存">
</td>
</tr>
</table>
</form>
// 批量保存数据
$('#batchSaveForm').on('submit',function(){
var uns = $('#batchSaveForm :input[name=username]');
var urs = $('#batchSaveForm :input[name=realname]');
var arr = [];
uns.each(function(index,item){
var obj = {};
obj.username = $(item).val();
arr.push(obj);
});
urs.each(function(index,item){
arr[index].realname = $(item).val();
});
$.ajaxSetup({
contentType:'application/json'
})
$.post('http://localhost:8888/users/batchSave',JSON.stringify(arr),function(){
alert('success');
});
return false;
});
后台代码如下:
/**
* 保存多个用户信息
* */
@ApiOperation(value="保存或修改用户信息",
response=List.class)
@PostMapping(value="/batchSave")
public User[] batchSave(@RequestBody User[] users) {
if(users!=null) {
for(User u : users) {
System.out.println(u);
}
}else {
System.out.println("null...");
}
return users;
}
3.2 axios的异步数据交互
axios相对比jquery来说,它是一个更加纯粹的ajax框架,并且是基于promise机制的,使用axios需要注意是axios默认会将数据转换为JSON格式进行提交,而jquery默认是表单数据格式。如果想要改变需要设置headers属性。
异步提交对象前端代码:
$('#userForm').on('submit',function(){
//3. 获取表单数据
var username = $('input[name=username]').val();
var password = $('input[name=password]').val();
var gender = $('input[name=gender]').val();
//4. 异步提交
axios.post('http://localhost:8888/users/saveOrUpdate',{
username:username,
password:password,
gender:gender
}).then(function(){
alert('保存成功!');
});
//2. 使用return false阻止表单的默认行为
return false;
});
后台代码注意接收的是JSON格式的数据
@ApiOperation(value="保存或修改用户信息",
response=User.class)
@PostMapping(value="/saveOrUpdate",consumes= "application/json")
public User saveOrUpdate(@RequestBody User user) {
if(user.getId()!=null) {
//修改操作
} else {
//保存操作
}
return user;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。