web中执行顺序,加载context-param参数 -> 按声明顺序执行listener -> 执行filter链 -> 执行servlet
一. context-param
context-param用来设置属性值,在listener,filter,servlet中都可以读取到该值
<!--自定义属性-->
<context-param>
<param-name>customName</param-name>
<param-value>customValue</param-value>
</context-param>
<!--ContextLoaderListener会读取contextConfigLocation属性-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
二. listener
在servlet-api中提供了ServletContextListener和ServletRequestListener两种监听器
下面我们自定义一个Listener,实现ServletContextListener接口,在该方法中获取context-param配置的属性值
public class SomeListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { System.out.println("SomeListener.contextInitialized"); ServletContext sc = sce.getServletContext(); String value = sc.getInitParameter("customName"); System.out.println("get customName value: " + value); } @Override public void contextDestroyed(ServletContextEvent sce) { System.out.println("SomeListener.contextDestroyed"); } }
在web.xml中配置listener
<listener> <listener-class>com.xxx.listener.SomeListener</listener-class> </listener>
使用spring web中的ContextLoaderListener,该类同样实现了ServletContextListener接口
执行该Listener时,默认会读取/WEB-INF/applicationContext.xml文件
可以通过context-param中的contextConfigLocation属性修改读取文件的位置
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
三. filter
实现Filter接口,在初始化时可以获取到context-param中的参数信息,也可以获取到filter中的init-param信息
在doFilter时可以做一些过滤操作,比如Shiro中的认证授权操作。
public class SessionFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("SessionFilter.init"); String filterValue = filterConfig.getInitParameter("filterKey"); System.out.println("SessionFilter get filterKey: " + filterValue); String customValue = filterConfig.getServletContext().getInitParameter("customName"); System.out.println("SessionFilter get customValue: " + customValue); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //do somthing if(request instanceof HttpServletRequest){ HttpServletRequest httpRequest = (HttpServletRequest) request; Cookie[] cookies = httpRequest.getCookies(); for (Cookie cookie : cookies) { if ("JSESSIONID".equals(cookie.getName())) { String sessionId = cookie.getValue(); System.out.println("sessionId is: " + sessionId); } } } chain.doFilter(request,response); } @Override public void destroy() { System.out.println("SessionFilter.destroy"); } }
配置web.xml
url-pattern4中匹配规则
- 以 / 开头和以 /* 为结尾的是路径匹配
- 以 *. 开头的是扩展名匹配,比如 *.dao 匹配以dao为结尾的资源
- 只有 / 是定义default servlet,当请求的url和url-pattern没有匹配的时候,把请求发送default servlet
- 精确匹配如: /a/b/c
所以Filter中的url-pattern要使用 /* 而不能使用 /
<filter> <filter-name>sessionFilter</filter-name> <filter-class>com.xxx.filter.SessionFilter</filter-class> <init-param> <param-name>filterKey</param-name> <param-value>filterValue</param-value> </init-param> </filter> <filter-mapping> <filter-name>sessionFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Tips:
如果自定义实现的Filter需要一个构造函数怎么办? 在配置Filter时没有提供这个配置项。
这时我们就可以使用DelegatingFilterProxy,它会去spring中根据Filter名字找bean,这样我们初始化Filter bean就可以了。
四. servlet
当请求经过filter过滤后,就会交给servlet处理,servlet是一个接口,其中service()是最终要调用的方法
如下我们继承HttpServlet,并重写他的service方法,在service方法中会传进来HttpServletRequest和HttpServletResponse
public class HelloServlet extends HttpServlet {
@Override
public ServletConfig getServletConfig() {
System.out.println("HelloServlet.getServletConfig");
return super.getServletConfig();
}
@Override
public void init() throws ServletException {
System.out.println("HelloServlet.init");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
session.setAttribute("username","sicwen");
session.setAttribute("password","123");
req.getRequestDispatcher("hello.jsp").forward(req,resp);
System.out.println("HelloServlet.service");
}
@Override
public void destroy() {
System.out.println("HelloServlet.destroy");
}
}
在web.xml中配置
<servlet> <servlet-name>hello</servlet-name> <servlet-class>com.xxx.servlet.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>