前记:在了解了基本的spring知识并且尝试运用ssm框架做了一些小的训练项目后,想要进一步熟悉ssm框架的开发,于是就通过他人的建议找到了由springMVC自带的开源项目jpetstore的源码来学习。
jpetstore的源码github地址:https:///making/spring-jpetstore.git
作为一个web项目的学习当然先从web.xml开始学习了,废话不多说先开始对web.xml文件进行解析吧:
原配置文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:jsp="http://java.sun.com/xml/ns/javaee/jsp"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<listener>
<listener-class>ik.am.jpetstore.app.common.session.HttpSessionEventLoggingListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:META-INF/spring/applicationContext.xml
classpath*:META-INF/spring/spring-security.xml
</param-value>
</context-param>
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>HttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<el-ignored>false</el-ignored>
<page-encoding>UTF-8</page-encoding>
<scripting-invalid>false</scripting-invalid>
<include-prelude>/WEB-INF/views/common/include.jsp</include-prelude>
</jsp-property-group>
</jsp-config>
<error-page>
<error-code>404</error-code>
<location>/WEB-INF/views/notFoundError.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/WEB-INF/views/systemError.jsp</location>
</error-page>
</web-app>
对各个配置项的解析如下:
1.配置DispatcherServlet的作用与功能:
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
DispatcherServlet(常说的前端控制器)是前端控制器设计模式的实现,提供Spring Web MVC的集中访问点,而且负责职责的分派,而且与Spring IoC容器无缝集成,从而可以获得Spring的所有好处。
DispatcherServlet主要用作职责调度工作,本身主要用于控制流程,主要职责如下:
1、文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析;
2、通过HandlerMapping,将请求映射到处理器(返回一个HandlerExecutionChain,它包括一个处理器、多个HandlerInterceptor拦截器);
3、通过HandlerAdapter支持多种类型的处理器(HandlerExecutionChain中的处理器);
4、通过ViewResolver解析逻辑视图名到具体视图实现;
5、本地化解析;
6、渲染具体的视图等;
7、如果执行过程中遇到异常将交给HandlerExceptionResolver来解析。
在该配置文件中主要用于映射处理器
2.CharacterEncodingFilter的配置以及作用:
原配置xml:
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
CharacterEncodingFilter过滤器是统一编码过滤器,它配置用于拦截所有请求,在进入Controller之前对编码进行统一设置,防止由于编码不统一造成乱码问题。其中CharacterEncodingFilter过滤器继承了OncePerRequestFilter,OncePerRequestFilter继承了GenericFilterBean,GenericFilterBean实现了Filter接口。
3.HiddenHttpMethodFilter的配置和作用:
原配置xml:
<filter>
<filter-name>HttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
浏览器form表单只支持GET与POST请求,而DELETE、PUT等method并不支持,spring3.0添加了一个过滤器,可以将这些请求转换为标准的http方法,使得支持GET、POST、PUT与DELETE请求,该过滤器为HiddenHttpMethodFilter。
HiddenHttpMethodFilter的父类是OncePerRequestFilter,它继承了父类的doFilterInternal方法,工作原理是将jsp页面的form表单的method属性值在doFilterInternal方法中转化为标准的Http方法,即GET,、POST、 HEAD、OPTIONS、PUT、DELETE、TRACE,然后到Controller中找到对应的方法。例如,在使用注解时我们可能会在Controller中用于@RequestMapping(value = "list", method = RequestMethod.PUT),所以如果你的表单中使用的是<form method="put">,那么这个表单会被提交到标了Method="PUT"的方法中。
4.<jsp-config></jsp-config>标签的配置以及作用
原项目配置如下
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<el-ignored>false</el-ignored>
<page-encoding>UTF-8</page-encoding>
<scripting-invalid>false</scripting-invalid>
<include-prelude>/WEB-INF/views/common/include.jsp</include-prelude>
</jsp-property-group>
</jsp-config>
总体来说<jsp-config></jsp-config>标签的作用主要是对<url-pattern></url-pattern>里边指定的jsp的属性的整体配置,包括编码方式、是否支持el表达式、加入公共的文件抬头等。
(1).<description>:设定的说明
(2).<display-name>:设定名称
(3).<url-pattern>:设定值所影响的范围,如:/CH2 或 /*.jsp
(4).<el-ignored>:若为true,表示不支持EL 语法
(5).<scripting-invalid>:若为true,表示不支持<% scripting %>语法
(6).<page-encoding>:设定JSP 网页的编码
(7).<include-prelude>:设置JSP 网页的抬头,扩展名为.jspf
(8).<include-coda>:设置JSP网页的结尾,扩展名为.jspf
5.<error-page></error-page>标签的配置和作用
<error-page>
<error-code>404</error-code>
<location>/WEB-INF/views/notFoundError.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/WEB-INF/views/systemError.jsp</location>
</error-page>
在java web项目中,有时我们需要在错误发生时,给出用户提示信息,或者显示站点维护者信息,再或者将错误替换为另一种表达以舒缓情绪。这时可以采用web.xml的error-page标签来实现。<error-code></error-code>用于配置错误类型,<location></location>用于配置出现指定错误类型时跳转的处理界面。
6.<context-param></context-param>标签的使用和作用
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:META-INF/spring/applicationContext.xml
classpath*:META-INF/spring/spring-security.xml
</param-value>
</context-param>
当服务器启动时,服务器会读取web.xml配置,当读到<listener></listener>和<context-param></context-param>这两个节点的时候,容器会将这两个节点set到ServletContext(上下文对象)中,这样我们在程序中就能通过这个上下文对象去取得我们这个配置值。在ContextLoaderListener的源码中存在这样两个方法:
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
@Override
public void contextDestroyed(ServletContextEvent event) {
closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
这两个方法的传递参数类型都是ServletContextEvent,进入这里ServletContextEvent类的源码,我们可以看到如下方法:
public ServletContextEvent(ServletContext source) {
super(source);
}
public ServletContext getServletContext () {
return (ServletContext) super.getSource();
}
可以看到ServletContext对象,由此可见 ServletContext上下文对象是贯穿在整个框架资源加载程序中的,在进入ServletContext的源码,可以看到以下接口方法(未完全列出):
public String getContextPath();
public ServletContext getContext(String uripath);
public int getMajorVersion();
public int getMinorVersion();
public int getEffectiveMajorVersion();
public int getEffectiveMinorVersion();
public String getMimeType(String file);
public Set<String> getResourcePaths(String path);
public URL getResource(String path) throws MalformedURLException;
public InputStream getResourceAsStream(String path);
public RequestDispatcher getRequestDispatcher(String path);
public RequestDispatcher getNamedDispatcher(String name);
public Servlet getServlet(String name) throws ServletException;
.......
从这些方法中我们可以看到ServletContext提供了大量的通过路径获取资源的方法,这些方法用于通过contextConfigLocation配置的文件路径来获取资源。
注:需要再次强调的是,在一个web项目中,当服务器启动是,服务器容器会读取web.xml文件的配置信息,并且将其转化成键值对的形式,交给创建的ServletContext对象以供整个web程序使用,同时需要注意的是web.xml文件是由服务器(例如Tomcat)解析的,而不是某个框架解析的。
6.ContextLoaderListener上下文监听器的配置与作用:
源码配置:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
该监听器用于监听处理ServletContext中的资源,在这里主要是加载applicationContext.xml和spring-security.xml配置文件中的资源。