本文主要是介紹一個(gè)基于SpringBoot的Web應(yīng)用范例士鸥,范例中根據(jù)自己多年的工作經(jīng)驗(yàn)及總結(jié)提供了一些使用建議,希望對(duì)大家有所啟發(fā)
-
代碼結(jié)構(gòu)概覽
代碼結(jié)構(gòu)很簡(jiǎn)單块饺,就是很常見(jiàn)的三層架構(gòu),通過(guò)包名來(lái)清晰的展現(xiàn)該種層次結(jié)構(gòu):
Web API封裝
Web API層主要是給前端提供web api接口,我們規(guī)定了拴袭,所有的api接口響應(yīng)報(bào)文必須是如下結(jié)構(gòu)體:
public class Response<T> {
private int status;
private String msg;
private T data;
public Response() {
}
public Response(int status, String msg, T data) {
this.status = status;
this.msg = msg;
this.data = data;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
其中 status表明接口狀態(tài)碼(成功/失敗/其他...,0表示成功), msg是對(duì)狀態(tài)碼的簡(jiǎn)單文字描述(比如:success曙博、失敗原因 等等), data是接口返回的具體數(shù)據(jù)
對(duì)返回報(bào)文格式進(jìn)行統(tǒng)一規(guī)定拥刻,有利于前端做一些公共邏輯:比如對(duì)非0狀態(tài)碼記錄console日志、對(duì)一些特定狀態(tài)碼執(zhí)行一些統(tǒng)一邏輯等等
返回統(tǒng)一報(bào)文格式是通過(guò)AOP來(lái)實(shí)現(xiàn)的父泳,并不需要在業(yè)務(wù)代碼中轉(zhuǎn)換成Response實(shí)體般哼,封裝代碼如下:
- 接口正常返回的情況:
@Order(1)
@ControllerAdvice(basePackages = AppContants.API_BASE_PACKAGE)
public class ApiResponseBodyAdvice implements ResponseBodyAdvice<Object> {
private static final Logger logger = LoggerFactory.getLogger(ApiResponseBodyAdvice.class);
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {
Response<Object> resp = new Response<>();
resp.setStatus(0);
resp.setMsg("success");
resp.setData(body);
if(returnType.getMethod().getReturnType() == String.class){
return JSON.toJSONString(resp);
}else{
return resp;
}
}
}
- 接口拋異常的情況:
@ControllerAdvice(basePackages = AppContants.API_BASE_PACKAGE)
public class ApiExceptionHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
private static final int UNKNOWN_EXCEPTION_STATUS = -2;
private static final int ILLEGAL_ARGUMENT_STATUS = -1;
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Response defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
Response response = new Response();
if (e instanceof AppException) {
response.setStatus(((AppException) e).getCode());
response.setMsg(e.getMessage());
} else if (e instanceof IllegalArgumentException) {
response.setStatus(ILLEGAL_ARGUMENT_STATUS);
response.setMsg(e.getMessage());
} else {
logger.error("Got exception,url=" + req.getRequestURI(), e);
response.setStatus(UNKNOWN_EXCEPTION_STATUS);
response.setMsg("接口異常");
}
return response;
}
}
經(jīng)過(guò)這樣的封裝后吴汪,業(yè)務(wù)代碼中不再涉及Response實(shí)體的轉(zhuǎn)換,如下例子所示:
@RestController
@Api(description = "用戶相關(guān)接口")
@RequestMapping("/api/user")
public class UserEndpoint {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private UserService userService;
@ApiOperation(value = "查詢用戶", notes = "根據(jù)用戶id查詢用戶詳情")
@GetMapping("/{userId}")
public User getUser(@PathVariable("userId") Integer userId) {
Preconditions.checkNotNull(userId, "user id not provided");
Preconditions.checkArgument(userId > 0, "user id must greater than 0");
return this.userService.getUser(userId);
}
@ApiOperation(value = "更新用戶信息")
@PostMapping("/update")
public void updateUser(@RequestBody User user) {
logger.info("User:{}", user);
}
}
在這里簡(jiǎn)單說(shuō)一下蒸眠,上面代碼有幾句關(guān)于參數(shù)校驗(yàn)的代碼(如下所示)漾橙,我們只需要簡(jiǎn)單用Preconditions工具類來(lái)進(jìn)行判斷,如果條件不滿足將會(huì)拋出IllegalArgumentException楞卡,這個(gè)未捕獲的異常將會(huì)在ApiExceptionHandler得到處理 并將返回status設(shè)置為-1霜运,msg設(shè)置為異常信息。這樣處理后顯得代碼特別簡(jiǎn)潔 有木有~
Preconditions.checkNotNull(userId, "user id not provided");
Preconditions.checkArgument(userId > 0, "user id must greater than 0");
-
Swagger API文檔
關(guān)于Swagger的介紹蒋腮,網(wǎng)上有很多淘捡,不了解的可以看看:Spring Boot中使用Swagger2構(gòu)建強(qiáng)大的RESTful API文檔Springboot 可以很簡(jiǎn)單地就把swagger 集成到應(yīng)用中,通過(guò)swagger api文檔池摧,可以減少前后端的溝通成本焦除,并且也給后端人員提供了便捷的調(diào)試接口的方式,非常推薦使用
Github 源代碼
本文中所涉及的完整的代碼已經(jīng)放到github上险绘,有興趣的童鞋可以看看:springboot-web-showcase