我們在上一章節中,講解了ContentNegotiating內容協商的使用及簡單原理分析,上一章節主要是講解內容協商在HttpMessage上的作用。
其實內容協商不僅僅可以作用在HttpMessage上,還可以作用在View視圖上,本章節我講解該內容。
一.內容協商視圖解析器
1.概述
ContentNegotiatingViewResolver自己並不解析視圖,而是委派給其他的視圖處理器。
爲了使這個解析器正常工作,order序號需要設置成比其他的視圖處理器高的優先級(默認就是最高的)。
2. ContentNegotiatingViewResolver細節:
- ContentNegotiationManager用於內容協商的策略可以手動設置指定,也可以通過FactoryBean自動生成;
- viewResolvers默認是去容器內找到所有的,當然你也可以手動set進來;
- 使用request的媒體類型,根據擴展名選擇不同的view輸出不同的格式;
- 不是自己處理view,而是代理給不同的ViewResolver來處理不同的view;
- 默認是支持Accept和後綴的協商方式的。並且還支持 邏輯視圖名.後綴的視圖解析方式;
- 依據View.getContentType匹配MediaType來完成的最佳匹配。
二.ContentNegotiatingViewResolver使用
在默認情況下,Spring MVC並沒有開啓ContentNegotiatingViewResolver內容協商視圖解析器,因此如果有同一接口資源,要用多視圖展示的需求,我們是需要自己手動配置來實現的。
所以接下來我帶大家,對同一個接口資源,返回多個View。
1. 需求介紹
我們要對同一個RESTful風格的URL,根據請求的不同,可以得到一個PDF視圖,一個JSON視圖,一個Html視圖。
2. 創建web項目(略)
參照之前的案例,我們創建一個新的web項目,過程略去。
3. 創建View視圖
3.1 創建PdfViewResolver類
package com.yyg.boot.resolver;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
/**
* @Description Description
* @Author 一一哥Sun
* @Date Created in 2020/3/22
*/
public class PdfViewResolver implements View {
@Override
public String getContentType() {
return MediaType.APPLICATION_PDF_VALUE;
}
@Override
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
response.getWriter().write("<html><body style='color:red'>This is [PDF] view</body></html>");
}
}
3.2 創建ExcelViewResolver類
package com.yyg.boot.resolver;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
/**
* @Description Description
* @Author 一一哥Sun
* @Date Created in 2020/3/22
*/
public class ExcelViewResolver implements View {
@Override
public String getContentType() {
return MediaType.APPLICATION_JSON_UTF8_VALUE;
}
@Override
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
response.getWriter()
.write("<html><body style='color:blue'>This is [JSON] view!</body></html>");
}
}
3.3 創建HtmlViewResolver類
package com.yyg.boot.resolver;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
/**
* @Description Description
* @Author 一一哥Sun
* @Date Created in 2020/3/22
*/
public class HtmlViewResolver implements View {
@Override
public String getContentType() {
return MediaType.TEXT_HTML_VALUE;
}
@Override
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
response.getWriter()
.write("<html><body style='color:green'>This is [HTML] view!</body></html>");
}
}
4. 進行視圖配置
將上面創建的視圖註冊到內容協調視圖解析器中,開啓Spring MVC在視圖上對ContentNegotiation內容協商的支持。
package com.yyg.boot.config;
import com.yyg.boot.resolver.ExcelViewResolver;
import com.yyg.boot.resolver.HtmlViewResolver;
import com.yyg.boot.resolver.PdfViewResolver;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;
import java.util.Map;
/**
* @Description Description
* @Author 一一哥Sun
* @Date Created in 2020/3/22
*/
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.enableContentNegotiation(new PdfViewResolver());
registry.enableContentNegotiation(new ExcelViewResolver());
registry.enableContentNegotiation(new HtmlViewResolver());
// 上面三個註冊方法必須在此方法之上執行
registry.enableContentNegotiation(false);
}
}
5. 創建Controller測試接口
package com.yyg.boot.web;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.util.MimeType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @Description 內容協商視圖解析器
* @Author 一一哥Sun
* @Date Created in 2020/3/21
*/
@Slf4j
@Controller
public class NegotiationController {
@GetMapping(value = "/show/{type}")
public String showUser(@PathVariable("type") String type) {
log.warn("type={}", type);
return "跟一一哥學習ContentNegotiatingViewResolver!";
}
}
6. 啓動程序,運行測試
我們在瀏覽器中輸入地址:
http://localhost:8080/show/a.pdf
可以看到如下效果:
我們在瀏覽器中輸入地址:
http://localhost:8080/show/a.json
可以看到如下效果:
我們在瀏覽器中輸入地址:
http://localhost:8080/show/a.html
可以看到如下效果:
而在沒有後綴名的情況下,以Accept的規則爲準。
所以可見擴展名的規則優先級高於Accept,符合我們上一章節中的理論知識。若沒有指定請求的擴展名,則Accept就會生效!