一個(gè) SpringBoot 項(xiàng)目該包含哪些?
閱讀本文大概需要 9?分鐘。
來(lái)自:https://juejin.cn/post/6844904083942277127
前言
基礎(chǔ)項(xiàng)目該包含哪些東西。
Swagger在線接口文檔。
CodeGenerator 代碼生成器。
統(tǒng)一返回。
通用的分頁(yè)對(duì)象。
常用工具類(lèi)。
全局異常攔截。
錯(cuò)誤枚舉。
自定義異常。
多環(huán)境配置文件。
Maven多環(huán)境配置。
日志配置。
JenkinsFile。
可以在評(píng)論區(qū)進(jìn)行補(bǔ)充
Swagger


常用的Swagger注解
@Api用于Controller@ApiOperation用于Controller內(nèi)的方法。@ApiResponses用于標(biāo)識(shí)接口返回?cái)?shù)據(jù)的類(lèi)型。@ApiModel用于標(biāo)識(shí)類(lèi)的名稱(chēng)@ApiModelProperty用于標(biāo)識(shí)屬性的名稱(chēng)
案例
@RestController
@Api(tags?=?"用戶(hù)")
@AllArgsConstructor
@RequestMapping("/user")
public?class?UserController?{
????private?IUserService?userService;
????/**
?????*?獲取用戶(hù)列表
?????*?@param?listUserForm?表單數(shù)據(jù)
?????*?@return?用戶(hù)列表
?????*/
????@ApiOperation("獲取用戶(hù)列表")
????@GetMapping("/listUser")
????@ApiResponses(
????????????@ApiResponse(code?=?200,?message?=?"操作成功",?response?=?UserVo.class)
????)
????public?ResultVo?listUser(@Validated?ListUserForm?listUserForm){
????????return?ResultVoUtil.success(userService.listUser(listUserForm));
????}
}復(fù)制代碼
@Data
@ApiModel("獲取用戶(hù)列表需要的表單數(shù)據(jù)")
@EqualsAndHashCode(callSuper?=?false)
public?class?ListUserForm?extends?PageForm<ListUserForm>?{
????/**
?????*?用戶(hù)狀態(tài)
?????*/
????@ApiModelProperty("用戶(hù)狀態(tài)")
????@NotEmpty(message?=?"用戶(hù)狀態(tài)不能為空")
????@Range(min?=??-1?,?max?=?1?,?message?=?"用戶(hù)狀態(tài)有誤")
????private?String?status;
}復(fù)制代碼
SwaggerConfiguration.java.CodeGenerator代碼生成器。
entity,service,serviceImpl,mapper,mapper.xml。省去了建立一大堆實(shí)體類(lèi)的麻煩。CodeGenerator.java.常用的封裝
統(tǒng)一返回 ResultVo
@Data
@ApiModel("固定返回格式")
public?class?ResultVo?{
????/**
?????*?錯(cuò)誤碼
?????*/
????@ApiModelProperty("錯(cuò)誤碼")
????private?Integer?code;
????/**
?????*?提示信息
?????*/
????@ApiModelProperty("提示信息")
????private?String?message;
????/**
?????*?具體的內(nèi)容
?????*/
????@ApiModelProperty("響應(yīng)數(shù)據(jù)")
????private?Object?data;
}復(fù)制代碼
抽象表單 BaseForm
public?abstract?class?BaseForm<T>?{
????/**
?????*?獲取實(shí)例
?????*?@return?返回實(shí)體類(lèi)
?????*/
????public?abstract?T?buildEntity();
}復(fù)制代碼
????/**
?????*?添加用戶(hù)
?????*?@param?userForm?表單數(shù)據(jù)
?????*?@return?true?或者?false
?????*/
????@Override
????public?boolean?addUser(AddUserForm?userForm)?{
????????User?user?=?new?User();
????????user.setNickname(userForm.getNickname());
????????user.setBirthday(userForm.getBirthday());
????????user.setUsername(userForm.getUsername());
????????user.setPassword(userForm.getPassword());
????????return?save(user);
????}復(fù)制代碼
/**
?*?添加用戶(hù)
?*?@param?userForm?表單數(shù)據(jù)
?*?@return?true?或者?false
?*/
@Override
public?boolean?addUser(AddUserForm?userForm)?{
????User?user?=?new?User();
????BeanUtils.copyProperties(this,user);
????return?save(user);
}復(fù)制代碼
@Data
@EqualsAndHashCode(callSuper?=?false)
public?class?AddUserForm?extends?BaseForm<User>?{
????/**
?????*?昵稱(chēng)
?????*/
????private?String?nickname;
????/**
?????*?生日
?????*/
????private?Date?birthday;
????/**
?????*?用戶(hù)名
?????*/
????private?String?username;
????/**
?????*?密碼
?????*/
????private?String?password;
????/**
?????*?構(gòu)造實(shí)體
?????*?@return?實(shí)體對(duì)象
?????*/
????@Override
????public?User?buildEntity()?{
????????User?user?=?new?User();
????????BeanUtils.copyProperties(this,user);
????????return?user;
????}
}復(fù)制代碼
/**
?*?添加用戶(hù)
?*?@param?userForm?表單數(shù)據(jù)
?*?@return?true?或者?false
?*/
@Override
public?boolean?addUser(AddUserForm?userForm)?{
????return?save(userForm.buildEntity());
}復(fù)制代碼
form可以繼承baseform并實(shí)現(xiàn)buildEntity()這樣可以更加符合面向?qū)ο螅?code style="font-family: Menlo, Monaco, Consolas, "Courier New", monospace;font-size: inherit;word-break: break-word;border-radius: 4px;overflow-x: auto;background: rgb(248, 248, 248);color: rgb(233, 105, 0);padding: 2px 4px;line-height: inherit;overflow-wrap: break-word;margin-right: 2px;margin-left: 2px;">service不需要關(guān)心form如何轉(zhuǎn)變成entity,只需要在使用的時(shí)候調(diào)用buildEntity()即可,尤其是在form?->?entity相對(duì)復(fù)雜的時(shí)候,這樣做可以減少service內(nèi)的代碼。讓代碼邏輯看起來(lái)更加清晰。通用的分頁(yè)對(duì)象
PageForm.calcCurrent()、PageVo.setCurrentAndSize()、PageVo.setTotal()這個(gè)幾個(gè)方法。PageForm
@Data
@ApiModel(value?=?"分頁(yè)數(shù)據(jù)",?description?=?"分頁(yè)需要的表單數(shù)據(jù)")
public?class?PageForm<T?extends?PageForm>>{
????/**
?????*?頁(yè)碼
?????*/
????@ApiModelProperty(value?=?"頁(yè)碼?從第一頁(yè)開(kāi)始?1")
????@Min(value?=?1,?message?=?"頁(yè)碼輸入有誤")
????private?Integer?current;
????/**
?????*?每頁(yè)顯示的數(shù)量
?????*/
????@ApiModelProperty(value?=?"每頁(yè)顯示的數(shù)量?范圍在1~100")
????@Range(min?=?1,?max?=?100,?message?=?"每頁(yè)顯示的數(shù)量輸入有誤")
????private?Integer?size;
????/**
?????*?計(jì)算當(dāng)前頁(yè)?,方便mysql?進(jìn)行分頁(yè)查詢(xún)
?????*?@return?返回?pageForm
?????*/
????@ApiModelProperty(hidden?=?true)
????public?T?calcCurrent(){
????????current?=?(current?-?1?)?*?size;
????????return?(T)?this;
????}
}復(fù)制代碼
PageVo
@Data
public?class?PageVo<T>?{
????/**
?????*?分頁(yè)數(shù)據(jù)
?????*/
????@ApiModelProperty(value?=?"分頁(yè)數(shù)據(jù)")
????private?List?records;
????/**
?????*?總條數(shù)
?????*/
????@ApiModelProperty(value?=?"總條數(shù)")
????private?Integer?total;
????/**
?????*?總頁(yè)數(shù)
?????*/
????@ApiModelProperty(value?=?"總頁(yè)數(shù)")
????private?Integer?pages;
????/**
?????*?當(dāng)前頁(yè)
?????*/
????@ApiModelProperty(value?=?"當(dāng)前頁(yè)")
????private?Integer?current;
????/**
?????*?查詢(xún)數(shù)量
?????*/
????@ApiModelProperty(value?=?"查詢(xún)數(shù)量")
????private?Integer?size;
????/**
?????*?設(shè)置當(dāng)前頁(yè)和每頁(yè)顯示的數(shù)量
?????*?@param?pageForm?分頁(yè)表單
?????*?@return?返回分頁(yè)信息
?????*/
????@ApiModelProperty(hidden?=?true)
????public?PageVo?setCurrentAndSize(PageForm>?pageForm) {
????????BeanUtils.copyProperties(pageForm,this);
????????return?this;
????}
????/**
?????*?設(shè)置總記錄數(shù)
?????*?@param?total?總記錄數(shù)
?????*/
????@ApiModelProperty(hidden?=?true)
????public?void?setTotal(Integer?total)?{
????????this.total?=?total;
????????this.setPages(this.total?%?this.size?>?0???this.total?/?this.size?+?1?:?this.total?/?this.size);
????}
}復(fù)制代碼
案例
ListUserForm
@Data
@ApiModel("獲取用戶(hù)列表需要的表單數(shù)據(jù)")
@EqualsAndHashCode(callSuper?=?false)
public?class?ListUserForm?extends?PageForm<ListUserForm>?{
????/**
?????*?用戶(hù)狀態(tài)
?????*/
????@ApiModelProperty("用戶(hù)狀態(tài)")
????@NotEmpty(message?=?"用戶(hù)狀態(tài)不能為空")
????@Range(min?=??-1?,?max?=?1?,?message?=?"用戶(hù)狀態(tài)有誤")
????private?String?status;
}復(fù)制代碼
UserServiceImpl
/**
?*?獲取用戶(hù)列表
?*?@param?listUserForm?表單數(shù)據(jù)
?*?@return?用戶(hù)列表
?*/
@Override
public?PageVo?listUser(ListUserForm?listUserForm)? {
????PageVo?pageVo?=?new?PageVo ().setCurrentAndSize(listUserForm);
????pageVo.setTotal(countUser(listUserForm.getStatus()));
????pageVo.setRecords(userMapper.listUser(listUserForm.calcCurrent()));
????return?pageVo;
}
/**
?*?獲取用戶(hù)數(shù)量
?*?@param?status?狀態(tài)
?*?@return?用戶(hù)數(shù)量
?*/
private?Integer?countUser(String?status){
????return?count(new?QueryWrapper().eq("status",status));
}復(fù)制代碼
UserController
/**
?*?獲取用戶(hù)列表
?*?@param?listUserForm?表單數(shù)據(jù)
?*?@return?用戶(hù)列表
?*/
@ApiOperation("獲取用戶(hù)列表")
@GetMapping("/listUser")
@ApiResponses(
????????@ApiResponse(code?=?200,?message?=?"操作成功",?response?=?UserVo.class)
)
public?ResultVo?listUser(@Validated?ListUserForm?listUserForm){
????return?ResultVoUtil.success(userService.listUser(listUserForm));
}復(fù)制代碼
注意的點(diǎn)
PageVo在實(shí)例化的時(shí)候需要設(shè)置當(dāng)前頁(yè)和每頁(yè)顯示的數(shù)量?可以調(diào)用
setCurrentAndSize()完成。進(jìn)行分頁(yè)查詢(xún)的時(shí)候,需要計(jì)算偏移量。
listUserForm.calcCurrent()
假如查詢(xún)第1頁(yè)每頁(yè)顯示10條記錄,前端傳遞過(guò)來(lái)的參數(shù)是
current=1&&size=10,這個(gè)時(shí)候limit 1,10沒(méi)有問(wèn)題。假如查詢(xún)第2頁(yè)每頁(yè)顯示10條記錄,前端傳遞過(guò)來(lái)的參數(shù)是
current=2&&size=10,這個(gè)時(shí)候limit 2,10就有問(wèn)題,實(shí)際應(yīng)該是limit 10,10。calcCurrent()的作用就是如此。
自帶的分頁(yè)查詢(xún)?cè)诖罅繑?shù)據(jù)下,會(huì)出現(xiàn)性能問(wèn)題。
常用工具類(lèi)
異常處理
異常信息拋出 ->?
ControllerAdvice?進(jìn)行捕獲格式化輸出內(nèi)容手動(dòng)拋出
CustomException并傳入ReulstEnum?——> 進(jìn)行捕獲錯(cuò)誤信息輸出錯(cuò)誤信息。
自定義異常
@Data
@EqualsAndHashCode(callSuper?=?false)
public?class?CustomException?extends?RuntimeException?{
????/**
?????*?狀態(tài)碼
?????*/
????private?final?Integer?code;
????/**
?????*?方法名稱(chēng)
?????*/
????private?final?String?method;
????/**
?????*?自定義異常
?????*
?????*?@param?resultEnum?返回枚舉對(duì)象
?????*?@param?method?????方法
?????*/
????public?CustomException(ResultEnum?resultEnum,?String?method)?{
????????super(resultEnum.getMsg());
????????this.code?=?resultEnum.getCode();
????????this.method?=?method;
????}
????/**
?????*?@param?code????狀態(tài)碼
?????*?@param?message?錯(cuò)誤信息
?????*?@param?method??方法
?????*/
????public?CustomException(Integer?code,?String?message,?String?method)?{
????????super(message);
????????this.code?=?code;
????????this.method?=?method;
????}
}復(fù)制代碼
錯(cuò)誤信息枚舉
@Getter
public?enum?ResultEnum?{
????/**
?????*?未知異常
?????*/
????UNKNOWN_EXCEPTION(100,?"未知異常"),
????/**
?????*?添加失敗
?????*/
????ADD_ERROR(103,?"添加失敗"),
????/**
?????*?更新失敗
?????*/
????UPDATE_ERROR(104,?"更新失敗"),
????/**
?????*?刪除失敗
?????*/
????DELETE_ERROR(105,?"刪除失敗"),
????/**
?????*?查找失敗
?????*/
????GET_ERROR(106,?"查找失敗"),
????;
????private?Integer?code;
????private?String?msg;
????ResultEnum(Integer?code,?String?msg)?{
????????this.code?=?code;
????????this.msg?=?msg;
????}
????/**
?????*?通過(guò)狀態(tài)碼獲取枚舉對(duì)象
?????*?@param?code?狀態(tài)碼
?????*?@return?枚舉對(duì)象
?????*/
????public?static?ResultEnum?getByCode(int?code){
????????for?(ResultEnum?resultEnum?:?ResultEnum.values())?{
????????????if(code?==?resultEnum.getCode()){
????????????????return?resultEnum;
????????????}
????????}
????????return?null;
????}
}復(fù)制代碼
全局異常攔截
@ControllerAdvice進(jìn)行實(shí)現(xiàn),常用的異常攔截配置可以查看?GlobalExceptionHandling。@Slf4j
@RestControllerAdvice
public?class?GlobalExceptionHandling?{
????/**
?????*?自定義異常
?????*/
????@ExceptionHandler(value?=?CustomException.class)
????public?ResultVo?processException(CustomException?e)?{
????????log.error("位置:{}?->?錯(cuò)誤信息:{}",?e.getMethod()?,e.getLocalizedMessage());
????????return?ResultVoUtil.error(Objects.requireNonNull(ResultEnum.getByCode(e.getCode())));
????}
????/**
?????*?通用異常
?????*/
????@ResponseStatus(HttpStatus.OK)
????@ExceptionHandler(Exception.class)
????public?ResultVo?exception(Exception?e)?{
????????e.printStackTrace();
????????return?ResultVoUtil.error(ResultEnum.UNKNOWN_EXCEPTION);
????}
}復(fù)制代碼
案例
Controller
/**
?*?刪除用戶(hù)
?*?@param?id?用戶(hù)編號(hào)
?*?@return?成功或者失敗
?*/
@ApiOperation("刪除用戶(hù)")
@DeleteMapping("/deleteUser/{id}")
public?ResultVo?deleteUser(@PathVariable("id")?String?id){
????userService.deleteUser(id);
????return?ResultVoUtil.success();
}復(fù)制代碼
Service
/**
?*?刪除用戶(hù)
?*?@param?id?id
?*/
@Override
public?void?deleteUser(String?id)?{
????//?如果刪除失敗拋出異常。?--?演示而已不推薦這樣干
????if(!removeById(id)){
????????throw?new?CustomException(ResultEnum.DELETE_ERROR,?MethodUtil.getLineInfo());
????}
}復(fù)制代碼
結(jié)果
注意的點(diǎn)
ResultEnum進(jìn)行統(tǒng)一維護(hù)。不同的業(yè)務(wù)使用不同的錯(cuò)誤碼。方便在報(bào)錯(cuò)時(shí)進(jìn)行分辨。快速定位問(wèn)題。多環(huán)境配置
SpringBoot多環(huán)境配置
dev,test,pre,prod,對(duì)于SpringBoot項(xiàng)目多建立幾個(gè)配置文件就可以了。然后啟動(dòng)的時(shí)候可以通過(guò)配置spring.profiles.active?來(lái)選擇啟動(dòng)的環(huán)境。java?-jar?BasicProject.jar?--spring.profiles.active=prod?? 復(fù)制代碼
Maven多環(huán)境配置
配置XML
<profiles>
????<profile>
????????
????????<id>devid>
????????<activation>
????????????<activeByDefault>trueactiveByDefault>
????????activation>
????????<properties>
????????????<activatedProperties>devactivatedProperties>
????????properties>
????profile>
????<profile>
????????
????????<id>testid>
????????<properties>
????????????<activatedProperties>testactivatedProperties>
????????properties>
????profile>
????<profile>
????????
????????<id>preid>
????????<properties>
????????????<activatedProperties>preactivatedProperties>
????????properties>
????profile>
????<profile>
????????
????????<id>prodid>
????????<properties>
????????????<activatedProperties>prodactivatedProperties>
????????properties>
????profile>
profiles>復(fù)制代碼
更改application.yml
spring:
??profiles:
????#?選擇環(huán)境
????active:?@activatedProperties@復(fù)制代碼
使用案例
mvn?clean?package?-P?prod
mvn?clean?package?-P?pre
mvn?clean?package?-P?test復(fù)制代碼
application.yml?會(huì)發(fā)現(xiàn)spring.profiles.active=@activatedProperties@?發(fā)生了改變。日志配置
JenkinsFile
代碼地址
https://gitee.com/huangxunhui/basic_project.git
慢一點(diǎn)才能更快
推薦閱讀:
微信掃描二維碼,關(guān)注我的公眾號(hào)
朕已閱?

