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; } }
注:下一篇請求加密驗籤和接口文檔使用。