TomCat
1. 程序架构
1.1 C/S
-
(client/server) 比如:QQ、 微信、 LOL
-
优点:有一部分代码写在客户端, 用户体验比较好。
-
缺点: 服务器更新,客户端也要随着更新。 占用资源大。
1.2 B/S
-
(browser/server) 比如:网页游戏 、 WebQQ、天猫、京东等
-
优点: 客户端只要有浏览器就可以了。占用资源小,不用更新。
-
缺点:用户体验不佳。
2. Web服务器
2.1 简介
在浏览器上输入地址 ,web服务器软件接收请求,然后响应消息。 处理客户端的请求, 返回资源(信息)
-
Web应用 需要服务器支撑
-
Tomcat apache
-
WebLogic BEA
-
Websphere IBM
-
IIS 微软
2.2 web资源
- web资源按实现的技术和呈现的效果的不同分为 静态资源和动态资源两种
- 静态资源:html,css,js,txt,mp4,jpg
- 动态资源:jsp界面,servlet程序
3. Tomcat
3.1 安装
官网下载,这里推荐安装Tomcat8,因为比较稳定。
启动步骤
-
安装, 直接解压 ,然后找到bin/startup.bat, 前提必须配置JAVA_HOME
-
启动startup.bat,能看到黑窗口表明成功安装,在浏览器的地址栏上输入: http://localhost:8080 , 有内容表明安装成功
PS: 如果双击了startup.bat, 看到一闪而过的情形,一般都是 JDK的环境变量没有配置。
3.2 目录介绍
bin 可执行程序
conf 配置文件
lib 服务器的 jar 包
logs 日记信息
temp 临时数据
webapps 专门用来存放部署的 Web 工程。
work 作时的目录, 用来存放 jsp 翻译为 Servlet的源码和 Session 钝化的目录。
4. 项目发布
PS:这里只推荐拷贝到webapps
文件夹下
项目发布步骤
- 在webapps下面新建一个文件夹
Test_Operator
, 然后拷贝文件放置到这个文件夹中 - 使用IP地址访问:http://localhost:8080/Test_Operator/index.html
- 看到画面即可成功发布。
5. idea整合
整合步骤:
- 创建web项目
- 增加web framework支持
- 发布项目到tomcat 方式二:step4
- 以war方式发布项目
方式二 :以war方式发布,在上面的基础上进行:
最后:把war文件拷贝到tomcat的webapps目录下,tomcat启动会自动解压这个war文件,我们可以直接访问。
HTTP
1. 简介
HTTP协议即 超文本传输协议 (HTTP-Hypertext transfer protocol)
它定义了浏览器 怎样向万维网服务器发送请求,以及服务器怎样把文档传送给浏览器。
HTTP是面向 应用层协议,它是万维网上能够可靠地交换文件的重要基础。 并规定了浏览器与服务器互相通信的规则
- 客户端发送给服务器的”信”,我们称之为”请求协议”。
- 服务器端发送给浏览器的”信”,我们称之为”响应协议”。
可以使用Fiddler文件进行抓包。
总之:HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。
2. 主要特点
- 简单快速
- 灵活
- 无连接
- 支持B/S和C/S模式
3. URL
3.1 组成
http://httpbin.org:8080/ROOT/index.jsp?username=mickey&password=123456
- 协议
http://
网页使用HTTP协议, - 域名
httpbin.org
- 端口
8080
不是必须的部分,可以省略,默认端口为:80 - 虚拟目录
ROOT
从第一个“/”开始 到“/”为止, - 文件名
index.jsp
从 “/”开始 到“?” - 参数
username=mickey&password=123456
剩下的为参数部分。
3.2 URI和URL区别
URI是(uniform resource identifier),统一资源标识符,用来唯一的标识一个资源。是以一种抽象的高层次概念定义统一资源标识
URL是uniform resource locator,统一资源定位器,它是一种具体的URI,即URL可以用来标识一个资源,还指明了如何定位这个资源
URNuniform resource name,统一资源命名,是通过名字来标识资源,比如mailto:java-net@java.sun.com
4. 请求和响应
4.1 Request
- 通过下面的代码向 服务器端(httpbin.org) 发送请求:
<form action="http://httpbin.org/get" method="get">
<input type="text" name="username" value="Wzx"><br>
<input type="text" name="password" value="123456"><br>
<input type="submit" value="提交">
</form>
<form action="http://httpbin.org/post" method="post">
<input type="text" name="username" value="Wzx"><br>
<input type="text" name="password" value="123456"><br>
<input type="submit" value="提交">
</form>
- 使用Fidller抓包结果:
4.2 Response
4.3 区别
-
GET提交的数据会放在URL之后,POST方法是把提交的数据放在HTTP包的Body(请求体)中.
-
GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制.
-
GET方式需要使用Request.QueryString来取得变量的值,而POST方式通过Request.Form来获取变量的值。
-
GET方式提交数据,会带来安全问题,如登录一个系统时用户名和密码将出现在URL上,信息可能会被窃取。
5. 状态码
1xx:指示信息-->表示请求已接收,但未响应
2xx:成功-->表示请求已被成功接收、理解、接受。
3xx:重定向-->要完成请求必须进行更进一步的操作
4xx:客户端错误-->请求有语法错误或请求无法实现
5xx:服务器端错误-->服务器未能实现合法的请求
常见的状态码
200 OK //客户端请求成功
400 Bad Request //客户端有语法错误
401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden //服务器收到请求,但是拒绝提供服务
404 Not Found //请求资源不存在,eg:输入了错误的URL
500 Internal Server Error //服务器发生不可预期的错误
503 Server Unavailable //服务器超时,一段时间后可能恢复正常
6. 请求方式
- get 请求指定的页面信息,并返回实体主体。
- head 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
- POST 数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
- PUT 从客户端向服务器传送的数据取代指定的文档的内容。
- DELETE 请求服务器删除指定的页面。
- CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。\
- OPTIONS 允许客户端查看服务器的性能。
- trace 回显服务器收到的请求,主要用于测试或诊断。
7. 工作原理
- 客户端连接到Web服务器
一个HTTP客户端,通常是浏览器,与Web服务器的HTTP端口(默认为80)建立一个TCP套接字连接。
- 发送HTTP请求
客户端向Web服务器发送一个文本的请求报文,一个请求报文由请求行、请求头部、空行和请求数据4部分组成。
- 服务器接受请求并返回HTTP响应
服务器将资源复本写到TCP套接字,由客户端读取。一个响应由状态行、响应头部、空行和响应数据4部分组成。
- 释放连接TCP连接
若connection 模式为close,则服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接;若
connection 模式为keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求;
- 客户端浏览器解析HTML内容
浏览器先解析响应行,查看请求的状态码。
然后解析响应头,响应头告知以下为若干字节的HTML文档和文档的字符集。
浏览器读取响应数据HTML,根据HTML的语法对其进行格式化,并在浏览器窗口中显示。
总结举例:在浏览器地址栏键入URL,按下回车之后会经历以下流程
1. 浏览器向 DNS 服务器请求解析该 URL 中的域名所对应的 IP 地址;
2. 解析出 IP 地址后,根据该 IP 地址和默认端口 80,和服务器建立TCP连接;
3. 浏览器发出读取文件(URL中域名后面部分对应的文件)的HTTP 请求,该请求报文作为 TCP 三次握手的第三个报文的数据发送给服务器;
4. 服务器对浏览器请求作出响应,并把对应的 html 文本发送给浏览器;
5. 释放 TCP连接;
6. 浏览器将该 html 文本并显示内容;
Servlet
1. Servlet
1.1 概念
- servlet是javaEE规范之一,规范就是接口
- Servlet就是javaweb三大组件之一,三大组件分别为:Servlet程序,Filter过滤器,listener监听器
- Servlet服务于HTTP协议的服务端的一个小程序,”接受请求,解析请求,根据请求业务做出响应“
- Servlet的作用可以总结为如下图:
1.2 入门案例
基于注解的配置
- 导入依赖
- 在src下创建HttpServlet
@WebServlet("/hello")//访问方式为:http://localhost:8080/servlet/hello
public class HelloServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) //使用post的响应方式
throws ServletException, IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(request.getInputStream()));
String line = null; 获取request请求的流 即请求体的参数
while ((line = in.readLine()) != null) {
System.out.println(line);//循环并打印在控制台
}
in.close();//关闭输入
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponseresponse) //使用Get的响应方式
throws ServletException, IOException {
System.out.println("queryString = " + request.getQueryString());//获取请求URL的参数部分
response.getWriter().print(request.getQueryString());//将获取的参数作为响应再写回去
}
}
基于XML的配置
- web.xml配置如下:
<servlet>
<servlet-name>hello</servlet-name> -->名字随意,但必须是唯一
<servlet-class>com.wzx.demo.ServletTest2</servlet-class> --> src下java文件的相对路径
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name> -->与上面的<servlet-name>的值一致
<url-pattern>/hello</url-pattern> -->‘/hello’必须唯一且不能省略‘/’该值为资源的URL路径
</servlet-mapping>
- 上面的代码HttpServlet.java文件的注解 == 该XML配置
1.3 Servlet生命周期
- 执行servlet的构造函数
- 执行init初始化方法
- 执行service方法,每次访问都会执行
- 执行destroy方法,当工程停止时调用
注意:1,2 是再第一次访问Servlet时才调用。
1.4 解决乱码
-
出现乱码的原因:idea使用的是UTF-8,浏览器使用的并非是UTF-8.会导致在浏览器输入中文,idea控制台出现乱码的情况。
-
解决方案:再idea右上角
configurations
再VM options处输入-Dfile.encoding=UTF-8 -Dconsole.encoding=UTF-8
即可。
1.5 Servlet继承图
1.6 配置详情
- 从Servlet3.0开始,使用Servlet有两种方式
- Servlet类上使用@WebServlet()注解
- web.xml文件中配置
- 常用的属性
1. initParams 配置初始化参数、
2. loadOnStartup 是否再启动是加载及加载顺序。
3. servlet-name 指定servlet的名字
4. urlPatterns 指定servlet的执行路径
5. value 等价于urlPatterns
@WebServlet(value="/hello",loadOnStartup=1)
6. /* 和 / 常用的拦截,拦截所有。
*.jpg 拦截指定的后缀
eg:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern> //将*.jpg形式的资源拦截,执行default的servlet程序
</servlet-mapping>
2. ServletConfig
2.1 简介
Servlet是程序配置的信息类。
ServletConfig的作用
- 获取 Servlet 程序的别名 servlet-name 的值
- 获取初始化参数 init-param
- 获取 ServletContext 对象
2.2 web.xml配置
1. web.xml展示:
<!-- ServletTest1 -->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.wzx.demo.ServletTest2</servlet-class>
<init-param>
<param-name>helloConfig1</param-name> 初始化参数名1
<param-value>hello servletconfigvalue1</param-value> 该参数的值1
</init-param>
<init-param>
<param-name>helloConfig2</param-name> 初始化参数名2
<param-value>hello servletconfig value2</param-value>该参数的值2
</init-param>
<load-on-startup>1</load-on-startup> 启动时是否加载,数字表示执行顺序
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<!-- ServletTest2 -->
<servlet>
<servlet-name>world</servlet-name>
<servlet-class>com.wzx.demo.ServletTest</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>world</servlet-name>
<url-pattern>/world</url-pattern>
</servlet-mapping>
2.3 servlet程序配置
2. hello.java
public class ServletTest2 extends HttpServlet {
public ServletTest2() {
System.out.println("hello构造函数");} //先执行构造函数
@Override
public void init(ServletConfig config) throws ServletException {//init方法
super.init(config); 得到配置的int-parameter参数; 必须要写
//init中使用servletconfig必须要使用super()
System.out.println(config.getInitParameter("helloConfig1"));//在init中获取初始化参数1的值
System.out.println(config.getInitParameter("helloConfig2"));//在init中获取初始化参数2的值
System.out.println("Hello Servlet 初始化");
}
@Override
public void destroy() {//destroy方法
System.out.println("hello销毁方法");
}
@Override//doPost
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(request.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
System.out.println("hello " + line);
}
in.close();
//得到配置的init-parameter参数
System.out.println(this.getInitParameter("helloConfig1"));//在post中得到init参数1
System.out.println(this.getInitParameter("helloConfig2"));//在post中得到init参数2
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("hello " + request.getQueryString());
response.getWriter().println(request.getQueryString());
}
}
3. world.java 于hello.java代码基本相同
public class ServletTest extends HttpServlet {
public ServletTest() {
System.out.println("world构造函数");
}
@Override
public void init() throws ServletException {
System.out.println("world初始化");
}
@Override
public void destroy() {
System.out.println("world销毁方法");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(request.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
System.out.println("world "+ line);
}
in.close();
//得到配置的init-parameter参数
System.out.println(this.getInitParameter("helloConfig1"));//null,出现null原因:在web.xml中未设置初始化参数
System.out.println(this.getInitParameter("helloConfig2"));//null,同理
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println( "world"+ request.getQueryString());
//将请求内容写回去
response.getWriter().println(request.getQueryString());
}
}
3. ServletContext
3.1 简介
ServletContext:Servlet上下文,servlet容器。
- 当WEB服务器启动时,会为每一个WEB应用程序(webapps下的每个目录就是一个应用程序)创建一块共享的存储区域
- ServletContext也叫做“公共区域”,也就是同一个WEB应用程序中,所有的Servlet和JSP都可以共享同一个区域。
- ServletContext在WEB服务器启动时创建,服务器关闭时销毁。
- ServletContext 对象是一个域对象。
3.2 作用域
域对象:可以像 Map 一样存取数据的对象, 叫域对象。这里的域指的是存取数据的操作范围
javaweb中有4个域对象分别如下
- pageContext
- request
- session
- application(ServletContext)
ServletContext 类的四个作用
- 获取 web.xml 中配置的参数 context-param
- 获取当前的工程路径, 格式: /工程路径
- 获取工程部署后在服务器硬盘上的绝对路径
- 像 Map 一样存取数据
3.3 web.xml配置
<context-param>
<param-name>contextParam1</param-name>//全局参数1
<param-value>servlet context parameter value1</param-value>
</context-param>
<context-param>
<param-name>contextParam2</param-name>//全局参数2
<param-value>servlet context parameter value2</param-value>
</context-param>
3.4 servlet.程序配置
1. hello.java
public class ServletTest2 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//作为全局作用域,必须先执行setAttribute方法才能执行getAttribute方法
getServletContext().setAttribute("globalKey", "hello servlet global");
//获取 全局 初始化参数//hello.java中可以获取,在该项目下的其它servlet程序均可获取
System.out.println(getServletConfig().getServletContext().getInitParameter("contextParam1"));
System.out.println(getServletConfig().getServletContext().getInitParameter("contextParam2"));
}//通过getServletConfig()方法获取
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println(getServletContext().getAttribute("globalKey"));//全局,一个web均可访问
//得到项目的绝对路径
System.out.println(this.getServletContext().getRealPath("/"));
}
}
2. world.java
public class ServletTest extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { }//doPost方法
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//全局之作用域,所以另一个servlet程序也可以访问
System.out.println("world " + getServletContext().getAttribute("globalKey"));
}
}
4. HttpServletRequest
4.1 简介
每次只要有请求进入 Tomcat 服务器, Tomcat 服务器就会把请求过来的 HTTP 协议信息解析好封装到Request 对象中。然后传递到 service 方法( doGet 和 doPost) 中给我们使用。 我们可以通过HttpServletRequest 对象获取到所有的请求
4.2 常用方法
1. getRequestURI() 获取请求的资源路径
getRequestURL() 获取请求的统一资源定位符(绝对路径)
getHeader() 获取请求头
getMethod() 获取请求的方式 GET 或 POST
2. getParameter() 获取请求的参数
getParameterValues() 获取请求的参数(多个值的时候使用)
3. setAttribute(key, value); 设置域数据
getAttribute(key); 获取域数据
4. getRequestDispatcher() 获取请求转发对象
5. 案例展示:
@WebServlet("/request")
public class requestDemo extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");//设置request解码的字符集
System.out.println("-----请求行------");
System.out.println("getRequestURI = " + request.getRequestURI());
//getRequestURI() 获取请求的资源路径 getRequestURL() 获取请求的统一资源定位符(绝对路径)
System.out.println("getRequestURL = " + request.getRequestURL());
//获取请求方法
System.out.println("Method=" + request.getMethod());//Post or Get
System.out.println("协议=" + request.getProtocol());//获取请求协议及其版本
System.out.println("------请求头------");//主要是各个属性:线面演示获取全部属性
Enumeration<String> header = request.getHeaderNames();//获取请求头的属性名 来获取所有的属性。
while (header.hasMoreElements()) {
String head = header.nextElement();
System.out.println(head + " : " + request.getHeader(head));//request.getHeader(head)属性值
}
System.out.println("------请求体------");//PS:使用API参数情况下不使用数据流。否则出错
System.out.println(request.getParameter("userName"));//得到一个参数:
System.out.println(Arrays.toString(request.getParameterValues("id"))); //同时得到同名的参数放在数组中
//得到并打印所有的参数
Map<String, String[]> parameterMap = request.getParameterMap();
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
System.out.println(entry.getKey() + " : " + Arrays.toString(entry.getValue()));
}
//获取请求体的参数名。
Enumeration<String> params = request.getParameterNames();
while (params.hasMoreElements()) {
String param = params.nextElement();
System.out.println(param);
}
}
}
4.3 request作用域
- request作用范围:在一次请求中可以访问的作用,当前的servlet和当前servlet转发的servlet可以访问
request.setAttribute("requestKey3", "hello servlet3 attribute value1");//在request作用域中设置属性
request.getAttribute("requestKey3") //request作用域取
5. HttpServletResponse
5.1 简介
HttpServletResponse 类在每次请求进来, Tomcat 服务器都会创建一个 Response 对象传递给 Servlet 程序去使用。
- HttpServletRequest 表示请求过来的信息,HttpServletResponse 表示所有响应的信息,
我们如果需要设置返回给客户端的信息, 都可以通过HttpServletResponse 对象来进行设置
两个输出流的说明
-
字节流 getOutputStream(); 常用于下载(传递二进制数据)
-
字符流 getWriter(); 常用于回传字符串(常用)
两个流同时只能使用一个。使用了字节流, 就不能再使用字符流, 反之亦然, 否则就会报错。
5.2 常用方法
setContentType() 设置客户端的解码方式
setStatus() 设置状态码
addHeader() 添加响应头属性
getWriter().pring() 写回
@WebServlet("/response")
public class ResponseDemo extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//设置响应字符集的解码方式.PS:做出响应时一定要放在第一位
response.setContentType("text/html;charset=UTF-8"); //设置客户端浏览器的解码方式
System.out.println("--------响应行-------");
response.setStatus(HttpServletResponse.SC_OK);//设置指定的响应码
System.out.println("----------响应头---------");
response.addHeader("user-name", "mickey");//添加响应头属性
System.out.println("----------响应体---------");
response.getWriter().print("中文响应体");//写回指定内容到客户端
}
}
6. 转发和重定向
6.1 区别
-
请求转发:服务器收到请求后, 从一个资源跳转到另一个资源的操作
-
请求重定向:服务器收到请求后 告诉客户端: 我给你地址。 你去新地址访问。 (因为之前的地址可能已经被废弃)
6.2 转发演示
1. 演示请求转发-->
servlet程序1
@WebServlet("/servlet1")
public class servlet1 extends HttpServlet {
@Override
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {//该方法所有请求方式都可以访问。
request.setAttribute("requestKey1", "request.setAttribute servelet1(value)");//request作用域
//在控制台打印请求体的参数。
request.getParameterMap().forEach((k, v) -> {
System.out.println("servlet1.name = " + k + " and value= " + Arrays.toString(v));
});
//转发发生在服务器内部,所以不用加context-path:/servlet。即:相对虚拟主机:从URL上相对。
request.getRequestDispatcher("/servlet2").forward(request, response);//发生转发
}
}
servlet程序2
@WebServlet("/servlet2")
public class servlet2 extends HttpServlet {
@Override
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter writer = response.getWriter();//向客户端响应
System.out.println(request.getAttribute("requestKey1"));//取出并打印request作用域中的属性
writer.print(request.getAttribute("requestKey1"));
writer.print("<hr>");
//向浏览器响应内容:参数列表
request.getParameterMap().forEach((k,v)->{//数据流
writer.print("servelt2.name = " + k + " and value= " + Arrays.toString(v));
});
}
}
运行结果:
6.3 重定向演示
2. 演示请求重定向 -->
servlet程序3
@WebServlet("/servlet3")
public class servlet3 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setAttribute("servlet3", "request.areat.servlet3");
//重定向方式一:response.sendRedirect("/servlet/servlet4");
//重定向方式二:
response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);//设置状态码302
response.setHeader("location", "/servlet/servlet4");
//跳转到错误界面:response.sendError(HttpServletResponse.SC_NOT_FOUND, "资源未找到");
}
}
servlet程序4
@WebServlet("/servlet4")
public class servlet4 extends HttpServlet {
@Override
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
request.getAttribute("servlet3");
PrintWriter out = response.getWriter();
out.print(request.getAttribute("servlet3")); //回应浏览器的请求-->响应
out.print("<hr>");
request.getParameterMap().forEach((k, v) -> {
out.print("servelt4.name = " + k + " and value= " + Arrays.toString(v)); //响应协议
out.print("<hr>"); //响应协议
out.print("123");
});
}
}
运行结果:
Jsp
1. 简介
JSP全名为Java Server Pages,中文名叫java服务器页面,其根本是一个简化的Servlet设计
它是在传统的网页HTML文件中插入Java程序段,从而形成JSP文件。 用JSP开发的Web应用是跨平台的,能在Linux和其它系统下运行
-
*.html 静态页面(包含固定的页面内容)
-
*.jsp 动态页面(页面数据可以动态更新,支持嵌套java代码和html代码)
-
与servlet同理,也需要导入依赖
2. 语法格式
- 在jsp中使用java代码 ---->使用小脚本<% java代码 %>
- 各种标签
- .jsp文件会自动产生session
1. 声明标签 <%!变量或者方法声明%>
2. 表达式标签 <%= 表达式%> 在页面上显示的效果
3. 程序代码标签 <%java代码%> 页面上动态展示内容
<%-- 变量或方法的声明,后面的表达式或小脚本可以使用 --%>
<%! LocalTime localTime = LocalTime.now();%>
<%--使用上面声明的变量--%>
<%=localTime%>
<%-- 表达式标签,等价于:<% out.print(LocalDate.now()) %> --%>
<%= LocalDate.now() %>
<%--小脚本--%>
<%LocalDateTime ldt = LocalDateTime.now();
out.print(ldt);%>
- jsp中的注释
<!-- html注释内容,查看源码时能看到 -->
<%-- jsp注释,查看页面源码时看不到 --%>
- 执行情况
第一次执行:
翻译index.jsp翻译成/work/..../index_jsp.java
编译index_jsp.java编译成class文件index_jsp.class
执行service
第二次执行:
执行service
PS:小脚本翻译成service中一段代码,使用out打印变量到页面。
脚本表达式默认使用out输出一个变量,
脚本声明,声明一个实例方法,或者实例变量
文件过程(了解):当浏览器访问http://localhost:8080/jsp/index.jsp时,服务器发现后缀为.jsp,它会根据路径找到index.jsp文件,
会将index.jsp翻译成index_jsp.java文件,对这个java文件进行编译,产生一个index_jsp.class文件,将class文件加载运行。
将JSP翻译成java文件,它是将JSP中的所有的HTML代码通过流进行输出,也就是说最终翻译成class,被虚拟机加载,它本质是servlet,
它就会往回响应,响应回去就是把JSP中的HTML代码以流的方式写回浏览器。所以在JSP中展示出了HTML代码
3 .内置对象
3.1 重要的对象
request、response、session、application、out、pagecontext、config、page、exception
request
request 对象是 javax.servlet.httpServletRequest类型的对象。该对象代表了客户端的请求信息,主要用于接受通过HTTP协议传送到服务器的数据。(包括头信息、系统信息、请求方式以及请求参数等)。request对象的作用域为一次请求。
response
response 代表的是对客户端的响应,主要是将JSP容器处理过的对象传回到客户端。response对象也具有作用域,它只在JSP页面内有效。所属类型:HttpServletResponse
pageContext
pageContext 对象的作用是取得任何范围的参数,通过它可以获取 JSP页面的out、request、reponse、session、application 等对象。pageContext对象的创建和初始化都是由容器来完成的,在JSP页面中可以直接使用 pageContext对象。
application
application 对象可将信息保存在服务器中,直到服务器关闭,否则application对象中保存的信息会在整个应用中都有效。与session对象相比,application对象生命周期更长,类似于系统的“全局变量” ServletContext
3.2 作用域
pageContext -> request -> session -> application
当前页面 单次请求有效 当前会话期间 服务器运行期间有效
代码演示:a.jsp设置参数;b,c获取参数,查看获取情况
1. a.jsp
<body>
<h5>a.jsp</h5>
<%--对象域--%>
<%
application.setAttribute("key1", "value1");
session.setAttribute("key2", "value2");
request.setAttribute("key3", "value3");
pageContext.setAttribute("key4", "value4");
request.getRequestDispatcher("/b.jsp").forward(request, response);//转发请求
%>
</body>
------------------------
2. b.jsp
<body>
<h5>b.jsp</h5>
<%--对象域--%>
<%
out.print(application.getAttribute("key1") + "<br>");//servletContext
out.print(session.getAttribute("key2") + "<br>");//同一个浏览器的会话,关闭浏览器后打开 或 打开另一个浏览器失效
out.print(request.getAttribute("key3") + "<br>");//HttpServletRequest 作用于一次请求或转发
out.print(pageContext.getAttribute("key4") + "<br>");//只能在该页面有效
%>
</body>
------------------------
3. c.jsp
<body>
<h5>c.jsp</h5>
<%--作为直接访问--%>
<%
out.print(application.getAttribute("key1") + "<br>");//true
out.print(session.getAttribute("key2") + "<br>");//true 同一个浏览器生效
out.print(request.getAttribute("key3") + "<br>");//false request不同
out.print(pageContext.getAttribute("key4") + "<br>");//false 不是同一个page
%>
</body>
4. EL表达式(重点)
1. <%--设置作用域参数--%>
<%
pageContext.setAttribute("key", "page scope value");
request.setAttribute("key", "request scope value");
session.setAttribute("key", "session scope value");
application.setAttribute("key", "application scope value");
pageContext.setAttribute("num", 100);
%>
2. <%--El表达式可以取出作用域中的数据--%>
<%--下面的表达式 == out.print(application.getAttribute(“key1”))--%>
${applicationScope.key}
${requestScope.key}<br>
${sessionScope.key}<%--取出session范围的属性--%>
3. ${key} <%--直接写参数:从作用范围从小到大遍历,所以结果为:page scope value--%>
4. <h5>EL表达式运算符</h5>
${key == "page scope value"}//可以进行加减乘除 判断
${num + 1}
6. <h5>el访问对象的属性</h5>
<%
User user = new User();
user.setUsername("mickey");
user.setPassword("123456");
user.setAge(18);
request.setAttribute("user", user);//前提:必须将属性放在作用域中才能访问
List<User> list = new ArrayList<>();
list.add(new User("abc", "123", 22));
list.add(new User("efg", "456", 25));
list.add(new User("789", "888", 24));
request.setAttribute("list1", list);
%>
${user.username}
${user.password}
${user.age}
${list1[2].username}
7. <h5>EL访问参数:URL中的参数</h5>
${param.name} <%--URL地址中的参数,如果为null,不显示--%>
<%--等价于--%>
<%=request.getParameter("name")%>
8. <h5>EL获取虚拟主机</h5>
${pageContext.request.contextPath}
<%--获取当前web页面的context-path:/jsp--%>
9. <%--导入已有的jsp文件--%>
<%@ include file="index.jsp"%>
10. 在jsp文件中的路径只推荐使用 基于虚拟主机的URL路径。而目录路径不推荐
5. JSTL
5.1 简介
JSP标准标签库(JSTL)是一个JSP标签集合,它封装了JSP应用的通用核心功能。如**迭代,条件判断,**XML文档操作,SQL标签。
根据JSTL标签所提供的功能,可以将其分为5个类别。
- 核心标签
- 格式化标签
- sql标签
- xml标签
- jstl函数
5.2 语法格式
- 作用:简化jsp页面编写代码
使用方式:
- 下载 jakarta-taglibs-standard-1.1.2.zip 包并解压,将jstl-1.2.jar文件放在WEB-INF/lib下
- 在JSP页面中引入
<%@ taglib prefix=”页面使用的名称” uri=”功能范围的路径”%>
功能范围 | uri | 前缀 |
---|---|---|
core | http://java.sun.com/jsp/jstl/core | c |
il8n | http://java.sun.com/jsp/jstl/fmt | fmt |
sql | http://java.sun.com/jsp/jstl/sql | sql |
xml | http://java.sun.com/jsp/jstl/xml | x |
functions | http://java.sun.com/jsp/jstl/function | fn |
5.3 核心标签
使用核心标签的语法为<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
核心标签的分类
- 表达式操作out、set、remove、catch
- 流程控制 if choose when otherwise
- 迭代操作 forEach forTokens
- URL操作 import param url redirect
案例演示
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
1. <h5>forEach标签的使用</h5> 循环控制 item:被迭代的集合对象 varStatus:存放相关成员信息 step:每次迭代的间隔数
<c:forEach begin="1" end="10" var="i">
${i}
</c:forEach>
<hr>
<c:forEach items="${userList}" var="u" varStatus="s">
${s.count} --- ${s.index} :: ${u.username} --- ${u.password} ---${u.age}<br>
</c:forEach>
<%
User user = new User("tomcat", "1234", 22);
request.setAttribute("userKey", user);
%></
>
2. <h5>if标签</h5> test:表达式的结果为true,则执行体内容,false则相反 var:结果(true或false)
<c:if test="${!userKey.username.equals(\"1234\")}" var="b1" scope="request">
user password=1234
</c:if>
${b1}
3. <h5>choose标签</h5> 作用相当于if-else
<c:choose>
<c:when test="${2 == 2}">
确实:2== 2
</c:when>
<c:otherwise>
确实不等于
</c:otherwise>
</c:choose>
4. <h5>out标签</h5> 输出(不重要)
<c:out value="${userKey.age}"></c:out><br>
${userKey.age}
5. <h5>set标签</h5> value:要被存储的值 var:存入的变量名称 Scope:var变量的JSP范围
<c:set var="name1" value="${requestScope.userKey.username.substring(3,6)}" scope="request"></c:set>
${name1}
<%--等价于:request.setAttribute("name1",${requestScope.userKey.username.substring(3,6)})--%>
6. <h5> redirect重定向</h5>
<%-- <c:redirect url="/index.jsp"></c:redirect>--%>
</body>
</html>
5.4 格式化标签
- fmt:formatDate作用:将日期类型格式化为指定模式的字符串
- value:将要被格式化的数据
- pattern:格式化的模式,与SimpleDateFormat的参数设置一样
- var:格式化后的字符串所要存放的变量,若不指定var,则会将格式化的结果直接显示在页面
- scope:变量存放的域属性空间,默认page
- fmt:formatNumbe 按照指定格式对数字进行格式化
- var:存储格式化结果的变量
- scope:var属性的作用域
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%
Date date = new Date();
request.setAttribute("date", date);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss.SSS");
out.print(sdf.format(date));
%>
1. <h5>formatDate</h5>
<%--等价于>--%>
<fmt:formatDate value="${date}" pattern="yyyy-MM-dd HH-mm-ss.SSS" var="fdate" scope="request">
</fmt:formatDate>
${fdate}
2. <h5>formatNumber</h5>
<%
double money = 123456.789;
request.setAttribute("balance", money);
DecimalFormat df = new DecimalFormat("#,###.##");
out.print(df.format(money));
%>
<%--等价于:下面的表达式--%>
<fmt:formatNumber value="${balance}" pattern="#,###.##" var="fbalance" scope="request"></fmt:formatNumber>
${fbalance}
</body>
</html>
Cookie
1. 简介
-
Cookie 翻译过来是饼干的意思。
-
Cookie 是服务器通知客户端保存键值对的一种技术。
-
客户端有了 Cookie 后, 每次请求都发送给服务器。
-
每个 Cookie 的大小不能超过 4kb
2. 创建Cookie
- 服务器(Tomcat)创建Cookie对象
Cookie cookie = new Cookie("key","value");
- 服务器通知客户端(浏览器)保存Cookies
response.addCookie(cookie);
- 传输时通过响应头Set-Cookie通知客户端保存Cookie
Set-Cookie : key = value
- 客户端收到响应后发现有Set-Cookie响应头,就去看有没有这个Cookie,没有就去创建有就修改
@WebServlet("/cookie")
public class CookieServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
response.setContentType("text/html; charset=UTF-8");//设置浏览器字符集
Cookie c1 = new Cookie("key1", "value1");//创建Cookie对象
Cookie c2 = new Cookie("key2", "value2");
response.addCookie(c1);//通知浏览器
response.addCookie(c2);
response.getWriter().print("Cookie添加成功");
}
}
- 浏览器存储的Cookie
3 . 服务器获取Cookie
-
服务器将Cookie对象传给浏览器后,浏览器会将Cookie随着请求一起发送给服务器,Cookie则在请求头中。
-
服务器通过
request.getCookies()
方法获取Cookies,但这是一个数组。需要我们自己去筛选我们需要的Cookie
//获取Cookie并打印Cookie在相应上
@WebServlet("/getcookie")
public class GetCookie extends HttpServlet {
//筛选Cookie的工具类
private Optional<Cookie> getCookie(String name, Cookie[] cookie) {
return Arrays.stream(cookie).filter(ck -> name.equals(ck.getName())).findFirst();
}
/*解析:
1. 因为request.getCookies()返回所有的Cookie数组,所以需要我们自己去 获取我们想要的
2. 获取数组流对象-->进行筛选(根据我们想要的Cookie名) -->获取第一个Option<Cookie>
3.
*/
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
//获取指定的Cookie方法
// Optional<Cookie> key1 = getCookie("key1", request.getCookies());
// Optional<Cookie> key2 = getCookie("key2", request.getCookies());
// System.out.println(key1.get().getName() + " | " + key1.get().getValue());
// System.out.println(key2.get().getName() + " | " + key2.get().getValue());
// Cookie key3 = getCookie("key3", request.getCookies()).orElse(new Cookie("key3", "空"));
// System.out.println(key3.getName() + " | " + key3.getValue());
//获取所有的Cookie
PrintWriter out = response.getWriter();
if (null != request.getCookies()) {
Arrays.stream(request.getCookies()).forEach(ck -> {
out.print(ck.getName() + " | " + ck.getValue() + "<br>");
});
}
}
}
4. Cookie值修改
- Cookie值的修改 = Cookie对象的创建
Cookie key1 = new Cookie("key1","value0");
response.addCookie(key1);
- 此时浏览器中有该值就进行覆盖。
5. Cookie字段
5.1 常用字段
field | 描述 |
---|---|
name | key-value键值对中的 key |
value | key-value键值对中的 value值 |
expires | cookie过期日期,过期后就会在自动删除 |
path | cookie的访问路径, 访问路径的值一般设为“/” ,表示所有页面都可以访问这个cookie |
domain | cookie的访问域名, 此属性设置指定域名下的页面才可以访问该cookie。 |
secure | cookie的安全属性,只有使用了HTTPS协议才可以被页面访问 |
httponly | 只读,所有脚本无法获取Cookie的信息 |
- 为什么要设置HttpOnly和Secure?
当设置了HttpOnly属性时, 通过脚本将无法获取到Cookie信息,主要用于防止XSS攻击。 而一旦设置了Secure属性时,
前后端之间只能在HTTPS协议通信情况下浏览器才能访问Cookie,使用HTTP协议时浏览器无法取到Cookie信息,同样是对Cookie信息的保护。
5.2 expires字段
-
作用:管理 Cookie 什么时候被销毁(删除)
-
方法:
setMaxAge()
-
大于0 表示在指定的秒数后过期
-
小于0 表示浏览器一关, Cookie 就会被删除(默认值是-1)
-
等于0 表示直接删除 Cookie
-
//Cookie的生命周期
Cookie c3 = new Cookie("key3","value3");
c3.setMaxAge(3600 * 24);//经过24 * 3600s后删除
Cookie c4 = new Cookie("key4", "value4");
c4.setMaxAge(-1);//关闭浏览器后删除
Cookie c5 = new Cookie("key5", "value5");
c5.setMaxAge(0);//直接删除,相当于不存在
response.addCookie(c3);
response.addCookie(c4);
response.addCookie(c5);
5.3 Path字段
- Cookie的path默认值是request.getContextPath 即:/cookie
//Cookie的Path注意事项:访问/cookie/getcookie
Cookie c6 = new Cookie("key6", "value6");
c6.setPath("/cookie/a.jsp");//在/cookie/getcookie中没有,因为该cookie是在/cookie/a.jsp及其后面的才有
Cookie c7 = new Cookie("key7", "value7");
c7.setPath("/cookie/b.jsp"); //同理
Cookie c8 = new Cookie("key8", "value8");
c8.setPath("/"); //都获取到
Cookie c9 = new Cookie("key9", "value9");
c9.setPath("/timao"); //在/cookie/getcookie中获取不到
- 匹配规则 -->前缀匹配
path = /;
path = /cookie-demo;
path = /cookie-demo/a.jsp;
以上的cookie访问/cookie-demo/a.jsp,会被随请求一起访问;
/path = /cookie/b.jsp的cookie访问/cookie-demo/a.jsp,不会被随请求一起访问;
5.4 Domain字段
-
Cookie的domain默认值是request.getServletName 即:/localhost 或 /a.file.com 这里使用后者
-
配置方法
1. 打开 c:\Windows\System32\drivers\etc\hosts 2. 添加如下内容: 127.0.0.1 file.com 127.0.0.1 a.file.com 127.0.0.1 b.file.com 127.0.0.1 image.com 其中file.com 为顶级域 a.file.com和b.file.com为子域
PS: 1. 访问http://a.file.com:8080/cookie/createcookie产生cookie
2. 访问http://b.file.com:8080/cookie/getcookie
Cookie c10 = new Cookie("key10", "value10");
c10.setDomain("file.com"); //c10为a.file.com 和b.file.com的顶级域,所以在b.file.com中会显示
Cookie c11 = new Cookie("key11", "value11");
c11.setDomain("a.file.com");//无法显示,不同域之间不共享
Cookie c12 = new Cookie("key12", "value12");
c12.setDomain("b.file.com"); //无法显示,浏览器在创建时自动过滤
Cookie c13 = new Cookie("key13", "value13");
c13.setDomain("image.com"); //无关项与c12相同
response.addCookie(c10);
response.addCookie(c11);
response.addCookie(c12);
response.addCookie(c13);
- 结论
- 只有c10这个顶级域能被子域共享
- cookie中设置当前域和当前域的顶级域,在当前域中都能访问,但在顶级域的另一个子域中只能访问顶级域
- 顶级域在子域中共享
6. JS访问Cookie
PS: 1. http://a.file.com:8080/cookie/c.html
2. http://b.file.com:8080/cookie/d.html
<body>
c.html
<script>
console.log(Cookies.get("key10"));//a.file.com 访问,c10是顶级域
Cookies.set("key21", "value21", {expires: 7, path: "cookie"})
Cookies.set("key22", "value22", {expires: 7, path: "cookie", domain: ".file.com"})//可以访问
Cookies.set("key23", "value23", {expires: 7, path: "cookie", domain: ".image.com"})//无关项无法访问
console.log(Cookies.get())
</script>
</body>
<body>
d.html
<script>
console.log(Cookies.get());//只有key10和key22可以访问
</script>
</body>
- 结论:JS中访问cookie无法共享,只有共同的顶级域才能共享顶级域的cookie
Session
1. 简介
-
“Session”(会话)是计算机中的一个概念,用于描述在一段时间内用户与系统之间的交互过程。
-
在网络应用程序中,"session"通常指 在打开网页或登录到应用程序 直到关闭网页或注销账户时结束整个时间段。
-
session的作用:维护用户的状态信息。在一个会话中,用户可以执行多个操作,浏览不同的页面,提交表单数据,与其他用户进行交互等。系统会使用会话ID来区分不同用户的操作,并保持各个操作之间的关联性。
-
应用场景:常见的应用场景是购物网站中的购物车功能。当用户将商品添加到购物车时,系统会使用会话来跟踪用户选择的商品和数量,以便在结算时提供准确的信息。
2. 登录案例
2.1 登录界面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/session/login" method="post"> 向login发送请求
用户名:<input type="text" name="username"><br>
密码:<input type="text" name="password"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
2.2 验证请求
@WebServlet("/login")
public class LoginDemo extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");//获取参数
String password = request.getParameter("password");
//进行表单验证
if ("Tomcat".equals(username) && "123456".equals(password)) {
//匹配成功,使用Session来保存登录信息
HttpSession session = request.getSession(true);//同过JSESSIONID在域中找到session
session.setAttribute("loginUser", "Tomcat");
//跳转到打印界面
response.sendRedirect("/session/getsession");//重定向到getsession
} else {
response.sendRedirect("/session/login.html");//密码错误:跳转到登录界面
}
}
}
2.3 做出响应
@WebServlet("/getsession")
public class GetSession extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
HttpSession session = request.getSession();//通过JSESSIONID在域中获取session
response.getWriter().print("登录用户" + session.getAttribute("loginUser").toString());//做出响应
}
}
3. Cookie-Session原理
3.1 运行原理
- 第一次请求,服务器创建session。并将session的id通过cookie的形式(在响应的响应头)中传送给浏览器
- 浏览器进行存储这个cookie
- 在发送请求时,该cookie 随着请求一同访问服务器
- 服务器通过该cookie在域中查找Session,并对该session进行操作
3.2 参数
HttpSession session = request.getSession(boolean b);
-
b == true(默认):如果当前会话有session就使用当前session;没有就产生新的session
-
b == false:有session就得到当前会话中的session,没有session就返回null
4. Session的生命周期
4.1 API方法
public void setMaxInactiveInterval(int interval)
设置 Session 的超时时间( 以秒为单位)。过时就会销毁
public void invalidate()
让当前 Session 会话马上超时无效。public int getMaxInactiveInterval()
获取 Session 的超时时间
4.2 设置方法
-
Tomcat默认超时时间:在 Tomcat 服务器的配置文件 web.xml中有默认的配置, 它就表示配置了当前 Tomcat 服务器下所有的 Session超时配置默认时长为: 30 分钟。
-
项目超时时间:你可以在你自己项目的 web.xml配置文件中配置。 就能修改项目中所有session的超时时间
<!--表示当前 web 工程。 创建出来 的所有 Session 默认是 20 分钟 超时时长-->
<session-config>
<session-timeout>20</session-timeout>
</session-config>
- 某个session的超时时间
使用上面的API方法:session.setMaxInactiveInterval(int interval)
如:session.setMaxInactiveInterval(10); //10s后失效
- 立即失效
使用API方法:session.invalidate()//立即失效
Filter
过滤器
1. 简介
-
Filter 过滤器它是 JavaWeb 的三大组件之一。 三大组件分别是: Servlet 程序、 Listener 监听器、 Filter 过滤器
-
作用: 拦截请求, 过滤响应。
-
需要拦截的场景:
- 权限检查
- 日记操作
- 事务管理
2. 过滤器链
3. 登录验证
3.1 准备工作
-
要求:目标下的所有资源(html 页面、 jpg 图片、 jsp 文件、 等等) 都必须是用户登录之后才允许访问。
-
原理:根据之前我们学过内容。 我们知道, 用户登录之后都会把用户登录的信息保存到 Session 域中。 所以要检查用户是否登录, 可以判断 Session 中否包含有用户登录的信息即可! ! !
// 如果等于 null, 就跳转到登录界面有登录
Object user = session.getAttribute("user");
if (user == null) {
request.getRequestDispatcher("/login.jsp").forward(request,response);
return;
}
- 原理图:
3.2 过滤器
- 配置文件:
1. Filter1配置
<filter>
<filter-name>filter1</filter-name>
<filter-class>com.wzx.demo.filter.Filter1</filter-class>
</filter>
<filter-mapping>
<filter-name>filter1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2. AdminFilter配置
<filter>
<filter-name>admin</filter-name>
<filter-class>com.wzx.demo.filter.AdminFilter</filter-class>
<init-param>
<param-name>passUrls</param-name>
<param-value>/filter/login;/filter/css;/filter/img</param-value> //放行css、js、img、以及校验界面
</init-param>
</filter>
<filter-mapping>
<filter-name>admin</filter-name>
<url-pattern>/*</url-pattern> //拦截所有
</filter-mapping>
- 过滤器1:
public class Filter1 implements Filter { -->过滤敏感词
@Override
public void init(FilterConfig filterConfig) throws ServletException {//初始化方法
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, //过滤方法
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
//使用自定义包装模式 -->完成过滤敏感词汇
CustomHttpServletRequestWrapper requestWrapper = new CustomHttpServletRequestWrapper(request);
filterChain.doFilter(requestWrapper, servletResponse);
/*原理:1. 自定义类作用:在HttpServletRequest的基础上添加业务
2. 先继承HttpServletRequestWrapper,并实现CustomHttpServletRequestWrapper()构造函数
3. 这里重写getParameter()方法,先使用原本的getParameter()方法获得value值,并对该值进行处理
4. if(name.equals("key"))并且key的值等于李佳琦-->则修改value值。最后返回value值。
5. 使用时,将reques传进去,进行包装,并将包装对象代替原来的request对象
6. 包装模式的作用:在不改变源代码的基础上增加业务。
*/ }
@Override
public void destroy() {//销毁方法
}
}
//自定义包装类
class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {//
public CustomHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
if (name.equals("key") && "李佳琦".equals(value)) {
return "XXX";//更改value值
}
return value;
}
}
- 过滤器2:
public class AdminFilter implements Filter {
String[] s;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
s = filterConfig.getInitParameter("passUrls").split(";");//根据“;”分割数据到数组中
/*解读:1. 上面代码 -- > 读取WEB-INF下的web.xml配置
2. filterConfig.getInitParameter()方法获取web.xml参数
3. 与servlet读取web.xml配置的方法相同
4. 与servlet之间的不同:filter中只能在初始化时读取,其它位置没有this关键字
*/}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
//将ServletRequest转为HttpservletRequest,Response同理
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpSession session = request.getSession();
String path = request.getRequestURI(); //相对路径 /filter/...
//放行, 登录成功的界面
for (int i = 0; i < s.length; i++) {//如果相等则可以访问资源。
if (path.startsWith(s[i])) {
filterChain.doFilter(request, response);
return;
}
}
//如果等于null表示还未登录 --> 需要跳转到 登录界面
if (session.getAttribute("username") == null) {
request.setAttribute("loginError", "请先登录");
request.getRequestDispatcher("/login.jsp").forward(request, response);
return;
}
//已登录,则可以随意访问
filterChain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
3.3 登录界面
- 表单登录login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set value="${pageContext.request.contextPath}" var="ctx"></c:set>
<html>
<head>
<title>Title</title>
<link rel="stylesheet" href="${ctx}/css/main.css" >
</head>
<body>
<h5 id="h5">${loginError}</h5>
<form action="${ctx}/login" method="post"> <!--向${ctx}/login = /filter/login发送请求-->
用户名:<input type="text" name="username"><br>
密码:<input type="text" name="password"><br>
<input type="submit" value="提交">
</form>
<img src="${ctx}/img/man00.jpg">
</body>
</html>
- 校验登录login
@WebServlet("/login")
public class LoginDemo extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
String username = request.getParameter("username");//获取表单传值的参数“username”
String password = request.getParameter("password");//获取表单传值的参数“password”
if ("Tomcat".equals(username) && "123456".equals(password)) {//进行校验
//匹配成功,使用Session来保存登录信息
HttpSession session = request.getSession(true);//session对话,
session.setAttribute("username", "Tomcat");
session.setAttribute("loginError",session.getAttribute("username"));//修改其值表示 已登陆
response.getWriter().print("登陆成功!");
}
}
}
3.4 目标资源
servlet顺序:1. 在web.xml配置的资源 > 使用注解配置的资源
程序访问顺序:在浏览器中想要访问servlet1
- 访问Filter1:因为filter1在web.xml中配置在前面
- 访问AdminFilter: 拦截所有
- 访问 login.jsp 第一次访问未登录,需要先登录 --> 跳转到 login 界面 显示登陆成功
- 访问目标资源:servlet1,此时就没有限制了。在访问时URL上添加:?key=李佳琦 -->会屏蔽该值.
@WebServlet("/servlet1")
public class Servlet1 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html; charset=UTF-8");
response.getWriter().print( request.getParameter("key") + "execute servlet1");
System.out.println("execute servlet1");
}
}
4 Filter生命周期
Filter 的生命周期包含几个方法:与servlet大体相同
-
构造器方法
-
init 初始化方法 :第 1, 2 步, 在 web 工程启动的时候执行(Filter 已经创建)
-
doFilter 过滤方法,每次拦截到请求, 就会执行
-
destroy 销毁, 停止 web 工程的时候, 就会执行(停止 web 工程, 也会销毁 Filter 过滤器)
5 FilterConfig
-
FilterConfig 类是 Filter的配置文件类。Tomcat 创建 Filter 时,也会同时创建 FilterConfig 类,该类包含 Filter 配置文件的信息。
-
FilterConfig 类的作用:获取 filter 过滤器的配置内容
-
获取 Filter 的名称 filter-name 的内容
-
获取在 Filter 中配置的 init-param 初始化参数
-
获取 ServletContext 对象
-
-
使用方法与servlet相同
-
PS:Filter 过滤器它只关心请求的地址是否匹配, 不关心请求的资源是否存在! ! !
Listener
监听器(了解即可)
1. 监听器简介
-
监听器(Listener)是一种特殊的组件,用于监听Web应用程序中的事件,并在事件发生时执行相应的操作。
-
监听器可以用于捕获和响应各种事件,从而实现对应用程序的控制和管理
-
监听器的相关概念:
-
事件源:被监听的对象(三个域对象 request、session、servletContext)
-
监听器:监听事件源对象事件源对象的状态的变化都会触发监听器
-
注册监听器:将监听器与事件源进行绑定
-
响应行为:监听器监听到事件源的状态变化时所涉及的功能代码(程序员编写代码)
-
2. 分类
第一维度按照被监听的对象划分:ServletRequest域、HttpSession域、ServletContext域
第二维度按照监听的内容分:监听域对象的创建与销毁的、监听域对象的属性变化(了解)
ServletContextAttributeListener
HttpSessionAttributeListener
ServletRequestAttributeListener
3. 案例演示
3.1 web.xml
<listener>
<listener-class>com.wzx.demo.MyListener</listener-class>
</listener>
<listener>
<listener-class>com.wzx.demo.MyHttpSessionListener</listener-class>
</listener>
PS:推荐使用web.xml,不建议使用注解
3.2 代码演示
1. 演示ServletContextListener --->当创建web项目和销毁web项目时被检测到并进行打印操作
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent){//监测创建web项目
System.out.println("contextInitialized");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {//监测销毁web项目
System.out.println("contextDestroyed");
}
}
2. 演示HttpSessionListener ---> 当创建和销毁session时被检测到并进行打印操作
public class MyHttpSessionListener implements HttpSessionListener {
// 实现接口方法
@Override
public void sessionCreated(HttpSessionEvent event) {
// 在 HttpSession 对象创建时执行的代码
HttpSession session = event.getSession();
// 执行创建逻辑
}
@Override
public void sessionDestroyed(HttpSessionEvent event) {
// 在 HttpSession 对象销毁时执行的代码
HttpSession session = event.getSession();
// 执行销毁逻辑
}
/*如果你还想监听 HttpSession 属性的添加、修改和删除事件,
可以实现 attributeAdded、attributeRemoved 和 attributeReplaced 方法。
*/
}
件源:被监听的对象(三个域对象 request、session、servletContext)
-
监听器:监听事件源对象事件源对象的状态的变化都会触发监听器
-
注册监听器:将监听器与事件源进行绑定
-
响应行为:监听器监听到事件源的状态变化时所涉及的功能代码(程序员编写代码)