第一章 Request原理和继承体系
1.1 Request的原理
- ①服务器会根据请求url中的资源路径,创建对应的Servlet的对象。
- ②服务器会创建request和response对象,request对象封装了请求消息数据,response对象封装了响应消息数据。
- ③服务器将request和response对象传递给Servlet的service方法,并且调用service方法。
- ④程序员可以来通过request对象来获取请求消息数据,可以通过response对象来设置响应消息数据。
- ⑤服务器在给浏览器做出响应之前,会从response对象中拿程序员设置的响应消息数据。
1.2 request的即成体系
第二章 Request获取请求数据
2.1 获取请求行数据
- 格式:
# 请求方式 资源路径 http协议
GET /taobao/crm?username=zhangsan HTTP/1.1
- 获取请求方式:
public String getMethod();
- 获取虚拟目录:/taobao
public String getContextPath();
- 获取Servlet路径:/crm
public String getServletPath();
- 获取get方式请求参数:username=zhangsan
public String getQueryString();
- 获取请求的URI:/taobao/crm
public String getRequestURI();
- 获取请求的URL:http://localhost:8080/taobao/crm
public StringBuffer getRequestURL();
- 获取协议及版本号:HTTP/1.1
public String getProtocol();
- 获取客户端的IP地址:
public String getRemoteAddr();
- 示例:
package com.sunxiaping.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(urlPatterns = {"/crm"}) public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); System.out.println("获取请求方式:" + method); String contextPath = req.getContextPath(); System.out.println("获取虚拟目录:" + contextPath); String servletPath = req.getServletPath(); System.out.println("获取Servlet的路径:" + servletPath); String queryString = req.getQueryString(); System.out.println("获取get方式的参数格式:" + queryString); String requestURI = req.getRequestURI(); System.out.println("获取请求的URI:" + requestURI); StringBuffer requestURL = req.getRequestURL(); System.out.println("获取请求的URL:" + requestURL); String protocol = req.getProtocol(); System.out.println("获取协议及版本号:" + protocol); String remoteAddr = req.getRemoteAddr(); System.out.println("获取客户端的IP地址:" + remoteAddr); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doGet(req, resp); } }
2.2 获取请求头数据
- 根据请求名称获取请求头的值:
public String getHeader(String name);
public Enumeration<String> getHeaders(String name);
- 获取所有的请求头:
public Enumeration<String> getHeaderNames();
- 示例:
package com.sunxiaping.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; import java.util.Enumeration; @WebServlet(urlPatterns = {"/crm"}) public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Enumeration<String> headerNames = req.getHeaderNames(); while (headerNames.hasMoreElements()) { String headerName = headerNames.nextElement(); Enumeration<String> headerValues = req.getHeaders(headerName); System.out.print("headerName:" + headerName + ",headerValues:"); while (headerValues.hasMoreElements()) { System.out.print(headerValues.nextElement()); } System.out.println(); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doGet(req, resp); } }
2.3 获取请求体数据
- 请求体:只有post请求方式,才有请求体,在请求体中封装了post请求的请求参数。
- 步骤:
- ①获取流对象。
// 获取字符输入流,只能操作字符数据 public BufferedReader getReader() throws IOException; // 获取字节输入流,可以操作所有类型数据 public ServletInputStream getInputStream() throws IOException;
- ②从流中拿数据。
- 示例:
- register.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>注册页面</title> </head> <body> <form action="${pageContext.request.contextPath}/register" method="post"> 用户名: <input type="text" name="username"/><br/> 密码: <input type="password" name="password"/><br/> <input type="submit" value="登录"> </form> </body> </html>
- RegisterServlet.java
package com.sunxiaping.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.BufferedReader; import java.io.IOException; @WebServlet(urlPatterns = {"/register"}) public class RegisterServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { BufferedReader reader = req.getReader(); String str; while (null != (str = reader.readLine())) { System.out.println(str); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doGet(req, resp); } }
2.4 其他功能
2.4.1 获取请求参数通用方式
- 根据参数名获取参数值:
public String getParameter(String name);
public String[] getParameterValues(String name);
- 获取所有的请求参数名称:
public Enumeration<String> getParameterNames();
- 获取所有请求参数的Map集合:
public Map<String, String[]> getParameterMap();
- 示例:
package com.sunxiaping.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; import java.util.Arrays; import java.util.Enumeration; @WebServlet(urlPatterns = {"/register"}) public class RegisterServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Enumeration<String> parameterNames = req.getParameterNames(); while (parameterNames.hasMoreElements()) { String parameterName = parameterNames.nextElement(); String[] values = req.getParameterValues(parameterName); System.out.println("参数名:" + parameterName + ",参数值:" + Arrays.toString(values)); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doGet(req, resp); } }
- 中文乱码问题:在Tomcat8以后,GET方式没有乱码问题。
- 对POST的乱码解决:
req.setCharacterEncoding("utf-8");
2.4.2 请求转发
- 一种在服务器内部的资源跳转方式。
- 步骤:
- ①通过request对象获取请求转发器对象:
public RequestDispatcher getRequestDispatcher(String path);
- ②使用RequestDispatcher对象来进行转发:
public void forward(ServletRequest request, ServletResponse response){}
- 特点:
- ①浏览器的地址栏不会变化。
- ②只能转发到当前服务器内部资源中。
- ③转发是一次请求。
2.4.3 共享数据
- 域对象:一个有作用范围的对象,可以在范围内共享数据。
- request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据。
- 在域中添加数据:
public void setAttribute(String name, Object o);
- 在域中删除数据:
public void removeAttribute(String name);
- 从域中获取数据:
public Object getAttribute(String name);
- 示例:
package com.sunxiaping.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(name = "ServletDemo1", urlPatterns = "/servletDemo1") public class ServletDemo1 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); request.setAttribute("msg", "你好,世界"); request.getRequestDispatcher("/servletDemo2").forward(request, response); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
package com.sunxiaping.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(name = "ServletDemo2",urlPatterns = "/servletDemo2") public class ServletDemo2 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); Object msg = request.getAttribute("msg"); System.out.println(msg); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
2.4.4 获取ServletContext对象
- 示例:
package com.sunxiaping.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(name = "ServletDemo1", urlPatterns = "/servletDemo1") public class ServletDemo1 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext servletContext = request.getServletContext(); System.out.println("servletContext:" + servletContext); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
第三章 Response对象
3.1 概述
- 代表响应信息。可以用来设置响应行、响应头、响应体。
- 设置状态码:
public void setStatus(int sc);
public void setStatus(int sc, String sm);
- 获取输出流:
public ServletOutputStream getOutputStream() throws IOException;
public PrintWriter getWriter() throws IOException;
- 设置请求头:
public void setHeader(String name, String value);
public void setDateHeader(String name, long date);
public void addDateHeader(String name, long date);
public void addHeader(String name, String value);
public void setIntHeader(String name, int value);
public void addIntHeader(String name, int value);
3.2 重定向
- 步骤:
- ①告诉浏览器重定向的状态码是302.
- ②告诉浏览器B资源的路径:通过响应头location。
- 示例:
- ServletDemo1.java
package com.sunxiaping.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(name = "ServletDemo1", urlPatterns = "/servletDemo1") public class ServletDemo1 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setStatus(302); response.setHeader("location", request.getContextPath()+"/servletDemo2"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
- ServletDemo2.java
package com.sunxiaping.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(name = "ServletDemo2",urlPatterns = "/servletDemo2") public class ServletDemo2 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("这是ServletDemo2"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
- 特点:
- ①地址栏发生改变。
- ②重定向可以访问其他站点(服务器)的资源。
- ③重定向是两次请求。
3.3 response之输出数据
- 示例:服务器输出字符数据到浏览器
package com.sunxiaping.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(name = "ServletDemo1", urlPatterns = "/servletDemo1") public class ServletDemo1 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置流的默认编码:iso-8859-1 为utf-8 response.setCharacterEncoding("utf-8"); //告诉浏览器,服务器发送的消息体数据的编码,建议浏览器使用该编码 response.setContentType("text/html;charset=utf-8"); response.getWriter().println("你好啊,Servlet"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
- 示例:服务器输出字节数据到浏览器
package com.sunxiaping.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(name = "ServletDemo1", urlPatterns = "/servletDemo1") public class ServletDemo1 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); response.getOutputStream().write("你好啊".getBytes("utf-8")); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
第四章 ServletContext对象
4.1 概述
- 代表整个web应用,可以和Servlet的容器(如Tomcat等)来通信。
4.2 功能
- ①获取MIME类型。
- ②域对象,共享数据。
- ③获取文件的真实路径(服务器路径)。
4.3 获取ServletContext对象
- 通过request对象获取ServletContext对象。
public ServletContext getServletContext();
- 示例:
package com.sunxiaping.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(name = "ServletContextDemo", urlPatterns = "/servletContextDemo") public class ServletContextDemo extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取ServletContext对象 ServletContext servletContext = request.getServletContext(); System.out.println("获取ServletContext对象:" + servletContext); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
4.4 获取MIME类型
- MIME类型:在互联网通信过程中定义的一种文件数据类型。
- 格式:大类型/小类型。
- 根据文件名获取文件的MIME类型:
package com.sunxiaping.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(name = "ServletContextDemo", urlPatterns = "/servletContextDemo") public class ServletContextDemo extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取ServletContext对象 ServletContext servletContext = request.getServletContext(); String mimeType = servletContext.getMimeType("index.html"); System.out.println("mimeType:" + mimeType); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
- 实际中,会使用Apache的tika判断文件类型。
<dependency> <groupId>org.apache.tika</groupId> <artifactId>tika-core</artifactId> <version>1.9</version> </dependency>
private static String getMimeType(File file) { if (file.isDirectory()) { return "the target is a directory"; } AutoDetectParser parser = new AutoDetectParser(); parser.setParsers(new HashMap<MediaType, Parser>()); Metadata metadata = new Metadata(); metadata.add(TikaMetadataKeys.RESOURCE_NAME_KEY, file.getName()); InputStream stream; try { stream = new FileInputStream(file); parser.parse(stream, new DefaultHandler(), metadata, new ParseContext()); stream.close(); } catch (TikaException | SAXException | IOException e) { e.printStackTrace(); } return metadata.get(HttpHeaders.CONTENT_TYPE); }
4.5 域对象(范围是整个web应用)
- 设置属性:
public void setAttribute(String name, Object object);
- 移除属性:
public void removeAttribute(String name);
- 根据属性名获取属性值:
public Object getAttribute(String name);
- 示例:
package com.sunxiaping.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(name = "ServletContextDemo", urlPatterns = "/servletContextDemo") public class ServletContextDemo extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取ServletContext对象 ServletContext servletContext = request.getServletContext(); servletContext.setAttribute("username", "zhangsan"); Object username = servletContext.getAttribute("username"); System.out.println("username:" + username); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
4.6 获取文件在服务器中的路径
- 获取文件的真实路径:
public String getRealPath(String path);
- 示例:
package com.sunxiaping.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(name = "ServletContextDemo", urlPatterns = "/servletContextDemo") public class ServletContextDemo extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取ServletContext对象 ServletContext servletContext = request.getServletContext(); String realPath = servletContext.getRealPath("/index.jsp"); System.out.println("realPath:" + realPath); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
第五章 文件下载
5.1 文件下载需求
- ①页面显示超链接。
- ②点击超链接后弹出下载提示框。
- ③完成图片文件下载。
5.2 分析
- ①超链接指向的资源如果能够被浏览器解析,则再浏览器中展示,如果不能被解析,则弹出下载提示框。
- ②任何资源都必须弹出下载提示框。
- ③使用响应头设置资源的打开方式:
content-disposition:attachment;filename=xxx
5.3 应用
- 示例:
- index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <a href="${pageContext.request.contextPath}/download?filename=桌面背景.jpg">桌面背景.jpg</a> </body> </html>
- DownloadServlet.java
package com.sunxiaping.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.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URLEncoder; @WebServlet(name = "DownloadServlet", urlPatterns = "/download") public class DownloadServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); request.setCharacterEncoding("utf-8"); //获取文件名 String filename = request.getParameter("filename"); //设置响应头信息 response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(filename, "utf-8")); //找到文件服务器的路径 String realPath = request.getServletContext().getRealPath("/image/" + filename); //创建InputStream对象 InputStream inputStream = new FileInputStream(realPath); //获取OutputStream对象 OutputStream outputStream = response.getOutputStream(); byte[] bytes = new byte[1024]; int len; while (-1 != (len = inputStream.read(bytes))) { outputStream.write(bytes, 0, len); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }