Spring中的主题(Theme)切换实现流程浅析
刚刚接触Theme时根本看不懂,代码的执行逻辑。这是个不详的征兆,多看几遍,反复捋捋,代码执行逻辑才初现端倪。
前置工作:
- Maven依赖
- servlet上下文环境
- 项目文件结构
- 代码链接点击打开链接charpter3/theme
- Maven依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.0.5.RELEASE</version>
</dependency>
</dependencies>
注意事项:spring-webmvc项目,必然要 引入spring-mvc依赖,可问题是存在传递依赖,也就是说spring-mvc依赖spring-core, spring-web, spring-context, spring-beans。所以这些依赖也要一并引入。
- servlet上下文环境
web.xml中的内容
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.mvc</url-pattern>
</servlet-mapping>
springmvc-servlet.xml中的内容
<context:component-scan base-package="com.wiley.beginningspring.ch3" />
<context:annotation-config />
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="themeSource" class="org.springframework.ui.context.support.ResourceBundleThemeSource"/>
<bean id="themeResolver" class="org.springframework.web.servlet.theme.SessionThemeResolver">
<property name="defaultThemeName" value="dark" />
</bean>
<mvc:interceptors>
<bean id="themeChangeInterceptor" class="org.springframework.web.servlet.theme.ThemeChangeInterceptor">
<property name="paramName" value="theme"/>
</bean>
</mvc:interceptors>
- 项目文件结构
好,至此,前置工作完成。现在来解读一下代码:
当我们在URL地址栏输入http://localhost:8080/form.mvc时,发生了什么?这是很重要的一点,对于初学者而言。
首先,http://localhost:8080/form.mvc会被转化成一个http请求,http请求首先到达前端控制器,这里的前端控制器也就是web.xml中出现的org.springframework.web.servlet.DispatcherServlet。所有的请求都逃不过DispatcherServlet的魔爪。URL中的form.mvc是模式匹配字段,对它的识别和匹配工作对应<url-pattern>*.mvc</url-pattern>,所有以.mvc结尾的请求最终汇入org.springframework.web.servlet.DispatcherServlet。前端控制器招呼映射处理器过来,说:嘿,映射处理器,你过来,看看form.mvc请求由那个控制器负责啊。映射处理器,掐指一算说,由FormController家的user负责,为什么呢?你看:
@Controller
public class FormController {
@RequestMapping(value = "/form")
public ModelAndView user() {
return new ModelAndView("form", "user", new User());
}
@RequestMapping(value = "/result")
public ModelAndView processUser(User user) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("u", user);
modelAndView.setViewName("result");
return modelAndView;
}
}
user头上带着一顶叫做/form的帽子,就是那个家伙啦,大哥,吼他,让他干活。于是前端控制器就把form.mvc请求交给了user()去处理,user()将处理的数据模型存放到一个大家都可以访问的地方:ModelAndView中,而且,user()还交代了,下一步工作的对象是form.jsp。DispatcherServlet听了user()的报告后,就把视图解析器叫过来说:你,干这个,干不好,打!于是试图解析器就从ModelAndView中去拿数据,将数据组装到form.jsp页面上指定的格子里,于是就交差了。DispatcherServlet听完了视图解析器的工作后,就把善后工作交给浏览器,浏览器渲染完后,你就能看到你的请求得到了答复。
问题来啦:矫情的你,觉得当前的页面太亮了。或者太暗了。你想可以随意地变更,于是你出的价钱合理,某个天才程序员帮你解决了问题,你竟然不知足,还想知道当你点击某个超链接时,这你的世界怎么就突然从白天转换成黑夜了。你百思不得解啊。你说,朝闻道,夕死可矣。那位满足了你需求的天才程序员说,什么价?...
开讲:Theme主题的变换
首先来看看springmvc-servlet.xml
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="themeSource" class="org.springframework.ui.context.support.ResourceBundleThemeSource"/>
<bean id="themeResolver" class="org.springframework.web.servlet.theme.SessionThemeResolver">
<property name="defaultThemeName" value="dark" />
</bean>
<mvc:interceptors>
<bean id="themeChangeInterceptor" class="org.springframework.web.servlet.theme.ThemeChangeInterceptor">
<property name="paramName" value="theme"/>
</bean>
</mvc:interceptors>
主题架构最核心的三个机制themeSource,themeResolver,themeChangeInterceptor。
themeSource是什么?专门读取路径中的属性文件,比如dark.properties,文件的格式是键值对形式,比如style=css/dark.css
themeResolver干什么的?当然是将主题文件进行处理啊,解析啊。
themeChangeInterceptor呢?切换主题的作用。
三者的分工不同,themeSource拿到很多主题资源,themeChangeInterceptor选择主题资源,themeResolver处理主题资源。具体又是怎么走的呢?看form.jsp代码中涉及到主题切换的一段代码:
<head>
<title>Spring MVC Themes</title>
<!-- 属性文件中定义的键值 -->
<link rel="stylesheet" href="<spring:theme code="style"/>" type="text/css" />
</head>
<body>
Theme :
<a href="?theme=light">Light</a> - <a href="?theme=dark">Dark</a>
<br/>
首先看<link rel="stylesheet" href="<spring:theme code="style"/>" type="text/css" />,这一段明显是引入主题资源的。可问题是没有看到主题资源包啊,以前引入.css,.js文件,那可是明明白白写清楚资源路径是啥,要引入的资源名又是啥。可是这个,看不出来。这就要扯到themeSource啦,因为资源是由他找到的,只有他找到了资源,你才可以用啊。问题是themeSource这个货,他是怎么找到资源的呢?这就要涉及到盘古开天辟地那会儿。在这里,只需要知道,themeSource创建时,他就会去寻找属性文件并且加载资源。就当是停懂了,可是<spring:theme code="style"/>这一坨又是什么东西?他就是资源啊。是资源列表啊。为啥啊?我已经说啦,加载的资源是以键值对的形式存在,此时的style好比如列表名。因为两个属性文件中的内容是style=css/dark.css和style=css/light.css。显然,此时的列表中有两个元素[css/dark.css, css/light.css]。默认情况下使用css/dark.css。为啥呢?因为springmvc-servlet.xml中这样写着:
<bean id="themeResolver" class="org.springframework.web.servlet.theme.SessionThemeResolver">
<property name="defaultThemeName" value="dark" />
</bean>
当你点击页面上<a href="?theme=light">Light</a> - <a href="?theme=dark">Dark</a>中的任意一个时,就发生了主题切换。这是怎么做到的呢?比如,你点击<a href="?theme=light">Light</a>,这可是一个超链接啊!它链接到哪里去呢?人家只给了一个?,岂有此理!其实啊,默认是由themeChangeInterceptor这个家伙负责处理,也就说跳转到themeChangeInterceptor这里来了,为什么呢?你点击<a href="?theme=light">Light</a>想干啥?切换主题啊!themeChangeInterceptor的天职就是为了切换而来的。让我们看看themeChangeInterceptor是如何处理的。
<mvc:interceptors>
<bean id="themeChangeInterceptor" class="org.springframework.web.servlet.theme.ThemeChangeInterceptor">
<property name="paramName" value="theme"/>
</bean>
</mvc:interceptors>
看不懂是吧?你要是能看懂,那真是见了鬼了。我这么聪明,第一次看到这也是一脸懵逼。其实是这样的:你点击一个超链接意味着什么?意味着你发起了一次http请求。http请求会将你请求的参数theme=light保存到request中。themeChangeInterceptor接收到http请求,也就拿到了request。然后,上面<mvc:interceptors>...</mvc:interceptors>,之间有这么一段<property name="paramName" value="theme"/>,也就是说,theme会被当作值赋给paramName,那好,theme是什么?theme可是键值对中的键啊!themeChangeInterceptor通过quest拿到了theme=light,又通过paramName拿到了theme,那他接下来要干嘛?当然是获取键值对中的值light啊。拿到light后干嘛?当然是根据light获取style列表中的light.css,然后自然是交给themeResolver进行解析啊。themeResolver解析完成后,交给浏览器渲染。最后切换后的主题效果就呈选在你的眼前啦。
上一篇: Cakephp 执行主要流程