REST(Representational State Transfer),中文翻译叫“表述性状态转移”。是 <span style="color:blue;font-size:15px;font-family:Microsoft YaHei;font-style:oblique;">Roy Thomas Fielding</span> 在他2000年的博士论文中提出的。它与传统的 SOAP Web 服务区别在于,REST关注的是要处理的数据,而 SOAP 主要关注行为和处理。要理解好 REST,根据其首字母拆分出的英文更容易理解。 **表述性(Representational):**对于 REST 来讲,咱们网络上的一个个URI资源能够用各类形式来表述,例如:XML、JSON或者HTML等。 **状态(State):**REST 更关注资源的状态而不是对资源采起的行为。 **转移(Transfer):**在网络传输过程当中,REST 使资源以某种表述性形式从一个应用转移到另外一个应用(如从服务端转移到客户端)。html
具体来讲,REST 中存在行为,它的行为是经过 HTTP 表示操做的方法来定义的即:GET、POST、PUT、DELETE、PATCH;GET用来获取资源,POST用来新建资源(也能够用于更新资源),PUT用来更新资源,DELETE用来删除资源,PATCH用来更新资源。 基于 REST 这样的观点,咱们须要避免使用 REST服务、REST Web服务 这样的称呼,这些称呼多少都带有一些强调行为的味道。java
**RESTful 架构:**是基于 REST 思想的时下比较流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,因此正获得愈来愈多网站的采用。git
在 spring 3.0 之后,spring 这对 springMVC 的一些加强功能对 RESTful 提供了良好的支持。在4.0后的版本中,spring 支持一下方式建立 REST 资源:github
代码清单web
package com.pengdh.controller; import com.pengdh.entity.EmployeeEntity; import com.pengdh.service.EmployeeService; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; /** * @author pengdh * @date: 2017-06-27 0:08 */ @Controller @RequestMapping("/employs") public class EmployeeController { @Autowired private EmployeeService empService; @RequestMapping(value = "/list", method = RequestMethod.GET, produces = { "application/json;charset=UTF-8" }) public List<EmployeeEntity> employs(Integer offset,Integer limit) { offset = offset == null ? 0 : offset; limit = limit == null ? 20 : limit; return empService.queryEmployList(offset,limit); } }
代码的大体过程是当客户端发起对 "/employs" 的 GET 请求时,将调用服务端的 employs 方法,服务端经过注入的 EmployeeService 获取到一个 EmployeeEntity 列表,并将列表以 JSON 的表述形式返回给客户端。spring
对于上述两种方式,第一种方式是经过 ContentNegotiatingViewResolver 做为 ViewResolver 的实现,主要是用于将资源渲染人类用户接口所须要的视图模型,如:HTML、JSP等也能够渲染。也能够针对不是人类客户端产生 JSON 或 XML,可是效果不是很理想,每每会产生一些不是客户端所须要的预期结果。如:客户端但愿获得的响应多是:{"name":"zhangs","age":"20"}。而模型是 key-value 组成的 map ,可能最终的响应是这样的:{"user":{"name":"zhangs","age":"20"}}。基于内容协商的这些限制,这里咱们主要讨论第二种方式:使用 Spring 的消息转换功能来生成资源表述。json
这是一种更为直接的方式,消息转换器可以将控制器产生的数据转换为服务于客户端的表述形式。经常使用的一些消息转换器如:Jackson 的 MappingJacksonHttpMessageConverter 实现 JSON 消息和 Java 对象的互相转换; JAXB 库的 Jaxb2RootElementHttpMessageConverter 实现 XML 和 Java 对象的相互转换等。api
正常状况下,当处理方法返回 Java 对象时,这个对象会放在模型中并在视图中渲染使用。可是,若是使用了消息转换功能的话,咱们须要告诉 Spring 跳过正常的模型/视图流程,并使用消息转换器。实现这种方式最简单的方式是在控制器的方法上添加 @ResponseBody 注解。如:restful
@RequestMapping(value = "/list", method = RequestMethod.GET, produces = { "application/json;charset=UTF-8" }) @ResponseBody public List<EmployeeEntity> employs(Integer offset,Integer limit) { offset = offset == null ? 0 : offset; limit = limit == null ? 20 : limit; return empService.queryEmployList(offset,limit); }
这里 @ResponseBody 注解会告知 Spring 将 List<EmployeeEntity> 转换成 JSON 这样的表述形式做为资源发送给客户端。网络
使用 @RequestBody 注解能够告知 Spring 查找一个消息转换器,未来自客户端的资源表述转换为对象。如:
@RequestMapping(value = "/save", method = RequestMethod.POST, produces = { "application/json;charset=UTF-8" }) public int saveEmploy(@RequestBody EmployeeEntity employeeEntity) { return empService.save(employeeEntity); }
Spring 4.0 引入了 @RestController 注解,在控制器是用 @RestController 代替 @Controller 的话,Spring 将会为该控制器的全部处理方法应用消息转换功能。咱们没必要在每一个方法都添加 @ResponseBody 注解了。如:
package com.pengdh.controller; import com.pengdh.entity.EmployeeEntity; import com.pengdh.service.EmployeeService; import java.util.List; 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.RequestMethod; import org.springframework.web.bind.annotation.RestController; /** * @author pengdh * @date: 2017-06-27 0:08 */ @RestController @RequestMapping("/employs") public class EmployeeController { @Autowired private EmployeeService empService; @RequestMapping(value = "/list", method = RequestMethod.GET, produces = { "application/json;charset=UTF-8" }) public List<EmployeeEntity> employs(Integer offset,Integer limit) { offset = offset == null ? 0 : offset; limit = limit == null ? 20 : limit; return empService.queryEmployList(offset,limit); } @RequestMapping(value = "/save", method = RequestMethod.POST, produces = { "application/json;charset=UTF-8" }) public int saveEmploy(@RequestBody EmployeeEntity employeeEntity) { return empService.save(employeeEntity); } }
能够利用 ResponseEntity 给客户端返回状态码、设置响应头信息等,如给客户端提供返回码:
@RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = { "application/json;charset=UTF-8" }) public ResponseEntity<EmployeeEntity> employById(@PathVariable long id) { HttpStatus status = null; EmployeeEntity employeeEntity = empService.selectById(id); if (employeeEntity != null) { status = HttpStatus.OK; } else { status = HttpStatus.NOT_FOUND; } return new ResponseEntity<EmployeeEntity>(employeeEntity, status); }
若是没有 if 判断,当根据 id 找不到对应的信息的时候,返回给客户端的状态码是默认的 HttpStatus.OK;当加上了判断条件后若是没有相应的信息返回则设置返回状态码为 HttpStatus.NOT_FOUND,最后经过 new 一个 ResponseEntity 会将查询信息和状态码一块儿返回到客户端。
@ExceptionHandler 能够用到控制器的方法中,处理特定的异常:
建立响应包装类 ResponseResult
package com.pengdh.dto; import java.io.Serializable; import org.springframework.http.HttpStatus; /** * 响应结果封装类 * * @author pengdh * @date: 2017-06-29 0:34 */ public class ResponseResult<T> implements Serializable { private static final long serialVersionUID = -3371934618173052904L; private int code; private String desc; private T data; public ResponseResult() { } public ResponseResult(int code, String desc) { this.code = code; this.desc = desc; } public ResponseResult(int code, T data) { this.code = code; this.data = data; } public int getCode() { return code; } public void setCode(HttpStatus code) { this.code = code; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public T getData() { return data; } public void setData(T data) { this.data = data; } @Override public String toString() { return "ResponseResult{" + "code=" + code + ", desc='" + desc + '\'' + ", data=" + data + '}'; } }
建立一个异常类 ResourceNotFound
package com.pengdh.exception; /** * 资源未找到异常 * * @author pengdh * @date: 2017-06-29 0:55 */ public class ResourceNotFound extends RuntimeException { private static final long serialVersionUID = 4880328265878141724L; public ResourceNotFound() { super(); } public ResourceNotFound(String message) { super(message); } public ResourceNotFound(String message, Throwable cause) { super(message, cause); } }
控制器 EmployeeController
package com.pengdh.controller; import com.pengdh.dto.ResponseResult; import com.pengdh.entity.EmployeeEntity; import com.pengdh.exception.ResourceNotFound; import com.pengdh.service.EmployeeService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; /** * @author pengdh * @date: 2017-06-27 0:08 */ @RestController @RequestMapping("/employs") public class EmployeeController { @Autowired private EmployeeService empService; @RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = { "application/json;charset=UTF-8" }) public ResponseResult<EmployeeEntity> employById(@PathVariable long id) { ResponseResult<EmployeeEntity> result = new ResponseResult<EmployeeEntity>(); HttpStatus status = null; EmployeeEntity employeeEntity = empService.selectById(id); if (employeeEntity == null) { throw new ResourceNotFound(String.valueOf(id)); } result.setCode(HttpStatus.OK); result.setData(employeeEntity); return result; } @ExceptionHandler(ResourceNotFound.class) public ResponseResult<Object> handlerException(ResourceNotFound e) { ResponseResult<Object> result = new ResponseResult<Object>(); result.setCode(HttpStatus.NOT_FOUND); result.setDesc(e.getMessage()); return result; } }
从控制器代码能够看出,咱们经过 @ExceptionHandler 能将控制器的方法的异常场景分出来单独处理。