1、用户访问 localhost:8080/test/index.jsp,请求被发送到 Tomcat,被监听 8080 端口并 处理 HTTP/1.1 协议的 Connector 获得。
2、Connector 把该请求交给它所在的 Service 的 Engine 来处理,并等待 Engine 的回应。
3、Engine 获得请求 localhost/test/index.jsp,匹配所有的虚拟主机 Host。
4、Engine 匹配到名为 localhost 的 Host 虚拟主机来处理/test/index.jsp 请求(即使匹配 不到会请求交给默认 Host 处理),Host 会根据/test 匹配它所拥有的所有的 Context。
5、匹配到的 Context 获得请求/index.jsp。
6、构造 HttpServletRequest 对象和 HttpServletResponse 对象,作为参数调用 JspServlet 的 doGet()或 doPost().执行业务逻辑、数据存储等程序。
7、Context 把执行完之后的结果通过 HttpServletResponse 对象返回给 Host。
8、Host 把 HttpServletResponse 返回给 Engine。
9、Engine 把 HttpServletResponse 对象返回 Connector。
10、Connector 把 HttpServletResponse 对象返回给客户 Browser。
当浏览器基于 get 方式请求我们创建 Servlet 时,我们自定义的 Servlet 中的 doGet 方法 会被执行。doGet 方法能够被执行并处理 get 请求的原因是,容器在启动时会解析 web 工程 中 WEB-INF 目录中的 web.xml 文件,在该文件中我们配置了 Servlet 与 URI 的绑定,容器通 过对请求的解析可以获取请求资源的 URI,然后找到与该 URI 绑定的 Servlet 并做实例化处理 (注意:只实例化一次,如果在缓存中能够找到这个 Servlet 就不会再做次实例化处理)。在实 例化时会使用 Servlet 接口类型作为引用类型的定义,并调用一次 init 方法,由于 HttpServlet 中重写了该方法所以最终执行的是 HttpServlet 中 init 方法(HttpServlet 中的 Init 方法是一个空 的方法体),然后在新的线程中调用 service 方法。由于在 HttpServlet 中重写了 Service 方法 所以最终执行的是 HttpServlet 中的 service 方法。在 service 方法中通过 request.getMethod() 获取到请求方式进行判断如果是 Get 方式请求就执行 doGet 方法,如果是 POST 请求就执行 doPost 方法。如果是基于 GET 方式提交的,并且在我们自定义的 Servlet 中又重写了 HttpServlet 中的 doGet 方法,那么最终会根据 Java 的多态特性转而执行我们自定义的 Servlet 中的 doGet 方法。
File->New Project,
创建web工程,选择Project JDK为1.8
在src内创建com.bjsxt.servlet文件
为项目添加 servlet-api.jar
点击apply,点击ok
在idea内配置Tomcat
修改项目的访问路径,定位到tomcat文件下的
apache-tomcat-8.0.21\webapps\ROOT文件
将 web 项目部署到 Tomcat 的 webapps 中
在 tomcat 的 webapps 中创建一个目录demo,用于存放web项目
指定输出 artifacts 的目录为 Tomcat 的 webapps 中的 demo 目录
启动 Tomcat,查看 demo 目录中的内容
在 Idea 中默认的并不会把 web 项目真正的部署到 Tomcat 的 webapps 目录中,而是通过为每个 web 项目创建一个独立的 Tomcat 副本并在 Tomcat 副本中通过的 Tomcat 的 Context 组件完成项目的目录指定,在 Context 组件的 docBase 属性中会指定 Idea 对 web 项目编译后 的目录 out/artifacts/…。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
输出
</body>
</html>
package com.bjsxt;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
// req.getRequestURL() --- 返回客户端浏览器发出请求时的完整的URL
StringBuffer requestURL = req.getRequestURL();
// req.getRequestURI() --- 返回请求行中指定资源部分。
String requestURI = req.getRequestURI();
// req.getRemoteAddr() --- 返回发出请求的客户机的 IP 地址
String remoteAddr = req.getRemoteAddr();
// resp.getWriter() --- 返回 WEB 服务器的 IP 地址
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
out.println("URL:"+requestURL+"
");
out.println("URI:"+requestURI+"
");
out.println("RemoteAddr:"+remoteAddr+"
");
String value1 = (String)servletContext.getAttribute("key1");
String value2 = (String)servletContext.getAttribute("key2");
out.println("Value1: "+value1+"
");
out.println("Value2: "+value2+"
");
out.println("");
out.println("");
out.flush();
out.close();
}
}
配置web.xml文件
<servlet>
<servlet-name>Servlet</servlet-name>
<servlet-class>com.bjsxt.servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet</servlet-name>
<url-pattern>/demo.do</url-pattern>
</servlet-mapping>
这样,我们在运行Tomcat之后,进入路径:
http://localhost:8080/demo/demo.do
即可获得请求信息
创建一个GetRequestDataServlet.class
package com.bjsxt;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* 获取请求数据
*/
public class GetRequestDataServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*req.setCharacterEncoding("utf-8");*/
String username = req.getParameter("username");
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
out.println("UserName:"+username+"
");
out.println("");
out.println("");
out.flush();
out.close();
}
}
在web.xml内配置:
<servlet>
<servlet-name>GetRequestDataServlet</servlet-name>
<servlet-class>com.bjsxt.GetRequestDataServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>GetRequestDataServlet</servlet-name>
<url-pattern>/getInfo.do</url-pattern>
</servlet-mapping>
在web下,创建一个文件夹html,存放addUser.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>addUser</title>
</head>
<body>
<form action="../getInfo.do" method="post">
用户名: <input type="text" name="username"/><br/>
<input type="submit" value="ok"/>
</form>
</body>
</html>
我们在获取请求数据的基础上进行改进
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*req.setCharacterEncoding("utf-8");*/
resp.setContentType("text/html;charset=utf-8");
String username = req.getParameter("username");
//多选框的数据获取
String[] userlikes = req.getParameterValues("userlike");
List<String> strings = Arrays.asList(userlikes);
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
out.println("UserName:"+username+"
");
out.println("strings:"+strings+"
");
out.println("");
out.println("");
out.flush();
out.close();
}
html页面:
<form action="../getInfo.do" method="post">
用户名: <input type="text" name="username"/><br/>
用户爱好:<input type="checkbox" name="userlike" value="sport"/>体育
<input type="checkbox" name="userlike" value="music"/>音乐
<input type="submit" value="ok"/>
</form>
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*req.setCharacterEncoding("utf-8");*/
resp.setContentType("text/html;charset=utf-8");
String username = req.getParameter("username");
//多选框的数据获取 -- 获取复选框(checkbox 组件)中的值,返回一个 String[]
String[] userlikes = req.getParameterValues("userlike");
List<String> strings = Arrays.asList(userlikes);
//获取所有提交数据的key,这个方法会返回一个枚举类型
Enumeration<String> parameterNames = req.getParameterNames();
List<String> keys = new ArrayList<>();
while(parameterNames.hasMoreElements()){
keys.add(parameterNames.nextElement());
}
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
out.println("UserName:"+username+"
");
out.println("strings:"+strings+"
");
out.println("Keys:"+keys+"
");
out.println("");
out.println("");
out.flush();
out.close();
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*req.setCharacterEncoding("utf-8");*/
resp.setContentType("text/html;charset=utf-8");
String username = req.getParameter("username");
//多选框的数据获取 -- 获取复选框(checkbox 组件)中的值,返回一个 String[]
String[] userlikes = req.getParameterValues("userlike");
List<String> strings = Arrays.asList(userlikes);
//获取所有提交数据的key,这个方法会返回一个枚举类型
Enumeration<String> parameterNames = req.getParameterNames();
List<String> keys = new ArrayList<>();
while(parameterNames.hasMoreElements()){
keys.add(parameterNames.nextElement());
}
// 获取请求中所有的数据并存放到一个 Map 结构中,
// 该方法返回一个 Map,其中 key 为 String 类型 value 为 String[]类型
Map<String, String[]> parameterMap = req.getParameterMap();
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
out.println("UserName:"+username+"
");
out.println("strings:"+strings+"
");
out.println("Keys:"+keys+"
");
//获取的是spring数组的key和spring数组的value
Iterator<Map.Entry<String,String[]>> iterator = parameterMap.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry<String,String[]> entry = iterator.next();
out.println("Keys:"+entry.getKey()+" Value:"+Arrays.asList(entry.getValue())+"
");
}
out.println("");
out.println("");
out.flush();
out.close();
}
有中文内容时,。在 Tomcat 中使用的是 ISO-8859-1 的单字节编码完成字节与字符的转换就会出现乱码
可以通过 req.setCharacterEncoding(“utf-8”)方法来对提 交的数据根据指定的编码方式重新做编码处理
我们开始设置请求编码
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//对象代表客户端的请求,使用utf-8的格式 可以让传过来的汉字在页面上没有乱码的显示
req.setCharacterEncoding("utf-8");
//对跳转前的页面的乱码现象进行处理,规定使用utf-8格式
resp.setContentType("text/html;charset=utf-8");
String username = req.getParameter("username");
//设定将发送的请求数据的编码方式从"iso-8859-1" 转为"utf-8"
String name = new String(username.getBytes("iso-8859-1"),"utf-8");
System.out.println(name);
//多选框的数据获取 -- 获取复选框(checkbox 组件)中的值,返回一个 String[]
String[] userlikes = req.getParameterValues("userlike");
List<String> strings = Arrays.asList(userlikes);
//获取所有提交数据的key,这个方法会返回一个枚举类型
Enumeration<String> parameterNames = req.getParameterNames();
List<String> keys = new ArrayList<>();
while(parameterNames.hasMoreElements()){
keys.add(parameterNames.nextElement());
}
// 获取请求中所有的数据并存放到一个 Map 结构中,
// 该方法返回一个 Map,其中 key 为 String 类型 value 为 String[]类型
Map<String, String[]> parameterMap = req.getParameterMap();
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
out.println("UserName:"+username+"
");
out.println("strings:"+strings+"
");
out.println("Keys:"+keys+"
");
//获取的是spring数组的key和spring数组的value
Iterator<Map.Entry<String,String[]>> iterator = parameterMap.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry<String,String[]> entry = iterator.next();
out.println("Keys:"+entry.getKey()+" Value:"+Arrays.asList(entry.getValue())+"
");
}
out.println("");
out.println("");
out.flush();
out.close();
}
注意:
req.setCharacterEncoding("utf-8");
和
String name = new String(username.getBytes("iso-8859-1"),"utf-8");
绝对路径
绝对路径访问资源表示直接以”/”作为项目的 Content Path。该方式适用于以”/”作为项目 的 Content Path。
相对路径
相对路径访问资源表示会相对于项目的 Content Path 作为相对路径。该方式适用于为项 目指定的具体的 Content Path。
package com.bjsxt;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
public class GetRequestHeaderServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// req.getHeader("headerKey") --- 根据请求头中的 key 获取对应的 value。
String header = req.getHeader("Accept-Language");
// req.getHeaderNames() --- 获取请求头中所有的 key,该方法返回枚举类型
Enumeration<String> headerNames = req.getHeaderNames();
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
out.println("Header:"+header+"
");
out.println("======================================="+"
");
while(headerNames.hasMoreElements()){
String key = headerNames.nextElement();
String value = req.getHeader(key);
out.println("Key:"+key+" Value: "+value+"
");
}
out.println("");
out.println("");
out.flush();
out.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
web.xml页面
<servlet>
<servlet-name>GetRequestHeaderServlet</servlet-name>
<servlet-class>com.bjsxt.GetRequestHeaderServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>GetRequestHeaderServlet</servlet-name>
<url-pattern>/getHeader.do</url-pattern>
</servlet-mapping>
编写一个servlet,如果浏览器的语言是zh-CN,显示“你好,聪明的中国人!”,
如果浏览器的语言设置为en-US,就显示“hello,American!”
package com.bjsxt;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class LanguageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取请求头内的浏览器的语言 accept-language
//对跳转前的页面的乱码现象进行处理,规定使用utf-8格式
resp.setContentType("text/html;charset=utf-8");
String header = req.getHeader("accept-language");
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
out.println("Header:"+header+"
");
if(header.indexOf("zh-CN")!=-1){
//找到的情况下
out.println("你好,聪明的中国人");
}else if (header.indexOf("zh-US")!=-1){
out.println("hello,America");
}else{
out.println("抱歉。当前浏览器语言不支持");
}
out.println("");
out.println("");
out.flush();
out.close();
}
}
web.xml:
<servlet>
<servlet-name>LanguageServlet</servlet-name>
<servlet-class>com.bjsxt.LanguageServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LanguageServlet</servlet-name>
<url-pattern>/getlanguage.do</url-pattern>
</servlet-mapping>
</web-app>
当有请求到达 Tomcat 时,Tomcat 会创建 HttpServletRequest 对象,并将该对象通过参数的方式传递到我们 Servlet 的方法中,当处理请求处理完毕并产生响应后该对象生命周期结束。
常见的字符型响应类型:
resp.setContentType(“text/html”)
设置响应类型为文本型,内容含有 html 字符串,是默认的响应类型
resp.setContentType(“text/plain”)
设置响应类型为文本型,内容是普通文本。
resp.setContentType(“application/json”)
设置响应类型为 JSON 格式的字符串
例子:
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
out.println("hello");
out.println("");
out.println("");
out.flush();
out.close();
}
使用resp.setContentType(“text/html”);时,页面内容:
使用resp.setContentType(“text/plain”);,页面内容:
什么时候设置
当你响应的文件是图片,影音时设置
常见的字节型响应:
resp.setContentType(“image/jpeg”)
设置响应类型为图片类型,图片类型为 jpeg 或 jpg 格式。
resp.setContentType(“image/gif”)
设置响应类型为图片类型,图片类型为 gif 格式。
读取jpg文件
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//读取图片文件
File file = new File("D:/IDEA/demo/web/images/1.JPG");
FileInputStream fis = new FileInputStream(file);
byte[] buff = new byte[fis.available()];
fis.read(buff);
//设置响应类型
resp.setContentType("image/jpeg");
//从HttpServletResponse对象中获取字节输出流对象。
OutputStream os = resp.getOutputStream();
os.write(buff);
os.flush();
os.close();
}
读取gif文件同理
导入gif文件的路径,同时设置响应类型为"images/gif"即可
response.setContentType(“text/html;charset=utf-8”);
设置服务端为浏览器产生响应的响应编码,服务端会根据此编码将响应内容的字符转换 为字节。同时客户端浏览器会根据此编码方式显示响应内容
response.sendRedirect(URL 地址)
重定向响应会在响应头中添加一个 Location 的 key 对应的 value 是给定的 URL。客户端 浏览器在解析响应头后自动向 Location 中的 URL 发送请求。
重定向响应特点:
重定向会产生两次请求两次响应。
重定向的 URL 是有客户端浏览器发送的。
跳转到百度页面:
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.sendRedirect("https://www.baidu.com");
}
创建一个搜索页面,通过百度搜索引擎完成内容搜索
创建一个aearch.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="../redirset.do" method="post">
搜索:<input type="text" name="search"/><br/>
<input type="submit" value="Search"/>
</form>
</body>
</html>
package com.bjsxt;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
String search = req.getParameter("search");
System.out.println(search);
resp.sendRedirect("https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd="+URLEncoder.encode(search,"utf-8"));
}
}
在web.xml内添加:
<servlet>
<servlet-name>RedirectServlet</servlet-name>
<servlet-class>com.bjsxt.RedirectServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RedirectServlet</servlet-name>
<url-pattern>/redirset.do</url-pattern>
</servlet-mapping>
</web-app>
在实现文件下载时,我们需要修改响应头,添加附加信息。
response.setHeader("Content-Disposition", "attachment; filename="+文件名);
Content-Disposition:attachment
该附加信息表示作为对下载文件的一个标识字段。不会在浏览器中显示而是直接做下载 处理。
filename=文件名
表示指定下载文件的文件名。
通过在响应内添加附加信息的方式实现文件的下载
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//读文件
File file = new File("D:/IDEA/demo/web/images/1.jpg");
FileInputStream fis = new FileInputStream(file);
byte[] buff = new byte[fis.available()];
fis.read(buff);
//在客户端浏览器下载文件之前产生响应,在响应内添加信息
//获取文件名称
resp.addHeader("Content-Disposition","attachment;filename="+file.getName());
//获取字节输出流,向客户端做输出
OutputStream os = resp.getOutputStream();
os.write(buff);
os.flush();
os.close();
}
//获取文件名称
resp.addHeader("Content-Disposition","attachment;filename="+new String(file.getName().getBytes("gbk"),"iso-8859-1"));
这样,就可以解决中文乱码
ServletContext 官 方 叫 Servlet 上 下 文 。 服 务 器 会 为 每 一 个 Web 应 用 创 建 一 个 ServletContext 对象。这个对象全局唯一,而且 Web 应用中的所有 Servlet 都共享这个对象。 所以叫全局应用程序共享对象
context.getRealPath(“path”)
该方法可以将一个相对路径转换为绝对路径,在文件上传与下载时需要用到该方法做路径的转换
用该方法修改文件的下载,使得图片可以下载项目内的图片
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取ServletContext对象
ServletContext servletContext = this.getServletContext();
//路径转换
String realPath = servletContext.getRealPath("/images/1-副本.JPG");
System.out.println(realPath);
//读文件
File file = new File(realPath);
System.out.println(file.getName());
FileInputStream fis = new FileInputStream(file);
byte[] buff = new byte[fis.available()];
fis.read(buff);
//在响应中添加附加信息
resp.addHeader("Content-Disposition","attachment;filename="+new String(file.getName().getBytes("gbk"),"iso-8859-1"));
OutputStream os = resp.getOutputStream();
os.write(buff);
os.flush();
os.close();
}
servletContext.getServerInfo()
返回 Servlet 容器的名称和版本号
servletContext.getMajorVersion()
返回 Servlet 容器所支持 Servlet 的主版本号。
servletContext.getMinorVersion()
返回 Servlet 容器所支持 Servlet 的副版本号。
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
//获取ServletContext对象
ServletContext servletContext = this.getServletContext();
String serverInfo = servletContext.getServerInfo();
int majorVersion = servletContext.getMajorVersion();
int minorVersion = servletContext.getMinorVersion();
//做字符输出流
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
out.println("Servlet容器的名称以及版本:"+serverInfo+"
");
out.println("容器所支持的Servlet的版本号:"+majorVersion+"."+minorVersion);
out.println("");
out.println("");
out.flush();
out.close();
}
<context-param>
<param-name>key</param-name>
<param-value>value</param-value>
</context-param>
servletContext.getInitParameter("key")
该方法可以读取 web.xml 文件中<context-param>标签中的配置信息。
servletContext.getInitParameterNames()
该方法可以读取 web.xml 文件中所有 param-name 标签中的值。
代码:
/**
* ServletContext对象读取web.xml文件中的信息
*/
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取ServletContext
ServletContext servletContext = this.getServletContext();
Enumeration<String> initParameterNames = servletContext.getInitParameterNames();
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
while(initParameterNames.hasMoreElements()){
String name = initParameterNames.nextElement();
out.println("Name:"+name+" Value: "+servletContext.getInitParameter(name)+"
");
}
out.println("");
out.println("");
out.flush();
out.close();
}
我们在xml文件内的web-app标签下设置子标签:
<context-param>
<param-name>key</param-name>
<param-value>value</param-value>
</context-param>
<context-param>
<param-name>name</param-name>
<param-value>BJSXT</param-value>
</context-param>
servletContext.setAttribute("key",ObjectValue)
向全局容器中存放数据。
servletContext.getAttribute("key")
从全局容器中获取数据。
servletContext.removeAttribute("key")
根据 key 删除全局容器中的 value。
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取ServletContext对象
ServletContext servletContext = this.getServletContext();
servletContext.setAttribute("key1","Oldlu");
servletContext.setAttribute("key2","Kevin");
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
String value1 = (String)servletContext.getAttribute("key1");
String value2 = (String)servletContext.getAttribute("key2");
out.println("Value1: "+value1+"
");
out.println("Value2: "+value2+"
");
out.println("");
out.println("");
out.flush();
out.close();
}
当容器启动时会创建 ServletContext 对象并一直缓存该对象,直到容器关闭后该对象生 命周期结束。ServletContext 对象的生命周期非常长,所以在使用全局容器时不建议存放业务数据。
ServletConfig 对象对应 web.xml 文件中的节点。当 Tomcat 初始化一个 Servlet 时,会将该 Servlet 的配置信息,封装到一个 ServletConfig 对象中。我们可以通过该对象读 取节点中的配置信息
取节点中的配置信息:
<servlet>
<servlet-name>servletName</servlet-name>
<servlet-class>servletClass</servlet-class>
<init-param>
<param-name>key</param-name>
<param-value>value</param-value>
</init-param>
</servlet>
servletConfig.getInitParameter("key")
该方法可以读取 web.xml 文件中标签中标签中的配置信息。
servletConfig.getInitParameterNames()
该方法可以读取 web.xml 文件中当前标签中所有标签中的值。
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取ServletConfig对象
ServletConfig servletConfig = this.getServletConfig();
//servletConfig.getInitParameterNames(): 该方法可以读取 web.xml 文件中当前标签中所有标签中的值。
Enumeration<String> initParameterNames = servletConfig.getInitParameterNames();
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
while(initParameterNames.hasMoreElements()){
String key = initParameterNames.nextElement();
//servletConfig.getInitParameter(key): 该方法可以读取 web.xml 文件中标签中标签中的配置信息
out.println("Key: "+key+" Value: "+servletConfig.getInitParameter(key)+"
");
}
out.println("");
out.println("");
out.flush();
out.close();
}
web.xml配置:
<servlet>
<servlet-name>GetConfigInfoServlet</servlet-name>
<servlet-class>com.bjsxt.GetConfigInfoServlet</servlet-class>
<init-param>
<param-name>key1</param-name>
<param-value>BJSXT</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>GetConfigInfoServlet</servlet-name>
<url-pattern>/getconfig.do</url-pattern>
</servlet-mapping>
Cookie 对象与 HttpSession 对象的作用是维护客户端浏览器与服务端的会话状态的两个 对象。由于 HTTP 协议是一个无状态的协议,所以服务端并不会记录当前客户端浏览器的访 问状态,但是在有些时候我们是需要服务端能够记录客户端浏览器的访问状态的,如获取当 前客户端浏览器的访问服务端的次数时就需要会话状态的维持。在 Servlet 中提供了 Cookie 对象与 HttpSession 对象用于维护客户端与服务端的会话状态的维持。二者不同的是 Cookie 是通过客户端浏览器实现会话的维持,而 HttpSession 是通过服务端来实现会话状态的维持。
Cookie 使用字符串存储数据
Cookie 使用 Key 与 Value 结构存储数据
单个 Cookie 存储数据大小限制在 4097 个字节
Cookie 存储的数据中不支持中文,Servlet4.0 中支持
Cookie 是与域名绑定所以不支持跨一级域名访问
Cookie 对象保存在客户端浏览器或系统磁盘中
Cookie 分为持久化 Cooke 与状态 Cookie
浏览器在保存同一域名所返回 Cookie 的数量是有限的。不同浏览器支持的数量不同,Chrome 浏览器为 50 个
浏览器每次请求时都会把与当前访问的域名相关的 Cookie 在请求中提交到服务端。
Cookie 对象的创建
Cookie cookie = new Cookie(“key”,“value”)
通过 new 关键字创建 Cookie 对象
response.addCookie(cookie) 通过 HttpServletResponse 对象将 Cookie 写回给客户端浏览器。
代码:
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建Cookie对象
Cookie cookie = new Cookie("name", URLEncoder.encode("北京尚学堂","utf-8"));
//设置Cookie的失效时间,一旦设置了失效时间,该Cookie为持久化Cookie
cookie.setMaxAge(60);
resp.addCookie(cookie);
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
out.println("Create Cookie
");
out.println("");
out.println("");
out.flush();
out.close();
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//在请求中获取Cookie对象
Cookie[] cookies = req.getCookies();
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
for(int i=0;i<cookies.length;i++){
Cookie cookie = cookies[i];
out.println("Name: "+cookie.getName()+" Value: "+ URLDecoder.decode(cookie.getValue(),"utf-8") +"
");
}
out.println("");
out.println("");
out.flush();
out.close();
}
上方的cookie对象的使用,是状态cookie的实例使用,也就是说,当浏览器被关闭后,再次进入浏览器访问路径,设置的內容就会消失
介绍:
状态 Cookie:浏览器会缓存 Cookie 对象。浏览器关闭后 Cookie 对象销毁。
持久化 Cookie:浏览器会对 Cookie 做持久化处理,基于文件形式保存在系统的指定目 录中。在 Windows10 系统中为了安全问题不会显示 Cookie 中的内容。
当 Cookie 对象创建后默认为状态 Cookie。可以使用 Cookie 对象下的 cookie.setMaxAge(60) 方法设置失效时间,单位为秒。一旦设置了失效时间,那么该 Cookie 为持久化 Cookie,浏 览器会将 Cookie 对象持久化到磁盘中。当失效时间到达后文件删除。
修改为持久化Cookie:
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建Cookie对象
Cookie cookie = new Cookie("name", URLEncoder.encode("北京尚学堂","utf-8"));
//设置Cookie的失效时间,一旦设置了失效时间,该Cookie为持久化Cookie
cookie.setMaxAge(60);
resp.addCookie(cookie);
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
out.println("Create Cookie
");
out.println("");
out.println("");
out.flush();
out.close();
}
在这里,我们做出的改动为
//设置Cookie的失效时间,一旦设置了失效时间,该Cookie为持久化Cookie
cookie.setMaxAge(60);
单位是秒
实现
当客户端浏览器第一次访问 Servlet 时返回“您好,欢迎您第一次访问!”,第 二次访问时返回“欢迎您回来!”
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取Cookie
Cookie[] cookies = req.getCookies();
boolean flag = false;
if(cookies != null){
for(Cookie cookie:cookies){
if("first".equals(cookie.getName())){
flag = true;
}
}
}
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
if(flag){
out.println("欢迎您回来!");
}else{
out.println("您好,欢迎您第一次访问!");
Cookie cookie = new Cookie("first","first");
//设置cookie的失效时间
cookie.setMaxAge(60);
resp.addCookie(cookie);
}
out.println("");
out.println("");
out.flush();
out.close();
}
Cookie 对于存储内容是基于明文的方式存储的,所以安全性很低。
不要在 Cookie 中存 放敏感数据。
在数据存储时,虽然在 Servlet4.0 中 Cookie 支持中文,但是建议对 Cookie 中 存放的内容做编码处理,也可提高安全性。
HttpSession 对象的创建是通过 request.getSession()方法来创建的。
getSession()方法还有一个重载方法getSession(true|false)。
当参数为true时与getSession() 方法作用相同。
当参数为 false 时则只去根据 SessionID 查找是否有与这个客户端浏览器对应
45 的 HttpSession,如果有则返回,如果没有 SessionID 则不会创建新的 HttpSession 对象。
//获取session
HttpSession session = req.getSession();
session.setAttribute("key",value)
将数据存储到 HttpSession 对象中
Object value = session.getAttribute("key")
根据 key 获取 HttpSession 中的数据,返回 Object
Enumeration<String> attributeNames = session.getAttributeNames()
获取 HttpSession 中所有的 key,返回枚举类型
session.removeAttribute("key")
根据 key 删除 HttpSession 中的数据
String id = session.getId()
根据获取当前 HttpSession 的 SessionID,返回字符串类型
先将数据存储到HttpSession对象内
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取session
HttpSession session = req.getSession();
session.setAttribute("key","bjsxt");
String Id = session.getId();
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
out.println("id:"+Id);
out.println("");
out.println("");
out.flush();
out.close();
}
我们查看获取到的session对象的id
根据 key 获取 HttpSession 中的数据,返回 Object
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
String value = (String)session.getAttribute("key");
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
out.println("value:"+value);
out.println("");
out.println("");
out.flush();
out.close();
}
先将数据存储到HttpSession对象内,同时进行判断
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String header = req.getHeader("User-Agent");
//获取session
HttpSession session = req.getSession();
if (header.indexOf("Chrome") != -1){
session.setAttribute("key","BJSXT-Chrome");
}else{
session.setAttribute("key","IE");
}
String Id = session.getId();
System.out.println(session+" "+Id);
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
out.println("id:"+Id);
out.println("");
out.println("");
out.flush();
out.close();
}
根据 key 获取 HttpSession 中的数据,返回 Object
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
String value = (String)session.getAttribute("key");
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
out.println("value:"+value);
out.println("");
out.println("");
out.flush();
out.close();
}
谷歌浏览器:
IE浏览器
我们可以在 web.xml 文件中指定 HttpSession 的超时时间,当到达指定的超时时间后,容 器就会销该 HttpSession 对象,单位为分钟。该时间对整个 web 项目中的所有 HttpSession 对 象有效。
web.xml
<session-config>
<session-timeout>1</session-timeout>
</session-config>
invalidate()方法是 HttpSession 对象中所提供的用于销毁当前 HttpSession 的方法。我们 通过调用该方法可以销毁当前 HttpSession 对象。
HttpSession session = req.getSession();
if (header.indexOf("Chrome") != -1){
session.setAttribute("key","BJSXT-Chrome");
//销毁当前HttpSession的方法
session.invalidate();
}else{
session.setAttribute("key","IE");
}
要求:当客户端浏览器第一次访问 Servlet 时返回“您好,欢迎您第一次访问!”,第 二次访问时返回“欢迎您回来!”
我们之前实现过 “ 通过 Cookie 实现客户端与服务端会话的维持 ”,在这里,我们通过HttpSession实现客户端和服务端回话的维持
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession(false);
boolean flag = true;
if (session == null){
flag = false;
//将req的session值设置为ture
req.getSession(true);
}
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
if(flag){
out.println("欢迎您回来!");
}else{
out.println("您好,欢迎您第一次访问!");
}
out.println("");
out.println("");
out.flush();
out.close();
}
在 HttpSession 对象生命周期中没有固定的创建时间与销毁时间。
何时创建取决于我们 什么时候第一次调用了 getSession()或 getSession(true)的方法。
HttpSession 对象的销毁时间 取决于超时时间的到达以及调用了 invalidate()方法。
如果没有超时或者没有调用 invalidate() 方法,那么 HttpSession 会一直存储。
默认超时时间为 30 分钟(Tomcat 的 web.xml 文件配置 的时间就是默认超时时间)。
因为HttpSession对象的生命周期不固定,我们一般只用HttpSession对象存放用户登录信息
自启动Servlet在Tomcat启动时就会实例化这个Servlet,他的实例化过程不依赖于请求,而是依赖于容器的启动。
可以通过在web.xml中的标签中通过1配置自启动Servlet。
web.xml
<servlet>
<servlet-name>AutoStartServlet</servlet-name>
<servlet-class>com.bjsxt.AutoStartServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>AutoStartServlet</servlet-name>
<url-pattern>/autostart.do</url-pattern>
</servlet-mapping>
/**
* 自启动Servlet
*/
public class AutoStartServlet extends HttpServlet {
@Override
public void init() throws ServletException {
System.out.println("Servlet Init...");
}
}
案例:
修改文件下载案例,通过自启动 Servlet 读取配置信息
配置web.xml文件:
<servlet>
<servlet-name>AutoStartServlet</servlet-name>
<servlet-class>com.bjsxt.AutoStartServlet</servlet-class>
<init-param>
<param-name>path</param-name>
<param-value>/images</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>AutoStartServlet</servlet-name>
<url-pattern>/autostart.do</url-pattern>
</servlet-mapping>
配置自启动文件,获取xml文件内的指定内容:
/**
* 自启动Servlet
*/
public class AutoStartServlet extends HttpServlet {
@Override
public void init() throws ServletException {
System.out.println("Servlet Init...");
ServletConfig servletConfig = this.getServletConfig();
String value = servletConfig.getInitParameter("path");
ServletContext servletContext = this.getServletContext();
servletContext.setAttribute("path",value);
}
}
修改文件下载代码:
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取ServletContext对象
ServletContext servletContext = this.getServletContext();
String path = (String) servletContext.getAttribute("path");
System.out.println(path);
//路径转换
String realPath = servletContext.getRealPath(path+"/1-副本.JPG");
System.out.println(realPath);
//读文件
File file = new File(realPath);
System.out.println(file.getName());
FileInputStream fis = new FileInputStream(file);
byte[] buff = new byte[fis.available()];
fis.read(buff);
//在响应中添加附加信息
resp.addHeader("Content-Disposition","attachment;filename="+new String(file.getName().getBytes("gbk"),"iso-8859-1"));
OutputStream os = resp.getOutputStream();
os.write(buff);
os.flush();
os.close();
}
在 Servlet 中使用的是多线程方式来执行 service()方法处理请求,所以我们在使用 Servlet 时需要考虑到线程安全问题,在多线程中对于对象中的成员变量是最不安全的,所以不要在 Servlet 中通过成员变量的方式来存放数据,如果一定要使用成员变量存储数据,在对数据 进行操作时需要使用线程同步的方式来解决线程安全问题,避免出现数据张冠李戴现象。
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
//线程同步
synchronized (this){
pw = resp.getWriter();
try{
//让线程做一个休眠
Thread.sleep(5000);
pw.println(name);
pw.flush();
pw.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
这样,在非要使用成员变量去存储数据时,对数据进行操作时使用线程的同步,在加载页面时保证线程的安全
精确匹配是指中配置的值必须与 url 完全精确匹配
<servlet-mapping>
<servlet-name>demoServlet</servlet-name>
<url-pattern>/demo.do</url-pattern>
</servlet-mapping>
http://localhost:8888/demo/demo.do 匹配 http://localhost:8888/demo/suibian/demo.do 不匹配
在允许使用统配符“”作为匹配规则,“”表示匹配任意字符。在扩展 名匹配中只要扩展名相同都会被匹配和路径无关。注意,在使用扩展名匹配时在 中不能使用“/”,否则容器启动就会抛出异常。
<servlet-mapping>
<servlet-name>demoServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
http://localhost:8888/demo/abc.do 匹配
http://localhost:8888/demo/suibian/haha.do 匹配 http://localhost:8888/demo/abc 不匹配
根据请求路径进行匹配,在请求中只要包含该路径都匹配。“*”表示任意路径以及子 路径。
<servlet-mapping>
<servlet-name>demoServlet</servlet-name>
<url-pattern>/suibian/*
http://localhost:8888/demo/suibian/haha.do 匹配 http://localhost:8888/demo/suibian/hehe/haha.do 匹配 http://localhost:8888/demo/hehe/heihei.do 不匹配
匹配“/”。匹配所有但不包含 JSP 页面
<url-pattern>/</url-pattern>
http://localhost:8888/demo/suibian.do 匹配 http://localhost:8888/demo/addUser.html 匹配 http://localhost:8888/demo/css/view.css 匹配 http://localhost:8888/demo/addUser.jsp 不匹配 http://localhost:8888/demo/user/addUser.jsp 不匹配
匹配所有
<url-pattern>/*
http://localhost:8888/demo/suibian.do 匹配 http://localhost:8888/demo/addUser.html 匹配 http://localhost:8888/demo/suibian/suibian.do 匹配
当一个 url 与多个 Servlet 的匹配规则可以匹配时,则按照 “ 精确路径 > 最长路径 > 扩展名”这样的优先级匹配到对应的 Servlet。
在 web.xml 文件中支持将多个 URL 映射到一个 Servlet 中,但是相同的 URL 不能同时映 射到两个 Servlet 中。
方式一:
demoServlet
/suibian/*
*.do
方式二:
demoServlet
/suibian/*
demoServlet
*.do
在 Servlet3.0 以及之后的版本中支持注解式开发 Servlet。对于 Servlet 的配置不在依赖于 web.xml 配置文件,而是使用@WebServlet 注解完成 Servlet 的配置。
/**
* 使用注解去开发Servlet
*/
//urlPatterns Servlet的访问URL,支持多个
@WebServlet(urlPatterns = "/ann.do")
public class AnnotationServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
out.println("Annotation Servlet!");
out.println("");
out.println("");
out.flush();
out.close();
}
}
<servlet>
<servlet-name>GetConfigInfoServlet</servlet-name>
<servlet-class>com.bjsxt.GetConfigInfoServlet</servlet-class>
<init-param>
<param-name>key1</param-name>
<param-value>BJSXT</param-value>
</init-param>
</servlet>
我们使用 @WebInitParam属性去取代web.xml的init-param
/**
* 通过注解方式读取Servlet的初始化配置信息
*/
@WebServlet(urlPatterns = "/initParam.do",initParams = {
@WebInitParam(name="key1",value = "value1"),@WebInitParam(name="key2",value = "value2")},loadOnStartup = 1)
public class InitParamServlet extends HttpServlet {
@Override
public void init() throws ServletException {
super.init();
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletConfig servletConfig = this.getServletConfig();
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
out.println("Value1: "+servletConfig.getInitParameter("key1")+"
");
out.println("Value2: "+servletConfig.getInitParameter("key2")+"
");
out.println("");
out.println("");
out.flush();
out.close();
}
}
String getContentType()
获取上传文件的文件的 MIME 类型
long getSize()
上传文件的大小
String getSubmittedFileName()
上传文件的原始文件名
我们创建一个html页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/fileupload" method="post" enctype="multipart/form-data">
文件描述:<input type="text" name="desc"/>
上传文件:<input type="file" name="file"/>
<input type="submit" value="OK"/>
</form>
</body>
</html>
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.UUID;
/**
* 使用注解完成文件的上传
*/
@WebServlet("/fileupload")
//上传的注解
@MultipartConfig
public class FileUploadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("进入fileupload");
req.setCharacterEncoding("utf-8");
String desc = req.getParameter("desc");
Part part = req.getPart("file");
/*
//获取文件上传的字节流
InputStream inputStream = part.getInputStream();*/
System.out.println("输出原名称:"+part.getSubmittedFileName());
//给文件改名
String fileName = UUID.randomUUID().toString()+part.getSubmittedFileName().substring(part.getSubmittedFileName().lastIndexOf("."));
//获取ServletContext对象
ServletContext servletContext = this.getServletContext();
//获取一个绝对路径
String realPath = servletContext.getRealPath("/images/"+fileName);
//路径转换 -- 将相对路径转为绝对路径
// String realPath = "D:/IDEA/ServletDemo/web/images/"+fileName;
System.out.println("路径:"+realPath);
//将上传的文件存放到获取到的路径
part.write(realPath);
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.println("");
out.println("");
out.println(" ITBZ ");
out.println("");
out.println("上传成功!"+desc);
out.println("");
out.println("");
out.flush();
out.close();
}
}
我们上传一个图片
这样,我们完成一个图片上传到指定文件夹下
文件目录:
正确的创建servlet以及导入项目的流程
跳转链接
Filter 过滤器是 Servlet 中的一个组件。
对从客户端向服务器端发送的请求进行过滤,也可以对服务器端返回的响应进行处理。
创建一个 Class 实现 Filter 接口,并实现接口中三个抽象方法。
init()方法:初始化方法,在创建 Filter 后立即调用。可用于完成初始化动作。
doFilter()方法:拦截请求与响应方法,可用于对请求和响应实现预处理。
destroy()方法:销毁方法,在销毁 Filter 之前自动调用。可用于完成资源释放等动作。
import javax.servlet.*;
import java.io.IOException;
/**
* 第一个Filter案例
*/
public class FirstFilter implements Filter {
/**
* init方法在这里是一个初始化方法
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("初始化方法");
}
/**
* 处理请求和响应的方法
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("预处理请求");
//对请求作放行处理
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("预处理响应");
}
/**
* 销毁方法,当filter被销毁之前会调用一次这个方法
*/
@Override
public void destroy() {
}
}
xml:
<filter>
<filter-name>FirstFilter</filter-name>
<filter-class>filter.FirstFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>FirstFilter</filter-name>
<url-pattern>/suibian/*
我们要实现一个可以对所有页面进行编码处理的效果
在原来的上传页面内,我们使用req.setCharacterEncoding(“utf-8”);对数据进行编码处理
如果去除,且不对文件进行改名处理,汉字文件名就会出现乱码
这样,我们进行一个当出现请求时进行编码处理的效果
import javax.servlet.*;
import java.io.IOException;
/**
* 处理请求编码Filter
*/
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//设置处理请求的编码
servletRequest.setCharacterEncoding("utf-8");
//对请求产生响应
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
web.xml:
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*
这样,当我们进行运行时,就会对请求的数据(/*)进行编码处理
FilterConfig 对象是用来读取中初始化参数的对象。该对象通过参数 传递到 init 方法中,用于读取初始化参数。
filterConfig.getInitParameter(“name”)
通过 name 获取对应的 value。
filterConfig.getInitParameterNames()
返回该 Filter 中所有中的值。
实例:
我们对上面的全局编码进行改造,因为编码格式不一定是utf-8
先在xml文件内添加init-name:
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>filter.EncodingFilter</filter-class>
<init-param>
<param-name>code</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*
在filter文件内,进行编码方式的获取与判断:
package filter;
import javax.servlet.*;
import java.io.IOException;
/**
* 处理请求编码Filter
*/
public class EncodingFilter implements Filter {
private String encoding;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String code = filterConfig.getInitParameter("code");
this.encoding = code;
System.out.println("encoding:"+encoding);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
if (this.encoding==null){
//说明在xml文件内没有给定编码,需要给定
//设置处理请求的编码
servletRequest.setCharacterEncoding("utf-8");
}else {
//说明在xml文件内有给定的编码,调用即可
servletRequest.setCharacterEncoding(this.encoding);
}
//对请求产生响应
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
这样,编码方式的选择就更加灵活
按照在 web.xml 文件中配置的上下顺序来决定先后。在上的先执行,在下的后执行。
注意:
当web.xml和注解同时存在,且都是对全部加载时进行操作,优先使用web.xml内的Filter,因为系统启动时,先去查看的是web.xml文件
import javax.servlet.annotation.WebFilter;
/**
* 注解Filter案例
*/
@WebFilter("/*")
public class FirstFilter2 implements Filter {
//代码区域
}
当使用注解式开发 Filter 时,执行顺序会根据 Filter 的名称进行排序的结果决定调用的顺序
监听器用于监听 web 应用中某些对象的创建、销毁、增加,修改,删除等动作的发 生,然后作出相应的响应处理。
按监听的对象划分,可以分为:
ServletContextListener 接口定义了 ServletContext 对象生命周期的监听行为。
package listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
* ServletCOntext对象生命周期监听器
*/
public class ServletContextLifeCycleListener implements ServletContextListener {
/**
* 当服务器被启动后就会调用这个方法
* ServletContext 对象创建后会触发该监听方法,并将 ServletContext 对象传递到该方法中。
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
//获取已经创建好的ServletContext对象
ServletContext servletContext = sce.getServletContext();
System.out.println("输出servletContext:"+servletContext);
System.out.println("ServletContext Init.....");
}
/**
* ServletContext 对象在销毁之前会触发该监听方法,并将 ServletContext 对象传递到该方 法中
*/
@Override
public void contextDestroyed(ServletContextEvent sce) {
ServletContext servletContext = sce.getServletContext();
System.out.println("销毁时再次输出servletContext:"+servletContext);
System.out.println("ServletContext Destory.....");
}
}
web.xml
<listener>
<listener-class>listener.ServletContextLifeCycleListener</listener-class>
</listener>
这样,一个监听器就设置完毕
我们关闭tomcat
这样,创建和销毁的是同一个对象
package listener;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
/**
* ServletContext对象属性操作监听器
*/
public class ServletContextAttr implements ServletContextAttributeListener {
/**
* 向 ServletContext 对象中添加属性时会触发该监听方法,
* 并将 ServletContext 对象传递到 该方法中。
* 触发事件的方法 servletContext.setAttribute("key","value")。
*
*/
@Override
public void attributeAdded(ServletContextAttributeEvent scae) {
System.out.println("-----------Added Start---------------");
System.out.println(scae.getName()+"-----"+scae.getValue());
System.out.println(scae.getServletContext());
System.out.println("------------Added End--------------");
}
/**
* 当从 ServletContext 对象中删除属性时会触发该监听方法,
* 并将 ServletContext 对象传递 到该方法中。
* 触发事件方法 servletContext.removeAttribute("key")。
*
*/
@Override
public void attributeRemoved(ServletContextAttributeEvent scae) {
System.out.println("-----------Removed Start---------------");
System.out.println(scae.getName()+"-----"+scae.getValue());
System.out.println(scae.getServletContext());
System.out.println("------------Removed End--------------");
}
/**
* 当从 ServletContext 对象中属性的值发生替换时会触发该监听方法,
* 并将 ServletContext 对象传递到该方法中。
* 触发事件的方法 servletContext.setAttribute("key","value")。
*
*/
@Override
public void attributeReplaced(ServletContextAttributeEvent scae) {
System.out.println("-----------Replaced Start---------------");
System.out.println(scae.getName()+"-----"+scae.getValue());
System.out.println(scae.getServletContext());
System.out.println("------------Replaced End--------------");
}
}
在web.xml内 :
<listener>
<listener-class>listener.ServletContextAttr</listener-class>
</listener>
我们创建一个servlet,给Servlet对象赋值:
package servlet;
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;
import java.io.IOException;
@WebServlet("/attr.do")
public class ServletContextAttrServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
servletContext.setAttribute("key","bjsxt");
servletContext.setAttribute("key","ITBZ");
servletContext.removeAttribute("key");
}
}
<listener>
<listener-class>listener.HttpSessionLifeCycleListener</listener-class>
</listener>
package listener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
* HttpSession对象的生命周期监听器
*/
public class HttpSessionLifeCycleListener implements HttpSessionListener {
@Override
/**
* HttpSession 对象创建后会触发该监听方法,并将已创建 HttpSession 对象传递到该方法中
*/
public void sessionCreated(HttpSessionEvent se) {
System.out.println(se.getSession());
System.out.println("Http Session Created....");
}
@Override
/**
* HttpSession 对象在销毁之前会触发该监听方法,并将要销毁的 HttpSession 对象传递到该方法中
* 关闭客户端浏览器不会触发这个方法
* 当计时器时间到时会触发,或者被调用才会被触发
*/
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println(se.getSession());
System.out.println("Http Session Destroyed....");
}
}
将数据存放到HttpSession对象内:
package servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/sessionAttr.do")
public class HttpSessionAttrServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
session.setAttribute("key","bjsxt");
session.setAttribute("key","BJSXT");
session.removeAttribute("key");
}
}
在 监听器内进行监听
package listener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
/**
* HttpSession对象属性监听器
*/
public class HttpSessionAttrListener implements HttpSessionAttributeListener {
@Override
/**
* 向 HttpSession 对象中添加属性时会触发该监听方法,
* 并将 HttpSession 对象传递到该方 法中。
* 触发事件的方法 HttpSession.setAttribute("key","value")。
*
*/
public void attributeAdded(HttpSessionBindingEvent se) {
System.out.println("---HttpSessionAttr--------Added Start---------------");
System.out.println(se.getName()+"-----"+se.getValue());
System.out.println(se.getSession());
System.out.println("----HttpSessionAttr--------Added End--------------");
}
@Override
/**
*当从 HttpSession 对象中删除属性时会触发该监听方法,
* 并将 HttpSession 对象传递到该 方法中。
* 触发事件方法 HttpSession.removeAttribute("key")。
*
*/
public void attributeRemoved(HttpSessionBindingEvent se) {
System.out.println("---HttpSessionAttr--------Removed Start---------------");
System.out.println(se.getName()+"-----"+se.getValue());
System.out.println(se.getSession());
System.out.println("----HttpSessionAttr--------Removed End--------------");
}
@Override
/**
* 当从 HttpSession 对象中属性的值发生替换时会触发该监听方法,
* 并将 HttpSession 对象 传递到该方法中。
* 触发事件的方法 HttpSession.setAttribute("key","value")。
*
*/
public void attributeReplaced(HttpSessionBindingEvent se) {
System.out.println("---HttpSessionAttr--------Replaced Start---------------");
System.out.println(se.getName()+"-----"+se.getValue());
System.out.println(se.getSession());
System.out.println("----HttpSessionAttr--------Replaced End--------------");
}
}
配置xml文件:
<listener>
<listener-class>listener.HttpSessionAttrListener</listener-class>
</listener>
ServletRequestListener 接口定义了 ServletReqest(是 HttpServletRequest 接口的父接口类 型)对象生命周期的监听行为。
package listener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;
/**
* 监听HttpServletRequest对象生命周期监听器
*/
public class HttpServletRequestLifeCycleListener implements ServletRequestListener {
@Override
/**
* HttpServletRequest 对象创建后会触发该监听方法,并将已创建 ServletRequest 对象传递 到该方法中
*/
public void requestInitialized(ServletRequestEvent sre) {
System.out.println((HttpServletRequest)sre.getServletRequest());
System.out.println("HttpServletRequest....Initialized");
}
@Override
/**
* HttpServletRequest 对象在销毁之前会触发该监听方法,并将要销毁的 ServletRequest 对 象传递到该方法中
*/
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println((HttpServletRequest)sre.getServletRequest());
System.out.println("HttpServletRequest....Destroyed");
}
}
ServletRequestAttributeListener 接口定义了对于 HttpServletRequest 对象属性操作的监听 行为
配置xml文件:
<listener>
<listener-class>listener.HttpServletRequestAttrListener</listener-class>
</listener>
package listener;
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.http.HttpServletRequest;
/**
* HttpServletRequest属性操作监听器
*/
public class HttpServletRequestAttrListener implements ServletRequestAttributeListener {
@Override
/**
* 向 HttpServletRequest 对象中添加属性时会触发该监听方法,
* 并将 ServletRequest 对象传 递到该方法中。
* 触发事件的方法 HttpServletRequest.setAttribute("key","value")。
*/
public void attributeAdded(ServletRequestAttributeEvent srae) {
System.out.println("---HttpServletRequestAttr--------Added Start---------------");
System.out.println(srae.getName()+"-----"+srae.getValue());
System.out.println((HttpServletRequest)srae.getServletRequest());
System.out.println("----HttpServletRequestAttr--------Added End--------------");
}
@Override
/**
* 当从 HttpServletRequest 对象中删除属性时会触发该监听方法,
* 并将 ServletRequest 对象 传递到该方法中。
* 触发事件方法 HttpServletRequest.removeAttribute("key")
*/
public void attributeRemoved(ServletRequestAttributeEvent srae) {
System.out.println("---HttpServletRequestAttr--------Removed Start---------------");
System.out.println(srae.getName()+"-----"+srae.getValue());
System.out.println((HttpServletRequest)srae.getServletRequest());
System.out.println("----HttpServletRequestAttr--------Removed End--------------");
}
@Override
/**
* 当从HttpServletRequest对象中属性的值发生替换时会触发该监听方法,并将ServletRequest 对象传递到该方法中
* 触发事件的方法 HttpServletRequest.setAttribute("key","value")。
*/
public void attributeReplaced(ServletRequestAttributeEvent srae) {
System.out.println("---HttpServletRequestAttr--------Replaced Start---------------");
System.out.println(srae.getName()+"-----"+srae.getValue());
System.out.println((HttpServletRequest)srae.getServletRequest());
System.out.println("----HttpServletRequestAttr--------Replaced End--------------");
}
}
package servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/requestAttr.do")
public class HttpServletRequestAttrServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("key","bjsxt");
req.setAttribute("key","BJSXT");
req.removeAttribute("key");
}
}
我们运行http://localhost:8080/requestAttr.do:
通过@WebListener注解去代替web.xml内的Listener的配置