课程回顾
XML解析: DOM4J、DOM、SAX、JDOM, getParent() 获取父节点,再删除
HTTP协议: 0.9、1.0、1.1 无状态协议
反射技术: Class类反射入口、获取类信息、属性信息、方法信息、构造方法信息、main方法、创建对象(newInstance())、调用方法( invoke )、强制访问( setAccessible(true) )
动态代理: Proxy.newInstance( 类加载器, 接口数组,InvocationHandler ) MyBatis框架使用动态代理、SpringAOP也是
概述
我们在编写Servlet的时候,重写的doGet方法、doPost方法包括两个参数: HttpServletRequest, HttpServletResponse ;这两个参数表示的请求和响应对象。请求和响应对象的创建是由Tomcat服务器来实现的,我们开发人员并不需要显示的创建这两个对象;可以直接使用。Web服务器收到一个http请求,会针对每个请求创建一个HttpServletRequest和HttpServletResponse对象,从客户端取数据找HttpServletRequest,向客户端发送数据就是HttpServletResponse。
特别感谢: CSDN博客——扬俊的小屋做的动画
HttpServletResponse接口
接口定义
public interface HttpServletResponse extends ServletResponse
所在的包: javax.servlet.http,常见的属性和方法见文档。
HttpServletResponse对象代表服务器的响应。该对象可以向客户端发送三种类型的数据:
- 响应头:响应的头部信息
- 响应码:响应的状态码
- 响应体:响应的具体数据
查看HttpServletResponse的API,可以看到这些相关的方法。查看响应的相关信息:
发送响应头
package com.ujiuye.web;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/resp2")
public class MyResponse2 extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String str = "对于IO操作来说,使用频率最高(也是最容易被遗忘)的就是close操作,好在Java规范使用了优雅的Closeable接口,这样我们只需简单封装调用此接口的方法即可。";
System.out.println("原始字节长度:"+str.getBytes().length);
//创建字节数组输出流,作为容器,默认长度32个字节
ByteArrayOutputStream bos = new ByteArrayOutputStream();
//创建压缩输出流,压缩,不存储
GZIPOutputStream zip = new GZIPOutputStream(bos);
//将原始字符串写到压缩输出流
zip.write(str.getBytes());
zip.close();
//把容器转换成字节数组
byte[] array = bos.toByteArray();
System.out.println("压缩后的长度:"+array.length);
//操作响应头
response.setHeader("Content-Encoding", "gzip");
response.setHeader("Content-Length", array.length+"");
response.setHeader("Accept-Range", "bytes");
response.setHeader("Cache-Control", "no-cache");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
执行结果:
发送响应头控制浏览器内容类型
- text/html;charset=utf8 文本或者HTML代码
- jpeg 图片格式
- pdf pdf文件
内容类型参考文件: apache-tomcat-8.5.51/conf/web.xml
package com.ujiuye.web;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/image")
public class MyResponseImage extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置响应头
response.setHeader("Content-Type", "jpeg");
//加载图片获取输入流
InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/01.jpeg");
//创建缓冲数组
byte[] b = new byte[1024];
//定义读取数据长度
int len = 0;
//循环读取并写到浏览器
ServletOutputStream sos = response.getOutputStream();
while( (len=in.read(b) ) != -1) {
sos.write(b, 0, len);
}
sos.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
http://localhost:8080/chapter13/image
发送响应头控制浏览器禁止缓存
protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException {
response.setDateHeader("expries", -1);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
}
发送响应头控制浏览器定时刷新
protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException {
response.setHeader("refresh", "5");//设置refresh响应头控制浏览器每隔5秒钟刷新一次
//response.setHeader("refresh", "3;url=https://www.baidu.com");//3秒钟跳转页面
}
发送响应码
Servlet在接收用户请求并进行业务处理之后要转向到另一个页面,譬如成功或失败页面,这个页面跳转过程称为重定向。HttpServletResponse中一般用sendRedirect进行重定向,也就是跳转到另一个页面或者Servlet。sendRedirect进行重定向做了下面2件事:
- 设置HTTP响应报头中的Status为302
- 设置HTTP响应报头中的Location值为指定的URL
HttpServletResponse定义了很多状态码的常量(具体可以查看Servlet的API),当需要向客户端发送响应状态码时,可以使用这些常量,避免了直接写数字,常见的状态码对应的常量:
- 状态码404对应的常量 SC_NOT_FOUND
- 状态码200对应的常量 SC_OK
- 状态码500对应的常量 SC_INTERNAL_SERVER_ERROR
用法
HttpServletResponse.sendRedirect("url?参数名1=参数值&参数名2=参数值");
实例
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
/*方法一:使用response.sendRedirect*/
//response.sendRedirect("index.html");
/*方法二:设置响应头和重定向地址*/
response.setHeader("Location", "index.html");
response.setStatus(HttpServletResponse.SC_FOUND);//设置302状态码,等同于response.setStatus(302);
}
发送响应体
通过response对象返回具体数据到浏览器是需要的数据传输媒介,分为: 字节流和字符流。
package com.ujiuye.web;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/refresh")
public class MyResponseRefresh extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf8");
/**
* 多学一招:使用HTML语言里面的标签来控制浏览器行为,模拟通过设置响应头控制浏览器行为
* response.setHeader("content-type", "text/html;charset=UTF-8");
*/
String str = "3秒钟跳转页面";
//输出中文: 字节流
//ServletOutputStream sos = response.getOutputStream();
//sos.write(str.getBytes());
//out.write("使用OutputStream输出数字:".getBytes("utf-8"));
//out.write( (1+"").getBytes());//字母d,
//字符流
PrintWriter out = response.getWriter();
out.println("字符流:" + str);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
注意:getOutputStream()和getWriter()这两个方法互相排斥,调用了其中的任何一个方法后,就不能再调用另一方法。
综合案例:文件下载
编写Servlet
package com.ujiuye.web;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/download")
public class MyResponseDownload extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置文件下载响应头
response.setHeader("Content-disposition", "attachment;filename=01.jpeg");
//加载图片获取输入流
InputStream in = getServletContext().getResourceAsStream("/WEB-INF/01.jpeg");
//获取输出流
ServletOutputStream out = response.getOutputStream();
//创建缓冲池
byte[] b = new byte[1024];
int len = 0;
while( (len = in.read(b)) != -1 ) {
out.write(b, 0, len);
}
out.close();
in.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
编写HTML页面
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="download">文件下载</a>
</body>
</html>
支持中文文件名
package com.ujiuye.web;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/download")
public class MyResponseDownload extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//加载图片获取输入流
String realPath = getServletContext().getRealPath("/WEB-INF/美女.jpeg");
String fileName = realPath.substring(realPath.lastIndexOf("/") + 1);
System.out.println("文件名称:"+fileName);
//设置文件下载响应头
response.setHeader("Content-disposition", "attachment;filename="+URLEncoder.encode(fileName, "utf-8"));
//InputStream in = getServletContext().getResourceAsStream("/WEB-INF/01.jpeg");
//获取流
FileInputStream in = new FileInputStream(realPath);
ServletOutputStream out = response.getOutputStream();
//创建缓冲池
byte[] b = new byte[1024];
int len = 0;
while( (len = in.read(b)) != -1 ) {
out.write(b, 0, len);
}
in.close();
out.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
综合案例:图片验证码
package com.ujiuye.web;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/code")
public class MyResponseCode extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 0.设置refresh响应头控制浏览器每隔5秒钟刷新一次
response.setHeader("refresh", "5");
// 1.在内存中创建一张图片
BufferedImage image = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);
// 2.得到图片
// Graphics g = image.getGraphics();
Graphics2D g = (Graphics2D) image.getGraphics();
g.setColor(Color.WHITE);// 设置图片的背景色
g.fillRect(0, 0, 80, 20);// 填充背景色
// 3.向图片上写数据
g.setColor(Color.BLUE);// 设置图片上字体的颜色
g.setFont(new Font(null, Font.BOLD, 20));
g.drawString(makeNum(), 0, 20);
// 4.设置响应头控制浏览器浏览器以图片的方式打开
response.setContentType("image/jpeg");// 等同于response.setHeader("Content-Type", "image/jpeg");
// 5.设置响应头控制浏览器不缓存图片数据
response.setDateHeader("expries", -1);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
// 6.将图片写给浏览器
ImageIO.write(image, "jpg", response.getOutputStream());
}
/**
* 生成随机数字
*/
private String makeNum() {
Random random = new Random();
String num = random.nextInt(9999999) + "";
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 7 - num.length(); i++) {
sb.append("0");
}
num = sb.toString() + num;
return num;
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
访问地址: http://localhost:8080/chapter13/code
HttpServletRequest接口
接口定义
HttpServletRequest接口的定义
public interface HttpServletRequest extends ServletRequest
父接口: ServletRequest接口的定义, 从定义可以看出ServletRequest是根接口。
public interface ServletRequest
Defines an object to provide client request information to a servlet. The servlet container creates a
ServletRequest
object and passes it as an argument to the servlet’sservice
method.定义一个提供客户端请求信息到一个Servlet的对象,Servlet容器创建一个ServletRequest对象并作为一个参数传递给Servlet的seivice方法。
A
ServletRequest
object provides data including parameter name and values, attributes, and an input stream. Interfaces that extendServletRequest
can provide additional protocol-specific data (for example, HTTP data is provided byHttpServletRequest
.一个ServletRequest对象提供的数据包括: 参数名称和参数值、属性值、输入流。继承自ServletRequest接口可以提供额外指定的协议参数,( 例如Http协议 )
实现类: HttpServletRequestWrapper
public class HttpServletRequestWrapper extends ServletRequestWrapper
implements HttpServletRequest
查看请求的相关信息:
获取请求行信息
package com.ujiuye.web2;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/line")
public class RequestLine extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String scheme = request.getScheme();//获取协议
String method = request.getMethod(); //请求方法
String url = request.getRequestURL().toString();//请求的URL
String uri = request.getRequestURI();//请求的URI
String param = request.getQueryString();//请求的参数
String protocol = request.getProtocol();//请求的协议
String path = request.getContextPath();//获取项目名称
response.setContentType("text/html;charset=utf8");
PrintWriter out = response.getWriter();
out.println("scheme:" + scheme + "<br/>");
out.println("method:" + method + "<br/>");
out.println("url:" + url + "<br/>");
out.println("uri:" + uri + "<br/>");
out.println("param:" + param + "<br/>");
out.println("protocol:" + protocol + "<br/>");
out.println("path:" + path + "<br/>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
http://localhost:8080/chapter13/line?username=admin&password=123456
获取请求头信息
获取请求的报文头信息:
- request.getHeader(“xx”) 根据指定的请求头获取值
- request.getHeaders(“xx”)根据指定的请求头获取值,值是多个;Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
- request.getHeaderNames()获取所有的请求头的名称,然后就可以根据名称再获取值
package com.ujiuye.web2;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/header")
public class RequestHeader extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf8");
PrintWriter out = response.getWriter();
Enumeration<String> en = request.getHeaderNames();//Iterator
while(en.hasMoreElements()) {
String name = en.nextElement();
String value = request.getHeader(name);
out.println(name + "-->" + value + "<br/>");
}
out.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
执行结果:
获取请求体信息
获得客户机请求参数(客户端提交的数据)
- getParameter(String)方法**(常用)**
- getParameterValues(String name)方法**(常用)**
- getParameterNames()方法(不常用)
- getParameterMap()方法**(编写框架时常用)**
注册页面
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="download">文件下载</a>
<h1>用户注册</h1>
<form name="regForm" action="registerServlet" method="post" id="regForm">
姓名: <input type="text" name="name" id="name"><br>
性别: 男<input type="radio" name="sex" id="radio1" value="男" checked>
女<input type="radio" name="sex" id="radio2" value="女"><br>
爱好:
抽烟<input type="checkbox" name="hobbies" value="抽烟">
喝酒<input type="checkbox" name="hobbies" value="喝酒">
打豆豆<input type="checkbox" name="hobbies" value="打豆豆" checked>
泡妞<input type="checkbox" name="hobbies" value="泡妞"><br/>
简介: <textarea name="mark" id="" cols="30" rows="10"></textarea><br>
学历: <select name="education" id="selEdu">
<optgroup label="非正常学历">
<option value="野鸡大学">野鸡大学</option>
<option value="家里蹲大学">家里蹲大学</option>
<option value="社会大学">社会大学</option>
</optgroup>
<optgroup label="正常学历">
<option value="初中">初中</option>
<option value="高中" selected="selected">高中</option>
<option value="大学">大学</option>
</optgroup>
</select><br>
<input type="submit" value="提交"/>
<input type="reset" value="重置"/>
</form>
</body>
</html>
注册Servlet
package com.ujiuye.web2;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/registerServlet")
public class RequestBody extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
//第一种方法: 根据表单组件名称获取值
String name = request.getParameter("name");
String sex = request.getParameter("sex");
String hobbies[] = request.getParameterValues("chk_hobbies");
String mark = request.getParameter("mark");
String edu = request.getParameter("education");
out.println("name:" + name + "<br/>");
out.println("sex:" + sex + "<br/>");
out.println("hobbies:" + Arrays.toString(hobbies) + "<br/>");
out.println("mark:" + mark + "<br/>");
out.println("edu:" + edu + "<br/>");
out.println("<hr/>");
//第二种方法: 如果表单的内容不详,如何获取表单数据? Map
Map<String,String[]> map = request.getParameterMap();
for(Map.Entry<String, String[]> entry : map.entrySet()) {
String names = entry.getKey();
String values[] = entry.getValue();
out.println(names + "--->" + Arrays.toString(values).replace("[", "").replace("]", "")+"<br/>");
}
//第三种方法: 先获取所有的名称,再跟据名字获取内容
out.println("<hr/>");
Enumeration<String> en = request.getParameterNames();
while(en.hasMoreElements()) {
String namess = en.nextElement();
if(namess.startsWith("chk_")) {
String [] values = request.getParameterValues(namess);
out.println(namess + "--->" +
Arrays.toString(values).replace("[", "").replace("]", "")+"<br/>");
}else {
String value = request.getParameter(namess);//多选的问题
out.println(namess + "--->" + value+"<br/>");
}
}
out.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
执行效果
获取请求客户端信息
package com.ujiuye.web2;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/remote")
public class RequestRemote extends HttpServlet{
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String addr = request.getRemoteAddr();//客户端IP地址
String host = request.getRemoteHost();//客户端主机
int port = request.getRemotePort();//客户端端口
String user = request.getRemoteUser();//客户端用户名称
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println("addr:" + addr+"<br/>");
out.println("host:" + host+"<br/>");
out.println("port:" + port+"<br/>");
out.println("user:" + user+"<br/>");
}
}
获取本地服务器信息
package com.ujiuye.web2;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Locale;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/local")
public class RequestLocal extends HttpServlet{
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String addr = request.getLocalAddr();//服务器IP
String host = request.getLocalName();//服务器名称
int port = request.getLocalPort();//服务器端口
//具体的服务器
String serverName = request.getServerName();
int serverPort = request.getServerPort();
//代表的本地信息,国家、语言
Locale local = request.getLocale();
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println("addr:" + addr+"<br/>");
out.println("host:" + host+"<br/>");
out.println("port:" + port+"<br/>");
out.println("local:" + local.getDisplayCountry() + ","+
local.getDisplayLanguage() +"<br/>");
out.println("serverName:" + serverName+"<br/>");
out.println("serverPort:" + serverPort+"<br/>");
}
}