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

          拒絕寫(xiě)重復(fù)代碼,試試這套開(kāi)源的 SpringBoot 組件

          共 11893字,需瀏覽 24分鐘

           ·

          2024-04-11 03:45

                

          往期熱門(mén)文章:

                    

          1、一次生產(chǎn)事故,來(lái)來(lái)回回搞了一個(gè)月,人麻了! 2、面試官:Git 如何撤回已 Push 的代碼?問(wèn)倒一大片。。。 3、SpringBoot 如何快速過(guò)濾出一次請(qǐng)求的所有日志? 4、千萬(wàn)不要把 Request 傳遞到異步線(xiàn)程里面!有坑! 5、別再用 offset 和 limit 分頁(yè)了,性能太差!

          1 簡(jiǎn)介

          Graceful Response是一個(gè)Spring Boot技術(shù)棧下的優(yōu)雅響應(yīng)處理器,提供一站式統(tǒng)一返回值封裝、全局異常處理、自定義異常錯(cuò)誤碼等功能,使用Graceful Response進(jìn)行web接口開(kāi)發(fā)不僅可以節(jié)省大量的時(shí)間,還可以提高代碼質(zhì)量,使代碼邏輯更清晰。
          強(qiáng)烈推薦你花3分鐘學(xué)會(huì)它!
          本項(xiàng)目案例工程代碼: https://github.com/feiniaojin/graceful-response-example.git ,注意選擇最新版本的分支。
          Spring Boot版本 Graceful Response版本 graceful-response-example分支
          2.x 3.2.1-boot2 3.2.0-boot2
          3.x 3.2.1-boot3 3.2.0-boot3
          注意,3.2.1-boot2版本的Graceful Response源碼由單獨(dú)的倉(cāng)庫(kù)進(jìn)行維護(hù),地址為: https://github.com/feiniaojin/graceful-response-boot2 3.2.1-boot2和3.2.1-boot3除了支持的SpringBoot版本不一樣,其他實(shí)現(xiàn)完全一致,Maven引用時(shí)只需要根據(jù)對(duì)應(yīng)的SpringBoot版本選擇Graceful Response的version即可,兩者的groupId、artifactId是一致的。

          2 快速入門(mén)

          2.1 Spring Boot接口開(kāi)發(fā)現(xiàn)狀

          目前,業(yè)界使用Spring Boot進(jìn)行接口開(kāi)發(fā)時(shí),往往存在效率底下、重復(fù)勞動(dòng)、可讀性差等問(wèn)題。以下偽代碼相信大家非常熟悉,我們大部分項(xiàng)目的Controller接口都是這樣的。
                @Controller
          public class Controller {

              @GetMapping("/query")
              @ResponseBody
              public Response query(Map<String, Object> paramMap) {
                  Response res = new Response();
                  try {
                      //1.校驗(yàn)params參數(shù)合法性,包括非空校驗(yàn)、長(zhǎng)度校驗(yàn)等
                      if (illegal(paramMap)) {
                          res.setCode(1);
                          res.setMsg("error");
                          return res;
                      }
                      //2.調(diào)用Service的一系列操作,得到查詢(xún)結(jié)果
                      Object data = service.query(params);
                      //3.將操作結(jié)果設(shè)置到res對(duì)象中
                      res.setData(data);
                      res.setCode(0);
                      res.setMsg("ok");
                      return res;
                  } catch (Exception e) {
                      //4.異常處理:一堆丑陋的try...catch,如果有錯(cuò)誤碼的,還需要手工填充錯(cuò)誤碼
                      res.setCode(1);
                      res.setMsg("error");
                      return res;
                  }
              }
          }
          這段偽代碼存在什么樣的問(wèn)題呢? 第一個(gè)問(wèn)題,效率低下。 Controller層的代碼應(yīng)該盡量簡(jiǎn)潔,上面的偽代碼其實(shí)只是為了將數(shù)據(jù)查詢(xún)的結(jié)果進(jìn)行封裝,使其以統(tǒng)一的格式進(jìn)行返回。例如以下格式的響應(yīng)體:
                {
            "code"0,
            "msg""ok",
            "data": {
              "id"1,
              "name""username"
            }
          }
          查詢(xún)過(guò)程中如果發(fā)生異常,需要在Controller進(jìn)行手工捕獲,根據(jù)捕獲的異常人工地設(shè)置錯(cuò)誤碼,當(dāng)然,也用同樣的格式封裝錯(cuò)誤碼進(jìn)行返回。 可以看到,除了調(diào)用service層的query方法這一行,其他大部分的代碼都執(zhí)行進(jìn)行結(jié)果的封裝,大量的冗余、低價(jià)值的代碼導(dǎo)致我們的開(kāi)發(fā)活動(dòng)效率很低。 第二個(gè)問(wèn)題,重復(fù)勞動(dòng)。 以上捕獲異常、封裝執(zhí)行結(jié)果的操作,每個(gè)接口都會(huì)進(jìn)行一次,因此造成大量重復(fù)勞動(dòng)。 第三個(gè)問(wèn)題,可讀性低。 上面的核心代碼被淹沒(méi)在許多冗余代碼中,很難閱讀,如同大海撈針。 我們可以通過(guò)Graceful Response這個(gè)組件解決這樣的問(wèn)題。搜索Java知音公眾號(hào),回復(fù)“Java題庫(kù)”,送你一份Java面試寶典

          2.2. 快速入門(mén)

          2.2.1 引入Graceful Response組件
          Graceful Response已發(fā)布至maven中央倉(cāng)庫(kù),我們可以直接引入到項(xiàng)目中。 maven依賴(lài)如下:
                <dependency>
              <groupId>com.feiniaojin</groupId>
              <artifactId>graceful-response</artifactId>
              <version>{latest.version}</version>
          </dependency>
          Spring Boot版本 Graceful Response最新版本
          2.x 3.2.1-boot2
          3.x 3.2.1-boot3
          2.2.2 啟用Graceful Response
          在啟動(dòng)類(lèi)中引入 @EnableGracefulResponse 注解,即可啟用Graceful Response組件。
                @EnableGracefulResponse
          @SpringBootApplication
          public class ExampleApplication {
              public static void main(String[] args) {
                  SpringApplication.run(ExampleApplication.classargs);
              }
          }
          2.2.3 Controller層
          引入Graceful Response后,我們不需要再手工進(jìn)行查詢(xún)結(jié)果的封裝,直接返回實(shí)際結(jié)果即可,Graceful Response會(huì)自動(dòng)完成封裝的操作。 Controller層示例如下。
                @Controller
          public class Controller {
              @RequestMapping("/get")
              @ResponseBody
              public UserInfoView get(Long id) {
                  log.info("id={}", id);
                  return UserInfoView.builder().id(id).name("name" + id).build();
              }
          }
          在示例代碼中,Controller層的方法直接返回了UserInfoView對(duì)象,沒(méi)有進(jìn)行封裝的操作,但經(jīng)過(guò)Graceful Response處理后,我們還是得到了以下的響應(yīng)結(jié)果。
                {
            "status": {
              "code""0",
              "msg""ok"
            },
            "payload": {
              "id"1,
              "name""name1"
            }
          }
          而對(duì)于命令操作(Command)盡量不返回?cái)?shù)據(jù),因此command操作的方法的返回值應(yīng)該是void,Graceful Response對(duì)于對(duì)于返回值類(lèi)型void的方法,也會(huì)自動(dòng)進(jìn)行封裝。
                public class Controller {
              @RequestMapping("/command")
              @ResponseBody
              public void command() {
                  //業(yè)務(wù)操作
              }
          }
          成功調(diào)用該接口,將得到:
                {
            "status": {
              "code""200",
              "msg""success"
            },
            "payload": {}
          }
          2.2.4 Service層
          在引入Graceful Response前,有的開(kāi)發(fā)者在定義Service層的方法時(shí),為了在接口中返回異常碼,干脆直接將Service層方法定義為Response,淹沒(méi)了方法的正常返回值。 Response的代碼如下。
                //lombok注解
          @Data
          public class Response {
              private String code;
              private String msg;
              private Object data;
          }
          直接返回Response的Service層方法:
                /**
           * 直接返回Reponse的Service
           * 不規(guī)范
           */

          public interface Service {
              public Reponse commandMethod(Command command);
          }
          Graceful Response引入 @ExceptionMapper 注解,通過(guò)該注解將異常和錯(cuò)誤碼關(guān)聯(lián)起來(lái),這樣Service方法就不需要再維護(hù)Response的響應(yīng)碼了,直接拋出業(yè)務(wù)異常,由Graceful Response進(jìn)行異常和響應(yīng)碼的關(guān)聯(lián)。搜索Java知音公眾號(hào),回復(fù)“Java題庫(kù)”,送你一份Java面試寶典 @ExceptionMapper 的用法如下。
                /**
           * NotFoundException的定義,使用@ExceptionMapper注解修飾
           * code:代表接口的異常碼
           * msg:代表接口的異常提示
           */

          @ExceptionMapper(code = "1404", msg = "找不到對(duì)象")
          public class NotFoundException extends RuntimeException {

          }
          Service接口定義:
                public interface QueryService {
              UserInfoView queryOne(Query query);
          }
          Service接口實(shí)現(xiàn):
                public class QueryServiceImpl implements QueryService {
              @Resource
              private UserInfoMapper mapper;

              public UserInfoView queryOne(Query query) {
                  UserInfo userInfo = mapper.findOne(query.getId());
                  if (Objects.isNull(userInfo)) {
                      //這里直接拋?zhàn)远x異常
                      throw new NotFoundException();
                  }
                  //……后續(xù)業(yè)務(wù)操作
              }
          }
          當(dāng)Service層的queryOne方法拋出 NotFoundException 時(shí),Graceful Response會(huì)進(jìn)行異常捕獲,并將NotFoundException對(duì)應(yīng)的異常碼和異常信息封裝到統(tǒng)一的響應(yīng)對(duì)象中,最終接口返回以下JSON。
                {
            "status": {
              "code""1404",
              "msg""找不到對(duì)象"
            },
            "payload": {}
          }
          2.2.5 參數(shù)校驗(yàn)
          Graceful Response對(duì)JSR-303數(shù)據(jù)校驗(yàn)規(guī)范和Hibernate Validator進(jìn)行了增強(qiáng),Graceful Response自身不提供參數(shù)校驗(yàn)的功能,但是用戶(hù)使用了Hibernate Validator后,Graceful Response可以通過(guò) @ValidationStatusCode 注解為參數(shù)校驗(yàn)結(jié)果提供響應(yīng)碼,并將其統(tǒng)一封裝返回。 例如以下的UserInfoQuery。
                @Data
          public class UserInfoQuery {
              @NotNull(message = "userName is null !")
              @Length(min = 6, max = 12)
              @ValidationStatusCode(code = "520")
              private String userName;
          }
          UserInfoQuery對(duì)象中定義了@NotNull和@Length兩個(gè)校驗(yàn)規(guī)則,在未引入Graceful Response的情況下,會(huì)直接拋出異常; 在引入Graceful Response但是沒(méi)有加入 @ValidationStatusCode 注解的情況下,會(huì)以默認(rèn)的錯(cuò)誤碼進(jìn)行返回; 在上面的UserInfoQuery中由于使用了 @ValidationStatusCode 注解,并指定異常碼為520,則當(dāng)userName字段任意校驗(yàn)不通過(guò)時(shí),都會(huì)使用異常碼520進(jìn)行返回,如下。
                {
            "status": {
              "code""520",
              "msg""userName is null !"
            },
            "payload": {}
          }
          而對(duì)于Controller層直接校驗(yàn)方法入?yún)⒌膱?chǎng)景,Graceful Response也進(jìn)行了增強(qiáng),如以下Controller。
                public class Controller {

              @RequestMapping("/validateMethodParam")
              @ResponseBody
              @ValidationStatusCode(code = "1314")
              public void validateMethodParam(
                      @NotNull(message = "userId不能為空")
           Long userId,
                      @NotNull(message = "userName不能為空") Long userName) 
          {
                  //省略業(yè)務(wù)邏輯
              }
          }
          如果該方法入?yún)⑿r?yàn)觸發(fā)了userId和userName的校驗(yàn)異常,將以錯(cuò)誤碼1314進(jìn)行返回,如下。
                {
            "status": {
              "code""1314",
              "msg""userId不能為空"
            },
            "payload": {}
          }
          2.2.6 自定義Response格式
          Graceful Response內(nèi)置了兩種風(fēng)格的響應(yīng)格式,并通過(guò) graceful-response.response-style 進(jìn)行配置。 graceful-response.response-style=0 ,或者不配置(默認(rèn)情況),將以以下的格式進(jìn)行返回:
                {
            "status": {
              "code"1007,
              "msg""有內(nèi)鬼,終止交易"
            },
            "payload": {
            }
          }
          graceful-response.response-style=1 ,將以以下的格式進(jìn)行返回:
                {
            "code""1404",
            "msg""not found",
            "data": {
            }
          }
          如果這兩種格式均不滿(mǎn)足業(yè)務(wù)需要,Graceful Response也支持用戶(hù)自定義響應(yīng)體,關(guān)于自定義響應(yīng)體的技術(shù)實(shí)現(xiàn),請(qǐng)到自定義Response格式進(jìn)行了解。 本項(xiàng)目提供的進(jìn)階功能,包括
          • 第三方組件汽車(chē)(Swagger、執(zhí)行器等)
          • 自定義響應(yīng)
          • 異常請(qǐng)求放行
          • 異常別名
          • 常用配置項(xiàng)
          目前該組件在GitHub上已經(jīng)有兩百多Star,很多朋友已經(jīng)開(kāi)始用了,大家可以通過(guò)下方鏈接了解下:
          • https://github.com/feiniaojin/graceful-response
              
                
                    
                      往期熱門(mén)文章:
                    
                  
                

          1 8種專(zhuān)坑同事 SQL寫(xiě)法,性能降低100倍,不來(lái)看看? 2、Spring Boot 項(xiàng)目統(tǒng)一結(jié)果,統(tǒng)一異常,統(tǒng)一日志,寫(xiě)的太好了! 3、知乎熱議:為什么多數(shù)程序員都不做個(gè)人獨(dú)立開(kāi)發(fā)? 4、谷歌搜索殺死了網(wǎng)頁(yè)緩存 5、項(xiàng)目終于用上了Spring狀態(tài)機(jī),那叫一個(gè)優(yōu)雅! 6、我,40歲碼農(nóng),還在荷蘭寫(xiě)低級(jí)代碼,不敢回國(guó)… 7、MyBatis Plus 解決大數(shù)據(jù)量查詢(xún)慢問(wèn)題 8、Spring賭上未來(lái):響應(yīng)式的 WebFlux 框架更優(yōu)雅,性能更強(qiáng)! 9、 面試官問(wèn)我 ,try catch 應(yīng)該在 for 循環(huán)里面還是外面?

          10、4 種策略讓 MySQL 和 Redis 數(shù)據(jù)保持一致


          瀏覽 44
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(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>
                  操比在线观看 | 日本国产在线 | 成人午夜大香蕉 | 五月婷婷中文 | 91日日艹|