前言
參考博客一個基於Spring Boot的API、RESTful API項目種子(骨架)
最近使用Spring Boot 配合 MyBatis 、通用Mapper插件、PageHelper分頁插件 連做了幾個中小型API項目,做下來覺得這套框架、工具搭配起來開發這種項目確實非常舒服,團隊的反響也不錯。在項目搭建和開發的過程中也總結了一些小經驗,與大家分享一下。
在開發一個API項目之前,搭建項目、引入依賴、配置框架這些基礎活自然不用多說,通常爲了加快項目的開發進度(早點回家)還需要封裝一些常用的類和工具,比如統一的響應結果封裝、統一的異常處理、接口簽名認證、基礎的增刪改差方法封裝、基礎代碼生成工具等等,有了這些項目才能開工。
然而,下次再做類似的項目上述那些步驟可能還要搞一遍,雖然通常是拿過來改改,但是還是比較浪費時間。所以,可以利用面向對象抽象、封裝的思想,抽取這類項目的共同之處封裝成了一個種子項目(估計大部分公司都會有很多類似的種子項目),這樣的話下次再開發類似的項目直接在該種子項目上迭代就可以了,減少無意義的重複工作。
我在此基礎上自個兒再DIY了一些功能,把lenosp腳手架添加進來,爲了方便開發後臺管理系統而不只是編寫API接口。大部分應用都需要後臺管理系統的支持,而有一套通用的後臺管理系統模板會很方便,這裏使用lenosp
腳手架,大家可以進入Gitee瞭解該項目:Gitee/一枚碼農/lenosp
因此我使用的種子項目是基於Maven多模塊開發的,整體骨架使用的是lenosp的設計,在上面擴展自己額外的功能。
特徵&提供
以下只對我自己新添加的一些特徵、配置進行簡要介紹。若要詳細理解種子項目,請移步我的另外一篇博客(製作中…)
-
最佳實踐的項目結構、配置文件、精簡POM
-
統一響應結果封裝及生成工具
因爲要給前端返回json格式的數據,這裏需要定義 統一返回碼、返回結果實體類。參考博客統一返回碼,返回結果實體類
Result
返回結果集封裝
@Data
@NoArgsConstructor
public class Result<T> implements Serializable{
private boolean success;//是否成功
private Integer code;// 返回碼
private String message;//返回信息
private T data;// 返回數據
public Result(ResultCode code) {
this.success = code.success;
this.code = code.code;
this.message = code.message;
}
public Result(ResultCode code,T data) {
this.success = code.success;
this.code = code.code;
this.message = code.message;
this.data = data;
}
public Result(Integer code,String message,boolean success) {
this.code = code;
this.message = message;
this.success = success;
}
public static Result SUCCESS(){
return new Result(ResultCode.SUCCESS);
}
public static Result ERROR(){
return new Result(ResultCode.SERVER_ERROR);
}
public static Result FAIL(){
return new Result(ResultCode.FAIL);
}
}
ResultCode
狀態碼封裝
public enum ResultCode {
SUCCESS(true,10000,"操作成功!"),
//---系統錯誤返回碼-----
FAIL(false,10001,"操作失敗"),
UNAUTHENTICATED(false,10002,"您還未登錄"),
UNAUTHORISE(false,10003,"權限不足"),
SERVER_ERROR(false,99999,"抱歉,系統繁忙,請稍後重試!");
//操作是否成功
boolean success;
//操作代碼
int code;
//提示信息
String message;
ResultCode(boolean success,int code, String message){
this.success = success;
this.code = code;
this.message = message;
}
public boolean success() {
return success;
}
public int code() {
return code;
}
public String message() {
return message;
}
}
- 統一異常處理
@RestControllerAdvice
public class GlobalExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(UnauthorizedException.class)
public Result handleShiroException(Exception ex) {
return new Result(10001,"無權訪問該資源",false);
}
@ExceptionHandler(AuthorizationException.class)
public Result AuthorizationException(Exception ex) {
return new Result(10001,"權限認證失敗",false);
}
/**
* 默認統一異常處理方法
* @ExceptionHandler 註解用來配置需要攔截的異常類型, 也可以是自定義異常
*/
@ExceptionHandler(Exception.class)
public Result runtimeExceptionHandler(Exception exception, HttpServletResponse response) {
logger.error("請求出現未知異常,異常信息爲: {}", exception.getMessage());
return new Result(10001,"請求出現未知異常,異常信息爲:"+exception.getMessage(),false);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result handleBindException(MethodArgumentNotValidException ex) {
/*
// 返回所有參數效驗錯誤信息
StringBuilder errMsg = new StringBuilder();
List<ObjectError> allErrors = ex.getBindingResult().getAllErrors();
for (ObjectError allError : allErrors) {
errMsg.append(allError.getDefaultMessage()).append(",");
}
return ResponseMessage.newErrorInstance(errMsg.toString());
*/
// 只返回一條參數校驗異常信息
FieldError fieldError = ex.getBindingResult().getFieldError();
assert fieldError != null;
logger.info("參數校驗異常:{}({})", fieldError.getDefaultMessage(),fieldError.getField());
return new Result(10001,fieldError.getDefaultMessage(),false);
}
@ExceptionHandler(BindException.class)
public Result handleBindException(BindException ex) {
logger.info("參數校驗異常:{}", ex.getMessage());
return new Result(10001,ex.getMessage(),false);
}
@ExceptionHandler(ConstraintViolationException.class)
public Result handleBindException(ConstraintViolationException ex) {
logger.info("參數校驗異常:{}", ex.getMessage());
return new Result(10001,ex.getMessage(),false);
}
}