Springboot 实现api接口(一)
一、序言
网络程序正朝着移动设备的方向发展,先后端分离、APP,最好的交互交互方式莫过于经过API接口实现。前端
本项目加密方式采用参数排序+key验签方式,后期可按需求更换java
本次咱们先了解一下Spring对API接口开发的支持,而后咱们采用Spring Boot搭建项目,本项目暂未使用权限管理系统,后期主键完善,可按需求对key进行配置或者使用安全框架进行管理。借用Swagger列出API接口,便于查阅。web
二、返回格式
根据当前趋势,API接口要求返回的格式通常为 application/json,有特殊行业如银行等返回格式为xml报文,本次统一使用json。Spring Boot返回json,提供了两种实现方式:类注解 和 方法注解。spring
类注解 @RestControllerjson
@RestController @RequestMapping("/user") public class UserController { @GetMapping("/saveUser") public Object saveUser(@Validated User user){ return user; } }
方法注解 @ResponseBody后端
@Controller @RequestMapping("/demo") public class Demo { @RequestMapping @ResponseBody public String getCapitalize(String args){ return args.toUpperCase(); } }
值得提醒的是,虽然都是均可以,但我更推荐使用类注解,项目的主要目的是提供和统一api接口,会显得咱们的编码风格十分统一,代码更加紧凑,不至于看起来零散。api
注:Mapping根据业务自行选择,推荐@GetMapping、@PostMapping格式。安全
三、接收参数/参数验证
- 举例说明
@GetMapping("/saveUser") public Object saveUser(@Validated User user){ return user; }
- 可使用validation进行参数验证
maven导包
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
在实体参数上添加注解来达到验证参数的效果,而后在方法参数前添加@Validated开启验证。若是参数错误会抛出BindException异常,后期统一异常处理响应。springboot
@Data @JsonInclude(JsonInclude.Include.NON_NULL)//解决参数为null不返回前端 public class User implements Serializable { private Long Id; @NotNull(message = "用户名不能为空") private String username; @NotNull(message = "年龄不能为空") private Integer age; private String email; }
四、异常统一处理
每一个过程都单独处理异常,系统的代码耦合度高,工做量大且很差统一,维护的工做量也很大。 为了将全部类型的异常处理从各处理过程解耦出来,保证相关处理过程的功能较单一,实现异常信息的统一处理和维护。网络
Spring MVC处理异常有3种方式:
-
使用Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver;
-
实现Spring的异常处理接口HandlerExceptionResolver 自定义本身的异常处理器;
-
使用@ExceptionHandler注解实现异常处理;
今天主要说springboot基于@ExceptionHandler注解实现异常处理
@ExceptionHandler注解:定义控制器发生异常后的操做,能够拦截全部控制器发生的异常。统一异常处理 ,经过@ExceptionHandler(value = Exception.class) 来指定捕获的异常。“@ControllerAdvice + @ExceptionHandle" 能够处理除“404”之外的运行异常。
- 建立BaseBusinessException类(自定义业务异常),继承RuntimeException类。
package com.cch.error; import lombok.Data; import lombok.NoArgsConstructor; /** * @Auther: cch * @Date: 2020/9/21 16:03 * @Description: 自定义异常返回结果实体类 */ @Data @NoArgsConstructor public class BaseBusinessException extends RuntimeException{ private BaseError error = DefaultError.SYSTEM_INTERNAL_ERROR; private String extMessage = null; public BaseBusinessException(String message) { super(message); this.extMessage = message; } public BaseBusinessException(String message, Throwable cause) { super(message, cause); this.extMessage = message; } public BaseBusinessException(Throwable cause) { super(cause); } public BaseBusinessException(BaseError error) { this.error = error; } public BaseBusinessException(String message, BaseError error) { super(message); this.extMessage = message; this.error = error; } public BaseBusinessException(String message, Throwable cause, BaseError error) { super(message, cause); this.extMessage = message; this.error = error; } public BaseBusinessException(Throwable cause, BaseError error) { super(cause); this.error = error; } }
- 建立统一响应类
package com.cch.error; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.Data; /** * @Auther: cch * @Date: 2020/9/21 16:12 * @Description: 相应结果实体类 */ @Data @JsonInclude(JsonInclude.Include.NON_NULL) public class Response { private String code; private Object data; private String message; }
- 建立ExceptionControllerAdvice类(全局异常处理器),使用ResponseEntity返回自定义响应码 – 508。
package com.cch.exception; import com.cch.error.BaseBusinessException; import com.cch.error.DefaultError; import com.cch.error.Response; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.validation.BindException; import org.springframework.validation.FieldError; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; /** * @Auther: cch * @Date: 2020/9/21 14:07 * @Description: 全局处理异常 */ @RestControllerAdvice public class ExceptionControllerAdvice { @ExceptionHandler(Exception.class) public ResponseEntity<Response> APIExceptionHandler(Exception exception) { Response response = new Response(); if (exception instanceof BaseBusinessException) { BaseBusinessException bbe = (BaseBusinessException)exception; response.setCode(bbe.getError().getErrorCode()); response.setData(bbe.getError().getErrorMessage()); if (exception.getMessage() != null) { response.setData(exception.getMessage()); } } else if (exception instanceof BindException) { BindException bindException = (BindException)exception; response.setCode(DefaultError.PARAMETER_ERROR.getErrorCode()); response.setData(DefaultError.PARAMETER_ERROR.getErrorMessage()); FieldError fieldError = bindException.getBindingResult().getFieldError(); response.setMessage(fieldError.getDefaultMessage()); }else{ exception.printStackTrace(); response.setCode(DefaultError.SYSTEM_INTERNAL_ERROR.getErrorCode()); response.setData(DefaultError.SYSTEM_INTERNAL_ERROR.getErrorMessage()); } return new ResponseEntity (response, HttpStatus.LOOP_DETECTED); } }
当项目中又异常可直接抛出,示例:
@GetMapping("/saveUser") public Object saveUser(@Validated User user){ if(user == null){ throw new BaseBusinessException("用户不能为空"); } return user; }
附:异常使用枚举,可根据我的需求灵活使用,这是我我的使用习惯。
BaseError接口
package com.cch.error; /** * @Auther: cch * @Date: 2020/9/21 16:06 * @Description: 异常枚举父接口 */ public interface BaseError { String getErrorCode(); String getErrorMessage(); }
可根据异常类型定义多个枚举,而后实现BaseError,示例通用异常:
package com.cch.error; /** * @Auther: cch * @Date: 2020/9/21 16:07 * @Description: 默认异常 */ public enum DefaultError implements BaseError { SYSTEM_INTERNAL_ERROR("0000", "系统内部错误"), PARAMETER_ERROR("0001","参数错误"); String errorCode; String errorMessage; private static final String ns = "DFT"; DefaultError(String errorCode, String errorMessage) { this.errorCode = errorCode; this.errorMessage = errorMessage; } @Override public String getErrorCode() { return ns + "." + errorCode; } @Override public String getErrorMessage() { return errorMessage; } }
注:下一篇请求加密验签和接口文档使用。