- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
在SpringMVC中的目标方法,最终返回的都是一个 视图 (有各种视图) 。
注意,这里的视图是一个类对象,不是一个页面!! 。
返回的视图都会由一个视图解析器来处理(视图解析器有很多种) 。
在默认情况下,我们都是返回默认的视图,然后返回的视图交由 SpringMVC 的 InternalResourcesViewResolver 默认视图解析器来处理的:
在实际开发中,因为业务需求,我们有时候需要自定义视图解析器 。
视图解析器可以配置多个,按照指定的顺序来对视图进行解析。如果上一个视图解析器不匹配,下一个视图解析器就会去解析视图,以此类推.
执行流程:
view.jsp,请求到 Handler 。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>自定义视图测试</title>
</head>
<body>
<h1>自定义视图测试</h1>
<a href="goods/buy">点击到自定义视图</a>
</body>
</html>
GoodsHandler.java 。
package com.li.web.viewresolver;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author 李
* @version 1.0
*/
@RequestMapping(value = "/goods")
@Controller
public class GoodsHandler {
@RequestMapping(value = "/buy")
public String buy(){
System.out.println("----------buy()---------");
return "liView";//自定义视图名
}
}
自定义视图 MyView.java 。
package com.li.web.viewresolver;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.view.AbstractView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
/**
* @author 李
* @version 1.0
* 1. MyView 继承了AbstractView,就可以作为了一个视图使用
* 2. @Component(value = "myView") ,该视图会注入到容器中,id为 liView
*/
@Component(value = "liView")
public class MyView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
//1.完成视图渲染
System.out.println("进入到自己的视图...");
//2.并且确定我们要跳转的页面,如 /WEB-INF/pages/my_view.jsp
/*
* 1.下面就是请求转发到 /WEB-INF/pages/my_view.jsp
* 2.该路径会被springmvc解析成 /web工程路径/WEB-INF/pages/my_view.jsp
*/
request.getRequestDispatcher("/WEB-INF/pages/my_view.jsp")
.forward(request, response);
}
}
结果页面 my_view.jsp 。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>my_view</title>
</head>
<body>
<h1>进入到my_view页面</h1>
<p>从自定义视图来的...</p>
</body>
</html>
springDispatcherServlet-servlet.xml 配置自定义视图解析器 。
<!--1.指定扫描的包-->
<context:component-scan base-package="com.li.web"/>
<!--2.配置视图解析器[默认的视图解析器]-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--配置属性 suffix(后缀) 和 prefix(前缀)-->
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--3.
3.1 配置自定义视图解析器 BeanNameViewResolver
3.2 BeanNameViewResolver 可以解析我们自定义的视图
3.3 属性 order 表示视图节解析器执行的顺序,值越小优先级越高
3.4 order 的默认值为最低优先级-LOWEST_PRECEDENCE
3.5 默认的视图解析器就是最低优先级,因此我们的自定义解析器会先执行
-->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<property name="order" value="99"/>
</bean>
<!--4.加入两个常规的配置-->
<!--支持SpringMVC的高级功能,比如:JSR303校验,映射动态请求-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--将SpringMVC不能处理的请求,交给tomcat处理,比如css,js-->
<mvc:default-servlet-handler/>
测试,访问view.jsp,点击超链接 。
成功跳转到 my_view.jsp 。
后台输出如下:说明整个执行流程如图所示.
自定义视图-工作流程:
Debug-01 。
(1)在GoodsHandler的目标方法中打上断点:
(2)点击debug,访问view.jsp,点击超链接,可以看到后台光标跳转到断点处:
(3)在源码 BeanNameViewResolver 的 resolveViewName 方法处打上断点:
(4)点击Resume,光标跳转到了这个断点处,viewName 的值就是自定义视图对象的 id:这里完成视图解析 。
resolveViewName 方法如下:
@Override
@Nullable
public View resolveViewName(String viewName, Locale locale) throws BeansException {
//获取ioc容器对象
ApplicationContext context = obtainApplicationContext();
//如果容器对象中不存在 目标方法返回的自定义视图对象id
if (!context.containsBean(viewName)) {
// Allow for ViewResolver chaining...
//就返回null,让默认的视图解析器处理该视图
return null;
}
//判断自定义的视图是不是 org.springframework.web.servlet.View 类型
if (!context.isTypeMatch(viewName, View.class)) {
//如果不是
if (logger.isDebugEnabled()) {
logger.debug("Found bean named '" + viewName + "' but it does not implement View");
}
// Since we're looking into the general ApplicationContext here,
// let's accept this as a non-match and allow for chaining as well...
return null;
}
//如果是,就返回这个自定义视图对象
return context.getBean(viewName, View.class);
}
(5)在自定义视图对象里打上断点:
(6)点击 resume,光标跳转到该断点:在这里完成视图渲染,并转发到结果页面 。
(7)最后由 tomcat 将数据返回给客户端:
将默认视图解析器的优先级调高:
debug-02 。
(1)仍然在GoodsHandler中添加断点:
(2)浏览器访问 view.jsp,可以看到后台光标跳转到了断点处:
(3)分别在默认视图解析器(InternalResourceViewResolver)和自定义视图解析器(BeanNameViewResolver) 中的方法中打上断点:
(4)点击resume,可以看到光标先跳到了默认视图解析器的 buildView 方法中:因为默认解析器的优先级在之前设置为最高.
buildView 方法:
@Override
protected AbstractUrlBasedView buildView(String viewName) throws Exception {
//根据目标方法返回的viewName创建一个View对象
InternalResourceView view = (InternalResourceView) super.buildView(viewName);
if (this.alwaysInclude != null) {
view.setAlwaysInclude(this.alwaysInclude);
}
view.setPreventDispatchLoop(true);
return view;
}
这个 View 对象的 url 是按照你配置的前缀和后缀,拼接完成的 url 。
(5)之后就会到该View对象进行视图渲染,然后由Tomcat将数据返回给客户端.
但是如果该url下没有/WEB-INF/pages/liView.jsp文件,就会报错:
视图解析器可以配置多个,按照指定的顺序来对视图进行解析。如果上一个视图解析器不匹配,下一个视图解析器就会去解析视图,以此类推:
在容器文件中,将默认的视图解析器调用优先级降低,提高自定义视图解析器的调用优先级。见2.2的容器文件配置 。
删除2.2中的自定义视图MyView.java。也就是说,自定义视图解析器解析目标方法返回的视图对象时,将会无法解析该视图,因为它不存在.
这时就会去调用下一个优先级的视图解析器,即默认视图解析器.
debug-03 。
(1)仍然在GoodsHandler中添加断点:
(2)浏览器访问 view.jsp,可以看到后台光标跳转到了断点处:
(3)在自定义的视图解析器 BeanNameViewResolver 中打上断点:
(4)点击resume,可以看到光标跳转到该断点处:
(5)因为在容器文件中找不到该视图对象的id了,因此会进入第一个分支,方法直接返回 null 。
(6)点击step over,光标跳转到中央控制器的 resolveViewName 方法中:
@Nullable
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
Locale locale, HttpServletRequest request) throws Exception {
if (this.viewResolvers != null) {
//循环调用视图解析器,直到某个视图解析器返回的view不为null
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
}
return null;
}
因为自定义视图解析器会返回 null,因此这里进入第二次循环,由默认的视图解析器去进行解析,然后返回对应的视图:
(7)在该方法中打上断点,点击 resume,可以看到此时 view 是由默认的视图解析器返回的视图对象,走的是默认机制.
(8)下一个就按照默认机制拼接的 url 去访问该页面,并进行渲染。然后由Tomcat返回给客户端。如果根据 url 找不到该页面,就报404错误.
补充:如果默认视图解析器优先级高,自定义的视图解析器优先级低,但是默认视图解析器返回的的View为null,这时候会继续调用自定义的视图解析器吗?
答:事实上,默认视图解析器返回的 View 不会为 null.
因为它是根据目标方法返回的字符串+你配置的前后缀进行 url 的拼接。只要目标方法返回了一个字符串,默认视图处理器就不会返回 null.
如果目标方法返回的是 null 呢?将会以目标方法的路径名称+配置的前后缀作为寻找页面的 url 。
因此在循环调用视图处理器的时候,一旦循环到默认视图处理器,就不会调用后面的自定义视图解析器.
目标方法中指定转发或者重定向:
例子 。
view.jsp 。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>请求转发或重定向</title>
</head>
<body>
<h1>请求转发或重定向</h1>
<a href="goods/order">测试在目标方法找中指定请求转发或重定向</a>
</body>
</html>
GoodsHandler.java 。
package com.li.web.viewresolver;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author 李
* @version 1.0
*/
@RequestMapping(value = "/goods")
@Controller
public class GoodsHandler {
//演示直接指定请求转发或者重定向
@RequestMapping(value = "/order")
public String order() {
System.out.println("=========order()=========");
//请求转发到 /WEB-INF/pages/my_view.jsp
//下面的路径会被解析/web工程路径/WEB-INF/pages/my_view.jsp
return "forward:/WEB-INF/pages/my_view.jsp";
}
}
访问 view.jsp,点击超链接:
成功进入到请求转发的页面:
请求转发也可以转发到WEB-INF目录之外的页面.
修改 GoodsHandler.java 的 order 方法:
//演示直接指定请求转发或者重定向
@RequestMapping(value = "/order")
public String order() {
System.out.println("=========order()=========");
//重定向
//1.对于重定向来说,不能重定向到/WEB-INF/目录下
//2.redirect 为重定向的关键字
//3./login.jsp 是在服务器解析的,解析为 /web工程路径/login.jsp
return "redirect:/login.jsp";
}
redeployTomcat,访问 view.jsp,点击超链接,可以看到成功重定向到 login.jsp页面 。
最后此篇关于day04-视图和视图解析器的文章就讲到这里了,如果你想了解更多关于day04-视图和视图解析器的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我一直在使用 AJAX 从我正在创建的网络服务中解析 JSON 数组时遇到问题。我的前端是一个简单的 ajax 和 jquery 组合,用于显示从我正在创建的网络服务返回的结果。 尽管知道我的数据库查
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
我在尝试运行 Android 应用程序时遇到问题并收到以下错误 java.lang.NoClassDefFoundError: com.parse.Parse 当我尝试运行该应用时。 最佳答案 在这
有什么办法可以防止etree在解析HTML内容时解析HTML实体吗? html = etree.HTML('&') html.find('.//body').text 这给了我 '&' 但我想
我有一个有点疯狂的例子,但对于那些 JavaScript 函数作用域专家来说,它看起来是一个很好的练习: (function (global) { // our module number one
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 8 年前。 Improve th
我需要编写一个脚本来获取链接并解析链接页面的 HTML 以提取标题和其他一些数据,例如可能是简短的描述,就像您链接到 Facebook 上的内容一样。 当用户向站点添加链接时将调用它,因此在客户端启动
在 VS Code 中本地开发时,包解析为 C:/Users//AppData/Local/Microsoft/TypeScript/3.5/node_modules/@types//index而不是
我在将 json 从 php 解析为 javascript 时遇到问题 这是我的示例代码: //function MethodAjax = function (wsFile, param) {
我在将 json 从 php 解析为 javascript 时遇到问题 这是我的示例代码: //function MethodAjax = function (wsFile, param) {
我被赋予了将一种语言“翻译”成另一种语言的工作。对于使用正则表达式的简单逐行方法来说,源代码过于灵活(复杂)。我在哪里可以了解更多关于词法分析和解析器的信息? 最佳答案 如果你想对这个主题产生“情绪化
您好,我在解析此文本时遇到问题 { { { {[system1];1;1;0.612509325}; {[system2];1;
我正在为 adobe after effects 在 extendscript 中编写一些代码,最终变成了 javascript。 我有一个数组,我想只搜索单词“assemble”并返回整个 jc3_
我有这段代码: $(document).ready(function() { // }); 问题:FB_RequireFeatures block 外部的代码先于其内部的代码执行。因此 who
背景: netcore项目中有些服务是在通过中间件来通信的,比如orleans组件。它里面服务和客户端会指定网关和端口,我们只需要开放客户端给外界,服务端关闭端口。相当于去掉host,这样省掉了些
1.首先贴上我试验成功的代码 复制代码 代码如下: protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
什么是 XML? XML 指可扩展标记语言(eXtensible Markup Language),标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。 你可以通过本站学习 X
【PHP代码】 复制代码 代码如下: $stmt = mssql_init('P__Global_Test', $conn) or die("initialize sto
在SQL查询分析器执行以下代码就可以了。 复制代码代码如下: declare @t varchar(255),@c varchar(255) declare table_cursor curs
前言 最近练习了一些前端算法题,现在做个总结,以下题目都是个人写法,并不是标准答案,如有错误欢迎指出,有对某道题有新的想法的友友也可以在评论区发表想法,互相学习🤭 题目 题目一: 二维数组中的
我是一名优秀的程序员,十分优秀!