1 include指令和include动作
1.1问题
在一个网站中的多个页面都需要存在相同的内容,比如在我们的BBS项目中
首页,列表页面,详情页面都需要展示:
每一个页面都需要判断用户是否登录。这时就需要在每个页面编写相同的重复的代码。为什么避免这样重复的写代码,所以解决思路就是写一个公共的程序,包含到当前的页面来。
1.2 include指令
案例:
首页和其他页面都需要top,添加一个外部的top.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <p> 这是头部,是top.jsp </p> |
在引用的页面中使用include指令引入页面:
Include是三大指令之一。
File指向要引入的页面。
在浏览器中查看源代码:
浏览器中是一段完整的HTML代码。
分析:
观察JSP生成的servlet文件
Top.jsp并未生成java文件,查看index_jsp.java文件:
发现top.jsp中的内容被完全包含在index.jsp中输出。
结论:include指令就是将file指定的页面的内容完全的包含到当前的页面中。被包含的页面不会单独执行。
1.3 include动作
案例:
创建foot.jsp类似于top.jsp编写
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <p> 这是版权部分,这是foot.jsp </p> <% String str = "abc"; %> |
在index和second页面中分别使用 include动作引入foot.jsp
观察浏览器中的HTML代码:
浏览器中依然是完整的HTML代码。
分析:
观察服务器端jsp生成的java代码
发现foot.jsp单独翻译成了一个java文件,并且编译执行了。
观察index_jsp.java源代码:
发现在需要foot.jsp的时候,只是调用了一个include的方法动态的引入了foot.jsp.
1.4 include的总结
Include指令称之为静态导入:<%@ include file=””%>
Include动作称之为动态导入:<jsp:include page=””/>
指令是将目标页面的代码完全包含进来,目标页面中的代码会成为当前页面中代码的一部分。所以我们要注意,在目标页面和当前页面中不能出现相同的变量,无论是java代码还是js代码。防止冲突。
动作是将目标页面单独执行,在运行时通过一个方法动态的导入目标页面的内容,目标页面和当前页面的java代码是不会冲突的。但是JS代码中的函数和变量会产生冲突。
什么时候使用指令,什么时候用动作。随意!
2过滤器
2.1概念
filter功能.它使用户可以改变一个request和修改一个response. Filter 不是一个servlet,它不能产生一个response,它能够在一个request到达servlet之前预处理request,也可以在response离开servlet时处理response.换种说法,filter其实是一个“servlet chaining“(servlet 链).
包括
1. 在servlet被调用之前截获;
2. 在servlet被调用之前检查servlet request;
3. 根据需要修改request头和request数据;
4. 根据需要修改response头和response数据;
5. 在servlet被调用之后截获.
2.2 编写一个Filter
编写一个类,实现接口javax.servelt.Filter。
package com.igeek.filter;
import java.io.IOException;
import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse;
public class FirstFilter implements javax.servlet.Filter{ /** * 初始化filter。当filter对象创建之后,就立刻执行。 * @param FilterConfig 类似于ServletConfig可以获取初始化参数 */ public void init(FilterConfig filterConfig) throws ServletException { System.out.println("初始化filter"); }
/** * 过滤器的核心方法,用于处理过滤业务 */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("执行过滤器FirstFilter"); } /** * filter对象消亡之前执行的方法,一般都是用来释放资源 */ public void destroy() { System.out.println("filter消亡释放资源"); }
} |
过滤器必须由servlet容器加载,所以也需要配置:
在web.xml文件中进行配置(配置和servlet非常相似)
<!-- 配置过滤器 --> <filter> <filter-name>firstFilter</filter-name> <filter-class>com.igeek.filter.FirstFilter</filter-class> </filter> <filter-mapping> <filter-name>firstFilter</filter-name> <url-pattern>/userAdd</url-pattern> </filter-mapping> |
配置中的url-pattern是过滤器要拦截的请求。类似于servlet中的url-pattren
启动服务器访问测试:
启动服务器的过程中,fitler就被创建了。
感觉上和servlet几乎一致,访问对应的url就进入对应的fitler执行对应的doFilter方法。
Servlet和filter是否可以交替使用????
2.3通过filter过滤请求
业务需求:登录拦截
当访问userAddservlet时需要用户登录,如果没有登录就进入登录页面。
[1]添加登录页面
<form action="login"> 登录名:<input type="text" name="loginName"> <input type="submit" value="登录"/> </form> |
[2]添加登录的servlet,登录成功之后将用户名添加到session中。
public class LoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.getSession().setAttribute("loginName", request.getParameter("loginName")); response.sendRedirect("inde.jsp"); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } |
[3]在firstFilter中添加拦截业务
package com.igeek.filter;
public class FirstFilter implements javax.servlet.Filter{ /** * 初始化filter。当filter对象创建之后,就立刻执行。 * @param FilterConfig 类似于ServletConfig可以获取初始化参数 */ public void init(FilterConfig filterConfig) throws ServletException { System.out.println("初始化filter"); }
/** * 过滤器的核心方法,用于处理过滤业务 */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("执行过滤器FirstFilter"); //将request对象强制类型转换为HttpServletRequest,因为tomcat传入的本身就是HttpServletRequest类型的对象 HttpServletRequest req = (HttpServletRequest)request; //判断用户是否登录 从session中取出用户名 HttpSession session = req.getSession(); //从session中取出登录名 Object name = session.getAttribute("loginName"); if(name!=null) {//登录名存在的 if(name.equals("admin")) {//登录成功 System.out.println("果然登录了:"+name); //继续访问userAdd //继续执行,不做拦截, /** * 如果有下一个filter,就执行下一个filter,如果没有就进入访问的资源。 */ chain.doFilter(req, response); return; } } //登录失败 System.out.println("还没登录就想添加用户"); req.setAttribute("loginError", "您没有登录!"); req.getRequestDispatcher("login.jsp").forward(request, response); return; } /** * filter对象消亡之前执行的方法,一般都是用来释放资源 */ public void destroy() { System.out.println("filter消亡释放资源"); }
}
|
[4] 添加一个userAddServlet模拟添加用户
public class UserAddServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("添加用户的servlet"); response.getWriter().append("Served at: ").append(request.getContextPath()); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }
} |
测试:
没登录的情况下:
直接转发进入登录页面。
登录之后的情况:
2.4 Filter的url-pattern
Filter的url本身和servlet的url没有什么区别。
但是从逻辑意义上来说,他就是用来过滤的,所有filter的url往往是一种模板。比如:
拦截所有/user/xxx 或者 user/xxx/xxx/xx
拦截所有的请求:
拦截某种后缀的请求:
2.5 Filter的执行顺序
在添加一个filter
public class SecondFitler implements Filter {
public void destroy() { }
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("执行了SecondFitler"); chain.doFilter(request, response); }
public void init(FilterConfig fConfig) throws ServletException { }
} |
配置First Filter和SecondFilter拦截相同的url。
测试:
主要由于配置顺序导致先配置先执行:
调整顺序再测试:
测试:
结论:先配置,先执行。
2.6处理中文乱码的filter
创建一个CharacterFilter
package com.igeek.filter;
import java.io.IOException;
import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest;
public class CharacterFilter implements Filter {
private String charSet = "utf-8";
@Override public void init(FilterConfig filterConfig) throws ServletException { //获取初始化参数 String cset = filterConfig.getInitParameter("charSet"); if(cset!=null && !"".equals(cset)) { charSet = cset; } }
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //设置字符集 //获取请求的方法 HttpServletRequest req = (HttpServletRequest)request; String method = req.getMethod(); if(method.equalsIgnoreCase("POST")) { //如果是post请求就设置字符集 req.setCharacterEncoding(charSet); }else { //tomcat7之前的需要解码 //tomcat8 不需要处理 } //无论如何都要放行 chain.doFilter(req, response); }
@Override public void destroy() {
}
} |
配置:
<!-- 字符集处理 --> <filter> <filter-name>CharacterFilter</filter-name> <filter-class>com.igeek.filter.CharacterFilter</filter-class> <init-param> <param-name>charSet</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
|
3监听器
3.1概念
监听器就是有一个对象在一直观察者某一个其他对象的状态,一旦被观察对象状态发生了变化,监听器可以做出对应的反应。
在javaWeb有三个被监听的对象,分别是:request,session,application对象。
主要监听对象的创建以及对象中属性的变化(添加了属性,修改了属性,删除了属性)。
监听器同样是由servlet容器(tomcat)创建运行的。编写好了之后同样要配置在web.xml中。
3.2创建监听器
[1]添加一个application对象被创建的监听器
添加一个类实现接口:javax.servlet.ServletContextListener
public class MyApplicationCreateListener implements ServletContextListener { /** * application对象初始化时触发 */ public void contextInitialized(ServletContextEvent sce) { System.out.println("application对象被初始化了"); } /** * application对象被销毁时触发 */ public void contextDestroyed(ServletContextEvent sce) { System.out.println("application对象被销毁了"); }
} |
在web.xml文件中配置监听器:
<!-- 配置监听器 --> <listener> <listener-class>com.igeek.filter.MyApplicationCreateListener</listener-class> </listener> |
启动和关闭服务器测试:
发现在启动服务器期间,监听器就监听到了application对象的初始化。关闭时同样监听到了对象的销毁。
监听器中的两个方法传入的参数:ServletContextEvent 的主要作用是获取application对象:
3.3六种不同的监听器
查看API:
Javax.servlet包中
Javax.servlet.http包中
逐个编写:
[1] 实现接口ServletContextAttributeListener 三个方法必须实现
/** * 参数 : 获取application对象,获取属性的名称, 获取属性的值 */ public void attributeAdded(ServletContextAttributeEvent scae) { // 获取application对象 ServletContext application = scae.getServletContext(); // 获取属性的名称 String attrName = scae.getName(); // 获取属性的值 Object attrValue = scae.getValue(); System.out.println("给applacation中添加属性:" + attrName + "-" + attrValue); }
// 当给删除application对象的属性后触发 public void attributeRemoved(ServletContextAttributeEvent scae) { // 获取属性的名称 String attrName = scae.getName(); // 获取属性的值 Object attrValue = scae.getValue(); System.out.println("删除applacation中属性:" + attrName + "-" + attrValue); }
// 当给替换application对象的属性后触发 public void attributeReplaced(ServletContextAttributeEvent scae) { // 获取属性的名称 String attrName = scae.getName(); // 获取属性的值 Object attrValue = scae.getValue(); System.out.println("修改applacation中属性:" + attrName + "-" + attrValue); ServletContext application = scae.getServletContext(); System.out.println("修改后的新值:"+application.getAttribute(attrName)); }
|
[2] 实现接口HttpSessionListener 实现两个方法:
/** * 创建session后触发 参数用于获取session对象 */ public void sessionCreated(HttpSessionEvent se) { // 获取session对象 HttpSession session = se.getSession(); System.out.println("创建session:" + session.getId()); }
/** * session销毁后触发 */ public void sessionDestroyed(HttpSessionEvent se) { // 获取session对象 HttpSession session = se.getSession(); System.out.println("销毁session:"+session.getId()); }
|
[3]实现接口HttpSessionAttributeListener 实现三个方法
// 实现了HttpSessionAttribute中的方法 @Override public void attributeAdded(HttpSessionBindingEvent se) { //获取session HttpSession session = se.getSession(); String name = se.getName(); Object value = se.getValue(); System.out.println("给session添加属性:"+name+"-"+value); }
@Override public void attributeRemoved(HttpSessionBindingEvent se) { String name = se.getName(); Object value = se.getValue(); System.out.println("删除session属性:"+name+"-"+value); }
@Override public void attributeReplaced(HttpSessionBindingEvent se) { String name = se.getName(); Object value = se.getValue(); System.out.println("修改session属性:"+name+"-"+value); HttpSession session = se.getSession(); System.out.println("修改后的值是:"+session.getAttribute(name)); }
|
[4]实现接口ServletRequestListener 实现两个方法:
// 初始化request @Override public void requestInitialized(ServletRequestEvent sre) { ServletRequest req = sre.getServletRequest(); System.out.println("销毁request:"+req.toString()); }
@Override public void attributeAdded(ServletRequestAttributeEvent srae) { String name = srae.getName(); Object value = srae.getValue(); System.out.println("给request添加属性:"+name+" - "+ value); }
|
[5]实现接口ServletRequsetAttributeListener 实现三个方法:
@Override public void attributeAdded(ServletRequestAttributeEvent srae) { String name = srae.getName(); Object value = srae.getValue(); System.out.println("给request添加属性:"+name+" - "+ value); }
@Override public void attributeRemoved(ServletRequestAttributeEvent srae) { String name = srae.getName(); Object value = srae.getValue(); System.out.println("删除request属性:"+name+" - "+ value); }
@Override public void attributeReplaced(ServletRequestAttributeEvent srae) { String name = srae.getName(); Object value = srae.getValue(); System.out.println("修改request属性:"+name+" - "+ value); ServletRequest req = srae.getServletRequest(); System.out.println("修改后的新值:"+req.getAttribute(name)); }
|
[6] 添加测试的servlet
public class ListenerServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取Application对象 ServletContext application = this.getServletContext(); application.setAttribute("appAttr", "application-VALUE - 1"); application.setAttribute("appAttr", "application-VALUE - 2"); application.removeAttribute("appAttr");
//session HttpSession session = request.getSession(); session.setAttribute("seAttr", "session - value -1"); session.setAttribute("seAttr", "session - value -2"); session.removeAttribute("seAttr"); session.setMaxInactiveInterval(5); session.invalidate();//主动销毁session
//给request添加属性 request.setAttribute("reqAttr", "request - value -1"); request.setAttribute("reqAttr", "request - value -2"); request.removeAttribute("reqAttr"); response.getWriter().append("Served at: ").append(request.getContextPath()); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }
} |
测试结果: