include指令&过滤器&监听器

本文详细解析了JSP中的include指令与动作的区别及应用,包括如何避免代码重复,提高开发效率。同时介绍了过滤器(filter)的概念、实现与配置,以及如何通过过滤器进行请求的预处理和响应的后处理。最后,深入探讨了监听器(listener)的作用,以及如何监听request、session、application对象的状态变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

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);

    }

 

}

 

测试结果:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值