Servlet三大作用域
在JSP中存在四大作用域:pageContext,request,session,application。
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>
不足:
- 直接访问JSP时,或者某个其他的地址时,人数没有增加.需要在每个地址都进行数据处理.
- 当服务器重启时,人数数据就丢失了.
解决以上问题:
-
解决各个地址数据处理问题,需要统一的请求访问处理.需要使用Filter ,过滤器.
-
当服务器重启时,数据丢失问题,当服务器关闭时,将此时内存中的数据进行持久化操作,当服务器重新启动时,读取持久化的数据,读到ServletContext中去,需要使用Listener,监听器.
Servlet中的Filter拦截器
什么是拦截器?
拦截器可以简单理解为拒绝你想拒绝的.对HTTP请求进行一个过滤处理,通过获取HTTP请求的信息,进行请求预处理.
如何使用Servlet拦截器?
-
创建一个类
-
实现Filter接口,重写方法
-
注册拦截器 : 告诉程序存在一个拦截
-
配置拦截的地址 : 告诉程序那些地址 不能直接访问,要先走拦截器
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>
注意点:
- 拦截器执行的先后顺序,在web.xml中先配置的优先执行,后配置的后执行.
- 当一个地址会被多个拦截器拦截时,先执行的拦截器,最后结束.
登录拦截
如果用户没有登录,则跳转到登录界面,让用户登录.
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>