您的位置:首页 > 编程语言 > Java开发

基于SpringMVC的RESTful API设计

2016-05-17 20:06 537 查看
REST(Representational State Transfer)描述了一种软件架构风格,相比SOAP和RPC更加简单明了,目前互联公司越来越流行提供RESTful形式的API供第三方调用。REST通过与标准的HTTP方法进行映射,能够完整地表述系统资源的各种形为。SpringMVC从3.0的开始增加了RESTful功能,因其快速简单、与Spring框架无缝集成等优点,被广大Java开发者奉为RESTful首选。本文基于SpringMVC3.2.5和maven讲解如何通过SpringMVC构造企业级应用基础的RESTful
API,对开发人员快速开发企业级项目集成有所帮助。

  1. 基于Maven创建SpringMVC工程

  Maven是一个项目管理工具,它包含了一个项目对象模型 (Project Object Model),使用Maven能够快速完成Spring MVC工程的创建,而不必去逐个下载Spring MVC的依赖jar包。

  Maven创建Spring MVC非常简单,主要包括以下几步:

  1)创建工程

mvn archetype:generate

-DgroupId=com.ibm.cdl

-DartifactId=spirngmvc-restful

-DarchetypeArtifactId=maven-archetype-webapp

-DinteractiveMode=false

  2)修改POM文件,内容如下:

  略

  3)基本框架已经生成,后续根据实际需求编辑RESTful API

  2. Token认证机制

  RESTful提供的API是无状态的,下一次调用请求与当前的调用请求是完全无关,但这就无法保证系统资源的安全性。Token机制就是用来解决无状态和安全性之间的矛盾。其实现机理主机如下:

  1)用户发送用户名和密码(加密密码),验证请求通过

  2)服务器通过SSO服务判断用户名和密码是否正确

  3)验证通过,返回Token及过期时间

  4)后边所有请求在这段时间内携带这一Token即可使用其他API

@Controller

@RequestMapping("/admin/v1/")

public class AuthenticateAPI {

@Autowired

private UserService userService;

/**

* 用户授权验证

* @param param

* @return

*/

@RequestMapping(value="/tokens",method=RequestMethod.POST)

@ResponseBody

public String authenticate(@RequestBody String param){

try {

User user = JSON.parseObject(param, User.class);

Token token = userService.login(user);

if(token == null){

throw new CutomizedException(HttpStatus.UNAUTHORIZED, "User authenticate failed.");

}

TokenResponseEntity tokenResponseEntity = new TokenResponseEntity();

tokenResponseEntity.setEntity(token);

tokenResponseEntity.setHttpStatus(HttpStatus.OK);

tokenResponseEntity.setMessage("User authenticate successful.");

return JSON.toJSONStringWithDateFormat(tokenResponseEntity, "yyyy-MM-dd HH:mm:ss", SerializerFeature.WriteDateUseDateFormat);

}catch(JSONException e){

throw new CutomizedException(HttpStatus.BAD_REQUEST, "Bad request body.");

}catch (Exception e) {

throw new CutomizedException(HttpStatus.INTERNAL_SERVER_ERROR, "Server internal error");

}

}

}

  3. Token验证

  考虑到安全性,除了Token认证的API外,其他所有的请求都需要经过Token验证,SpringMVC提供的@ModelAttribute("tokenIdValidateResult")注解能够预先对所有方法进Token有效性的验证,一旦Token过期或者Token验证失败,则不允许调用方进行相关操作,具体实现过程如下:

/**

* All Method need to validate token id

* @param headers

* @return

*/

@ModelAttribute("tokenIdValidateResult")

public TokenValidateResult validateTokenId(@RequestHeader HttpHeaders headers){

String tokenId=headers.getFirst("X-Auth-Token");

Token searchToken = new Token();

searchToken.setTokenId(tokenId);

if(StringUtils.isEmpty(tokenId)){

return TokenValidateResult.TOKEN_EMPTY;

}

Token token=tokenService.findOneByExample(searchToken);

//Token not exists

if(token==null){

return TokenValidateResult.TOKEN_NOT_EXIST;

}

//Token 过期

if(token.getExpireTime().before(new Date())){

return TokenValidateResult.TOKEN_EXPIRED;

}

//Success

return TokenValidateResult.SUCCESS;

}

  4. 创建资源

  创建资源采用HTTP中的POST请求来实现。

  创建Resource API示例:

@Controller

@RequestMapping(value="/resources/v1")

public class ResourceAPI {

@RequestMapping(method=RequestMethod.POST)

@ResponseBody

public ResourceResponseEntity createResource(@ModelAttribute("tokenIdValidateResult")TokenValidateResult tokenIdValidateResult,@RequestHeader HttpHeaders headers,@JsonParam ResourceReponseEntity resourceResponseEntity ) {

if(tokenIdValidateResult == TokenValidateResult.SUCCESS){

try {

String tokenId=headers.getFirst("X-Auth-Token");

Token searchToken = new Token();

searchToken.setTokenId(tokenId);

//TODO:创建Resource

return resourceResponseEntity;

} catch (Exception e) {

throw new CutomizedException(e);

}

}else{

//异常处理交给异常处理框架

throw new CutomizedException(HttpStatus.UNAUTHORIZED,"Token validte failed,ErrorCode:"+tokenIdValidateResult);

}

}

}

  5. 更新资源属性

  更新资源采用HTTP中的PUT请求来实现。具体实现如下:

@Controller

@RequestMapping(value="/resources/v1")

public class ResourceAPI {

@RequestMapping(value="/{id}",method=RequestMethod.PUT)

@ResponseBody

public ResourceResponseEntity createResource(@ModelAttribute("tokenIdValidateResult")TokenValidateResult tokenIdValidateResult,

@PathVariable Integer id,

@RequestHeader HttpHeaders headers,

@JsonParam Resource resource) {

if(tokenIdValidateResult == TokenValidateResult.SUCCESS){

try {

String tokenId=headers.getFirst("X-Auth-Token");

Token searchToken = new Token();

searchToken.setTokenId(tokenId);

//TODO:更新Resource

return resourceResposeEntity;

} catch (Exception e) {

throw new CutomizedException(e);

}

}else{

//异常处理交给异常处理框架

throw new CutomizedException(HttpStatus.UNAUTHORIZED,"Token validte failed,ErrorCode:"+tokenIdValidateResult);

}

}

}

  6. 删除资源

  删除资源采用HTTP中的DELETE请求来实现。具体实现如下:

@Controller

@RequestMapping(value="/resources/v1")

public class ResourceAPI {

@RequestMapping(value="/{id}",method=RequestMethod.DELETE)

@ResponseBody

public ResourceResponseEntity createResource(@ModelAttribute("tokenIdValidateResult")TokenValidateResult tokenIdValidateResult,

@PathVariable Integer id,

@RequestHeader HttpHeaders headers) {

if(tokenIdValidateResult == TokenValidateResult.SUCCESS){

try {

String tokenId=headers.getFirst("X-Auth-Token");

Token searchToken = new Token();

searchToken.setTokenId(tokenId);

//TODO:删除Resource

return resourceResposeEntity;

} catch (Exception e) {

throw new CutomizedException(e);

}

}else{

//异常处理交给异常处理框架

throw new CutomizedException(HttpStatus.UNAUTHORIZED,"Token validte failed,ErrorCode:"+tokenIdValidateResult);

}

}

}

  7. 获取资源列表及单个资源信息

  获取资源信息采用HTTP协议中的GET请求实现,具体实现如下:

@Controller

@RequestMapping(value="/resources/v1")

public class ResourceAPI {

@RequestMapping(method=RequestMethod.GET)

@ResponseBody

public ResourceResponseEntity createResource(@ModelAttribute("tokenIdValidateResult")TokenValidateResult tokenIdValidateResult,@RequestHeader HttpHeaders headers) {

if(tokenIdValidateResult == TokenValidateResult.SUCCESS){

try {

String tokenId=headers.getFirst("X-Auth-Token");

Token searchToken = new Token();

searchToken.setTokenId(tokenId);

//TODO:删除Resource列表

return resourceResposeEntity;

} catch (Exception e) {

throw new CutomizedException(e);

}

}else{

//异常处理交给异常处理框架

throw new CutomizedException(HttpStatus.UNAUTHORIZED,"Token validte failed,ErrorCode:"+tokenIdValidateResult);

}

}

@RequestMapping(value="/{id}",method=RequestMethod.GET)

@ResponseBody

public ResourceResponseEntity createResource(@ModelAttribute("tokenIdValidateResult")TokenValidateResult tokenIdValidateResult,

@PathVariable Integer id,

@RequestHeader HttpHeaders headers) {

if(tokenIdValidateResult == TokenValidateResult.SUCCESS){

try {

String tokenId=headers.getFirst("X-Auth-Token");

Token searchToken = new Token();

searchToken.setTokenId(tokenId);

//TODO:获取单个资源信息

return resourceResposeEntity;

} catch (Exception e) {

throw new CutomizedException(e);

}

}else{

//异常处理交给异常处理框架

throw new CutomizedException(HttpStatus.UNAUTHORIZED,"Token validte failed,ErrorCode:"+tokenIdValidateResult);

}

}

}

  8. 异常处理

  API在调用过程中总会出现各种各样的异常情况,Spring MVC提供了@ControllerAdvice以及ResponseEntityExceptionHandler类,专门用来自定义输出错误格式。只要在发生异常的地方将异常消息直接抛出,这样所有的异常都统一由自定义的异常处理类来处理,具体如下:

@ControllerAdvice

public class RestExceptionHandler extends ResponseEntityExceptionHandler {

@ExceptionHandler(value = { VMWareException.class })

public final ResponseEntity<?> handleVMWareException(VMWareException ex, WebRequest request) {

HttpHeaders headers = new HttpHeaders();

headers.setContentType(MediaType.parseMediaType(MediaTypes.TEXT_PLAIN_UTF_8));

return handleExceptionInternal(ex, ex.getMessage(), headers, ex.status, request);

}

@ExceptionHandler(value = { PowerException.class })

public final ResponseEntity<?> handlePowerException(PowerException ex, WebRequest request) {

HttpHeaders headers = new HttpHeaders();

headers.setContentType(MediaType.parseMediaType(MediaTypes.TEXT_PLAIN_UTF_8));

return handleExceptionInternal(ex, ex.getMessage(), headers, ex.status, request);

}

@ExceptionHandler(value = { UspException.class })

public final ResponseEntity<?> handleUspException(UspException ex, WebRequest request) {

HttpHeaders headers = new HttpHeaders();

headers.setContentType(MediaType.parseMediaType(MediaTypes.TEXT_PLAIN_UTF_8));

return handleExceptionInternal(ex, ex.getMessage(), headers, ex.status, request);

}

@ExceptionHandler(value = { KVMException.class })

public final ResponseEntity<?> handleKVMException(KVMException ex, WebRequest request) {

HttpHeaders headers = new HttpHeaders();

headers.setContentType(MediaType.parseMediaType(MediaTypes.TEXT_PLAIN_UTF_8));

return handleExceptionInternal(ex, ex.getMessage(), headers, ex.status, request);

}

}

  这里的异常都封装了具体的HTTPStatus代码,这样第三方就能够清楚地知道调用时的出错类型,常见的HTTP错误代码有





  9. 总结

  本文主要讲解了如何通过Spring MVC封装RESTful API,包括Token的认证机制,封装资源的CRUD操作,异常处理等,对开发人员快速开发企业级项目集成有所帮助。

参考资料

1. http://www.ruanyifeng.com/blog/2011/09/restful.html
2. http://www.ruanyifeng.com/blog/2011/09/restful.html
3. http://jinnianshilongnian.iteye.com/blog/1866350
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: