web 服务器:可以被浏览器访问到的服务器
常见的 web 服务器:
web 项目: 部署在 web 服务器上面,可以被浏览器直接访问到的项目,特点:项目的结构得按照指定规则
web 资源:
网络中有很多的计算机,它们直接的信息交流,称之为:交互。
在互联网交互的过程的有两个非常典型的交互方式 —— B/S 交互模型和 C/S 交互模型。
C/S架构 Client/Server 客户端/服务器
特点:需要安装一个客户端,例如:QQ客户端 游戏各种客户端 迅雷客户端
优点:效果比较炫,好看
缺点:占用硬盘空间,服务器只要升级就要求客户端跟着升级
B/S架构 Browser/Server 浏览器/服务器
特点:不需要安装客户端,一个浏览器足矣,例如:网页淘宝 网页京东 网页12306
优点:不会占用硬盘空间,服务器只要升级不要求跟着升级
缺点:效果不炫,所有压力都在服务器
相同点: 都需要和服务器进行数据交互,都是先有请求,后给响应,一定是请求和响应成双成对
bin 里面存放的都是tomcat的二进制命令 关注点:开启服务: startup.bat 关闭服务:shutdown.bat
conf 里面存放的都是tomcat的配置文件 关注点:server.xml(配置端口) web.xml
lib 里面存放的都是tomcat运行过程中提供支撑的jar包
logs 里面存放的都是日志文件 关注点:错误信息的日志文件查看 catalina.2020-xx-xx.log
temp 里面存放的是tomcat运行过程中创建的临时文件 由tomcat维护
work 里面存放的内容和jsp相关
webapps(核心) 用来存放web项目 存放在这个里面的项目可以被浏览器直接访问到 http://localhost:8080 --> webapps文件夹下
方式1:配置独立xml文件
在 tomcat/conf 目录下新建一个 Catalina 目录(如果已经存在无需创建)
在 Catalina 目录下创建 localhost 目录(如果已经存在无需创建)
在 localhost 中创建 xml 配置文件,名称为:xxx.xml(xxx名就是项目的浏览器访问别名)
xxx.xml中代码如下:
<Context docBase="项目所在的硬盘位置" />
好处:使用配置文件对项目的部署和卸载不用重启 tomcat 了,也不影响 tomcat 整体的配置文件
方式2:配置 server.xml,添加 context 标签
在 server.xml 配置文件的最后加上如下代码:
<Context path="项目的浏览器访问别名" docBase="项目所在的硬盘位置" />
注意:谨慎使用(最好单独独立出来一个配置文件)
在电脑安装一个 tomcat 软件,将电脑变成 web 服务器,步骤:
Tomcat启动的常见问题总结
1、一闪而过
原因:没有配置环境变量JAVA_HOME 或者配置错误
解决:配置环境变量JAVA_HOME,因为tomcat在启动的时候会去找环境变量JAVA_HOME
Tomcat的底层需要JDK的支撑
JAVA_HOME=jdk的安装路径(不要加bin目录)
path=%JAVA_HOME%\bin
2、报错 java.net.BindException: Address already in use: bind
原因:端口号被占用
解决:
方式1:结束正在占用端口的进程
1) netstat -ano 查看端口对应的pid
2) 打开任务管理器 结束pid对应的进程
方式2:改变自己的端口号
修改conf文件夹中的server.xml 大概在69行的位置
或者修改端口号为80: 80是默认端口号.可以不写
idea 自动用的是虚拟路径的方式给 tomcat 管理的
idea集成tomcat步骤:
idea创建web项目:
idea发布项目:
概念:
协议:规定了被约束对象都需要去遵守的规则
http协议:
作用:
请求内容分为:
请求行(第一行)
POST /web02_1/demo1.html HTTP/1.1
提交方式 要请求的服务器资源 使用的是http协议的那个版本(固定)
请求头(key:value)
数据的格式:键值对的数据
常用头数据:Referer User-Agent
请求体(要传递给服务器的页面数据)
只有 post 提交才有 是页面表单的数据要传递给服务器的内容
响应内容分为:
响应行
// 组成部分:
HTTP/1.1 200
固定协议版本 状态码
// 常见的响应状态码:
200 OK 请求已成功,响应也没问题。出现此状态码是表示正常状态。
302 资源重定向
304 去找缓存数据
403 服务器拒绝执行 (文件或文件夹加了权限)
404 请求的资源没找到
405 请求的方法不存在
500 服务器错误 (代码写的有问题)
响应头
常用响应头:
响应体
浏览器页面要解析显示的内容即是响应体的内容
get 提交的数据不安全,因为所有的页面表单数据都在请求行中,意味着资源都在地址栏暴露了
post 提交的数据安全,因为所有的页面表单数据都在请求体中,意味着资源都不会在地址栏暴露了
get 提交有着大小的限制,post 提交没有大小的限制
get 提交没有请求体,所有的表单的数据都在请求行中
post 有请求体,所有的表单数据都在请求体中
在 JavaEE 规范中,WEB 项目存在一定的目录结构,具体结构如
web项目(myweb)
|| ------ 静态资源(如html、css、js、img等)、二级目录等
||
||
|| ------ WEB-INF目录(放在该目录下的资源浏览器是不能直接访问到)
|| ------ classess目录:放的都是java代码的 .class
|| ------ lib目录:放入项目需要的jar
|| ------ web.xml:配置文件(配置的是项目的内容) 是tomcat首先会去加载的配置文件
servlet如果是2.5的版本这个web.xml文件必须有
servlet如果是3.0的版本这个web.xml文件可以不要 用注解代替
java web 项目服务器有三大技术:Servlet、Filter、Listener
servlet:本质就是一个类,这个类实现了 java 提供的 Servlet 规范。
可以对浏览器的请求和响应进行处理
filter:本质上是一个类,这个类需要实现 java 提供的 Filter 规范。
可以对浏览器访问服务器资源时的一种拦截,可以让符合条件放行,不符合条件不放行
listener:本质上是一个类,实现了 java 的 Listener 规范,可以监听其它对象(域)的状态变化
Servlet 运行在服务端的 Java 小程序,是 sun 公司提供一套规范,用来处理客户端请求、响应给浏览器的动态资源。
servlet 的实质就是 java 代码,通过 java 的 API 动态的向客户端输出内容。
servlet 的作用:
servlet 与普通的 java 程序的区别:
**servlet2.5 的方式:**必须有 web.xml 配置文件
三个步骤创建一个 servlet:
创建一个类实现 servlet 接口
重写 service 方法
在 web.xml 文件中配置创建的类(将请求路径和 java 程序的对应关系建立起来)
tomcat 只要一启动,就会去加载 web.xml 文件,只加载一次
只要这个 web.xml 配置文件修改了任何一处,都要重新 tomcat 重新加载
servlet 的创建和服务方法、service 的执行都是由 tomcat 自动完成
servlet3.0 的方式:没有web.xml配置文件
步骤:
创建 JavaEE6(含6) 以上的工程
创建一个类实现 servlet 接口,并在实现类上标注 @WebServle 注解
@WebServlet 注解的属性:
示例:@WebServlet(name = “HelloServlet”, urlPatterns = “/hello”)
一个对象从创建到消亡的过程,就是生命周期。
和 servlet 的生命周期相关的 3 个方法:
// Servlet对象只要一创建出来就会调用的方法
void init(ServletConfig var1)
// 处理浏览器交互的方法
void service(ServletRequest var1, ServletResponse var2)
// 销毁的方法
void destroy()
Servlet 的生命周期:
servlet 的继承体系:HttpServlet(功能最多)extends GenericServlet implements Servlet接口
在 servlet 中,真正执行程序逻辑的是 service 方法时,对于 servlet 的初始化和销毁,一般由服务器调用执行,开发者本身不需要关心。
企业开发中:继承 HttpServlet,只需要复写 doget 和 dopost 方法,而开发工具已经提供好了模板,直接用即可
在创建 servlet 后,如果想要这个 servlet 可以被访问到,必须在 web.xml 文件中对其进行配置。
url-pattern 标签就是用于确定访问一个 servlet 的路径
示例:
<servlet>
<servlet-name>ServletDemo1servlet-name>
<servlet-class>cn.itcast.web.ServletDemo1servlet-class>
servlet>
<servlet-mapping>
<servlet-name>ServletDemo1servlet-name>
<url-pattern>/sd1url-pattern>
<url-pattern>/sd2url-pattern>
<url-pattern>/sd3url-pattern>
<url-pattern>/sdurl-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>ServletDemo2servlet-name>
<url-pattern>/aaaurl-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>ServletDemo3servlet-name>
<url-pattern>*.dourl-pattern>
servlet-mapping>
注:
一个servlet也可以被不同的路径映射,但一般在开发中,只需要配置一个有效路径即可
路径映射的配置方式:
完全匹配:必须以 / 开始
例如: /ms1、 /aaa/ms1、/aaa/bb/cc/ms1
目录匹配:必须以 / 开始,以 *
结束
例如: /*
、/aaa/*
扩展名(后缀名)匹配:以 *.xx
结束(xx 代表的是后缀名)。注意:不能以 / 开始
例如:*.action
、*.do
多种匹配的优先级:完全匹配 > 目录匹配 > 扩展名匹配
只有一个 servlet 会执行,执行的结果是按照优先级去执行的
load-on-startup 标签可以设置 servlet 的加载优先级别和容器是否在启动时加载该 servlet
当值为 0 或者大于 0 时,代表容器启动时加载该 servlet。正数的值越小,启动时加载该 servlet 的优先级越高。
如果为负数,则容器启动时不会加载该 servlet,只有该 servlet 被选择时才会加载。
servlet 的默认创建是在第一次访问的时候
示例:
<servlet>
<servlet-name>ServletDemo1servlet-name>
<servlet-class>cn.itcast.web.ServletDemo1servlet-class>
<load-on-startup>2load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>ServletDemo1servlet-name>
<url-pattern>/*url-pattern>
servlet-mapping>
注:
数字 1 被 tomcat 默认的 servlet 给占用了,在 tomcat 的 web.xml 中可以看到也使用了一个 servlet
tomcat 一启动会加载 2 个 web.xml 文件,一个是项目自定义的 web.xml,一个 tomcat 的 web.xml
<servlet>
<servlet-name>defaultservlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServletservlet-class>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>defaultservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
该 servlet 是 tomcat 创建的,主要用来处理其它的 servlet 处理不了的请求
比如在当前下访问不到的资源都会走该 servlet,该 servlet 底层默认走写好的页面(404 500…)
servlet 的访问路径分为 2 种:
绝对路径
带协议的绝对路径
地址栏的地址方式,一般用于外部资源的访问,例如:http://localhost:8080/web02/ms5
不带协议的绝对路径
把协议和端口名省略,永远只能访问到本机的资源,一般用于内部资源的访问, 例如:/web02/ms5,
特点:以/开头 以资源名结尾
相对路径:相对比较的是地址栏的地址
特点:同级目录及以下 以 ./ 开头、以资源名结尾(也可省略 ./ )
父级目录 以 …/ 开头,返回父级目录
HttpServletRequest 对象代表浏览器端的请求,当浏览器端通过 HTTP 协议访问服务器时,HTTP 请求中的所有信息都封装在这个对象中,开发人员通过这个对象的 api,可以获得客户通过浏览器传递过来的数据。
HttpServletRequest 对象的作用:封装浏览器的请求数据(请求行、请求头 、请求体)
HttpServletRequest extends ServletRequest
获取请求行数据(请求方式、访问的资源、协议版本)
// 获取请求方式
String getMethod()
// 获取请求行中的资源名部分
String getRequestURI()
// 获取客户端请求完整URL
StringBuffer getRequestURL()
// 获取请求协议和版本
String getProtocol()
// 获取端口
int getLocalPort()
// 获取请求者的ip地址
String getRemoteAddr()
// 获取当前的项目名路径
String getContextPath()
获取请求头数据(键值对 key/value 的数据)
// 根据请求头的key获取value
String getHeader(String key)
// 例如:Referer可以获取到来源地址(没有来源为null:直接访问) --防盗链
// 例如:User-Agent可以获取用户的浏览器版本信息 --下载必备、处理下载乱码的
// 返回此请求包含的所有头名称
Enumeration getHeaderNames()
获取请求体数据(所有浏览器提交的表单数据)
// 获取单一name对应的value值
String getParameter(String name)
// 获取多个name对应的多个value值
String[] getParameterValues(String name)
// 获取页面所有的value值
Map<String,String[]> getParameterMap()
// 注意:key:对应的是表单中name属性名,value对应的的是表单的name属性的value值
// 设置编码。一般设置为 utf-8,否则请求中中文可能会乱码
void setCharacterEncoding(String var1)
作为容器数据存取删(request 也被称为域对象)
// 存储数据
void setAttribute(String name, Object o)
// 获取数据
Object getAttribute(String name)
// 移除数据
void removeAttribute(String name)
注意:若想要在多个 servlet 之间的使用 request 传递数据,则需要保证多个 servlet 之间使用的是同一个 request 对象,可以使用请求转发。
request.getRequestDispatcher("/servlet的地址").forward(request, response);
HttpServletResponse 对象:服务器用来给浏览器写内容的一个对象
服务器有数据如果想给浏览器:只能按照 http 协议的规定通过3个方向给:响应行、响应头、响应体
操作响应行
格式:协议/版本 状态码
示例:HTTP/1.1 200
状态码含义
200 请求响应已成功
302 重定向
304 去找缓存数据
403 服务器拒绝执行 (文件或文件夹加了权限)
404 请求的资源没找到
405 请求的方法不存在
500 服务器错误 (代码写的有问题)
操作响应头
格式:key:valu
API 方法:
// 设置键值对形式的响应头
setHeader(String key,String value)
常用响应头:
// content-type:通知浏览器响应的内容是什么类型的,并且用什么编码解析内容。解决响应回去的中文乱码问题
response.setHeader("content-type","文件的类型;charset=utf-8");
// 简写
response.setContentType("文件的类型;charset=utf-8");
// location:重定向
response.setHeader("location", "/day31/sd4");
response.setStatus(302);
// 简写
response.sendRedirect("url");
// refresh:定时刷新
response.setHeader("refresh","秒数;url=跳转的路径");
// content-disposition:通知浏览器写回去的东西要以附件形式打开 (只用于下载)。默认情况下都是页面直接展示写回去的数据
response.setHeader("content-disposition","attachment;filename=" + aaa.jpg);
操作响应体
页面上要展示的内容
API 方法:
// 字符流
PrintWriter getWriter()
// 字节流 (二进制)
ServletOutputStream getOutputStream()
特点:
ServletContext:servlet 的上下文对象(全局管理者对象),是一个全局的储存信息的空间。
一个 web 项目只有一个全局管理者(SevletContext对象)
原生获取 ServletContext 对象
在继承 HttpServlet 或 GenericServlet 的自定义类中,直接通过父类方法 getServletContext() 获取 ServletContext 对象
public ServletContext getServletContext()
Spring 项目获取 ServletContext 对象
通过 spring 注入自动注入(推荐)
@Autowired
private ServletContext servletContext;
通过 HttpServletRequest 对象
@GetMapping("/test")
public String test(HttpServletRequest request) {
ServletContext servletContext = request.getServletContext();
return "success";
}
实现 WebApplicationInitializer 接口,重写 onStartup() 方法
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import org.springframework.web.WebApplicationInitializer;
public class ApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
System.out.println(servletContext);
}
}
创建一个实现 ServletContextListener 的监听器
// 必不可少,声明为监听器,注册到web容器中
@WebListener
public class InitContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
ServletContext servletContext = servletContextEvent.getServletContext();
System.out.println(servletContext);
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
通过 ContextLoader 类
ServletContext servletContext = ContextLoader.getCurrentWebApplicationContext().getServletContext();
注意:使用这种方式需要 webApplicationContext 完成初始化后才能获取到 servletContext 对象,否则获取的是空值导致空指针异常
操作 ServletContext 对象
数据存取操作:保存在 ServletContext 中的数据是项目全局共享的数据,可以用来在多个 servlet 之间传递信息数据
// 存。特点:可以存多对 但是存在key值覆盖
void setAttribute(String name, Object value)
// 取。特点: \没取到返回null
Object getAttribute(String name)
// 删
void removeAttribute(String name)
读取项目资源的方法
// 获取WEB项目的磁盘路径。场景:上传
String getRealPath(String path)
// 根据WEB项目的磁盘资源获取流。场景:下载
InputStream getResourceAsStream(String path)
// 获取web.xml中标签的参数内容
String getInitParameter(String name)
会话技术的作用:是用来存储会话过程中,浏览器和服务器交互产生的N多数据的
会话技术的分类:
使用 cookie 或 session 去存储浏览器和服务器交互中产生的数据的场景:
作用:存储数据进行传递的
特点:
cookie 的整个使用过程(完成私人数据在多个 servlet 之间进行数据传递):
cookie的应用场景
注意:
cookie 中不能出现特殊符号,例如:空格,分号(;) ,逗号(,)
如果存入的数据不合法,会出现一个错误:
java.lang.IllegalArgumentException: An invalid character [32] was present in the Cookie value
cookie 对于基本符号、数字、和字母是可以存储的。
如果一定要在 cookie 中保存非法数据,可以将非法数据转换成符号、数字、和字母形式存储,要使用的时候再转换成正常的数据(解码)即可。
cookie 存入的数据有大小限制 4kb
Cookie:
// 创建cookie对象
Cookie(String name, String value)
// 获取cookie的名称
String getName()
// 获取cookie的值
String getValue()
// 设置cookie的最大生存时间(单位:秒),超过了该时间后Cookie会自动销毁
void setMaxAge(int expiry)
// 设置cookie的有效路径。浏览器根据这个路径判断在访问哪些资源时携带该cookie给服务器
void setPath(String uri)
HttpServletResponse:
// 将cookie发送给浏览器。注意:服务器可以给浏览器传递多个cookie,浏览器都会保存,但存在key值覆盖
void addCookie(Cookie cookie)
HttpServletRequest:
// 获取浏览器发送的cookie
Cookie[] getCookies()
注意:
cookie 主要是通过名称和路径来确定他的唯一性的
例如:以下表示的是两个 cookie,虽然名字一样,但是路径不同 , 所以两个 cookie 可以同时存在。
/day04/a/b/cookie1
/day04/a/cookie1
如果路径和名称一样,后添加的 cookie 将覆盖前者
Cookie 的生命周期
会话级别的 Cookie:默认,关闭了浏览器 Cookie 就销毁了.
持久级别的 Cookie:可以设置指定 cookie 在浏览器的存活时间,Cookie 就不会随着浏览器关闭而销毁了
// 设置cookie的最大生存时间(单位:秒),超过了该时间后Cookie会自动销毁
void setMaxAge(int expiry)
// >0 : 有效时间
// =0 :过期(清除)
注意:
当时间为 0 的时候,意思为立即删除此Cookie(前提:path 和 name 必须一致)
要删除已经存在的 cookie,用来覆盖的 cookie 的名称与路径必须与原来的 cookie 一致
Cookie 的有效路径
// 设置cookie的有效路径。浏览器根据这个路径判断在访问哪些资源时携带该cookie给服务器
void setPath(String uri)
session 是保存在服务器端的会话技术,当通常情况下,Session 是借助 Cookie 技术来传递 ID 属性的。
session 的作用:为了保存会话中产生的数据
特点:
作用范围:
session 中的数据在一次会话中共享
因为在一次会话中,访问多少个 servlet,获取到的 session 都是同一个
但是如果不在一次会话中,多个 servlet 中产生的不再是同一个 session 对象
底层原因是不同会话中 cookie 携带的 jessionid(session 的 id)不一样
生命周期:
创建:java 认为当浏览器首次执行到了 request.getSession 方法的时候创建 session 对象
销毁:
被动销毁:默认当前 session 30 分钟不使用会被销毁
主动销毁:session.invalidate()
服务器非正常关闭 session 会销毁
服务器正常关闭 session 不会销毁,会持久化到硬盘上,服务器开启后,会默认从硬盘上回到服务器中
session 的与 cookie 的区别
cookie | session | |
---|---|---|
会话数据保存的位置 | 浏览器 | 服务器 |
数据的安全性 | 不安全 | 安全 |
存储数据是否有限制 | 有。4kb,且只能字符串 | 无 |
HttpServletRequest
// 获取session对象
HttpSession getSession()
HttpSession
// 在session中保存数据
void setAttribute(String name, Object value)
// 从session中获取数据。注意:返回值是Object,因此需要将返回值强制转换才能方便使用
Object getAttribute(String name)
// 从session中移除数据
void removeAttribute(String name)
在一次会话中,使用的都是同一个 session 对象剖析:
session 的一切是由 request.getSession() 开始
当程序执行到 request.getSession() 方法时,首先会判断用户的浏览器是否携带了 jsessionid
用户浏览器没有携带 jsessionid:
tomcat 会在服务器上开启一块空间(创建一个新的session对象),用来存入数据,然后会创建一个 cookie,将这块空间的地址记录给 cookie(key:jessionid),然后将这个 cookie 写回给访问者的浏览器(会话级别)
用户浏览器携带了 jsessionid:
tomcat 就不会再去开启空间(创建 session),而是根据浏览器带来的 jessionid 找到 session 地址,从该 session 中取出数据
过滤器的使用场景:
Filter:是 Java 中预先定义好了的接口,可以过滤不同的内容,具体怎么过滤,需要使用者定义一个实现类,然后实现接口中的过滤方法,在方法中书写过滤的条件。filter 是对客户端访问资源的过滤,符合条件放行,不符合条件不放行
主要作用:对浏览器的请求进行拦截过滤的
Filter 接口 API
// 过滤器的初始化方法
void init(FilterConfig filterConfig)
// 过滤器的核心过滤方法。写具体的过滤逻辑
void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
// 过滤器的销毁方法
void destroy()
使用步骤
创建一个 java 类,实现 filter 的接口,并实现方法 doFilter()
//@WebFilter(filterName = "MyFilter1",urlPatterns = "/sd1")
public class MyFilter implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
//核心过滤方法
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("MyFilter进行服务器资源的过滤了...");
//默认是拦截不放行的 手动放行(固定代码)
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {}
}
注册 filter
方式1:在自定义的 filter 类上添加 @WebFilter 注解:
@WebFilter(filterName = "MyFilter1", urlPatterns = "/sd1")
filterName 属性:过滤器名称
urlPatterns 属性:过滤器生效的接口路径
路径配置规则与 servlet 相同(完全匹配、目录匹配、拓展名匹配)
方式2:在 web.xml 中配置 filter 要拦截的资源
<filter>
<filter-name>MyFilterfilter-name>
<filter-class>cn.itcast.filter.MyFilterfilter-class>
filter>
<filter-mapping>
<filter-name>MyFilterfilter-name>
<url-pattern>/sd1url-pattern>
filter-mapping>
过滤器链:需要对同一个请求,进行多次不同业务的过滤时,可以配置多个过滤器,只有所有的过滤器都对请求进行了放行,请求才能访问到目标资源,只要多个过滤器中只有一个过滤器不放行请求,那么这个请求都不能够访问到目标资源。多个过滤器组成的一个整体称为过滤器链。而且,过滤器链中的过滤器是一个一个的执行的,一个过滤器执行完毕之后,会执行下一个过滤器,后面没有过滤器了,才会访问到目标资源。只要其中一个过滤器没有放行,那么这个过滤器后面的过滤器也都不会执行了。
过滤器链中多个过滤器的执行顺序:
filter 的执行流程
filter 的生命周期
从 filter 的出生到 filter 的死亡,有3个方法:
init() :过滤器的初始化方法
服务器启动时在 servlet 容器创建 filter 对象后执行一次 init 方法
在要求过滤器做任何过滤工作之前,init 方法必须成功完成
void init(FilterConfig filterConfig)
参数说明:
filterConfig :当前 filter 的配置对象
作用:
dofilter() :过滤器的核心过滤方法
当请求符合 Filter 拦截路径时,都会执行 doFilter 方法,访问一次执行一次。
void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
参数说明:
注意:
destory() :过滤器的销毁方法
当关闭服务器时,销毁当前 filter 时执行
filter 默认只拦截 Request(浏览器过来的请求,包括重定向),不拦截 Forward(服务器内部的请求,即请求转发)
如果想让filter拦截服务器内部的请求:
注解方式
配置 dispatcherTypes 属性,属性值新增 DispatcherType.FORWARD
@WebFilter(dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.FORWARD})
该注解属性配置既会拦截浏览器过来的请求,又会拦截服务器内部的请求
xml 方式配置
在
的标签中添加标签
,但是这种配置将 filter 默认的拦截方式给覆盖了,只会拦截服务器内部的请求,不会再拦截默认的浏览器请求了
想让 filter 拦截服务器内部的请求又拦截浏览器过来的请求:
<filter-mapping>
<filter-name>MyFilter2filter-name>
<url-pattern>/*url-pattern>
<dispatcher>FORWARDdispatcher>
<dispatcher>REQUESTdispatcher>
filter-mapping>
浏览器发出的任何请求,通过过滤器统一处理中文乱码。
@WebFilter(filterName = "EnCodingFilter",urlPatterns = "/*")
public class EnCodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
// 在执行servlet获取数据和响应数据之前执行该代码
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
// 放行之前 处理中文乱码
chain.doFilter(req, resp);
}
@Override
public void destroy() {}
@WebFilter(filterName = "FeifaFilter",urlPatterns = "/sd3")
public class FeifaFilter implements Filter {
private List<String> list;
//服务器启动就执行 且只执行一次
@Override
public void init(FilterConfig config) throws ServletException {
// 加载一个非法字符的文档(properties)
//底层:会自动去src下加载后缀名为properties的文件
ResourceBundle bundle = ResourceBundle.getBundle("feifa");
String value = bundle.getString("feifa");
// 读取文档中的数据,放入到集合中
String[] arr = value.split(",");
list = Arrays.asList(arr);
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
// 获取用户发表的言论
HttpServletRequest request=(HttpServletRequest)req;
HttpServletResponse response=(HttpServletResponse)resp;
String info = request.getParameter("info");
// 判断言论是否合法
// 遍历循环集合,将集合的非法字符和接受到的数据做包含
// 包含上:就是非法 没包含上:就是合法
for(String value:list){
if(info.contains(value)){
// 不合法--不放行 直接给浏览器响应信息
// 包含上:就是非法
response.getWriter().print("你发表的言论有非法行为,请思考后再发表...");
return;
}
}
//合法--直接放行
chain.doFilter(request, resp);
}
@Override
public void destroy() {}
web 监听器是一种 Servlet 中的特殊的类,可以帮助开发者监听web中的特定事件,比如 ServletContext, HttpSession, ServletRequest 的创建和销毁等。可以在某些动作前后增加处理,实现监控。
Listener 的作用:监听 ServletContext, HttpSession, ServletRequest 三大域对象的状态变化(三个域对象的创建和销毁)
使用场景:
系统启动时初始化信息
ServletContextListenner 用来监听 ServletContext 对象的创建和销毁的
当项目启动,servletContext 对象被创建时,会调用 ServletContextListenner 的 contextInitialized 方法,所以可以在此方法中初始化项目需要的信息
注:spring 框架会使用到它
统计在线人数
每当一个用户访问项目的时候,都会创建一个 session 会话。所以当前 session 会话被创建,当前在线用 户 +1,每当 session 会话被销毁,当前在线用户 -1
HttpSessionListener 可以用来监听 session 对象的创建和销毁的,所以可以在 HttpSessionListener 中的监听 session 对象创建和销毁的方法中控制在线人数的加减
java 提供了监听器规范,不同的监听器规范要监听的内容不一样
常见监听器:
ServletContextListener(常用):监听 ServletContext 对象的创建和销毁
例如:框架的配置文件在服务器启动就执行
ServletRequestListener :监听 ServletRequest 对象的创建和销毁
HttpSessionListener :监听 HttpSession 对象的创建和销毁
API
ServletContextListenner 接口
// 监听 servletcontext 对象的创建
void contextInitialized(ServletContextEvent sce)
// 监听 servletcontext 对象的销毁
void contextDestroyed(ServletContextEvent sce)
ServletRequestListener 接口
// 监听 ServletRequest 对象的创建
void requestInitialized(ServletRequestEvent servletRequestEvent)
// 监听 ServletRequest 对象的创建
void requestDestroyed(ServletRequestEvent servletRequestEvent)
HttpSessionListener 接口
// 监听 HttpSession 对象的创建
void sessionCreated(HttpSessionEvent httpSessionEvent)
// 监听 HttpSession 对象的创建
void sessionDestroyed(HttpSessionEvent httpSessionEvent)
使用步骤(以 ServletContextListenner 监听器为例)
创建一个类实现 ServletContextListenner 接口,并实现方法 contextInitialized() 和contextDestroyed()
// 监听servletContext对象的创建和销毁。需实现java提供的监听器规范(ServletContextListener)
//@WebListener
public class ServletContextLoaderListener implements ServletContextListener {
// 当servletContext对象被创建了,监听器触发,该方法执行
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("servletContext对象被创建了...");
// 让服务器一加载,就读取框架的配置信息,进行加载
ServletContext servletContext = servletContextEvent.getServletContext();
String value = servletContext.getInitParameter("spring");
System.out.println("就可以正式根据获取到的配置文件名,对该文件的内容进行加载了:"+value);
System.out.println("正在加载该配置文件中....");
}
@Override //当servletContext对象被销毁了 监听器触发 该方法执行
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("servletContext对象被销毁了...");
}
}
注册监听器
方式1:在实现类上添加注解 @WebListene
方式2:在 xml 中配置
<listener>
<listener‐class>com.itheima.listenner.MyServletContextListenner1listener‐class> listener>
session 监听器,统计 session 个数
import javax.servlet.ServletContext;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
@WebListener()
public class MyHttpSession implements HttpSessionListener {
//当前在线人数的属性名称
private static final String NUMBER = "NUMBER";
/*
* session 创建时触发
*/
@Override
public void sessionCreated(HttpSessionEvent event) {
//会话创建了,有新用户访问网站
HttpSession session = event.getSession();
//新创建的会话对象
ServletContext servletContext = session.getServletContext();
//获取当前项目环境对象
System.out.println("session创建了" + session.getId());
Integer n = (Integer) servletContext.getAttribute(NUMBER);
//当前在线人数
if( n== null){
//如果 n==null 说明是第一个用户 ,直接设置n=1
servletContext.setAttribute(NUMBER, 1);
}else{
//如果n != null 直接累加
servletContext.setAttribute(NUMBER, ++n);
}
//如果 n==null 说明是第一个用户 ,直接设置n=1
//如果 n != null 直接累加
}
/*
* session销毁时触发
*/
@Override
public void sessionDestroyed(HttpSessionEvent event) {
//会话销毁了,有用户的会话对象销毁了
HttpSession session = event.getSession();
//新创建的会话对象
ServletContext servletContext = session.getServletContext();
//获取当前项目环境对象
System.out.println("session销毁了" + session.getId());
Integer n = (Integer) servletContext.getAttribute(NUMBER);
//当前在线人数 //直接减1
servletContext.setAttribute(NUMBER, ‐‐n);
}
}
浏览器页面的中文数据请求给服务器,如果使用的 post 提交,服务器接受会发生乱码
解决:处理请求的中文数据乱码
request.setCharacterEncoding("utf-8");
服务器给浏览器中文数据的时候,浏览器会发生乱码行为
解决: 处理响应的中文数据乱码
response.setContentType("text/html;charset=utf-8");
服务器给浏览器附件框的时候,附件框上有中文,会发生乱码行为(下载才会有附件框)
解决:
获取用户的浏览器版本
火狐版本的浏览器:返回去的附件中文设置 base64 编码
其它版本的浏览器:返回去的附件中文设置 utf-8 编码
String value = request.getHeader("user-agent");
String encode;
if(value.contains("Firefox")){
//火狐浏览器中文(base64)
Base64.Encoder encoder = Base64.getEncoder();
encode = "=?utf-8?B?" + encoder.encodeToString(fileName.getBytes("utf-8")) + "?=";
} else {
//其它浏览器中文(utf-8)
encode = URLEncoder.encode(fileName, "utf-8");
}
//小说.txt --%E5%B0%8F%E8%AF%B4.txt
response.setHeader("content-disposition", "attachment;filename=" + encode);
重定向多次请求,请求转发一次请求
重定向是浏览器向服务器发送访问,请求转发是服务器内部资源互相访问
重定向是response对象的API,请求转发是request对象的API
重定向可以访问自己的项目也可以访问别的项目,请求转发只能访问当前自己的项目a
// 重定向。可以访问外部项目
response.sendRedirect(request.getContextPath() + "/sd11");
// 请求转发。只能访问当前项目
request.getRequestDispatcher("/sd7").forward(request,response);
域对象可以在多个 servlet/jsp 之间进行数据传递
java 后端的域对象有 3 个:
ServletContext(公共数据)
创建:服务器只要启动就创建,且只创建一个
销毁:服务器关闭就销毁
存入数据的作用范围:整个 web 项目的所有 servlet 都共享
因为整个 web 项目只有一个 ServletContext,所有 servlet 中获取的都是同一个 ServletContext 对象
request
创建:请求一次创建一次
销毁:响应即销毁
存入数据的作用范围:只能是一次请求的多次转发中共享数据
只有在一次请求的多次转发中涉及到的多个 servlet 使用的才是一个 request 对象
session(私有数据)
创建:java 认为当浏览器首次执行到了 request.getSession 方法的时候创建 session 对象
销毁:
被动销毁:默认当前 session 30 分钟不使用会被销毁
主动销毁:session.invalidate()
服务器非正常关闭 session 会销毁
服务器正常关闭 session 不会销毁,会持久化到硬盘上,服务器开启后,会默认从硬盘上回到服务器中
存入数据的作用范围:在一次会话中涉及的多个servlet可以共享数据
因为一次会话中,多个 sevlet 中获取的 session 是同一个
域对象操作的 API
// 存放数据
void setAttribute(String name, Object value)
// 获得数据
Object getAttribute(String name)
// 删除数据
void removeAttribute(String name)