首頁 > 軟體

SpringBoot整合Web開發之Json資料返回的實現

2022-08-15 10:02:14

本章概要

  • 返回JSON資料
  • 靜態資源存取

返回JSON資料

預設實現

JSON 是目前主流的前後端資料傳輸方式,Spring MVC中使用訊息轉換器HTTPMessageConverter對JSON的轉換提供了很好的支援,在Spring Boot中更進一步,對相關設定做了進一步的簡化。預設情況下,建立一個Spring Boot專案後,新增Web依賴,程式碼如下:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

這個依賴中預設加入了jackson-databind 作為JSON處理器,此時不需要新增額外的JSON處理器就能返回一段JSON了。建立一個Book實體類:

public class Book {
    private int id;
    private String name;
    private String author;
    @JsonIgnore
    private Float price;
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date publicationDate;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
    public Float getPrice() {
        return price;
    }
    public void setPrice(Float price) {
        this.price = price;
    }
    public Date getPublicationDate() {
        return publicationDate;
    }
    public void setPublicationDate(Date publicationDate) {
        this.publicationDate = publicationDate;
    }
}

然後建立BookController,返回Book物件即可:

@Controller
public class BookController {
    @GetMapping(value = "/book")
    @ResponseBody
    public Book books(){
        Book b1 = new Book();
        b1.setId(1);
        b1.setAuthor("唐家三少");
        b1.setName("斗羅大陸Ⅰ");
        b1.setPrice(60f);
        b1.setPublicationDate(new Date());
        return b1;
    }
}

當然,如果需要頻繁地用到@ResponseBody 註解,那麼可以採用@RestController 組合註解代替@Controller和@ResponseBody ,程式碼如下:

@RestController
public class BookController {
    @GetMapping(value = "/book")
    public Book books(){
        Book b1 = new Book();
        b1.setId(1);
        b1.setAuthor("唐家三少");
        b1.setName("斗羅大陸Ⅰ");
        b1.setPrice(60f);
        b1.setPublicationDate(new Date());
        return b1;
    }
}

此時在瀏覽器中輸入"http://localhost:8081/book",即可看到返回了JSON資料,如圖:

這是Spring Boot 自帶的處理方式。如果採用這種方式,那麼對於欄位忽略、日期格式化等常見需求都可以通過註解來解決。這是通過Spring 中預設提供的 MappingJackson2HttpMessageConverter 來實現的,當然也可以根據需求自定義轉換器。

自定義轉換器

常見的JSON 處理器除了jsckson-databind之外,還有Gson 和 fastjson ,針對常見用法來舉例。

1. 使用Gson

Gson是 Goole 的一個開源JSON解析框架。使用Gson,需要先去處預設的jackson-databind,然後引入Gson依賴,程式碼如下:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
  <exclusions>
    <!--       排除預設的jackson-databind         -->
    <exclusion>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
    </exclusion>
  </exclusions>
</dependency>
<!--    引入Gson依賴    -->
<dependency>
  <groupId>com.google.code.gson</groupId>
  <artifactId>gson</artifactId>
</dependency>

由於Spring Boot 中預設提供了Gson的自動轉換類 GsonHttpMessageConvertersConfiguration,因此Gson的依賴新增成功後,可以像使用jackson-databind 那樣直接使用Gson。但在Gson進行轉換是,如果想對日期資料進行格式化,那麼還需要開發者自定義HTTPMessageConverter。先看 GsonHttpMessageConvertersConfiguration 中的一段程式碼:

@Bean
@ConditionalOnMissingBean
public GsonHttpMessageConverter gsonHttpMessageConverter(Gson gson) {
    GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
    converter.setGson(gson);
    return converter;
}

@ConditionalOnMissingBean 註解標識當前專案中沒有提供 GsonHttpMessageConverter 時才會使用預設的 GsonHttpMessageConverter ,所以開發者只需要提供一個 GsonHttpMessageConverter 即可,程式碼如下:

@Configuration
public class GsonConfig {
    @Bean
    GsonHttpMessageConverter gsonHttpMessageConverter(){
        GsonHttpMessageConverter gsonHttpMessageConverter = new GsonHttpMessageConverter();
        GsonBuilder builder = new GsonBuilder();
        builder.setDateFormat("yyyy-MM-dd");
        builder.excludeFieldsWithModifiers(Modifier.PROTECTED);
        Gson gson = builder.create();
        gsonHttpMessageConverter.setGson(gson);
        return gsonHttpMessageConverter;
    }
}

程式碼解釋:

  • 開發者自己提供一個GsonHttpMessageConverter 的範例
  • 設定Gson解析日期的格式
  • 設定Gson解析是修飾符為 protected 的欄位被過濾掉
  • 建立Gson物件放入GsonHttpMessageConverter 的範例中並返回

此時,將Book類中的price欄位的修飾符改為 protected ,去掉註解,程式碼如下:

public class Book {
    private int id;
    private String name;
    private String author;
    protected Float price;
    private Date publicationDate;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
    public Float getPrice() {
        return price;
    }
    public void setPrice(Float price) {
        this.price = price;
    }
    public Date getPublicationDate() {
        return publicationDate;
    }
    public void setPublicationDate(Date publicationDate) {
        this.publicationDate = publicationDate;
    }
}

此時在瀏覽器中輸入"http://localhost:8081/book",檢視返回結果,如圖:

2. 使用fastjson

fastjson是阿里巴巴的一個開源 JSON 解析框架,是目前 JSON 解析速度最快的開源框架,該框架也可以整合到 Spring Boot 中。不同於Gson,fastjson整合完成之後並不能立馬使用,需要開發者提供相應的 HttpMessageConverter 後才能使用,整合fastjson需要先除去jackson-databind 依賴,引入fastjson 依賴:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
  <exclusions>
    <!--       排除預設的jackson-databind         -->
    <exclusion>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
    </exclusion>
  </exclusions>
</dependency>
<!--    引入fastjson依賴    -->
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
</dependency>

然後設定fastjson 的 HttpMessageConverter :

@Configuration
public class MyFastJsonConfig {
    @Bean
    FastJsonHttpMessageConverter fastJsonHttpMessageConverter(){
        FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setDateFormat("yyyy-MM-dd");
        fastJsonConfig.setCharset(Charset.forName("UTF-8"));
        fastJsonConfig.setSerializerFeatures(
                SerializerFeature.WriteClassName,
                SerializerFeature.WriteMapNullValue,
                SerializerFeature.PrettyFormat,
                SerializerFeature.WriteNullListAsEmpty,
                SerializerFeature.WriteNullStringAsEmpty
        );
        fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
        return fastJsonHttpMessageConverter;
    }
}

程式碼解釋:

  • 自定義 MyFastJsonConfig 完成對 FastJsonHttpMessageConverter Bean的提供
  • 設定JSON解析過程的一些細節,例如日期格式、資料編碼、是否在生成的JSON中輸出類名、是否輸出value為null的資料、生成的JSON格式化、空集合輸出[]而非null、空字串輸出""而非null等基本設定

還需要設定一下響應編碼,否則會出現亂碼的情況,在application.properties 中新增如下設定:

# 是否強制對HTTP響應上設定的字元集進行編碼。
spring.http.encoding.force-response=true

BookController 跟 使用Gson的 BookController 一致即可,此時在瀏覽器中輸入"http://localhost:8081/book",檢視返回結果,如圖:

對於 FastJsonHttpMessageConverter 的設定,除了上邊這種方式之外,還有另一種方式。

在Spring Boot 專案中,當開發者引入 spring-boot-starter-web 依賴後,該依賴又依賴了 spring-boot-autoconfigure , 在這個自動化設定中,有一個 WebMvcAutoConfiguration 類提供了對 Spring MVC 最進本的設定,如果某一項自動化設定不滿足開發需求,開發者可以針對該項自定義設定,只需要實現 WebMvcConfig 介面即可(在Spring Boot 5.0 之前是通過繼承 WebMvcConfigurerAdapter 來實現的),程式碼如下:

@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters){
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        FastJsonConfig config = new FastJsonConfig();
        config.setDateFormat("yyyy-MM-dd");
        config.setCharset(Charset.forName("UTF-8"));
        config.setSerializerFeatures(
                SerializerFeature.WriteClassName,
                SerializerFeature.WriteMapNullValue,
                SerializerFeature.PrettyFormat,
                SerializerFeature.WriteNullListAsEmpty,
                SerializerFeature.WriteNullStringAsEmpty
        );
        converter.setFastJsonConfig(config);
        converters.add(converter);
    }
}

程式碼解釋:

  • 自定義 MyWebMvcConfig 類實現 WebMvcConfigurer 介面中的 configureMessageConverters 方法
  • 將自定義的 FastJsonHttpMessageConverter 加入 converter 中

注意:如果使用了Gson , 也可以採用這種方式設定,但是不推薦。因為當專案中沒有 GsonHttpMessageConverter 時,Spring Boot 會自己提供一個 GsonHttpMessageConverter ,此時重寫 configureMessageConverters 方法,引數 converters 中已經有 GsonHttpMessageConverter 的範例了,需要替換已有的 GsonHttpMessageConverter 範例,操作比較麻煩,所以對於Gson,推薦直接提供 GsonHttpMessageConverter 。

靜態資源存取

在Spring MVC 中,對於靜態資源都需要開發者手動設定靜態資源過濾。Spring Boot 中對此也提供了自動化設定,可以簡化靜態資源過濾設定。

預設策略

Spring Boot 中對於Spring MVC 的自動化設定都在 WebMvcAutoConfiguration 類中,因此對於預設的靜態資源過濾策略可以從這個類中一窺究竟。

在 WebMvcAutoConfiguration 類中有一個靜態內部類 WebMvcAutoConfigurationAdapter ,實現了 WebMvcConfigurer 介面。WebMvcConfigurer 介面中有一個方法 addResourceHandlers 是用來設定靜態資源過濾的。方法在 WebMvcAutoConfigurationAdapter 類中得到了實現,原始碼如下:

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
...
    String staticPathPattern = this.mvcProperties.getStaticPathPattern();
    if (!registry.hasMappingForPattern(staticPathPattern)) {
        customizeResourceHandlerRegistration(
            registry.addResourceHandler(staticPathPattern)
            .addResourceLocations(getResourceLocations(
                this.resourceProperties.getStaticLocations()))
            .setCachePeriod(getSeconds(cachePeriod))
            .setCacheControl(cacheControl));
    }
}

Spring Boot 在這裡進行了預設的靜態資源過濾設定,其中 staticPathPattern 預設定義在 WebMvcProperties 中,定義內容如下:

/**
 * Path pattern used for static resources.
 */
private String staticPathPattern = "/**";

this.resourceProperties.getStaticLocations() 獲取到的預設靜態資源位置定義在 ResourceProperties 中,程式碼如下:

private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
    "classpath:/META-INF/resources/", "classpath:/resources/",
    "classpath:/static/", "classpath:/public/" };

在 getResourceLocations 方法中,對這4個靜態資源位置做了擴充,程式碼如下:

static String[] getResourceLocations(String[] staticLocations) {
    String[] locations = new String[staticLocations.length
                                    + SERVLET_LOCATIONS.length];
    System.arraycopy(staticLocations, 0, locations, 0, staticLocations.length);
    System.arraycopy(SERVLET_LOCATIONS, 0, locations, staticLocations.length,
                     SERVLET_LOCATIONS.length);
    return locations;
}

其中 SERVLET_LOCATIONS 的定義是一個{ “/” }。

綜上可以看到,Spring Boot 預設會過濾所有的靜態資源,而靜態資源的位置一共有5個,分別是"classpath:/META-INF/resources/“、“classpath:/resources/”、“classpath:/static/”、“classpath:/public/”、”/“,一般情況下Spring Boot 專案不需要webapp目錄,所以第5個”/"可以暫時不考慮。剩下4個路徑載入的優先順序如下:

如果開發者使用IDEA建立Spring Boot 專案,就會預設建立出 classpath:/static/ 目錄,靜態資源一般放在這個目錄即可。重啟專案,存取瀏覽器"http://localhost:8081/p1.jpg",即可存取靜態資源。

自定義策略

1. 在組態檔中定義

在application.properties中直接定義過濾規則和靜態資源位置,如下:

# 靜態資源過濾規則
spring.mvc.static-path-pattern=/staticFile/**
# 靜態資源位置
spring.resources.static-locations=classpath:/staticFile/

在resources目錄下新建目錄 staticFile,放入檔案, 重啟專案,存取瀏覽器"http://localhost:8081/staticFile/p1.jpg",即可存取靜態資源。此時再次存取"http://localhost:8081/p1.jpg"會提示 404

2. Java編碼定義

實現 WebMvcConfigurer 介面即可,然後覆蓋介面的 addResourceHandlers 方法,如下:

@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry){
        registry.addResourceHandler("/staticFile/**").addResourceLocations("classpath:/staticFile/");
    }
}

到此這篇關於SpringBoot整合Web開發之Json資料返回的實現的文章就介紹到這了,更多相關SpringBoot Json資料返回內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com