Web服务器收到客户端的 HTTP 请求,会针对每一次请求,分别创建一个用于代表请求的 request 对象和代表响应的 response 对象。
request 和 response 对象既然代表请求和响应,那我们要获取客户机提交过来的数据,只需要找 request 对象就行了。要向客户机输出数据,只需要找 response 对象就行了。
ServletResponse<I>
// 通用的 Response,提供了一个响应应该具有的最基本的属性和方法HttpServletResponse<I>
// 在 ServletResponse 的基础上针对 HTTP 协议增加了很多强化的属性和方法HTTP 协议规定一个 HTTP 响应分为状态行、响应头、实体内容三个部分。于是 response 对象中封装了向客户端发送响应状态码、响应头、实体数据的方法。
public void setStatus(int sc)
public void setHeader(String name, String value)
public void setIntHeader(String name, int value)
public void setDateHeader(String name, long date)
public void addHeader(String name, String value)
public void addIntHeader(String name, int value)
public void addDateHeader(String name, long date)
public ServletOutputStream getOutputStream() throws IOException
public java.io.PrintWriter getWriter() throws IOException
public void setContentType(String type)
text/html;charset=UTF-8
。public void setCharacterEncoding(String charset)
setContentType
设置了字符编码,则此方法将重写该字符编码,也就是说 setContentType
兼并了 setCharacterEncoding
的功能。response.getOutputStream().write("计算机".getBytes());
getBytes()
使用平台的默认字符集(GBK) 将此 String 编码为 byte[]response.getWriter().write("计算机");
?
的二进制编码代替???
Content-Disposition
attachment;filename=...
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// HTTP请求头和响应头中不能包含中文, 只能包含ISO中有的字符
// response.setHeader("Content-Disposition", "attachment;filename=成绩单.png");
response.setHeader("Content-Disposition", "attachment;filename="
+ URLEncoder.encode("成绩单", "UTF-8") + ".png");
InputStream is = new FileInputStream(getServletContext().getRealPath("成绩单.png"));
OutputStream out = response.getOutputStream();
byte[] bys = new byte[1024];
int i = 0;
while((i=is.read(bys)) != -1)
out.write(bys, 0, i);
is.close();
// response 提供的输出流用不着你来关
}
static String encode(String s, String enc)
response.setHeader("Refresh", "1");
每隔1s刷新当前页面response.setHeader("Refresh", "5;url=/03_ReqResp/index.jsp");
5s 后跳转到 index.jsp<meta>
也可以模拟响应头的功能
<meta http-equiv="Refresh" content="3;url=/03_ReqResp/index.jsp"></meta>
<meta>
的内容当作响应头来处理response.setIntHeader("Expires", -1);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
// 这个时间是个毫秒值,是从1970年1月1日00:00:00开始算的
response.setDateHeader("Expires", System.currentTimeMillis() + 1000l*3600*24*30);
response.setStatus(302);
response.setHeader("Location", "/03_RequestAndResponse/index.jsp");
// ↑等价↓
response.sendRedirect("/03_RequestAndResponse/index.jsp");
在大部分情况下请求重定向和转发的效果是差不多的,这时候我们推荐使用转发,以减少对服务器的访问。而在某些情况下是需要使用转发的,目的往往是为了改变浏览器地址栏里的地址(如登录成功后转到主页),和更改刷新操作(如加入商品到购物车后转到购物车页面的操作)
public class ImageServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setDateHeader("Expires", -1);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
// 在内存中构建出一张图片
int height = 30;
int width = 120;
int posX = 5;
int posY = 22;
int bang = 20;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 获取图像上的画布
Graphics2D graphics = (Graphics2D) image.getGraphics();
// 设置画布背景色
graphics.setColor(Color.GRAY);
graphics.fillRect(0, 0, width, height);
// 设置边框
graphics.setColor(Color.RED);
// 边框本身也有宽度, 边框线本身的宽度 + width/height => 右边和下边的线正好出去了
graphics.drawRect(0, 0, width-1, height-1);
// 画一些干扰先
graphics.setColor(Color.CYAN);
for(int i = 0; i < 5; i++)
// x1, y1, x2, y2: 使用当前颜色在点 (x1, y1) 和 (x2, y2) 之间画一条线
graphics.drawLine(randNum(0, width), randNum(0, height), randNum(0, width), randNum(0, height));
// 写字
String base = ""; // 中文字库
for(int i = 0; i < 4; i++) {
graphics.setColor(new Color(randNum(0, 255), randNum(0, 255), randNum(0, 255)));
graphics.setFont(new Font("黑体", Font.BOLD, bang));
int r = randNum(-45, 45);
graphics.rotate(1.0 * r / 180 * Math.PI, posX + i*30, posY);
graphics.drawString(base.charAt(randNum(0, base.length()-1))+"", posX + i*30, posY);
graphics.rotate(1.0 * -r / 180 * Math.PI, posX + i*30, posY);
}
// 将图片输出到browser
ImageIO.write(image, "jpg", response.getOutputStream());
}
private Random rand = new Random();
private int randNum(int begin, int end) {
return begin + rand.nextInt(end - begin);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
<script type="text/javascript">
function changeImg(obj) {
obj.src = "/03_ReqAndResp/servlet/ValiImg?time="+new Date().getTime();
}
</script>
<body>
验证码:<input type="text" name="valiStr" />
<img src="/03_ReqAndResp/servlet/ValiImg" style="cursor: pointer;" onClick="changeImg(this)"/>
</body>
getOutputSteam()
和 getWriter()
这两个方法互斥,调用了其中的任一方法后,就不能再调用另一方法
IllegalStateException: getOutputStream() has already been called for this response
getOutputStream()
,然后再请求转发到 BServlet,BServlet 又调用了 getWriter()
;② 调用了 getOutputStream()
,然后 close()
,再调用 getWriter()
。service()
结束后,Servlet 引擎将检查 getWriter()
/getOutputStream()
返回的输出流对象是否已经调用过 close()
,如果没有,Servlet 引擎会调用 close()
关闭该输出流(不建议自己手动关)// 获取Client请求的完整URL
String url = request.getRequestURL().toString();
// url: http://localhost/03_ReqResp/servlet/ClientInfoServlet
System.out.println("url: " + url);
// 获取client请求的资源部分的URI
String uri = request.getRequestURI();
// uri: /03_ReqResp/servlet/ClientInfoServlet
System.out.println("uri: " + uri);
// 获取请求行中参数部分
String qStr = request.getQueryString();
// qStr: name=liu&pw=123
System.out.println("qStr: " + qStr);
// 获取client的IP地址
String ip = request.getRemoteAddr();
// ip: 127.0.0.1
System.out.println("ip: " + ip);
// 获取client请求方式
String method = request.getMethod();
// method: GET
System.out.println("method: " + method);
// [*]获取当前web应用的虚拟目录名称!!!
String webName = request.getContextPath();
// webName: /03_ReqResp
System.out.println("webName: " + webName);
String getHeader(String name)
Enumeration<String> getHeaders(String name)
Enumeration<String> getHeaderNames()
int getIntHeader(String name)
long getDateHeader(String name) // 日期对应的毫秒值
Referer
请求头实现"防盗链"String getParameter(name)
String[] getParameterValues(name)
Enumeration<String> getParameterNames()
Map<String, String[]> getParameterMap()
void setAttribute(String name, Object o)
Object getAttribute(String name)
void removeAttribute(String name)
Enumeration getAttributeNames()
[请求转发] request.getRequestDispatcher("_____").forward(request, response);
response.flush()
),再请求转发,不会成功,将会抛出异常 IllegalStateException: Cannot forward after response has been committed
。原因:HTTP 一次请求对应一次响应。当响应 committed 之后,这一次的请求响应就已经结束了。这时候你再转发(转发:请求 A,A 不做响应,交给 B 来作响应),让别的 Servlet 来做响应,已经晚了,故抛出异常。[请求包含] request.getRequestDispatcher("_____").include(request, response);
RequestDispatcher.include()
用于将 RequestDispatcher 对象封装的资源内容作为当前响应内容的一部分包含进来,从而实现可编程的服务器端包含功能。即:将两个资源的输出进行合并后输出RequestDispatcher.forward()
只能将请求转发给同一个 WEB 应用中的组件;而HttpServletResponse.sendRedirect()
还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对 URL 重定向到其他站点的资源。HttpServletResponse.sendRedirect()
的相对 URL 以 /
开头,它是相对于服务器的根目录;如果创建 RequestDispatcher 对象时指定的相对 URL 以 /
开头,它是相对于当前WEB应用程序的根目录。HttpServletResponse.sendRedirect()
重定向的访问过程结束后,浏览器地址栏中显示的URL会发生改变,由初始的 URL 地址变成重定向的目标 URL;调用 RequestDispatcher.forward()
的请求转发过程结束后,浏览器地址栏保持初始的 URL 地址不变。HttpServletResponse.sendRedirect()
对浏览器的请求直接作出响应,响应的结果就是告诉浏览器去重新发出对另外一个 URL 的访问请求;RequestDispatcher.forward()
在服务器端内部将请求转发给另外一个资源,浏览器只知道发出了请求并得到了响应结果,并不知道在服务器程序内部发生了转发行为。RequestDispatcher.forward()
的调用者与被调用者之间共享相同的 request 对象和 response 对象,它们属于同一个访问请求和响应过程;而 HttpServletResponse.sendRedirect()
调用者与被调用者使用各自的 request 对象和 response 对象,它们属于两个独立的访问请求和响应过程。
路径写法:
servletContext.getRealPath(""); // 给一个相对于web应用目录的路径
ClassLoader.getResource(""); // 给一个相对于类加载目录的路径
File file = new File(""); // 相对于程序的启动目录
new InputStream(""); // 相对于程序的启动目录
<a href="/webName/…">
<form action="/webName/…">
<img src="/webName/…">
response.setHeader("Location", "/webName/…");
response.setHeader("refresh", "/webName/…");
response.sendRedirect("/webName/…");
Request.getRequestDispatcher("/index.jsp").include(req, resp);
Request.getRequestDispatcher("/index.jsp").forward(req, resp);
原文:https://www.cnblogs.com/liujiaqi1101/p/13388425.html