<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>

          一份 Spring Boot 項目搭建模板 ~

          共 3982字,需瀏覽 8分鐘

           ·

          2020-11-11 02:40


          來源:juejin.im/post/6844904083942277127

          • 前言
          • 基礎(chǔ)項目該包含哪些東西。
          • Swagger
          • CodeGenerator代碼生成器。
          • 常用的封裝
          • 通用的分頁對象
          • 常用工具類
          • 異常處理
          • 多環(huán)境配置
          • 日志配置
          • JenkinsFile
          • 代碼地址
          • 結(jié)尾

          前言

          建立一個全新的項目,或者把舊的龐大的項目,進行拆分成多個項目。在建立新的項目中,經(jīng)常需要做一些重復的工作,比如說拷貝一下常用的工具類,通用代碼等等。所以就可以做一個基礎(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ù)。當然這一切都需要在代碼中進行配置。

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

          常用的Swagger注解

          • @Api用于Controller
          • @ApiOperation用于Controller內(nèi)的方法。
          • @ApiResponses用于標識接口返回數(shù)據(jù)的類型。
          • @ApiModel用于標識類的名稱
          • @ApiModelProperty用于標識屬性的名稱

          案例

          @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<ListUserForm>?{

          ????/**
          ?????*?用戶狀態(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<T>?{

          ????/**
          ?????*?獲取實例
          ?????*?@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<User>?{

          ????/**
          ?????*?昵稱
          ?????*/

          ????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>service不需要關(guān)心form如何轉(zhuǎn)變成entity,只需要在使用的時候調(diào)用buildEntity()即可,尤其是在form -> entity相對復雜的時候,這樣做可以減少service內(nèi)的代碼。讓代碼邏輯看起來更加清晰。


          通用的分頁對象

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

          PageForm

          @Data
          @ApiModel(value?=?"分頁數(shù)據(jù)",?description?=?"分頁需要的表單數(shù)據(jù)")
          public?class?PageForm<T?extends?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;

          ????/**
          ?????*?計算當前頁?,方便mysql?進行分頁查詢
          ?????*?@return?返回?pageForm
          ?????*/

          ????@ApiModelProperty(hidden?=?true)
          ????public?T?calcCurrent(){
          ????????current?=?(current?-?1?)?*?size;
          ????????return?(T)?this;
          ????}
          }

          PageVo

          @Data
          public?class?PageVo<T>?{
          ????/**
          ?????*?分頁數(shù)據(jù)
          ?????*/

          ????@ApiModelProperty(value?=?"分頁數(shù)據(jù)")
          ????private?List?records;
          ????/**
          ?????*?總條數(shù)
          ?????*/

          ????@ApiModelProperty(value?=?"總條數(shù)")
          ????private?Integer?total;

          ????/**
          ?????*?總頁數(shù)
          ?????*/

          ????@ApiModelProperty(value?=?"總頁數(shù)")
          ????private?Integer?pages;

          ????/**
          ?????*?當前頁
          ?????*/

          ????@ApiModelProperty(value?=?"當前頁")
          ????private?Integer?current;

          ????/**
          ?????*?查詢數(shù)量
          ?????*/

          ????@ApiModelProperty(value?=?"查詢數(shù)量")
          ????private?Integer?size;

          ????/**
          ?????*?設(shè)置當前頁和每頁顯示的數(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<ListUserForm>?{

          ????/**
          ?????*?用戶狀態(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è)置當前頁每頁顯示的數(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ā)習慣引入。


          異常處理

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

          • 異常信息拋出 -> 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


          <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>

          更改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日志配置

          JenkinsFile

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


          代碼地址

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

          結(jié)尾

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

          END


          有熱門推薦?

          1.?實戰(zhàn)篇:一個核心系統(tǒng) 3 萬多行代碼的重構(gòu)之旅

          2.?IntelliJ IDEA 超全優(yōu)化設(shè)置,效率杠杠的!

          3.?自從上線了 Prometheus 監(jiān)控告警,真香!

          4.?RabbitMQ 線上事故!慌的一批,腦袋一片空白。。。

          最近面試BAT,整理一份面試資料Java面試BATJ通關(guān)手冊,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫、數(shù)據(jù)結(jié)構(gòu)等等。

          獲取方式:點“在看”,關(guān)注公眾號并回復?Java?領(lǐng)取,更多內(nèi)容陸續(xù)奉上。

          文章有幫助的話,在看,轉(zhuǎn)發(fā)吧。

          謝謝支持喲 (*^__^*)

          瀏覽 36
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  麻豆天天爱天天 | 你懂的视频在线 | 久久久91av | 考逼网| 午夜视频一区二区 |