Servlet作用域

Servlet三大作用域

​ 在JSP中存在四大作用域pageContextrequestsessionapplication

​  pageContext: PageContext

​  request: HttpServletRequest

​  session: HttpSession

  application: ServletContext

在Servlet中只存在三大作用域:

​  HttpServletRequest  一次请求

  HttpSession  一次会话

  ServletContext  当前应用

关于3大作用域使用:

​  三大作用域的使用,其本质是根据作用域的范围,生命周期决定其使用的方式.

​  当我们的数据只需要在一次请求之间进行传递时,优先HttpServletRequest :例如 : 你的数据需要传递给下一个地址.

​  当我们的数据,在多次请求时需要实现共享时,优先使用HttpSession.例如: 用户的多个操作,都需要用户ID或者检查是否存在用户信息时.

  当我们的数据,在整个应用是全局唯一的,且大家都可以访问,使用时,使用ServletContext.: 例如 : 整个应用的访问人数.虽然用户访问的地址不同,但是整个应用的访问人数都应该增长.此时使用ServletContext.

​ 例如:全局的常量值,也可以使用ServletContext.

ServletContext的使用

获取ServletContext作用域对象.

// 1. 获取ServletContext
ServletContext context1 = req.getServletContext();
System.out.println(context1);
ServletContext context2 = this.getServletContext();
System.out.println(context2);
ServletContext context3 = req.getSession().getServletContext();
System.out.println(context3);
ServletContext context4 = this.getServletConfig().getServletContext();
System.out.println(context4);
// 在整个项目,全局只有一个ServletContext对象,所有对象都共有它.

ServletContext的核心方法:

// 1. 获取ServletContext
ServletContext context = req.getServletContext();
// 2. ServletContext相关方法
// 1. 作用域属性相关方法
// context.setAttribute(name, object); // 设置作用域属性值
// context.getAttribute(name) // 根据属性名 从作用域中获取值
// context.getAttributeNames()// 获取作用域中所有的属性名
// context.removeAttribute(name); // 删除作用域中属性值
// 2. 作用域初始化属性值相关方法
// context.getInitParameter(name) // 根据参数名称,获取初始化参数对应的值
// context.getInitParameterNames() // 获取所有初始化参数的name值集合
// 获取初始化参数的  name 属性值
Enumeration<String> initParameterNames = context.getInitParameterNames();
while(initParameterNames.hasMoreElements()) {
	String  name = initParameterNames.nextElement();
	System.out.println(name);
	System.out.println(context.getInitParameter(name));
}
// 获取服务器资源路径 
String contextPath = context.getContextPath();// 获取项目名称
System.out.println(contextPath);
String realPath = context.getRealPath("/");// 获取项目的物理路径
System.out.println(realPath);
realPath = context.getRealPath("img");// 获取项目中img文件夹的物理路径,只能获取,webContent下面直接文件夹
System.out.println(realPath);
realPath = context.getRealPath("child");// 获取项目的物理路径    返回child物理路径错误的   img/child
System.out.println(realPath);
Set<String> resourcePaths = context.getResourcePaths("/"); // 获取webContent文件夹下面文件信息
for (String string : resourcePaths) {
	System.out.println(string);
}

ServletContext案例:应用访问人数

​ 每次请求,网站访问人数+1。

​ 每次处理请求时,获取ServletContext对象,从中拿到当前网站的访问人数.然后人数加1,且将新的数据放入的ServletContext作用域。

package com.sxt.servlet;

import java.io.IOException;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(urlPatterns = {"/goods.do"})
public class ServletContextDemo03 extends HttpServlet {

	private static final long serialVersionUID = -197877897340974325L;

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		//获取ServletContext
		ServletContext context = req.getServletContext();
		//获取当前人数
		Object count = context.getAttribute("count");
		//判断数据是否合法
		if(count == null) {
			// 第一次访问
			context.setAttribute("count", 1);
		}else {
			// 非第一次访问
			int m = Integer.parseInt(count.toString()) + 1;
			context.setAttribute("count", m);
		}
		resp.sendRedirect("index.jsp");
	}
}

jsp:在页面显示访问次数

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
访问人数为:${count}
</body>
</html>

不足:

  1. 直接访问JSP时,或者某个其他的地址时,人数没有增加.需要在每个地址都进行数据处理.
  2. 当服务器重启时,人数数据就丢失了.

解决以上问题:

  1. 解决各个地址数据处理问题,需要统一的请求访问处理.需要使用Filter ,过滤器.

  2. 当服务器重启时,数据丢失问题,当服务器关闭时,将此时内存中的数据进行持久化操作,当服务器重新启动时,读取持久化的数据,读到ServletContext中去,需要使用Listener,监听器.

Servlet中的Filter拦截器

什么是拦截器?

​  拦截器可以简单理解为拒绝你想拒绝的.对HTTP请求进行一个过滤处理,通过获取HTTP请求的信息,进行请求预处理.

如何使用Servlet拦截器?

  1. 创建一个类

  2. 实现Filter接口,重写方法

  3. 注册拦截器 : 告诉程序存在一个拦截

  4. 配置拦截的地址 : 告诉程序那些地址 不能直接访问,要先走拦截器

   package com.sxt.filter;
   
   import java.io.IOException;
   import java.util.Enumeration;
   
   import javax.servlet.Filter;
   import javax.servlet.FilterChain;
   import javax.servlet.FilterConfig;
   import javax.servlet.ServletException;
   import javax.servlet.ServletRequest;
   import javax.servlet.ServletResponse;
   
   public class MyFilter implements Filter {
   	
   	/**
   	 *	初始化方法
   	 */
   	@Override
   	public void init(FilterConfig filterConfig) throws ServletException {
   		System.out.println("======init========");
   		//filterConfig.getFilterName() : 获取拦截器的名称
   		System.out.println(filterConfig.getFilterName());
   		
   		// filterConfig.getInitParameter(name) // 根据 name值 获取初始化参数
   		//filterConfig.getInitParameterNames() // 获取所有的 初始化参数的name值
   		// 获取配置的初始化参数
   		Enumeration<String> initNames = filterConfig.getInitParameterNames();
   		while(initNames.hasMoreElements()) {
   			String name = initNames.nextElement();
   			System.out.println(name);
   			System.out.println(filterConfig.getInitParameter(name));
   		}
   	}
   	
   	/**
   	 * 	进行拦截处理
   	 */
   	@Override
   	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
   			throws IOException, ServletException {
   		System.out.println("======doFilter=======");
   		//进行预处理
   		//放行
   		System.out.println("放行前");
   		chain.doFilter(request, response);
   		System.out.println("放行后");
   	}
   	/**
   	 * 	销毁  释放资源
   	 */
   	@Override
   	public void destroy() {
   		System.out.println("=======destroy=======");
   	}
   
   }

Filter注册配置

   <?xml version="1.0" encoding="UTF-8"?>
   <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
     <display-name>06filter</display-name>
     <welcome-file-list>
       <welcome-file>index.html</welcome-file>
       <welcome-file>index.htm</welcome-file>
       <welcome-file>index.jsp</welcome-file>
       <welcome-file>default.html</welcome-file>
       <welcome-file>default.htm</welcome-file>
       <welcome-file>default.jsp</welcome-file>
     </welcome-file-list>
     <!-- 注册拦截器 -->
     <filter>
     	<filter-name>myFilter</filter-name>
     	<filter-class>com.sxt.filter.MyFilter</filter-class>
     	<!-- 配置filter初始化参数 -->
     	<init-param>
           <!-- 初始化参数name值 -->
     		<param-name>initName1</param-name>
            <!-- 初始化参数对应的value值 -->
     		<param-value>initValue1</param-value>
     	</init-param>
     	<init-param>
     		<param-name>initName2</param-name>
     		<param-value>initValue2</param-value>
     	</init-param>
     </filter>
     <!-- 配置拦截的地址 -->
     <filter-mapping>
     	<filter-name>myFilter</filter-name>
     	<url-pattern>/*</url-pattern>
     </filter-mapping>
   </web-app>

拦截案例

编码过滤器案例:所有的请求和响应统一设置编码格式.

package com.sxt.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;

/**
 * @ClassName: CharsetFilter 
 * @Description: 编码过滤器   统一设置编码
 * @author: Mr.T
 * @date: 2019年11月4日 下午2:37:53
 */
public class CharsetFilter implements Filter {
	
	private static  String charset;

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		charset = filterConfig.getInitParameter("charset");
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		System.out.println("======只拦截.do 后缀结尾======");
		//设置编码
		request.setCharacterEncoding(charset);
		response.setCharacterEncoding(charset);
		//放行
		System.out.println(".do 放行前");
		chain.doFilter(request, response);
		System.out.println(".do 放行后");
	}

	@Override
	public void destroy() {	
	}

}
<!-- 注册编码拦截器 -->
<filter>
  	<filter-name>charsetFilter</filter-name>
  	<filter-class>com.sxt.filter.CharsetFilter</filter-class>
  	<init-param>
  		<param-name>charset</param-name>
  		<param-value>UTF-8</param-value>
  	</init-param>
</filter>
<!-- 配置拦截的地址 -->
<filter-mapping>
  	<filter-name>charsetFilter</filter-name>
  	<!-- 只拦截.do后缀结尾的 -->
  	<url-pattern>*.do</url-pattern>
</filter-mapping>

注意点:

  1. 拦截器执行的先后顺序,在web.xml中先配置的优先执行,后配置的后执行.
  2. 当一个地址会被多个拦截器拦截时,先执行的拦截器,最后结束.

登录拦截

​  如果用户没有登录,则跳转到登录界面,让用户登录.

package com.sxt.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;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * @ClassName: LoginFilter 
 * @Description: 登录拦截器
 * 	在用户请求一些资源信息时,假如用户没有登录,则让用户登录
 * 	登录拦截器  不拦截静态资源信息,例如:  js文件,css文件 , 图片资源  ,只拦截:  jsp 和 .do后缀
 * 	并且: 一些特殊的动态请求信息,也放行:  验证码   登录请求  注册
 * @author: Mr.T
 * @date: 2019年11月4日 下午3:22:52
 */
public class LoginFilter implements Filter {

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		/**
		 * 1.获取 用户登录状态 : 	从session 拿到当前用户
		 * 	若当前用户存在,则说明已经登录
		 * 	若不存在 则没有登录,判断用户的请求信息.
		 * 		例如: 如果用户请求的验证码,则放行
		 * 		例如:	 如果用户是登录请求,则也放行
		 */
		// 将请求和响应对象 进行转型
		HttpServletRequest req =  (HttpServletRequest) request;
		HttpServletResponse resp =  (HttpServletResponse) response;
		//获取session
		HttpSession session = req.getSession();
		//从session中 拿到当前用户信息
		Object user = session.getAttribute("user");
		//用户存在
		if(user != null) {
			//放行
			chain.doFilter(request, response);
			return;
		}
		//用户不存在
		//获取用户的请求信息: 
		String uri = req.getRequestURI();
		//请求验证码  
		String service = req.getParameter("service");
		if(uri.endsWith("checkCode.do") ) {
			//放行
			chain.doFilter(request, response);
			return;
		}
		// 登录请求 放行
		if(uri.endsWith("user.do")&& "login".equals(service) ) {
			//放行
			chain.doFilter(request, response);
			return;
		}
		//注册页面  登录页面放行
		if(uri.endsWith("register.jsp") || uri.endsWith("login.jsp") ) {
			//放行
			chain.doFilter(request, response);
			return;
		}
		// 注册请求放行
		if(uri.endsWith("user.do")&& "register".equals(service) ) {
			//放行
			chain.doFilter(request, response);
			return;
		}
		//其他情况去登录页面
		resp.sendRedirect("login.jsp");
	}

	@Override
	public void destroy() {
		
	}

}

web.xml配置

 <!-- 登录拦截器 -->
  <filter>
  	<filter-name>LoginFilter</filter-name>
  	<filter-class>com.sxt.filter.LoginFilter</filter-class>
  </filter>
  <!-- 配置拦截的地址 -->
  <filter-mapping>
  	<filter-name>LoginFilter</filter-name>
  	<!-- 只拦截.do后缀结尾的 -->
  	<url-pattern>*.do</url-pattern>
    <!-- 只拦截jsp 后缀 -->  
  	<url-pattern>*.jsp</url-pattern>
  </filter-mapping>
原文地址:https://www.cnblogs.com/lyang-a/p/12562951.html