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

          一個(gè) SpringBoot 項(xiàng)目該包含哪些?

          共 27775字,需瀏覽 56分鐘

           ·

          2021-03-14 14:07

          小編領(lǐng)讀:

          你會搭建一個(gè)springboot項(xiàng)目嗎?有哪些點(diǎn)需要注意的?其實(shí)都差不多,記住幾個(gè)流程!


          作者:不一樣的科技宅

          juejin.im/post/6844904083942277127

          前言

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

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

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

          • Swagger 在線接口文檔。

          • CodeGenerator 代碼生成器。

          • 統(tǒng)一返回。

          • 通用的分頁對象。

          • 常用工具類。

          • 全局異常攔截。

          • 錯(cuò)誤枚舉。

          • 自定義異常。

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

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

          • 日志配置。

          • JenkinsFile。

          ?

          可以在評論區(qū)進(jìn)行補(bǔ)充

          ?

          Swagger

          寫接口文檔通常是一件比較頭疼的事情,然而 swagger 就用是用來幫我們解決這個(gè)問題的??梢栽诰€生成接口文檔,并且可以在頁面上進(jìn)行測試。

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

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

          常用的 Swagger 注解

          • @Api用于Controller

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

          • @ApiResponses用于標(biāo)識接口返回?cái)?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<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ǔ)項(xiàng)目內(nèi)的SwaggerConfiguration.java.

          CodeGenerator 代碼生成器。

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

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

          搜索公縱號:MarkerHub,關(guān)注回復(fù)[ vue ]獲取前后端入門教程!

          常用的封裝

          統(tǒng)一返回 ResultVo

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

          @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;  
            
          }  


          抽象表單 BaseForm

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


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

          /**  
           * 添加用戶  
           * @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 進(jìn)行重構(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)造實(shí)體  
               * @return 實(shí)體對象  
               */
            
              @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)的實(shí)體類然后**「保存」或者「更新」**。

          所以對于這類的form可以繼承baseform并實(shí)現(xiàn)buildEntity()這樣可以更加符合面向?qū)ο螅?code style="padding-right: 5px;padding-left: 5px;font-family: Courier, "Courier New", monospace;background-color: bisque;">service不需要關(guān)心form如何轉(zhuǎn)變成entity, 只需要在使用的時(shí)候調(diào)用buildEntity()即可,尤其是在form -> entity相對復(fù)雜的時(shí)候,這樣做可以減少service內(nèi)的代碼。讓代碼邏輯看起來更加清晰。

          通用的分頁對象

          涉及到查詢的時(shí)候,絕大多數(shù)都需要用到分頁,所以說封裝分頁對象就很有必要??梢宰⒁庀?nbsp;PageForm.calcCurrent()PageVo.setCurrentAndSize()、PageVo.setTotal()這個(gè)幾個(gè)方法。

          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;  
            
              /**  
               * 計(jì)算當(dāng)前頁 ,方便mysql 進(jìn)行分頁查詢  
               * @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<T> 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<T> 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<UserVo> listUser(ListUserForm listUserForm) {  
              PageVo<UserVo> pageVo = new PageVo<UserVo>().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<User>().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));  
          }  


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

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

          為什么要計(jì)算偏移量呢?

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

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

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

          ?

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

          ?

          常用工具類

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

          異常處理

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

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

          • 手動拋出CustomException并傳入ReulstEnum ——> 進(jìn)行捕獲錯(cuò)誤信息輸出錯(cuò)誤信息。

          自定義異常

          @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 錯(cuò)誤信息  
               * @param method  方法  
               */
            
              public CustomException(Integer code, String message, String method) {  
                  super(message);  
                  this.code = code;  
                  this.method = method;  
              }  
            
          }  


          錯(cuò)誤信息枚舉

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

          @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進(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);  
              }  
          }  


          案例

          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é)果

          「將報(bào)錯(cuò)代碼所在的文件第多少行都打印出來。方便排查?!?/strong>

          注意的點(diǎn)

          所有手動拋出的錯(cuò)誤信息,都應(yīng)在錯(cuò)誤信息枚舉ResultEnum進(jìn)行統(tǒng)一維護(hù)。不同的業(yè)務(wù)使用不同的錯(cuò)誤碼。方便在報(bào)錯(cuò)時(shí)進(jìn)行分辨??焖俣ㄎ粏栴}。

          多環(huán)境配置

          SpringBoot 多環(huán)境配置

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

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

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


          Maven 多環(huán)境配置

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

          配置 XML
          <!--  配置環(huán)境  -->  
          <profiles>  
              <profile>  
                  <!-- 開發(fā) -->  
                  <id>dev</id>  
                  <activation>  
                      <activeByDefault>true</activeByDefault>  
                  </activation>  
                  <properties>  
                      <activatedProperties>dev</activatedProperties>  
                  </properties>  
              </profile>  
              <profile>  
                  <!-- 測試 -->  
                  <id>test</id>  
                  <properties>  
                      <activatedProperties>test</activatedProperties>  
                  </properties>  
              </profile>  
              <profile>  
                  <!-- 準(zhǔn)生產(chǎn) -->  
                  <id>pre</id>  
                  <properties>  
                      <activatedProperties>pre</activatedProperties>  
                  </properties>  
              </profile>  
              <profile>  
                  <!-- 生產(chǎn) -->  
                  <id>prod</id>  
                  <properties>  
                      <activatedProperties>prod</activatedProperties>  
                  </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 日志配置,參考

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

          JenkinsFile

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

          結(jié)尾

          如果覺得對你有幫助,可以隨手點(diǎn)個(gè)在看哦,謝謝。

          -END-


          PS:歡迎在留言區(qū)留下你的觀點(diǎn),一起討論提高。如果今天的文章讓你有新的啟發(fā),歡迎轉(zhuǎn)發(fā)分享給更多人。

          Java后端編程交流群已成立

          公眾號運(yùn)營至今,離不開小伙伴們的支持。為了給小伙伴們提供一個(gè)互相交流的平臺,特地開通了官方交流群。掃描下方二維碼備注 進(jìn)群 或者關(guān)注公眾號 Java后端編程 后獲取進(jìn)群通道。


          —————END—————

          推薦閱讀:


          最近面試BAT,整理一份面試資料Java面試BAT通關(guān)手冊,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫、數(shù)據(jù)結(jié)構(gòu)等等。
          獲取方式:關(guān)注公眾號并回復(fù) java 領(lǐng)取,更多內(nèi)容陸續(xù)奉上。
          明天見(??ω??)??
          瀏覽 17
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                    丁香五月网站 | 日日色色| 18禁黄网站禁片免费观看 | 成人三级无码久久 | 草逼逼|