前言
在上一章节中,壹哥 给大家讲解了ContentNegotiating内容协商的简单使用及原理分析,让我们明白了内容协商在HttpMessage上的作用。
我们知道,利用ContentNegotiating可以实现访问同一个URL接口,可以访问不同格式的数据,比如返回JSON、XML格式;那么如果我想使用同样的数据内容来呈现出不同的View该怎么办呢?这就要用到我今天要讲的内容了。
内容协商不仅可以作用在HttpMessage上面,还可以作用在我们输出的View视图内容上,本章节我会继续讲解这一块的内容。
一. 内容协商视图解析器
1. 概述
我们利用ContentNegotiatingViewResolver内容协调视图解析器,可以实现RESTful中的一个重要特性,即对同一个URL资源,可以有多种表述方式。ContentNegotiatingViewResolver视图解析器可以允许我们使用同样的内容数据来呈现出不同的View。
但ContentNegotiatingViewResolver自己并不解析视图,而是委派给其他的视图处理器。为了使这个解析器正常工作,order序号需要设置成比其他的视图处理器高的优先级(默认就是最高的)。
2. ContentNegotiatingViewResolver细节:
- ContentNegotiationManager用于内容协商的策略可以手动设置指定,也可以通过FactoryBean自动生成;
- viewResolvers默认是去容器内找到所有的,当然你也可以手动set进来;
- 使用request的媒体类型,根据扩展名选择不同的view输出不同的格式;
- 不是自己处理view,而是代理给不同的ViewResolver来处理不同的view;
- 默认是支持Accept和后缀的协商方式的。并且还支持 逻辑视图名.后缀的视图解析方式;
- 依据View.getContentType匹配MediaType来完成的最佳匹配。
3. 内容协调视图解析器工作原理图
二. ContentNegotiatingViewResolver的使用
在默认情况下,SpringMVC并没有开启ContentNegotiatingViewResolver内容协商视图解析器,因此如果有同一接口资源,要用多视图展示的需求,我们是需要自己手动配置来实现的。
所以接下来我会带大家,实现访问同一个URL接口,返回多个View的效果。
1. 需求介绍
我们要对同一个RESTful风格的URL,根据请求的不同,可以得到一个PDF视图,一个JSON视图,一个Html视图。
2. 创建web项目(略)
参照之前的案例,我们创建一个新的web项目,过程略去。
3. 创建View视图
我们在项目中创建一个com.yyg.boot.resolver包,在这个包中创建如下3个核心代码类。
3.1 创建PdfViewResolver类
创建一个可以输出PDF内容的视图解析类。
packagecom.yyg.boot.resolver; importorg.springframework.http.MediaType; importorg.springframework.web.servlet.View; importorg.springframework.web.servlet.ViewResolver; importorg.springframework.web.servlet.view.ContentNegotiatingViewResolver; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; importjava.util.Map; /*** @Description Description* @Author 一一哥Sun* @Date Created in 2020/3/22*/publicclassPdfViewResolverimplementsView { publicStringgetContentType() { returnMediaType.APPLICATION_PDF_VALUE; } publicvoidrender(Map<String, ?>model, HttpServletRequestrequest, HttpServletResponseresponse) throwsException { response.getWriter() .write("<html><body style='color:red'>This is [PDF] view</body></html>"); } }
3.2 创建ExcelViewResolver类
创建一个可以输出Excel内容的视图解析类。
packagecom.yyg.boot.resolver; importorg.springframework.http.MediaType; importorg.springframework.web.servlet.View; importorg.springframework.web.servlet.view.ContentNegotiatingViewResolver; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; importjava.util.Map; /*** @Description Description* @Author 一一哥Sun* @Date Created in 2020/3/22*/publicclassExcelViewResolverimplementsView { publicStringgetContentType() { returnMediaType.APPLICATION_JSON_UTF8_VALUE; } publicvoidrender(Map<String, ?>model, HttpServletRequestrequest, HttpServletResponseresponse) throwsException { response.getWriter() .write("<html><body style='color:blue'>This is [JSON] view!</body></html>"); } }
3.3 创建HtmlViewResolver类
创建一个可以输出HTML内容的视图解析类。
packagecom.yyg.boot.resolver; importorg.springframework.http.MediaType; importorg.springframework.web.servlet.View; importorg.springframework.web.servlet.view.ContentNegotiatingViewResolver; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; importjava.util.Map; /*** @Description Description* @Author 一一哥Sun* @Date Created in 2020/3/22*/publicclassHtmlViewResolverimplementsView { publicStringgetContentType() { returnMediaType.TEXT_HTML_VALUE; } publicvoidrender(Map<String, ?>model, HttpServletRequestrequest, HttpServletResponseresponse) throwsException { response.getWriter() .write("<html><body style='color:green'>This is [HTML] view!</body></html>"); } }
3.4 最终目录结构图
下图是以上3个类的最终存储位置。
4. 进行视图配置
将上面创建的视图注册到内容协调视图解析器中,开启Spring MVC在视图上对ContentNegotiation内容协商的支持。
packagecom.yyg.boot.config; importcom.yyg.boot.resolver.ExcelViewResolver; importcom.yyg.boot.resolver.HtmlViewResolver; importcom.yyg.boot.resolver.PdfViewResolver; importorg.springframework.context.annotation.Configuration; importorg.springframework.http.MediaType; importorg.springframework.web.servlet.View; importorg.springframework.web.servlet.ViewResolver; importorg.springframework.web.servlet.config.annotation.ViewResolverRegistry; importorg.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; importorg.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; importorg.springframework.web.servlet.view.ContentNegotiatingViewResolver; importorg.springframework.web.servlet.view.InternalResourceViewResolver; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; importjava.util.Locale; importjava.util.Map; /*** @Description Description* @Author 一一哥Sun* @Date Created in 2020/3/22*/publicclassWebMvcConfigextendsWebMvcConfigurationSupport { publicvoidconfigureViewResolvers(ViewResolverRegistryregistry) { registry.enableContentNegotiation(newPdfViewResolver()); registry.enableContentNegotiation(newExcelViewResolver()); registry.enableContentNegotiation(newHtmlViewResolver()); // 上面三个注册方法必须在此方法之上执行registry.enableContentNegotiation(false); } }
5. 创建Controller测试接口
然后我们创建一个Controller接口,方便后面进行调用测试。
packagecom.yyg.boot.web; importlombok.extern.slf4j.Slf4j; importorg.springframework.http.MediaType; importorg.springframework.stereotype.Controller; importorg.springframework.util.MimeType; importorg.springframework.web.bind.annotation.GetMapping; importorg.springframework.web.bind.annotation.PathVariable; importorg.springframework.web.bind.annotation.ResponseBody; /*** @Description 内容协商视图解析器* @Author 一一哥Sun* @Date Created in 2020/3/21*/publicclassNegotiationController { value="/show/{type}") (publicStringshowUser( ("type") Stringtype) { log.warn("type={}", type); return"跟一一哥学习ContentNegotiatingViewResolver!"; } }
6. 启动程序运行测试
6.1 测试输出pdf内容视图
重启项目后,我们在浏览器中输入地址:
http://localhost:8080/show/a.pdf
可以看到如下效果:
6.2 测试输出json内容视图
如果我们在浏览器中输入如下地址:
http://localhost:8080/show/a.json
可以看到如下效果:
6.3 测试输出html内容视图
如果我们在浏览器中输入如下地址:
http://localhost:8080/show/a.html
可以看到如下效果:
6.4 测试默认视图
而在没有后缀名的情况下,以Accept的规则为准。
所以可见扩展名的规则优先级高于Accept,符合我们上一章节中的理论知识。若没有指定请求的扩展名,则Accept就会生效!
结语
至此,我们就利用ContentNegotiatingViewResolver实现了今天的效果,虽然ContentNegotiatingViewResolver这个类名看着很长,但是实际使用起来也并不是很难,你学会了吗?
今日小作业:
请在学生管理系统中,设计一个学生自我介绍功能,能够以不同的格式输出学生信息。