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

基于SpringMVC的RESTful API设计

2016-06-29 20:19 459 查看


基于SpringMVC的RESTful API设计  


 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: