<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 搭建實際項目開發(fā)中的腳手架

          共 18600字,需瀏覽 38分鐘

           ·

          2021-03-14 21:44

          本來已收錄到我寫的10萬字Springboot經典學習筆記中,筆記在持續(xù)更新……文末有領取方式

          前面的文章中,我主要給大家講解了 Spring Boot 中常用的一些技術點,這些技術點在實際項目中可能不會全部用得到,因為不同的項目可能使用的技術不同,但是希望大家都能掌握如何使用,并能自己根據實際項目中的需求進行相應的擴展。

          不知道大家了不了解單片機,單片機里有個最小系統(tǒng),這個最小系統(tǒng)搭建好了之后,就可以在此基礎上進行人為的擴展。這節(jié)課我們要做的就是搭建一個 “Spring Boot 最小系統(tǒng)架構” 。拿著這個架構,可以在此基礎上根據實際需求做相應的擴展。

          從零開始搭建一個環(huán)境,主要要考慮幾點:統(tǒng)一封裝的數(shù)據結構、可調式的接口、json的處理、模板引擎的使用(本文不寫該項,因為現(xiàn)在大部分項目都前后端分離了,但是考慮到也還有非前后端分離的項目,所以我在源代碼里也加上了 thymeleaf)、持久層的集成、攔截器(這個也是可選的)和全局異常處理。一般包括這些東西的話,基本上一個 Spring Boot 項目環(huán)境就差不多了,然后就是根據具體情況來擴展了。

          結合前面的課程和以上的這些點,本文手把手帶領大家搭建一個實際項目開發(fā)中可用的 Spring Boot 架構。整個項目工程如下圖所示,學習的時候,可以結合我的源碼,這樣效果會更好。

          工程架構

          1. 統(tǒng)一的數(shù)據封裝

          由于封裝的 json 數(shù)據的類型不確定,所以在定義統(tǒng)一的 json 結構時,我們需要用到泛型。統(tǒng)一的 json 結構中屬性包括數(shù)據、狀態(tài)碼、提示信息即可,構造方法可以根據實際業(yè)務需求做相應的添加即可,一般來說,應該有默認的返回結構,也應該有用戶指定的返回結構。如下:

          /**
           * 統(tǒng)一返回對象
           * @author shengwu ni
           * @param <T>
           */

          public class JsonResult<T{

              private T data;
              private String code;
              private String msg;

              /**
               * 若沒有數(shù)據返回,默認狀態(tài)碼為0,提示信息為:操作成功!
               */

              public JsonResult() {
                  this.code = "0";
                  this.msg = "操作成功!";
              }

              /**
               * 若沒有數(shù)據返回,可以人為指定狀態(tài)碼和提示信息
               * @param code
               * @param msg
               */

              public JsonResult(String code, String msg) {
                  this.code = code;
                  this.msg = msg;
              }

              /**
               * 有數(shù)據返回時,狀態(tài)碼為0,默認提示信息為:操作成功!
               * @param data
               */

              public JsonResult(T data) {
                  this.data = data;
                  this.code = "0";
                  this.msg = "操作成功!";
              }

              /**
               * 有數(shù)據返回,狀態(tài)碼為0,人為指定提示信息
               * @param data
               * @param msg
               */

              public JsonResult(T data, String msg) {
                  this.data = data;
                  this.code = "0";
                  this.msg = msg;
              }
              
              /**
               * 使用自定義異常作為參數(shù)傳遞狀態(tài)碼和提示信息
               * @param msgEnum
               */

              public JsonResult(BusinessMsgEnum msgEnum) {
                  this.code = msgEnum.code();
                  this.msg = msgEnum.msg();
              }

              // 省去get和set方法
          }

          大家可以根據自己項目中所需要的一些東西,合理的修改統(tǒng)一結構中的字段信息。

          2. json的處理

          Json 處理工具很多,比如阿里巴巴的 fastjson,不過 fastjson 對有些未知類型的 null 無法轉成空字符串,這可能是 fastjson 自身的缺陷,可擴展性也不是太好,但是使用起來方便,使用的人也蠻多的。這節(jié)課里面我們主要集成 Spring Boot 自帶的 jackson。主要是對 jackson 做一下對 null 的配置即可,然后就可以在項目中使用了。

          /**
           * jacksonConfig
           * @author shengwu ni
           */

          @Configuration
          public class JacksonConfig {
              @Bean
              @Primary
              @ConditionalOnMissingBean(ObjectMapper.class)
              public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder
          {
                  ObjectMapper objectMapper = builder.createXmlMapper(false).build();
                  objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
                      @Override
                      public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
                          jsonGenerator.writeString("");
                      }
                  });
                  return objectMapper;
              }
          }

          這里先不測試,等下面 swagger2 配置好了之后,我們一起來測試一下。

          3. swagger2在線可調式接口

          有了 swagger,開發(fā)人員不需要給其他人員提供接口文檔,只要告訴他們一個 Swagger 地址,即可展示在線的 API 接口文檔,除此之外,調用接口的人員還可以在線測試接口數(shù)據,同樣地,開發(fā)人員在開發(fā)接口時,同樣也可以利用 Swagger 在線接口文檔測試接口數(shù)據,這給開發(fā)人員提供了便利。使用 swagger 需要對其進行配置:

          /**
           * swagger配置
           * @author shengwu ni
           */

          @Configuration
          @EnableSwagger2
          public class SwaggerConfig {

              @Bean
              public Docket createRestApi() {
                  return new Docket(DocumentationType.SWAGGER_2)
                          // 指定構建api文檔的詳細信息的方法:apiInfo()
                          .apiInfo(apiInfo())
                          .select()
                          // 指定要生成api接口的包路徑,這里把controller作為包路徑,生成controller中的所有接口
                          .apis(RequestHandlerSelectors.basePackage("com.itcodai.course18.controller"))
                          .paths(PathSelectors.any())
                          .build();
              }

              /**
               * 構建api文檔的詳細信息
               * @return
               */

              private ApiInfo apiInfo() {
                  return new ApiInfoBuilder()
                          // 設置頁面標題
                          .title("Spring Boot搭建實際項目中開發(fā)的架構")
                          // 設置接口描述
                          .description("跟武哥一起學Spring Boot第18課")
                          // 設置聯(lián)系方式
                          .contact("倪升武," + "微信公眾號:程序員私房菜")
                          // 設置版本
                          .version("1.0")
                          // 構建
                          .build();
              }
          }

          到這里,可以先測試一下,寫一個 Controller,弄一個靜態(tài)的接口測試一下上面集成的內容。

          @RestController
          @Api(value = "用戶信息接口")
          public class UserController {

              @Resource
              private UserService userService;

              @GetMapping("/getUser/{id}")
              @ApiOperation(value = "根據用戶唯一標識獲取用戶信息")
              public JsonResult<User> getUserInfo(@PathVariable @ApiParam(value = "用戶唯一標識") Long id) {
                  User user = new User(id, "倪升武""123456");
                  return new JsonResult<>(user);
              }
          }

          然后啟動項目,在瀏覽器中輸入 localhost:8080/swagger-ui.html 即可看到 swagger 接口文檔頁面,調用一下上面這個接口,即可看到返回的 json 數(shù)據。

          4. 持久層集成

          每個項目中是必須要有持久層的,與數(shù)據庫交互,這里我們主要來集成 mybatis,集成 mybatis 首先要在 application.yml 中進行配置。

          # 服務端口號
          server:
            port: 8080

          # 數(shù)據庫地址
          datasource:
            url: localhost:3306/blog_test

          spring:
            datasource: # 數(shù)據庫配置
              driver-class-name: com.mysql.jdbc.Driver
              url: jdbc:mysql://${datasource.url}?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false&maxReconnects=10
              username: root
              password: 123456
              hikari:
                maximum-pool-size: 10 # 最大連接池數(shù)
                max-lifetime: 1770000

          mybatis:
            # 指定別名設置的包為所有entity
            type-aliases-package: com.itcodai.course18.entity
            configuration:
              map-underscore-to-camel-case: true # 駝峰命名規(guī)范
            mapper-locations: # mapper映射文件位置
              - classpath:mapper/*.xml

          配置好了之后,接下來我們來寫一下 dao 層,實際中我們使用注解比較多,因為比較方便,當然也可以使用 xml 的方式,甚至兩種同時使用都行,這里我們主要使用注解的方式來集成,關于 xml 的方式,大家可以查看前面課程,實際中根據項目情況來定。

          public interface UserMapper {

              @Select("select * from user where id = #{id}")
              @Results({
                      @Result(property = "username", column = "user_name"),
                      @Result(property = "password", column = "password")
              })
              User getUser(Long id);

              @Select("select * from user where id = #{id} and user_name=#{name}")
              User getUserByIdAndName(@Param("id") Long id, @Param("name") String username);

              @Select("select * from user")
              List<User> getAll();
          }

          關于 service 層我就不在文章中寫代碼了,大家可以結合我的源代碼學習,這一節(jié)主要帶領大家來搭建一個 Spring Boot 空架構。最后別忘了在啟動類上添加注解掃描 @MapperScan("com.itcodai.course18.dao")

          5. 攔截器

          攔截器在項目中使用的是非常多的(但不是絕對的),比如攔截一些置頂?shù)?url,做一些判斷和處理等等。除此之外,還需要將常用的靜態(tài)頁面或者 swagger 頁面放行,不能將這些靜態(tài)資源給攔截了。首先先自定義一個攔截器。

          public class MyInterceptor implements HandlerInterceptor {

              private static final Logger logger = LoggerFactory.getLogger(MyInterceptor.class);

              @Override
              public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

                  logger.info("執(zhí)行方法之前執(zhí)行(Controller方法調用之前)");
                  return true;
              }

              @Override
              public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
                  logger.info("執(zhí)行完方法之后進執(zhí)行(Controller方法調用之后),但是此時還沒進行視圖渲染");
              }

              @Override
              public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
                  logger.info("整個請求都處理完咯,DispatcherServlet也渲染了對應的視圖咯,此時我可以做一些清理的工作了");
              }
          }

          然后將自定義的攔截器加入到攔截器配置中。

          @Configuration
          public class MyInterceptorConfig implements WebMvcConfigurer {
              @Override
              public void addInterceptors(InterceptorRegistry registry) {
                  // 實現(xiàn)WebMvcConfigurer不會導致靜態(tài)資源被攔截
                  registry.addInterceptor(new MyInterceptor())
                          // 攔截所有url
                          .addPathPatterns("/**")
                          // 放行swagger
                          .excludePathPatterns("/swagger-resources/**");
              }
          }

          在 Spring Boot 中,我們通常會在如下目錄里存放一些靜態(tài)資源:

          classpath:/static
          classpath:/public
          classpath:/resources
          classpath:/META-INF/resources

          上面代碼中配置的 /** 是對所有 url 都進行了攔截,但我們實現(xiàn)了 WebMvcConfigurer 接口,不會導致 Spring Boot 對上面這些目錄下的靜態(tài)資源實施攔截。但是我們平時訪問的 swagger 會被攔截,所以要將其放行。swagger 頁面在 swagger-resources 目錄下,放行該目錄下所有文件即可。

          然后在瀏覽器中輸入一下 swagger 頁面,若能正常顯示 swagger,說明放行成功。同時可以根據后臺打印的日志判斷代碼執(zhí)行的順序。

          6. 全局異常處理

          全局異常處理是每個項目中必須用到的東西,在具體的異常中,我們可能會做具體的處理,但是對于沒有處理的異常,一般會有一個統(tǒng)一的全局異常處理。在異常處理之前,最好維護一個異常提示信息枚舉類,專門用來保存異常提示信息的。如下:

          public enum BusinessMsgEnum {
              /** 參數(shù)異常 */
              PARMETER_EXCEPTION("102""參數(shù)異常!"),
              /** 等待超時 */
              SERVICE_TIME_OUT("103""服務調用超時!"),
              /** 參數(shù)過大 */
              PARMETER_BIG_EXCEPTION("102""輸入的圖片數(shù)量不能超過50張!"),
              /** 500 : 發(fā)生異常 */
              UNEXPECTED_EXCEPTION("500""系統(tǒng)發(fā)生異常,請聯(lián)系管理員!");

              /**
               * 消息碼
               */

              private String code;
              /**
               * 消息內容
               */

              private String msg;

              private BusinessMsgEnum(String code, String msg) {
                  this.code = code;
                  this.msg = msg;
              }

              public String code() {
                  return code;
              }

              public String msg() {
                  return msg;
              }

          }

          在全局統(tǒng)一異常處理類中,我們一般會對自定義的業(yè)務異常最先處理,然后去處理一些常見的系統(tǒng)異常,最后會來一個一勞永逸(Exception 異常)。

          @ControllerAdvice
          @ResponseBody
          public class GlobalExceptionHandler {

              private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

              /**
               * 攔截業(yè)務異常,返回業(yè)務異常信息
               * @param ex
               * @return
               */

              @ExceptionHandler(BusinessErrorException.class)
              @ResponseStatus(value 
          = HttpStatus.INTERNAL_SERVER_ERROR)
              public JsonResult handleBusinessError(BusinessErrorException ex) {
                  String code = ex.getCode();
                  String message = ex.getMessage();
                  return new JsonResult(code, message);
              }

              /**
               * 空指針異常
               * @param ex NullPointerException
               * @return
               */

              @ExceptionHandler(NullPointerException.class)
              @ResponseStatus(value 
          = HttpStatus.INTERNAL_SERVER_ERROR)
              public JsonResult handleTypeMismatchException(NullPointerException ex) {
                  logger.error("空指針異常,{}", ex.getMessage());
                  return new JsonResult("500""空指針異常了");
              }

              /**
               * 系統(tǒng)異常 預期以外異常
               * @param ex
               * @return
               */

              @ExceptionHandler(Exception.class)
              @ResponseStatus(value 
          = HttpStatus.INTERNAL_SERVER_ERROR)
              public JsonResult handleUnexpectedServer(Exception ex) {
                  logger.error("系統(tǒng)異常:", ex);
                  return new JsonResult(BusinessMsgEnum.UNEXPECTED_EXCEPTION);
              }

          }

          其中,BusinessErrorException 是自定義的業(yè)務異常,繼承一下 RuntimeException 即可,具體可以看我的源代碼,文章中就不貼代碼了。在 UserController 中有個 testException 方法,用來測試全局異常的,打開 swagger 頁面,調用一下該接口,可以看出返回用戶提示信息:”系統(tǒng)發(fā)生異常,請聯(lián)系管理員!“。當然了,實際情況中,需要根據不同的業(yè)務提示不同的信息。

          7. 總結

          本文主要手把手帶領大家快速搭建一個項目中可以使用的 Spring Boot 空架構,主要從統(tǒng)一封裝的數(shù)據結構、可調式的接口、json的處理、模板引擎的使用(代碼中體現(xiàn))、持久層的集成、攔截器和全局異常處理。一般包括這些東西的話,基本上一個 Spring Boot 項目環(huán)境就差不多了,然后就是根據具體情況來擴展了。

          該文已收錄到我寫的《10萬字Springboot經典學習筆記》中,點擊下面小卡片,進入【Java開發(fā)寶典】,回復:筆記,即可免費獲取。

          點贊是最大的支持 

          瀏覽 61
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  一区二区三区四区精品视频 | 一级射视屏 | 超碰在线中文1159 | 五月婷婷第四色 | 亚洲影院在线观看 |