目录
四、Accept:application/json与Content-Type:application/json
2.Content-Type:application/json
一、restful与传统的接口的区别
首先需要了解的是,restful与传统的接口设计有什么不同,它又有什么好处。
1.传统的接口设计思路:
1.请求路径: 见名知意
2.请求方式: 传统模式会忽略 @RequestMapping
3.请求参数: 由需求决定
4.请求响应: 模板路径/由需求决定
2.Restful风格接口设计思路:
1.请求路径:由当前接口操作的资源来确定 一个使用资源复数作为路径,比如:/employees
2.请求方式: 根据接口对资源操作决定 增:post 删:delete 改:put 查 get
3.请求参数:由需求决定
4.请求响应:由需求和公司规范决定,一般建议响应数据格式是json格式
Restful 这是一种设计风格,而不是标准,只是提供了一组设计原则和约束条件,具体的操作还是要结合公司和项目的要求。
二、Restful 几种请求响应
get/collection:返回资源对象的列表(数组)
get/collection/resource 返回单个资源对象
post/collection/resource 返回新生成的资源对象
put/collection/resource 返回完整的资源对象
patch/collection/resource 返回完整的资源对象
delete/colllection/resource 返回一个空文档
举个例子来讲,以前传统的请求接口的方式:
http://www.langfeives.cn.employee/list
http://www.langfeives.cn.employee/get?id=1
http://www.langfeives.cn.employee/save?name=xx
http://www.langfeives.cn.employee/update?id=1&name=xx
http://www.langfeives.cn.employee/delete?id=1
而Restful方式:
http://www.langfeives.cn.employees 路径都是一样的,只不过采取的方法不一样
新增:post
更新:put
删除:delete
查询:get
三、HTTP响应状态码
200 表示请求成功
400 用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的
所谓幂等就是 不管进行多少次重复操作,都是实现相同的结果
401 表示用户没有权限 (令牌、用户名、密码错误)
403 表明用户得到权限(和401相对),但是访问是被禁止的
404 NOT FOUND 用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的
500 服务器发生错误,用户将无法判断发出的请求是否成功
资源的表现形式
什么是幂等?
简单来讲就是不管进行多少次重复操作,都是实现相同的结果。
四、Accept:application/json与Content-Type:application/json
Accept:application/json
代表客户端希望接受的数据类型 只能是发请求的时候用的。
Content-Type:application/json
代表客户端/服务器 携带的数据的类型。
五、实例演示(代码)
实体类:
@Data
public class Employee{
private Long id;
private String name;
private int age;
}
控制层:
public class EmployeeController{
@RequestMapping("/hello")
@ResponseBody
public String hello(){
return "ok"
}
}
获取,新增,更新,删除员工信息:
/* 请求路径---确定资源---employees
请求方法--查询--get
请求参数 --过滤条件--无
请求响应---所有员工 List<Employee>----json
*/
@RequestMapping(value ="/employees",method = RequestMethod.GET)
@ResponseBody
public List<Employee> list(){
//查询mysql数据库,得到员工列表信息
//假装查询数据库得到list集合
List<Employee> list = Arrays.asList(new Employee(1,"zhangsan",18),new Employee(2,"lisi",18))
return list;
}
新增一个员工:
/*请求路径---确定资源---employees
请求方法--添加--post
请求参数 --员工相关属性--name,age
请求响应--- 新增员工对象--Employee----json
*/
@RequestMapping(value ="/employees",method = RequestMethod.POST)
@ResponseBody
public Employee save(Employee employee){
//查询mysql数据库,得到员工列表信息
//假装添加数据成功,返回自动增长的id值
employee.setId(1);
return employee;
}
更新一个员工
/*请求路径---确定资源---employees
请求方法--更新--put
请求参数 --员工相关属性--id,name,age
请求响应--- 新增员工对象--Employee----json
*/
@RequestMapping(value ="/employees",method = RequestMethod.PUT)
@ResponseBody
public Employee update(Employee employee){
employee.setName(employee.getName()+"_update");
return employee;
}
删除一个员工
/*请求路径---确定资源---employees
请求方法--删除--delete
请求参数 --员工相关属性--id
请求响应---删除之后的状态--JsonResult----json
JsonResult: 统一的响应返回值;
*/
@RequestMapping(value ="/employees",method = RequestMethod.DELETE)
@ResponseBody
public JsonResult update(Employee employee){
//假装删除成功
return JsonResult.success;
}
JsonResult类:
@Setter
@Getter
public class JsonResult{
private int code; //请求操作完之后返回的状态码,操作成功200,操作失败500,没有登录403
private String msg; //请求操作之后返回信息
private Object data; //请求的响应数据
public JsonResult(int code,String msg,Object data){
this.code = code;
this.msg = msg;
this.data = data;
}
public static JsonResult error(String msg){
return new JsonResult(500,msg,null);
}
public static JsonResult error(String msg,Object data){
return new JsonResult(500,msg,data);
}
public static JsonResult success(String msg){
return new JsonResult(500,"操作成功",null);
}
public static JsonResult success(String msg,Object data){
return new JsonResult(500,"操作成功",data);
}
}
如果查询某个员工的信息,那么按照上述思路应该是:
/*请求路径---确定资源---employees
请求方法--查询--get
请求参数 --id
请求响应---某一个员工--Employee----json
*/
@RequestMapping(value ="/employees",method = RequestMethod.GET)
@ResponseBody
public Employee detail(Long id){
return new Employee(id,"zhangsan",18);
}
}
但是这样的话,无论是映射路径上还是请求方法上都和查询所有员工的接口完全相同,springmvc会认为是同一个接口,从而报错,既然不能同时存在,那应该如何解决这一问题呢?
有如下两种方法;
1.使用多级路径方法 比如:/employees/details
2.使用参数路径方式 比如:/employees/{id} 将请求参数作为路径的一部分 进行url区分
参数路径:/employees/{id} ,其中{id} 参数占位符
客户端访问: http://localhost:80/employees/1 1就是id参数值
注意点:
接口要获取参数路径中参数必须使用@PathVarible,目的是让springmvc 是参数解析器从路径中解析出参数并进行复制
如果参数路径中的占位符名称与请求映射方法形式参数名称不一致时,必须明确指定映射
如: /employees/{eid} -------->@PathVarible("eid") long id
如果参数路径中包含很多个参数时,可以按下面这种写法:
@RequestMapping(value = "/employees/{id}{name}/{age}",method = RequestMethod.GET)
@RequsetBody
public Employee info(@PathVarible Long id,@PathVarible String name,@PathVarible int age){
return new Employee (id,name,age)
}
但是采用这种写法,就这么看着就已经很麻烦了,如果是十几个参数难道要一个一个解析么,答案肯定不是这样的,我们可以直接封装在对象当中,这样也是能够取到的:
@RequestMapping(value = "/employees/{id}{name}/{age}",method = RequestMethod.GET)
@RequsetBody
public Employee info(Employee employee){
return employee;
}
接下来对比一下这些的url有什么不同:
对应的url: http://localhost:80/employees?id=1&name=zhangsan
@RequestMapping(value = "/employees",method = RequestMethod.GET)
@RequsetBody
public Employee detail(Long id,String name){
return new Employee(id,name,18);
}
对应的url: http://localhost:80/employees/1?name=zhangsan
@RequestMapping(value = "/employees{id}",method = RequestMethod.GET)
@RequsetBody
public Employee detail(@PathVarible Long id,String name){
return new Employee(id,name,18);
}
对应的url: http://localhost:80/employees/1/zhangsan
@RequestMapping(value = "/employees/{id}/{name}",method = RequestMethod.GET)
@RequsetBody
public Employee detail(@PathVarible Long id,@PathVarible String name){
return new Employee(id,name,18);
}
六、url 组成部分:
协议://ip:端口/路径?参数1=参数1值&参数2=参数2值...
例如:http://localhost:80/employees?id=1&name=zhangsan
七、参数路径优缺点:
优点:可以在一定程度上隐藏参数
缺点: 如果参数较多,url路径就很长,不优雅
在真实的开发中一般是采用两者混用。
如何在页面上调用接口(js)
<script>
$(function(){
$("btn1").click(function(){
//发起异步请求---查单个
$.get("/employees/1",function(data){
console.log(data);
})
})
$("btn2").click(function(){
//发起异步请求---查多个
$.get("/employees",function(data){
console.log(data);
})
})
$("btn2").click(function(){
//发起异步请求---添加
$.post("/employees",{name:"zhangsan",age:18},function(data){
console.log(data);
})
})
$("btn2").click(function(){
//发起异步请求---更新
$.ajax({
url:"/employees",
type:"PUT",
data:{id:1,name:"zhangsan",age:18},
success:function(data){
console.log(data);
}
})
})
})
</script>
注意点:
传统的SpringMvc默认不支持put请求,需要配置处理put或者patch请求方式的过滤器。
<filter> <filter-name>httpPutFormContentFilter</filter-name> <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class> </filter> <filter> <filter-name>httpPutFormContentFilter</filter-name> <servlet-name>springMVC</servlet-name> </filter>
八、Restful的风格简化
实际上按照上面的写法会有很多重复的内容,因此还有更简化的方法,下面进行对比介绍
正常:
@Controller
public class EmplyeeController{
@RequestMapping(value ="/employees",method = RequestMethod.GET)
@ResponseBody
public List<Employee> list(){
List<Employee> list = Arrays.asList(new Employee(1,"zhangsan",18),new Employee(2,"lisi",18))
return list;
}
@RequestMapping(value ="/employees",method = RequestMethod.POST)
@ResponseBody
public Employee save(Employee employee){
employee.setId(1);
return employee;
}
@RequestMapping(value ="/employees",method = RequestMethod.PUT)
@ResponseBody
public Employee update(Employee employee){
employee.setName(employee.getName()+"_update");
return employee;
}
@RequestMapping(value ="/employees",method = RequestMethod.DELETE)
@ResponseBody
public JsonResult update(Employee employee){
return JsonResult.success;
}
}
简化后:
@RestController //等价于: @RequstBody+@Controller
@RequestMapping("employees")
public class EmplyeeController{
@GetMapping
public List<Employee> list(){
List<Employee> list = Arrays.asList(new Employee(1,"zhangsan",18),new Employee(2,"lisi",18))
return list;
}
@GetMapping("/{id}")
public List<Employee> detail(@PathVarible Long id){
List<Employee> list = Arrays.asList(new Employee(1,"zhangsan",18),new Employee(2,"lisi",18))
return list;
}
@PostMapping
public Employee save(Employee employee){
employee.setId(1);
return employee;
}
@PutMapping
public Employee update(Employee employee){
employee.setName(employee.getName()+"_update");
return employee;
}
@DeleteMapping
public JsonResult update(Employee employee){
return JsonResult.success;
}
}