Ajax 是 Asynchronous Javascript And XML(异步 JavaScript 和 XML)的简称,是指一种创建交互式、快速动态网页应用的网页开发技术,通过在后台与服务器进行少量数据交换,可以使网页实现异步更新,即可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
REST 是 Representational State Transfer(表述性状态转变)的简称,于2000年被提出,使用 HTTP、URI、XML、JSON 等标准和协议,支持轻量级、跨平台、跨语言的架构设计,是 Web 服务的一种架构风格。RESTful 是遵循 REST 风格的一种 Web 服务。 通过不同请求方法实现对资源的增删改查操作,通过统一的接口实现4种操作,保证一个资源对应一个请求地址。
在 RESTful 中,介绍了通过配置 HiddenHttpMethodFilter 实现 RESTful。由于 Ajax 可以直接发送 GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE 8种请求方法,因此不需要配置 HiddenHttpMethodFilter。
Restful风格的API是一种软件架构风格,设计风格而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
在Restful风格中,用户请求的url使用同一个url而用请求方式:get,post,delete,put...等方式对请求的处理方法进行区分,这样可以在前后台分离式的开发中使得前端开发人员不会对请求的资源地址产生混淆和大量的检查方法名的麻烦,形成一个统一的接口。
在Restful风格中,现有规定如下:
了解这个风格定义以后,我们举个例子:
如果当前url是 http://localhost:8080/User,那么用户只要请求这样同一个URL就可以实现不同的增删改查操作,例如:
http://localhost:8080/User?_method=get&id=1001 这样就可以通过get请求获取到数据库 user 表里面 id=1001 的用户信息
http://localhost:8080/User?_method=post&id=1001&name=zhangsan 这样可以向数据库 user 表里面插入一条记录
http://localhost:8080/User?_method=put&id=1001&name=lisi 这样可以将 user表里面 id=1001 的用户名改为lisi
http://localhost:8080/User?_method=delete&id=1001 这样用于将数据库 user 表里面的id=1001 的信息删除
这样定义的规范我们就可以称之为restful风格的API接口,我们可以通过同一个url来实现各种操作。
接下来我们讲解spring-mvc中是如何实现restful风格API接口的,并且对其中出现的问题进行解决!(java web对 put 和 delete 请求的不支持问题)
首先我们搭建好spring mvc的项目接口,并按照restful风格写好控制器,这里我写了一个User控制器类和一个User "Action" :
这里的controller 和 action的url地址是按照restful风格编写的 访问地址 /User/User 用method区分请求方法
我们的前台使用的是jquery ajax进行请求:
有人会问了? 为什么delete 和put用的也是post的请求,这里就要说说java里面对put和delete的不支持了。java里面原本是对put和delete请求进行过滤掉的(不知道为什么要这么做),而且在servlet里面还有doGet,doPost,doDelete,doPut的对应方法,但是不可以使用(尴尬不尴尬),同样spring mvc里面也有对应的method=RequestMethod.PUT 和Delete,但是ajax里面type写成Put、Delete是可以访问到对应的方法的,但是参数却无法传递过去,所有传递过去的参数都是null(郁闷不郁闷)!C#就不会这样,C#的API编程需要开启一下PUT和Delete就可以了,并不需要java里面这么复杂,说到这里我们解决一下这个问题:
首先在springMVC 项目的Web.xml里面增加一个过滤器filter:
hiddenHttpMethodFilter
org.springframework.web.filter.HiddenHttpMethodFilter
hiddenHttpMethodFilter
/*
这一段的方法是用 org.springframework.web.filter.HiddenHttpMethodFilter 的内置过滤器类进行对http请求的标准化。这样让我们可以自己声明请求的方式。
配置完成这个以后,我们在ajax里面需要传递一个参数_method:"PUT" 和 _method:"DELETE",但是请求方式仍然是POST
这样配置的话,我们已经可以实现对DELETE修饰的方法进行访问,同样_method:'PUT'我们可以对PUT修饰的方法进行访问,这样我们上面定义的控制器类已经可以实现了。
S1 在web.xml中开启put和delete的支持
hiddenHttpMethodFilter
org.springframework.web.filter.HiddenHttpMethodFilter
hiddenHttpMethodFilter
/*
S2 导入jackson的jar包
com.fasterxml.jackson.core
jackson-core
2.9.3
com.fasterxml.jackson.core
jackson-annotations
2.9.3
com.fasterxml.jackson.core
jackson-databind
2.9.3
S3 Controller配置:由于从前端页面接收的字符串格式为Json格式,所以在后台Controller中使用对象接收时要在参数前使用@RequestBody,否则会报415错误
关于@RequestBody的用法请见 点击打开链接
@RestController
@RequestMapping(value="user")
public class LoginController {
@RequestMapping(value="/manage", method=RequestMethod.POST)
public String add(@RequestBody User user) {
System.out.println("post: username----" + user.getUsername());
System.out.println("post: password----" + user.getPassword());
if(StringUtils.isBlank(user.getUsername()) || StringUtils.isBlank(user.getPassword())) {
return "failed";
}
return "success";
}
@RequestMapping(value="/manage", method=RequestMethod.PUT)
public String update(@RequestBody User user) {
System.out.println("put: username-------" + user.getUsername());
System.out.println("put: password-------" + user.getPassword());
if(StringUtils.isBlank(user.getUsername()) || StringUtils.isBlank(user.getPassword())) {
return "failed";
}
return "success";
}
@RequestMapping(value="/manage", method=RequestMethod.DELETE)
public String delete(@RequestBody User user) {
System.out.println("delete: username-------" + user.getUsername());
System.out.println("delete: password-------" + user.getPassword());
if(StringUtils.isBlank(user.getUsername()) || StringUtils.isBlank(user.getPassword())) {
return "failed";
}
return "success";
}
}
S4 ajax中的写法
$.ajax({
type: "post",
url: "xxx",
contentType: "application/json",
data: JSON.stringify({username: $('#username').val()}),
success: function(result){
//此处省略
},
error: function(result){
//此处省略
}
});
@RequestMapping是用来映射请求的,比如get请求,post请求,或者REST风格与非REST风格的。 该注解可以用在类上或者方法上,如果用于类上,表示该类中所有方法的父路径。
举例:类SpringMVCTest包含方法testRequestMapping
@RequestMapping ( "/testRequestMapping" )
public String testRequestMapping(){
System.out.println( "testRequestMapping" );
return SUCCESS;
}
注意这里 在方法级别上添加了注解@RequestMapping(“/testRequestMapping”), 表示可以通过“/testRequestMapping”相对路径来定位到这个方法,同时我们在SpringMVCTest类上也放了一个类级别的 RequestMapping的注解:
@RequestMapping ( "/springmvc" )
@Controller
public class SpringMVCTest {
注意这里 还添加了一个@Controller的注解,该注解在SpringMVC 中,负责处理由DispatcherServlet 分发的请求,它把用户请求 的数据经过业务处理层处理之后封装成一个Model ,然后再把该Model 返回给对应的View 进行展示。至此有了一个 “springmvc/testRequestMapping”这样的路径,我们就能够定位到testRequestMapping这个方法上,然后执行 方法内的方法体。
再补充一点,RequestMapping可以实现模糊匹配路径,比如:
/springmvc/**/lastTest 就可以匹配/springmvc/firstTest/secondTest/lastTest这样的路径。
@PathVariable
该注解用来映射请求URL中绑定的占位符。通过@PathVariable可以将URL中占位符的参数绑定到controller处理方法的入参中,没听懂?看例子:
@RequestMapping ( "/testPathVariable/{id}" )
public String testPathVariable( @PathVariable (value= "id" ) Integer id){
System.out.println( "testPathVariable:" + id);
return SUCCESS;
}
在index.jsp中我们添加一条连接,用来触发一个请求:
< a href="springmvc/testPathVariable/1">testPathVariable a >< br />< br />
我们可以 看到这里有一个超链接,点击后会进入到springmvc/testPathVariable/1对应的controller处理的方法中,那我们现在就 是想获取到这个请求参数中的“1”,所以在testPathVariable方法上加入“/testPathVariable/
{id}的具体对应在该方法的参数中,通过@PathVariable(value="id")来声明要接收的请求参数,并通过Integer id来绑定和接收。通过该种方式,我们就可以得到前台页面请求的参数“1”。
@RequestParam
该注解也是用来获取请求参数的。那么该注解和@PathVariable有何不同呢? 还是看例子:
在SpringMVCTest中添加方法:
@RequestMapping (value= "/testRequestParam" )
public String testRequestParam( @RequestParam (value= "username" ) String username, @RequestParam (value= "age" , required= false , defaultValue= "0" ) int age){
System.out.println( "testRequestParam" + " username:" + username + " age:" +age);
return SUCCESS;
}
在index.jsp添加超链接标签:
< a href="springmvc/testRequestParam?username=jackie&age=12">testRequestParam a >< br />< br />
点击页面 上的超链接,就会匹配controller中testRequestParam方法上的RequestMapping的路径。注意在该方法中,我们通过 @RequestParam这个注解声明了两个变量,用来获取请求中query所带的参数值,一个是username后的值,另一个是age后面的值。
看到这 里,你大概已经明白了@PathVariable和@RequestParam之间的一些区别了吧,对于像 “springmvc/testPathVariable/1”这样的请求,我们通过@PathVariable来绑定请求的参数;而对于类似 “springmvc/testRequestParam?username=jackie&age=12”这样的请求参数是以键值对出现的,我 们通过@RequestParam来获取到如username或age后的具体请求值。