4.20 HttpServletRequest对象的生命周期
当有请求到达Tomcat时,Tomcat会创建HttpServletRequest对象,并将该对象通过参数的方式传递到我们Servlet的方法中,当处理请求处理完毕并产生响应后该对象生命周期结束。
4.21 设置响应类型
4.21.1 HttpServletResponse对象
HttpServletResponse对象代表服务器的响应。这个对象中封装了响应客户端浏览器的流对象,以及向客户端浏览器响应的响应头、响应数据、响应状态码等信息。
设置响应类型
resp.setContentType("MIME")
该方法可通过MIME-Type设置响应类型。默认响应的是text/html页面
Type | Meaning |
application/msword | Microsoft Word document |
application/octet-stream | Unrecognized or binary data |
application/pdf | Acrobat (.pdf) file |
application/postscript | PostScript file |
application/vnd.lotus-notes | Lotus Notes file |
application/vnd.ms-excel | Excel spreadsheet |
application/vnd.ms-powerpoint | PowerPoint presentation |
application/x-gzip | Gzip archive |
application/x-java-archive | JAR file |
application/x-java-serialized-object | Serialized Java object |
application/x-java-vm | Java bytecode (.class) file |
application/zip | Zip archive |
application/json | JSON |
audio/basic | Sound file in .au or .snd format |
audio/midi | MIDI sound file |
audio/x-aiff | AIFF sound file |
audio/x-wav | Microsoft Windows sound file |
image/gif | GIF image |
image/jpeg | JPEG image |
image/png | PNG image |
image/tiff | TIFF image |
image/x-xbitmap | X Windows bitmap image |
text/css | HTML cascading style sheet |
text/html | HTML document |
text/plain | Plain text |
text/xml | XML |
video/mpeg | MPEG video clip |
video/quicktime | QuickTime video clip |
4.21.2 设置字符型响应
响应的类型是文本类型的时候可以使用字符响应
常见的字符型响应类型:
设置响应类型为文本型,内容含有html字符串,是默认的响应类型
resp.setContentType("text/html")
设置响应类型为文本型,内容是普通文本。
resp.setContentType("text/plain")
package cn.it.servlet; 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 ResponseServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //设置响应类型 resp.setContentType("text/plain"); PrintWriter pw = resp.getWriter(); pw.println("<!DOCTYPE html>"); pw.println("<html lang=en>"); pw.println("<head>"); pw.println("<meta charset=UTF-8>"); pw.println("<title>Document</title>"); pw.println("</head>"); pw.println("<body>"); pw.println("<font color=red>HelloWorld</font>"); pw.println("</body>"); pw.println("</html>"); pw.flush(); pw.close(); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } }
设置响应类型为JSON格式的字符串。
resp.setContentType("application/json")
4.21.3设置字节型响应
响应图片视频等二进制文件的话需要使用字节响应。
设置响应类型为图片类型,图片类型为jpeg或jpg格式。
resp.setContentType("image/jpeg")
package cn.it.servlet; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; //设置字节响应 public class ResponseBitServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //读取D盘图片文件 File file = new File("D:/aa.jpg"); //创建读取图片的IO流对象 InputStream in = new FileInputStream(file); //图片缓存区 BufferedInputStream bis = new BufferedInputStream(in); //设置响应类型为 resp.setContentType("image/jpeg"); //获取字节输出流对象 BufferedOutputStream bos = new BufferedOutputStream(resp.getOutputStream()); int temp = 0; while ((temp = bis.read()) != -1) { bos.write(temp); } bos.flush(); bos.close(); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } }
设置响应类型为图片类型,图片类型为gif格式。
resp.setContentType("image/gif")
4.22 设置响应编码(针对响应字符)
response.setContentType("text/html;charset=utf-8");
不仅发送到浏览器的内容会使用UTF-8编码,而且还通知浏览器使用UTF-8编码方式进行显示。所以总能正常显示中文
response.setCharacterEncoding("utf-8");
仅仅是发送的浏览器的内容是UTF-8编码的,至于浏览器是用哪种编码方式显示不管。 所以当浏览器的显示编码方式不是UTF-8的时候,就会看到乱码,需要手动指定浏览器编码。
4.23 重定向响应
response.sendRedirect(URL地址)
重定向响应会在响应头中添加一个Location的key对应的value是给定的URL。客户端浏览器在解析响应头后自动向Location中的URL发送请求。
重定向响应特点:
- 重定向会产生两次请求两次响应。
- 重定向的URL是由客户端浏览器发送的。
- 浏览器地址栏会有变化。
package cn.it.servlet; 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 doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); //获取内容 String search = req.getParameter("search"); //在使用get请求数据的时候需要将中文进行url编码(转成%十六进制%) resp.sendRedirect("https://www.baidu.com/s?tn=39042058_40_oem_dg&ie=utf-8&wd="+ URLEncoder.encode(search,"utf-8")); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } }
4.24 文件下载
在实现文件下载时,我们需要在响应头中添加附加信息。
response.addHeader("Content-Disposition", "attachment; filename="+文件名);
Content-Disposition:attachment
该附加信息表示作为对下载文件的一个标识字段。不会在浏览器中显示而是直接做下载处理。
filename=文件名
表示指定下载文件的文件名。
package cn.it.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; //文件下载 public class FileDownServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //读取下载文件 File file = new File("d:/aa.jpg"); //文件字节输入流 FileInputStream fis = new FileInputStream(file); //文件字节缓冲流 BufferedInputStream bis = new BufferedInputStream(fis); //在响应中添加文件下载的信息 resp.addHeader("Content-Disposition", "attachment; filename="+file.getName()); //产生响应 文件字节缓冲输出流 BufferedOutputStream bos = new BufferedOutputStream(resp.getOutputStream()); int temp = 0; while ((temp = bis.read()) != -1) { bos.write(temp); } bos.flush(); bos.close(); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } }
4.25 解决下载时文件名中文乱码问题
resp.addHeader("Content-Disposition", "attachment; filename="+new String(file.getName() .getBytes("gbk"),"iso-8859-1"));
4.26 ServletContext对象
ServletContext对象介绍
ServletContext官方叫Servlet上下文。服务器会为每一个Web应用创建一个ServletContext对象。这个对象全局唯一,而且Web应用中的所有Servlet都共享这个对象。所以叫全局应用程序共享对象。
ServletContext对象的作用
- 相对路径转绝对路径
- 获取容器的附加信息
- 读取配置信息(web.xml)
- 全局容器
4.26.1 相对路径转绝对路径
该方法可以将一个相对路径转换为绝对路径,在文件上传与下载时需要用到该方法做路径的转换。转换的目的是为了实现跨平台。
context.getRealPath("path")
添加目录时最好将该项目所在的tomcat中的位置删除,重新启动tomcat。
//获取ServletContext对象 ServletContext servletContext = this.getServletContext(); //路径转换 相对路径转换为绝对路径 String realPath = servletContext.getRealPath("/img/哈哈.jpg"); //读取下载文件 File file = new File(realPath);
4.26.2 获取容器的附加信息(基本信息)
返回Servlet容器的名称和版本号
servletContext.getServerInfo()
返回Servlet容器所支持Servlet的主版本号。
servletContext.getMajorVersion()
返回Servlet容器所支持Servlet的副版本号。
servletContext.getMinorVersion()
package cn.it.servlet; 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 GetBaseInfoServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = this.getServletContext(); //获取当前服务器的信息 String serverInfo = servletContext.getServerInfo(); //获取主版本号 int majorVersion = servletContext.getMajorVersion(); //获取副版本号 int minorVersion = servletContext.getMinorVersion(); //响应到浏览器 resp.setContentType("text/html;charset=UTF-8"); PrintWriter writer = resp.getWriter(); writer.println("当前服务器的信息:"+serverInfo); writer.println("主版本号:"+majorVersion); writer.println("副版本号:"+minorVersion); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } }
4.26.3 获取web.xml中的信息
<context-param> <param-name>key</param-name> <param-value>value</param-value> </context-param>
servletContext.getInitParameter("key")
该方法可以读取web.xml文件中标签中的配置信息。
servletContext.getInitParameterNames()
该方法可以读取web.xml文件中所有param-name标签中的值。
<context-param> <param-name>name</param-name> <param-value>张三</param-value> </context-param> <context-param> <param-name>password</param-name> <param-value>123</param-value> </context-param>
package cn.it.servlet; 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; import java.util.Enumeration; //读取配置web.xml配置文件中的<context-param>节点信息 public class ContextInfo extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取servletContext对象 ServletContext servletContext = this.getServletContext(); Enumeration<String> initParameterNames = servletContext.getInitParameterNames(); resp.setContentType("text/html;charset=utf-8"); PrintWriter writer = resp.getWriter(); while (initParameterNames.hasMoreElements()) { String name = initParameterNames.nextElement(); String initParameter = servletContext.getInitParameter(name); writer.println("name:"+name+",value:"+initParameter); } writer.flush(); writer.close(); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } }
4.26.4 全局容器
servletContext.setAttribute("key",ObjectValue)
向全局容器中存放数据。
servletContext.getAttribute("key")
package cn.it.servlet; 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 GlobalContext extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取全局数据 ServletContext servletContext = this.getServletContext(); resp.setContentType("text/html;charset=UTF-8"); PrintWriter writer = resp.getWriter(); writer.println(servletContext.getAttribute("key1")); writer.println(servletContext.getAttribute("key2")); writer.flush(); writer.close(); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override public void init() throws ServletException { //服务器初始化时添加全局数据 ServletContext servletContext = this.getServletContext(); servletContext.setAttribute("key1","张三"); servletContext.setAttribute("key2","李四"); } }
4.26.5 ServletContext对象生命周期
当容器启动时会创建ServletContext对象并一直缓存该对象,直到容器关闭后该对象生命周期结束。ServletContext对象的生命周期非常长,所以在使用全局容器时不建议存放业务数据。
4.27 ServletConfig对象
ServletConfig对象对应web.xml文件中的<servlet>节点。当Tomcat初始化一个Servlet时,会将该Servlet的配置信息,封装到一个ServletConfig对象中。我们可以通过该对象读取<servlet>节点中的配置信息
<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>
读取web.xml文件中标签中标签中的配置信息
servletConfig.getInitParameter("key")
该方法可以读取web.xml文件中当前标签中所有标签中的值。
servletConfig.getInitParameterNames()
<servlet> <servlet-name>GetServletConfig</servlet-name> <servlet-class>cn.it.servlet.GetServletConfig</servlet-class> <init-param> <param-name>key1</param-name> <param-value>张三</param-value> </init-param> <init-param> <param-name>key2</param-name> <param-value>李四</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>GetServletConfig</servlet-name> <url-pattern>/config.do</url-pattern> </servlet-mapping>
package cn.it.servlet; import javax.servlet.ServletConfig; 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 GetServletConfig extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取ServletConfig对象 ServletConfig servletConfig = this.getServletConfig(); Enumeration<String> initParameterNames = servletConfig.getInitParameterNames(); resp.setContentType("text/html;charset=UTF-8"); PrintWriter writer = resp.getWriter(); while (initParameterNames.hasMoreElements()) { String name = initParameterNames.nextElement(); String initParameter = servletConfig.getInitParameter(name); writer.println(name+":"+initParameter); } writer.flush(); writer.close(); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } }
4.28 Cookie对象与HttpSession对象
Cookie对象与HttpSession对象的作用是维护客户端浏览器与服务端的会话状态的两个对象。由于HTTP协议是一个无状态的协议,所以服务端并不会记录当前客户端浏览器的访问状态,但是在有些时候我们是需要服务端能够记录客户端浏览器的访问状态的,如获取当前客户端浏览器的访问服务端的次数时就需要会话状态的维持。在Servlet中提供了Cookie对象与HttpSession对象用于维护客户端与服务端的会话状态的维持。二者不同的是Cookie是通过客户端浏览器实现会话的维持,而HttpSession是通过服务端来实现会话状态的维持。
4.28.1 Cookie对象的特点
- Cookie使用字符串存储数据
- Cookie使用Key与Value结构存储数据
- 单个Cookie存储数据大小限制在4097个字节
- Cookie存储的数据中不支持中文,Servlet4.0中支持
- Cookie是与域名绑定所以不支持跨一级域名访问
- Cookie对象保存在客户端浏览器内存或系统磁盘中
- Cookie分为持久化Cooke与状态Cookie
- 浏览器在保存同一域名所返回Cookie的数量是有限的。不同浏览器支持的数量不同,Chrome浏览器为50个
- 浏览器每次请求时都会把与当前访问的域名相关的Cookie在请求中提交到服务端。
4.28.2 Cookie对象的创建
通过new关键字创建Cookie对象
Cookie cookie = new Cookie("key","value")
通过HttpServletResponse对象将Cookie写回给客户端浏览器。
response.addCookie(cookie)
package cn.it.servlet; import javax.servlet.ServletException; import javax.servlet.http.Cookie; 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 CookieServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //创建cookie对象 Cookie cookie = new Cookie("key1","张三"); //通过响应对象将cookie写回客户端 resp.addCookie(cookie); resp.setContentType("text/html;charset=UTF-8"); PrintWriter writer = resp.getWriter(); writer.println("cookie"); writer.flush(); writer.close(); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } }
4.28.3 获取Cookie中的数据
浏览器每次请求时都会把与当前访问的域名相关的Cookie在请求中提交到服务端。通过HttpServletRequest对象获取Cookie,返回Cookie数组。在Servlet4.0中的Cookie的Value开始支持中文存储。
Cookie[] cookies = request.getCookies();
package cn.it.servlet; import javax.servlet.ServletException; import javax.servlet.http.Cookie; 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 GetCookiesServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Cookie[] cookies = req.getCookies(); resp.setContentType("text/html;charset=UTF-8"); PrintWriter writer = resp.getWriter(); for (Cookie cookie : cookies) { writer.print(cookie.getName() + "=" + cookie.getValue()); } writer.flush(); writer.close(); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } }
4.28.4 Cookie跨域问题
域名分类:域名分为顶级域、顶级域名(一级域名)、二级域名。
域名等级的区别:一级域名比二级域名更高级,二级域名是依附于一级域名之下的附属分区域名,即二级域名是一级域名的细化分级。例如:baidu.com 为一级域名,news.baidu.com为二级域名。
Cookie不支持一级域名的跨域,支持二级域名的跨域。
就是在访问百度的域名时,浏览器不会将cookie提交给百战的服务器。百度之间可以实现cookie共享。
4.28.5 状态Cookie与持久化Cookie
状态Cookie:Cookie对象仅会被缓存在浏览器所在的内存中。当浏览器关闭后Cookie对象 也会被销毁。
持久化Cookie:浏览器会对Cookie做持久化处理,基于文件形式保存在系统的指定目录中。在Windows10系统中为了安全问题不会显示Cookie中的内容。
当Cookie对象创建后默认为状态Cookie。可以使用Cookie对象下的cookie.setMaxAge(60)方法设置失效时间,单位为秒。一旦设置了失效时间,那么该Cookie为持久化Cookie,浏览器会将Cookie对象持久化到磁盘中。当失效时间到达后文件删除。
4.28.6 通过Cookie实现客户端与服务端会话的维持
package cn.it.servlet; import javax.servlet.ServletException; import javax.servlet.http.Cookie; 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 WelcomeServlet extends HttpServlet { @Override 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 (cookie.getName().equals("welcome")){ System.out.println(cookie.getValue()); flag = true; break; } } } resp.setContentType("text/html;charset=UTF-8"); PrintWriter writer = resp.getWriter(); if (flag){ writer.println("欢迎回来"); }else { writer.println("第一次访问"); //状态写回 Cookie cookie = new Cookie("welcome", "123 "); cookie.setMaxAge(60); resp.addCookie(cookie); } writer.flush(); writer.close(); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } }