<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一個 SpringBoot 項目該包含哪些?

          共 4154字,需瀏覽 9分鐘

           ·

          2020-10-18 08:25

          ?點? Stephen?關(guān) 注 我?



          作者:不一樣的科技宅??

          juejin.im/post/6844904083942277127


          前言

          建立一個全新的項目,或者把舊的龐大的項目,進行拆分成多個項目。在建立新的項目中,經(jīng)常需要做一些重復(fù)的工作,比如說拷貝一下常用的工具類,通用代碼等等。

          所以就可以做一個基礎(chǔ)的項目方便使用,在經(jīng)歷新項目的時候,直接在基礎(chǔ)項目上進行簡單配置就可以開發(fā)業(yè)務(wù)代碼了。

          基礎(chǔ)項目該包含哪些東西。

          • Swagger在線接口文檔。

          • CodeGenerator 代碼生成器。

          • 統(tǒng)一返回。

          • 通用的分頁對象。

          • 常用工具類。

          • 全局異常攔截。

          • 錯誤枚舉。

          • 自定義異常。

          • 多環(huán)境配置文件。

          • Maven多環(huán)境配置。

          • 日志配置。

          • JenkinsFile。

          可以在討論區(qū)進行補充


          Swagger

          寫接口文檔通常是一件比較頭疼的事情,然而swagger就用是用來幫我們解決這個問題的。可以在線生成接口文檔,并且可以在頁面上進行測試。

          可以非常清楚的顯示,請求數(shù)據(jù)已經(jīng)響應(yīng)數(shù)據(jù)。當(dāng)然這一切都需要在代碼中進行配置。

          「注意的點:接口文檔只能在測試/開發(fā)環(huán)境開啟,其他環(huán)境請關(guān)閉。」

          常用的Swagger注解

          • @Api用于Controller

          • @ApiOperation用于Controller內(nèi)的方法。

          • @ApiResponses用于標(biāo)識接口返回數(shù)據(jù)的類型。

          • @ApiModel用于標(biāo)識類的名稱

          • @ApiModelProperty用于標(biāo)識屬性的名稱

          案例

          @RestController??
          @Api(tags?=?"用戶")??
          @AllArgsConstructor??
          @RequestMapping("/user")??
          public?class?UserController?{??
          ??
          ????private?IUserService?userService;??
          ??
          ????/**??
          ?????*?獲取用戶列表??
          ?????*?@param?listUserForm?表單數(shù)據(jù)??
          ?????*?@return?用戶列表??
          ?????*/??
          ????@ApiOperation("獲取用戶列表")??
          ????@GetMapping("/listUser")??
          ????@ApiResponses(??
          ????????????@ApiResponse(code?=?200,?message?=?"操作成功",?response?=?UserVo.class)??
          ????)??
          ????public?ResultVo?listUser(@Validated?ListUserForm?listUserForm){??
          ????????return?ResultVoUtil.success(userService.listUser(listUserForm));??
          ????}??
          ??
          }??
          ?
          @Data??
          @ApiModel("獲取用戶列表需要的表單數(shù)據(jù)")??
          @EqualsAndHashCode(callSuper?=?false)??
          public?class?ListUserForm?extends?PageForm?{??
          ??
          ????/**??
          ?????*?用戶狀態(tài)??
          ?????*/??
          ????@ApiModelProperty("用戶狀態(tài)")??
          ????@NotEmpty(message?=?"用戶狀態(tài)不能為空")??
          ????@Range(min?=??-1?,?max?=?1?,?message?=?"用戶狀態(tài)有誤")??
          ????private?String?status;??
          ??
          }??

          對應(yīng)的swagger的配置可以查看基礎(chǔ)項目內(nèi)的SwaggerConfiguration.java.

          CodeGenerator代碼生成器。

          mybatis_plus代碼生成器可以幫我們生成entity,service,serviceImpl,mapper,mapper.xml。省去了建立一大堆實體類的麻煩。

          由于配置太長這里就不貼出來了,對應(yīng)的CodeGenerator的配置可以查看基礎(chǔ)項目內(nèi)的CodeGenerator.java.


          常用的封裝

          統(tǒng)一返回 ResultVo

          將所有的接口的響應(yīng)數(shù)據(jù)的格式進行統(tǒng)一。

          @Data??
          @ApiModel("固定返回格式")??
          public?class?ResultVo?{??
          ??
          ????/**??
          ?????*?錯誤碼??
          ?????*/??
          ????@ApiModelProperty("錯誤碼")??
          ????private?Integer?code;??
          ??
          ????/**??
          ?????*?提示信息??
          ?????*/??
          ????@ApiModelProperty("提示信息")??
          ????private?String?message;??
          ??
          ????/**??
          ?????*?具體的內(nèi)容??
          ?????*/??
          ????@ApiModelProperty("響應(yīng)數(shù)據(jù)")??
          ????private?Object?data;??
          ??
          }??

          抽象表單 BaseForm

          public?abstract?class?BaseForm?{??
          ??
          ????/**??
          ?????*?獲取實例??
          ?????*?@return?返回實體類??
          ?????*/??
          ????public?abstract?T?buildEntity();??
          ??
          }??

          有小伙伴可能有疑問了,這個類有啥用呢。先看一下,下面的代碼。

          /**??
          ?*?添加用戶??
          ?*?@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);??
          }??

          重構(gòu)一下,感覺清爽了一些。

          /**??
          ?*?添加用戶??
          ?*?@param?userForm?表單數(shù)據(jù)??
          ?*?@return?true?或者?false??
          ?*/??
          @Override??
          public?boolean?addUser(AddUserForm?userForm)?{??
          ????User?user?=?new?User();??
          ????BeanUtils.copyProperties(this,user);??
          ????return?save(user);??
          }??
          ?

          使用BaseForm進行重構(gòu) AddUserForm 繼承 BaseForm并重寫buildEntity

          @Data??
          @EqualsAndHashCode(callSuper?=?false)??
          public?class?AddUserForm?extends?BaseForm?{??
          ??
          ????/**??
          ?????*?昵稱??
          ?????*/??
          ????private?String?nickname;??
          ??
          ????/**??
          ?????*?生日??
          ?????*/??
          ????private?Date?birthday;??
          ??
          ????/**??
          ?????*?用戶名??
          ?????*/??
          ????private?String?username;??
          ??
          ????/**??
          ?????*?密碼??
          ?????*/??
          ????private?String?password;??
          ??
          ????/**??
          ?????*?構(gòu)造實體??
          ?????*?@return?實體對象??
          ?????*/??
          ????@Override??
          ????public?User?buildEntity()?{??
          ????????User?user?=?new?User();??
          ????????BeanUtils.copyProperties(this,user);??
          ????????return?user;??
          ????}??
          }??
          /**??
          ?*?添加用戶??
          ?*?@param?userForm?表單數(shù)據(jù)??
          ?*?@return?true?或者?false??
          ?*/??
          @Override??
          public?boolean?addUser(AddUserForm?userForm)?{??
          ????return?save(userForm.buildEntity());??
          }??

          上面的代碼有沒有種似曾相識的感覺,很多情況都是將接受到的參數(shù),轉(zhuǎn)變成對應(yīng)的實體類然后「保存」或者「更新」

          所以對于這類的form可以繼承baseform并實現(xiàn)buildEntity()這樣可以更加符合面向?qū)ο螅?code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;border-radius: 4px;background-color: rgba(27, 31, 35, 0.047);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;box-sizing: border-box !important;overflow-wrap: break-word !important;">service不需要關(guān)心form如何轉(zhuǎn)變成entity,只需要在使用的時候調(diào)用buildEntity()即可,尤其是在form?->?entity相對復(fù)雜的時候,這樣做可以減少service內(nèi)的代碼。讓代碼邏輯看起來更加清晰。


          通用的分頁對象

          涉及到查詢的時候,絕大多數(shù)都需要用到分頁,所以說封裝分頁對象就很有必要。可以注意下?PageForm.calcCurrent()PageVo.setCurrentAndSize()PageVo.setTotal()這個幾個方法。

          PageForm

          @Data??
          @ApiModel(value?=?"分頁數(shù)據(jù)",?description?=?"分頁需要的表單數(shù)據(jù)")??
          public?class?PageForm>{??
          ??
          ????/**??
          ?????*?頁碼??
          ?????*/??
          ????@ApiModelProperty(value?=?"頁碼?從第一頁開始?1")??
          ????@Min(value?=?1,?message?=?"頁碼輸入有誤")??
          ????private?Integer?current;??
          ??
          ????/**??
          ?????*?每頁顯示的數(shù)量??
          ?????*/??
          ????@ApiModelProperty(value?=?"每頁顯示的數(shù)量?范圍在1~100")??
          ????@Range(min?=?1,?max?=?100,?message?=?"每頁顯示的數(shù)量輸入有誤")??
          ????private?Integer?size;??
          ??
          ????/**??
          ?????*?計算當(dāng)前頁?,方便mysql?進行分頁查詢??
          ?????*?@return?返回?pageForm??
          ?????*/??
          ????@ApiModelProperty(hidden?=?true)??
          ????public?T?calcCurrent(){??
          ????????current?=?(current?-?1?)?*?size;??
          ????????return?(T)?this;??
          ????}??
          }??

          PageVo

          @Data??
          public?class?PageVo?{??
          ????/**??
          ?????*?分頁數(shù)據(jù)??
          ?????*/??
          ????@ApiModelProperty(value?=?"分頁數(shù)據(jù)")??
          ????private?List?records;??
          ????/**??
          ?????*?總條數(shù)??
          ?????*/??
          ????@ApiModelProperty(value?=?"總條數(shù)")??
          ????private?Integer?total;??
          ??
          ????/**??
          ?????*?總頁數(shù)??
          ?????*/??
          ????@ApiModelProperty(value?=?"總頁數(shù)")??
          ????private?Integer?pages;??
          ??
          ????/**??
          ?????*?當(dāng)前頁??
          ?????*/??
          ????@ApiModelProperty(value?=?"當(dāng)前頁")??
          ????private?Integer?current;??
          ??
          ????/**??
          ?????*?查詢數(shù)量??
          ?????*/??
          ????@ApiModelProperty(value?=?"查詢數(shù)量")??
          ????private?Integer?size;??
          ??
          ????/**??
          ?????*?設(shè)置當(dāng)前頁和每頁顯示的數(shù)量??
          ?????*?@param?pageForm?分頁表單??
          ?????*?@return?返回分頁信息??
          ?????*/??
          ????@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);??
          ????}??
          }??

          案例

          ListUserForm
          @Data??
          @ApiModel("獲取用戶列表需要的表單數(shù)據(jù)")??
          @EqualsAndHashCode(callSuper?=?false)??
          public?class?ListUserForm?extends?PageForm?{??
          ??
          ????/**??
          ?????*?用戶狀態(tài)??
          ?????*/??
          ????@ApiModelProperty("用戶狀態(tài)")??
          ????@NotEmpty(message?=?"用戶狀態(tài)不能為空")??
          ????@Range(min?=??-1?,?max?=?1?,?message?=?"用戶狀態(tài)有誤")??
          ????private?String?status;??
          ??
          }??
          UserServiceImpl
          /**??
          ?*?獲取用戶列表??
          ?*?@param?listUserForm?表單數(shù)據(jù)??
          ?*?@return?用戶列表??
          ?*/??
          @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;??
          }??
          ??
          /**??
          ?*?獲取用戶數(shù)量??
          ?*?@param?status?狀態(tài)??
          ?*?@return?用戶數(shù)量??
          ?*/??
          private?Integer?countUser(String?status){??
          ????return?count(new?QueryWrapper().eq("status",status));??
          }??
          UserController
          /**??
          ?*?獲取用戶列表??
          ?*?@param?listUserForm?表單數(shù)據(jù)??
          ?*?@return?用戶列表??
          ?*/??
          @ApiOperation("獲取用戶列表")??
          @GetMapping("/listUser")??
          @ApiResponses(??
          ????????@ApiResponse(code?=?200,?message?=?"操作成功",?response?=?UserVo.class)??
          )??
          public?ResultVo?listUser(@Validated?ListUserForm?listUserForm){??
          ????return?ResultVoUtil.success(userService.listUser(listUserForm));??
          }??

          注意的點
          • PageVo在實例化的時候需要設(shè)置「當(dāng)前頁」「每頁顯示的數(shù)量」?可以調(diào)用setCurrentAndSize()完成。

          • 進行分頁查詢的時候,需要計算偏移量。listUserForm.calcCurrent()

          為什么要計算偏移量呢?

          • 假如查詢第1頁每頁顯示10條記錄,前端傳遞過來的參數(shù)是current=1&&size=10,這個時候limit 1,10沒有問題。

          • 假如查詢第2頁每頁顯示10條記錄,前端傳遞過來的參數(shù)是current=2&&size=10,這個時候limit 2,10就有問題,實際應(yīng)該是limit 10,10calcCurrent()的作用就是如此

          為什么不用MybatisPlus自帶的分頁插件呢?

          自帶的分頁查詢在大量數(shù)據(jù)下,會出現(xiàn)性能問題。

          常用工具類

          常用工具類可以根據(jù)自己的開發(fā)習(xí)慣引入。


          異常處理

          異常處理的大致流程主要如下。

          • 異常信息拋出 ->?ControllerAdvice?進行捕獲格式化輸出內(nèi)容

          • 手動拋出CustomException并傳入ReulstEnum?——> 進行捕獲錯誤信息輸出錯誤信息。

          自定義異常

          @Data??
          @EqualsAndHashCode(callSuper?=?false)??
          public?class?CustomException?extends?RuntimeException?{??
          ??
          ????/**??
          ?????*?狀態(tài)碼??
          ?????*/??
          ????private?final?Integer?code;??
          ??
          ????/**??
          ?????*?方法名稱??
          ?????*/??
          ????private?final?String?method;??
          ??
          ??
          ????/**??
          ?????*?自定義異常??
          ?????*??
          ?????*?@param?resultEnum?返回枚舉對象??
          ?????*?@param?method?????方法??
          ?????*/??
          ????public?CustomException(ResultEnum?resultEnum,?String?method)?{??
          ????????super(resultEnum.getMsg());??
          ????????this.code?=?resultEnum.getCode();??
          ????????this.method?=?method;??
          ????}??
          ??
          ????/**??
          ?????*?@param?code????狀態(tài)碼??
          ?????*?@param?message?錯誤信息??
          ?????*?@param?method??方法??
          ?????*/??
          ????public?CustomException(Integer?code,?String?message,?String?method)?{??
          ????????super(message);??
          ????????this.code?=?code;??
          ????????this.method?=?method;??
          ????}??
          ??
          }??

          錯誤信息枚舉

          根據(jù)業(yè)務(wù)進行添加。

          @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;??
          ????}??
          ??
          ????/**??
          ?????*?通過狀態(tài)碼獲取枚舉對象??
          ?????*?@param?code?狀態(tài)碼??
          ?????*?@return?枚舉對象??
          ?????*/??
          ????public?static?ResultEnum?getByCode(int?code){??
          ????????for?(ResultEnum?resultEnum?:?ResultEnum.values())?{??
          ????????????if(code?==?resultEnum.getCode()){??
          ????????????????return?resultEnum;??
          ????????????}??
          ????????}??
          ????????return?null;??
          ????}??
          ??
          }??

          全局異常攔截

          全局異常攔截是使用@ControllerAdvice進行實現(xiàn),常用的異常攔截配置可以查看 GlobalExceptionHandling。

          @Slf4j??
          @RestControllerAdvice??
          public?class?GlobalExceptionHandling?{??
          ??
          ????/**??
          ?????*?自定義異常??
          ?????*/??
          ????@ExceptionHandler(value?=?CustomException.class)??
          ????public?ResultVo?processException(CustomException?e)?{??
          ????????log.error("位置:{}?->?錯誤信息:{}",?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);??
          ????}??
          }??

          案例

          Controller
          /**??
          ?*?刪除用戶??
          ?*?@param?id?用戶編號??
          ?*?@return?成功或者失敗??
          ?*/??
          @ApiOperation("刪除用戶")??
          @DeleteMapping("/deleteUser/{id}")??
          public?ResultVo?deleteUser(@PathVariable("id")?String?id){??
          ????userService.deleteUser(id);??
          ????return?ResultVoUtil.success();??
          }??
          Service
          /**??
          ?*?刪除用戶??
          ?*?@param?id?id??
          ?*/??
          @Override??
          public?void?deleteUser(String?id)?{??
          ????//?如果刪除失敗拋出異常。?--?演示而已不推薦這樣干??
          ????if(!removeById(id)){??
          ????????throw?new?CustomException(ResultEnum.DELETE_ERROR,?MethodUtil.getLineInfo());??
          ????}??
          }??
          結(jié)果

          「將報錯代碼所在的文件第多少行都打印出來。方便排查。」

          注意的點

          所有手動拋出的錯誤信息,都應(yīng)在錯誤信息枚舉ResultEnum進行統(tǒng)一維護。不同的業(yè)務(wù)使用不同的錯誤碼。方便在報錯時進行分辨。快速定位問題。


          多環(huán)境配置

          SpringBoot多環(huán)境配置

          對于一個項目來講基本都4有個環(huán)境dev,test,pre,prod,對于SpringBoot項目多建立幾個配置文件就可以了。

          然后啟動的時候可以通過配置spring.profiles.active?來選擇啟動的環(huán)境。

          java?-jar?BasicProject.jar?--spring.profiles.active=prod??

          Maven多環(huán)境配置

          假如想在打包的時候動態(tài)指定環(huán)境,這個時候就需要借助Maven的xml來實現(xiàn)。

          配置XML
          ??
          ??
          ??????
          ??????????
          ????????dev??
          ??????????
          ????????????true??
          ????????
          ??
          ??????????
          ????????????dev??
          ????????
          ??
          ????
          ??
          ??????
          ??????????
          ????????test??
          ??????????
          ????????????test??
          ????????
          ??
          ????
          ??
          ??????
          ??????????
          ????????pre??
          ??????????
          ????????????pre??
          ????????
          ??
          ????
          ??
          ??????
          ??????????
          ????????prod??
          ??????????
          ????????????prod??
          ????????
          ??
          ????
          ??
          ??
          更改application.yml
          spring:??
          ??profiles:??
          ????#?選擇環(huán)境??
          ????active:?@activatedProperties@??
          使用案例
          mvn?clean?package?-P?prod??
          mvn?clean?package?-P?pre??
          mvn?clean?package?-P?test??

          打包完可以解壓開查看application.yml?會發(fā)現(xiàn)spring.profiles.active=@activatedProperties@?發(fā)生了改變。


          日志配置

          采用logback日志配置,參考

          https://gitee.com/huangxunhui/basic_project/blob/master/src/main/resources/logback-spring.xml

          JenkinsFile

          JenkinsFile肯定顧名思義是給jenkins用的。主要是配置項目根據(jù)如何進行構(gòu)建并發(fā)布到不同的環(huán)境。需要去了解pipeline語法,以及如何配置jenkins

          代碼地址

          https://gitee.com/huangxunhui/basic_project.git

          結(jié)尾

          ??如果覺得對你有幫助,可以多多評論,多多點贊哦,也可以到我的主頁看看,說不定有你喜歡的文章,也可以隨手點個關(guān)注哦,謝謝。



          瀏覽 40
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产日韩在线欧美视频免费观看 | 欧美在线观看视频 | 日本三级韩国三级欧美三级 | 国产成人精品午夜精品 | 国内三级免费看 |