您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“Spring Boot數據響應問題實例分析”,內容詳細,步驟清晰,細節處理妥當,希望這篇“Spring Boot數據響應問題實例分析”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
響應頁面指的是我們如何發送一個請求,跳轉到指定頁面。將會在后面的視圖解析中說明。 響應頁面常見于開發單體應用。 響應數據常見于開發前后端分離的應用。后端代碼主要用來接收請求。前端頁面給我們發送過來請求,給前端響應json數據。或者給前端響應xml、圖片、音視頻數據。
在前后端分離開發過程中,后端一般會將數據集封裝成一個JSON對象響應給前端 ,一般只需要標準ResponseBody即可給前端返回數據
假設給前端自動返回json數據,需要引入相關的依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- web場景自動引入了json場景 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-json</artifactId> <version>2.3.4.RELEASE</version> <scope>compile</scope> </dependency>
控制層代碼如下:引入了依賴后,給方法上標注@ResponseBody,就可以給前端自動返回JSON數據。
@Controller public class ResponseTestController { @ResponseBody //原理就是利用返回值處理器里面消息轉換器進行處理 @GetMapping("/test/person") public Person getPerson(){ Person person = new Person(); person.setAge(28); person.setBirth(new Date()); person.setUserName("zhangsan"); return person; } }
測試:
返回值處理器判斷是否支持這種類型返回值supportsReturnType
返回值處理器調用handleReturnValue進行處理
RequestResponseBodyMethodProcessor可以處理返回值標了@ResponseBody注解的。
內容協商(瀏覽器默認會以請求頭的方式告訴服務器他能接受什么樣的內容類型)
服務器最終根據自己自身的能力,決定服務器能生產出什么樣內容類型的數據,
SpringMVC會挨個遍歷所有容器底層的HttpMessageConverter,看誰能處理?(也就是把對象轉換成為json數據)
得到MappingJackson2HttpMessageConverter消息轉換器可以將對象寫為json
利用MappingJackson2HttpMessageConverter將對象轉為json再寫出去。
利用MessageConverters進行處理將數據寫為json
SpringMVC到底支持哪些返回值
ModelAndView //包含數據和頁面
Model
View
ResponseEntity
ResponseBodyEmitter
StreamingResponseBody
HttpEntity
HttpHeaders
Callable //異步
DeferredResult
ListenableFuture
CompletionStage
WebAsyncTask
有 @ModelAttribute 且為對象類型的
@ResponseBody 注解 ---> RequestResponseBodyMethodProcessor;處理器//即在方法上或者類上是否標注@ResponseBody
HTTPMessageConverter原理
MessageConverter規范
HttpMessageConverter:看是否支持將 此 Class類型的對象,轉為MediaType類型的數據。 例子:CanWrite將Person對象轉為JSON。canRead或者 JSON轉為Person
默認的MessageConverter
0 - 只支持Byte類型的
1 - String
2 - String
3 - Resource
4 - ResourceRegion
5 - DOMSource.class \ SAXSource.class) \ StAXSource.class \StreamSource.class \Source.class
6 - MultiValueMap
7 - true //支持將任意對象轉為指定的,不管是什么都支持
8 - true
9 - 支持注解方式xml處理的。
最終 MappingJackson2HttpMessageConverter 把對象轉為JSON(利用底層的jackson的objectMapper轉換的)
根據客戶端接收能力不同【有的只接收xml,有的只接收json】,返回不同媒體類型的數據。比如返回xml數據給前
引入支持XML依賴:
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> </dependency>
重新編譯該項目運行 ,返回了xml數據
在上面的測試中,此時如果我用postman發送相同的請求,則得到的是json數據,為啥同樣的請求,方式不一樣,返回的數據不一樣呢。原因就是請求頭中規定的數據響應先后順序
查看請求頭
內容協商Accept中,瀏覽器具備什么類型數據的接收能力,可以看到xml數據是優先被接收的。
可用Postman軟件分別測試返回json和xml:只需要改變請求頭中Accept字段(application/json、application/xml)。Http協議中規定的,告訴服務器本客戶端可以接收的數據類型。
為了方便內容協商,開啟基于請求參數的內容協商功能。
spring: contentnegotiation: favor-parameter: true #開啟請求參數內容協商模式
發請求:
json類型: http://localhost:8080/test/person?format=json
xml類型:http://localhost:8080/test/person?format=xml
確定客戶端接收什么樣的內容類型;
1、Parameter策略優先確定是要返回json數據(獲取請求頭中的format的值) 2、最終進行內容協商返回給客戶端json即可。
判斷當前響應頭中是否已經有確定的媒體類型。MediaType
獲取客戶端(PostMan、瀏覽器)支持接收的內容類型。(獲取客戶端Accept請求頭字段)【application/xml】
contentNegotiationManager 內容協商管理器 默認使用基于請求頭的策略
HeaderContentNegotiationStrategy 確定客戶端可以接收的內容類型
遍歷循環所有當前系統的 MessageConverter,看誰支持操作這個對象(Person)
找到支持操作Person的converter,把converter支持的媒體類型統計出來。
客戶端需要【application/xml】。服務端能力【10種、json、xml】
進行內容協商的最佳匹配媒體類型
用 支持 將對象轉為 最佳匹配媒體類型 的converter。調用它進行轉化 。
導入了jackson處理xml的包,xml的converter就會自動進來
WebMvcConfigurationSupport jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader); if (jackson2XmlPresent) { Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.xml(); if (this.applicationContext != null) { builder.applicationContext(this.applicationContext); } messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.build())); }
實現多協議數據兼容。json、xml、x-guigu
@ResponseBody 響應數據出去 調用 RequestResponseBodyMethodProcessor 處理
Processor 處理方法返回值。通過 MessageConverter 處理
所有 MessageConverter 合起來可以支持各種媒體類型數據的操作(讀、寫)
內容協商找到最終的 messageConverter;
要自定義SpringMVC的什么功能,即通過一個入口給容器中添加一個 WebMvcConfigurer
假設你想基于自定義請求參數的自定義內容協商功能。換句話,在地址欄輸入http://localhost:8080/test/person?format=gg返回數據,跟http://localhost:8080/test/person且請求頭參數`Accept:application/x-guigu`的返回自定義協議數據的一致。
演示
通過上文分析,我們只需要實現WebMvcConfigurer接口,并實現了configureMessageConverters方法,就可以達到自定義消息轉換器的目的。例如,我不想用jackson了,想用fastjson的消息轉換器,我們可以添加fastjson相關的MessageConverter就可以了
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); List<MediaType> fastMediaTypes = new ArrayList<>(); fastMediaTypes.add(MediaType.TEXT_HTML); fastMediaTypes.add(MediaType.APPLICATION_JSON); fastConverter.setSupportedMediaTypes(fastMediaTypes); FastJsonConfig fastJsonConfig = new FastJsonConfig(); fastJsonConfig.setSerializerFeatures( SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullStringAsEmpty, SerializerFeature.WriteNullListAsEmpty, SerializerFeature.WriteDateUseDateFormat); SerializeConfig serializeConfig = SerializeConfig.globalInstance; serializeConfig.put(BigInteger.class, ToStringSerializer.instance); serializeConfig.put(Long.class, ToStringSerializer.instance); serializeConfig.put(Long.TYPE, ToStringSerializer.instance); fastJsonConfig.setSerializeConfig(serializeConfig); fastConverter.setFastJsonConfig(fastJsonConfig); converters.add(fastConverter); } }
測試
@Data public class Person { private String userName; private Integer age; //使用fastjson的注解進行轉換 @JSONField(format = "yyyy-MM-dd") private Date birth; private Pet pet; }
除此之外,這些都是默認的,我們可以進行擴展,如下實現自定義的設置轉化,如下,利用這個代碼:
@Bean public WebMvcConfigurer webMvcConfigurer(){ return new WebMvcConfigurer() { @Override public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { } } }
測試
@Configuration(proxyBeanMethods = false) public class WebConfig { @Bean public WebMvcConfigurer webMvcConfigurer(){ return new WebMvcConfigurer() { @Override public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { converters.add(new GuiguMessageConverter()); } } } }
/** * 自定義的Converter */ public class GuiguMessageConverter implements HttpMessageConverter<Person> { @Override public boolean canRead(Class<?> clazz, MediaType mediaType) { return false; } @Override public boolean canWrite(Class<?> clazz, MediaType mediaType) { return clazz.isAssignableFrom(Person.class); } /** * 服務器要統計所有MessageConverter都能寫出哪些內容類型 * * application/x-guigu * @return */ @Override public List<MediaType> getSupportedMediaTypes() { return MediaType.parseMediaTypes("application/x-guigu"); } @Override public Person read(Class<? extends Person> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { return null; } @Override public void write(Person person, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { //自定義協議數據的寫出 String data = person.getUserName()+";"+person.getAge()+";"+person.getBirth(); //寫出去 OutputStream body = outputMessage.getBody(); body.write(data.getBytes()); } }
測試:
import java.util.Date; @Controller public class ResponseTestController { /** * 1、瀏覽器發請求直接返回 xml [application/xml] jacksonXmlConverter * 2、如果是ajax請求 返回 json [application/json] jacksonJsonConverter * 3、如果硅谷app發請求,返回自定義協議數據 [appliaction/x-guigu] xxxxConverter * 屬性值1;屬性值2; * * 步驟: * 1、添加自定義的MessageConverter進系統底層 * 2、系統底層就會統計出所有MessageConverter能操作哪些類型 * 3、客戶端內容協商 [guigu--->guigu] * * 作業:如何以參數的方式進行內容協商 * @return */ @ResponseBody //利用返回值處理器里面的消息轉換器進行處理 @GetMapping(value = "/test/person") public Person getPerson(){ Person person = new Person(); person.setAge(28); person.setBirth(new Date()); person.setUserName("zhangsan"); return person; } }
日后開發要注意,有可能我們添加的自定義的功能會覆蓋默認很多功能,導致一些默認的功能失效。
讀到這里,這篇“Spring Boot數據響應問題實例分析”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。