以下部分概念来自于https://www.cnblogs.com/EvanLiu/p/3352229.html,侵删
request和response
根据servlet的生命周期来分析:
Web服务器接收到客户端的http请求,创建Servlet时会覆盖service()方法,或doGet()/doPost(),
这些方法都有两个参数,一个为代表请求的request和代表响应response。
service()方法的request和response:
来自ServletResponse接口
doGet()/doPost()方法的request和response:
HttpServletResponse/Request接口继承ServletResponse接口,ServletResponse/Request并没有提供与HTTP协议相关API,HttpServletResponse/Request添加了与协议相关API,功能更强大
JavaEE API 中并没有提供HttpServletResponse/Request实现类---实现类由tomcat服务器提供的
HttpServletRequest类封装客户端相关信息,服务器Servlet程序可以通过request对象操作客户端信息
HttpServletResponse类封装服务器向客户端发送响应数据信息,Servlet程序通过response对象向客户端发送响应
【Response】
响应对象,服务器向客户端发送的信息,包装成响应对象发送过去
常用api
1. 通过response设置响应行
设置响应行的状态码
常用状态码:200 302 304 404 500
200 请求处理成功
302 客户端重定向
304 客户端访问资源没有被修改,客户端访问本地缓存
404 访问资源不存在
500 服务器内部出错
setStatus(int sc)
// 响应行
// 修改状态码
resp.setStatus(404);
2.通过response设置响应头
addHeader(String name, String value)
addIntHeader(String name, int value)
addDateHeader(String name, long date)
setHeader(String name, String value)
setDateHeader(String name, long date)
setIntHeader(String name, int value)
* 其中,add表示添加,而set表示设置
setHeader:设置响应头信息
addHeader:添加响应头信息
package com.bwf.response;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//只要在Servlet上设置@WebServlet标注,容器就会自动读取当中的信息。下面的@WebServlet告诉容器,如
//果请求的URL是"/demo2",则由Demo2Servlet的实例提供服务。可以使用@WebServlet提供更多信息。
@WebServlet("/demo2")
public class Demo2Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置响应头,同名的key会被覆盖
// resp.setHeader("name", "zhangsan");
// resp.setHeader("name", "lisi");
// resp.setHeader("upwd", "123");
// 添加响应头,同名的header不会被覆盖
// resp.addHeader("name", "zhangsan");
// resp.addHeader("name", "lisi");
// resp.addHeader("upwd", "123");
// html的<meta>标签的作用其实就是模拟一个响应头
// 比如定时刷新
//resp.setHeader("refresh", "3;url=");
resp.setHeader("refresh", "3;url=http://www.baidu.com");
//在HTML页面中存在一类非常特殊标签<meta>,<meta>起到设置头信息作用
//<meta content="3;url=http://www.baidu.com" http-equiv="refresh"> ---- 完成自动跳转
}
}
重定向sendRedirect(url);
下图表示,访问localhost:8080/my1019/s1的服务原本交由RedirectServlet1的实例来提供,但是在RedirectServlet1的doGet方法内,重定向到了RedirectServlet2
具体代码:
s1(原本访问的servlet)
package com.bwf.response;
import java.io.IOException;
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("/s1")
public class RedirectServlet1 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("访问了s1");
// 重定向到s2
// 状态码改到302
// response.setStatus(302);
// 还要设置响应头告诉浏览器, 应该跳到的地址
// response.setHeader("Location", "/Servlet03/s2");
// 测试时要观察的地方 输入的是第一个Servlet的url
// 1. 页面展示
// 2. 请求次数 network
// 3. 地址栏
// 更直观的方式
response.sendRedirect("/Servlet03/s2"); //重定向的url参数交给浏览器解析,需要给出完整路径
}
}
s2(用户收到s1的响应后,重新访问的servlet)
package com.bwf.response;
import java.io.IOException;
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("/s2")
public class RedirectServlet2 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().write("zhe shi RedirectServlet2");
}
}
浏览器实际上做了2次访问,第一次访问s1,服务器对httpservletresponse对象设置了重定向,浏览器收到了302重定向状态码和重定向location的url,再次访问location 的url(在浏览器f12调试信息的network菜单中查看)
在浏览器的url栏可以看到,访问的是主机号/项目名/s1
但是最终显示页面是主机号/项目名/s2
3.通过response设置响应体
(1)响应体设置文本
PrintWriter getWriter() //获得字符流
设置编码格式
html的默认编码解码格式为ISO-8859-1,
iso-8859-1是单字节表示,所以无法表示255之上的字节,比如中文就会变成乱码,所以需要设置编码格式和解码格式.
package com.bwf.response;
import java.io.IOException;
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("/content")
public class ContentServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 给response设置码表 UTF-8
// response.setCharacterEncoding("UTF-8");
// 告诉浏览器, 解析文字的方式(码表)
// 设置响应头
// response.setHeader("Content-Type", "text/html;charset=UTF-8");
// 也可以这样写
response.setContentType("text/html;charset=UTF-8");
// 设置响应体
response.getWriter().write("<h1>中国</h1>");
}
}
setCharacterEncoding 和 setContentType区别?
setCharacterEncoding 设置响应内容编码,无法设置浏览器查看编码
setContentType设置响应内容编码,同时通知浏览器查看编码
*在响应头信息中 Content-Type:text/html;charset=utf-8
结论:setContentType具备setCharacterEncoding编码功能,现实开发中,只需要使用setContentType就可以了
(2)响应体设置字节
ServletOutputStream getOutputStream() //获得字节流
注意:
1)getOutputStream和getWriter不能同时使用
2)必须在getOutputStream和getWriter之前设置响应编码
3)getOutputStream和getWriter输出内容是HTTP响应体
4)getOutputStream和getWriter存在缓冲区,在service方法结束时,自动关闭流,flush缓冲区内容
【Request】
request对象是从客户端向服务器发出请求,包括用户提交的信息以及客户端的一些信息。客户端可通过HTML表单或在网页地址后面提供参数的方法提交数据,然后服务器通过request对象的相关方法来获取这些数据。request的各种方法主要用来处理客户端浏览器提交的请求中的各项参数和选项。
1. 通过request获得请求行
获得客户端的请求方式:String getMethod()
获得请求的资源:
String getRequestURI()
StringBuffer getRequestURL()
uri和url的区别:
URI标记了一个网络资源,仅此而已; URL标记了一个WWW互联网资源(用地址标记),并给出了他的访问地址。(URI是Uniform Resource Identifier,表示是一个资源; URL是Uniform Resource Locator,表示是一个地址
*String getContextPath() ---web应用的名称
String getQueryString() ---- get提交url地址后的参数字符串
username=zhangsan&password=123
注意:request获得客户机(客户端)的一些信息
request.getRemoteAddr() --- 获得访问的客户端IP地址
2.通过request获得请求头
long getDateHeader(String name)
*String getHeader(String name):通过key获取请求头里对应的value值
Enumeration getHeaderNames():获得所有在请求头里的键,并通过getHeader方法获取里面的值
Enumeration getHeaders(String name):
int getIntHeader(String name)
package com.bwf.request;
import java.io.IOException;
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;
/**
* Servlet implementation class RequestServlet2
*/
@WebServlet("/req2")
public class RequestServlet2 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获得请求头信息
// User-Agent
// String userAgent = request.getHeader("User-Agent");
// System.out.println("User-Agent : " + userAgent);
// 获得所有在请求头里的键,并通过getHeader方法获取里面的值
Enumeration<String> headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()){
String element = headerNames.nextElement();
System.out.println(element + " : " + request.getHeader(element));
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
* referer头的作用:
HTTP Referer是header的一部分,当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器我是从哪个页面链接过来的,服务器基此可以获得一些信息用于处理。 - 做防盗链
package com.bwf.request;
import java.io.IOException;
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("/news")
public class NewsServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html; charset=UTF-8");
String news = "<h1>独家新闻</h1>中国国足已经9比0战胜了巴西";
// 拿出Referer头
String referer = request.getHeader("Referer");
//为了防止空指针的情况,用常量来调用equals方法
if("http://localhost:8080/Servlet03/2.html".equals(referer)){
// 我自己过来的, 看新闻
response.getWriter().write(news);
}else{
// 不是我自己过来的
response.getWriter().write("抱歉!你是盗链的!");
}
}
}
3.通过request获得请求体
请求体中的内容是通过post提交的请求参数
String getParameter(String name)
String[] getParameterValues(String name)
Enumeration getParameterNames()
Map<String,String[]> getParameterMap()
* post提交方式的乱码问题
浏览器首先会根据contentType的charset编码格式来对post表单的参数进行编码然后提交给服务器,post方法提交的参数是放在方法体内,在服务器端同样也是用contentType中设置的字符集来进行解码(这里与get方式就不同了).
如何解决:设置解码方式和浏览器的编码方式一致就可以了
request.setCharacterEncoding("UTF-8");
* get提交的方式的乱码问题
get方式提交的参数是放在url中,和主机号,资源名包装成了请求字符串,再转换成字节用流的方式传输,字符转换成字节采用的是utf-8码表,但是tomcat服务器默认解码方式是iso-8859-1,解码和编码方式不统一.所以中文会出现乱码
如何解决:
先把get方法收到的乱码参数用iso8859-1码表编码,再用utf-8解码
parameter = new String(parameter.getbytes("iso8859-1"),"utf-8");
4. 其他功能
(1) request对象也是一个存储数据的域对象(k-v形式)
setAttribute(String name, Object o):设置属性
getAttribute(String name):拿出属性,为空时返回null
removeAttribute(String name):移除属性
*** 注意:ServletContext域与Request域的生命周期比较?
ServletContext:
创建:服务器启动
销毁:服务器关闭
域的作用范围:整个web应用
request:
创建:访问时创建request
销毁:响应结束request销毁
域的作用范围:一次请求中
(2)request完成请求转发
获得请求转发器----path是转发的地址
RequestDispatcher getRequestDispatcher(String path)
通过转发器对象转发
requestDispathcer.forward(ServletRequest request, ServletResponse response)
转发图例:
package com.bwf.request;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
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("/ds1")
public class DispatchServlet1 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("用户访问了DispatchServlet1");
// 域对象作用
request.setAttribute("name", "tom");
//设置转发的url,并返回请求转发对象
RequestDispatcher dispatcher = request.getRequestDispatcher("/ds2");
//把请求和响应对象发给请求转发对象处理
dispatcher.forward(request, response);
}
}
package com.bwf.request;
import java.io.IOException;
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("/ds2")
public class DispatchServlet2 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html; charset=UTF-8");
response.getWriter().write("<h1>恭喜" + request.getAttribute("name") +" ,访问到了最新的DispatchServlet2</h1>");
}
}
注意:转发与重定向的区别?
1)重定向两次请求,转发一次请求
2)重定向地址栏的地址变化,转发地址不变
3)重新定向可以访问外部网站 转发只能访问内部资源
4)转发的性能要优于重定向
举例:有个学生问陈老师问题,但是陈老师不会,隔壁韩老师会
1.转发:陈老师问韩老师,韩老师把结果告诉陈老师,陈老师再告诉学生
2.请求:陈老师告诉学生韩老师的联系方式,让学生再去问韩老师得到结果
转发和重定向的应用
a.转发:
付费网站:通过采用转发,可以确保付费网站的url不公开(地址栏不变)
b.重定向:
登录功能:用户登录成功后进入欢迎页面
如果把欢迎页面(url)放入收藏夹,那么(过段时间)再次登录就不能进入欢迎页面,需要把它重定向到登录页面