HttpServletRequest和HttpServletResponse
它俩分别是用来获取请求报文,设置响应报文!
HttpServletRequest
HttpServletRequest封装了请求报文,我们可以从中获取到的内容有:
1.获取请求参数
2.获取请求行(展示当前请求的信息)
3.获取请求头信息
4.请求转发
request获取请求参数
- String request.getParameter(name):获取浏览器传输的单个的请求参数
- String[] request.getParameterValues(name):获取浏览器传输的多个同名的请求参数的值的数组
准备一个页面用于提交用户名、密码、爱好
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Hello,tomcat</h1>
<form action="FirstServlet" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
爱好:<input type="checkbox" name="hobby" value="AA">AA
<input type="checkbox" name="hobby" value="BB">BB
<input type="checkbox" name="hobby" value="CC">CC
<input type="checkbox" name="hobby" value="CC">DD
<input type="checkbox" name="hobby" value="CC">EE<br>
<input type="submit" value="提交"><br>
</form>
</body>
</html>
页面效果如下:
别问我问什么选CD????单纯喜欢这俩个字母而已,咦~
public class FirstServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, UnsupportedEncodingException {
// 不管是get还是post都能获取
// 获取浏览器传输的单个请求参数
String username = request.getParameter("username");
String password = request.getParameter("password");
//获取浏览器传输多个同名的请求参数
String[] hobbies = request.getParameterValues("hobby");
System.out.println("username:"+username+",password:"+password+",hobby:"+ Arrays.toString(hobbies));
}
}
控制台打印结果:
HttpServletRequest解决请求参数中文乱码问题
request.setCharacterEncoding("UTF-8");
因为编码不一致:浏览器有浏览器的编码,服务器有服务器的编码。
tomcat8.5 解决了get请求的中文乱码问题,tomcat 7 get请求有中文乱码问题
获取请求参数之前设置,在设置编码之前不能获取任何获取请求参数才有效
先设置编码过滤器,再来设置获取请求参数过滤器
public class FirstServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, UnsupportedEncodingException {
//解决中文乱码
request.setCharacterEncoding("UTF-8");
//获取请求参数
String username = request.getParameter("username");
String password = request.getParameter("password");
String[] hobbies = request.getParameterValues("hobby");
System.out.println("username:"+username+",password:"+password+",hobby:"+ Arrays.toString(hobbies));
}
}
中文乱码问题得到解决:
request获取请求相关信息
request.getContextPath();//获取当前web应用上下文路径
public class ServletMM extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取当前web应用上下文路径
String contextPath = request.getContextPath();
// 获取协议
String scheme = request.getScheme();
// 获取服务器的端口号
int serverPort = request.getServerPort();
// 获取服务器ip地址
String serverName = request.getServerName();
// 获取发送请求的统一资源定位符(在网络中的地址)
StringBuffer requestURL = request.getRequestURL();
// 获取发送请求的统一资源标识符 (资源在服务器的地址,上下文路径下的资源路径)
String requestURI = request.getRequestURI();
System.out.println("统一资源定位符:"+requestURL.toString());
System.out.println("统一资源标识符:"+requestURI);
}
}
request 获取请求头信息
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取当前请求的来源路径
String cookie = request.getHeader("cookie");//参数写请求头的键,键不区分大小写
System.out.println("cookie:"+cookie);
}
request获取请求体(扩展)
request.getReader()//获取字符输出流,缓冲流可以一次读一行
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
BufferedReader bufferedReader = request.getReader();
//获取字符输出流,缓冲流可以一次读一行
String line = bufferedReader.readLine();
System.out.println(line);
}
request请求转发
是将当前的请求传递到下一个资源继续进行处理,是响应浏览器的一种方式。
request.getRequestDispatcher("/success.html").forward(request,response);//请求转发
请求转发特点:
请求转发时浏览器地址栏没有发生变化,浏览器只发送了一次请求,最终实现的页面跳转发生在服务器内部,浏览器是不知道的!
这里/success.html,“/”可以加也可以不加,加了之后是绝对路径,因为是请求转发,所以/是由服务器解析的,这个路径问题一会专门讲。用老师的话说:路径问题是个大问题!
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 请求转发:是将当前的请求传递到下一个资源继续进行处理
// 交给页面处理请求就是展示给用户
request.getRequestDispatcher("/success.html").forward(request,response);
}
请求转发举例
理论上我请求的是ServletMM,实际上给我转发到了success.html(也即在服务器内部给我跳转到了success.html,页面显示的最终效果就是success.html的内容)。
且我们发现请求转发时浏览器地址栏没有发生变化。也就是说,既然显示的是success.html页面的内容,地址栏应该像第二张图那样才对呀,可是事实上请求转发的地址栏就是第一张图那样。应证了那句:请求转发是在服务器内部跳转的。
HttpServletResponse
封装服务器发送到浏览器的响应报文,因此可以通过此对象设置当前响应相关的信息
PrintWriter中的write()和print()会把数据存储在响应体响应给浏览器
区别是:print可以将任意类型输出给浏览器,它俩效果是一样的。
将任意类型输出给浏览器
//字符输出流,输出文本 标签会被浏览器解析
response.getWriter().print("<h1>Tomorrow is another day</h1>");
//字节输出流,输出文件
ServletOutputStream outputStream = response.getOutputStream();
// writer.write("helloworld");
如向浏览器发送内容 <h1>Tomorrow is another day</h1>,看的出来h1标签也是被解析了的
那要是向浏览器发送的内容中有中文呢?
如我要给浏览器发送 <h1>顺为凡,逆则仙</h1>,如下:
//字符输出流,输出文本 标签会被浏览器解析
response.getWriter().print("<h1>顺为凡,逆则仙</h1>");
这时候浏览器就蒙蔽了,,,解析成这个样子了:
解决响应到浏览器数据的乱码问题:
//设置响应报文中存储数据的编码格式
response.setCharacterEncoding("UTF-8");
//设置浏览器解码格式,以文本形式存在的html,
// 这一块忘记点进去setContentType去源码找text/html;charset=UTF-8
response.setContentType("text/html;charset=UTF-8");
//字符输出流,输出文本 标签会被浏览器解析
response.getWriter().print("<h1>顺为凡,逆则仙</h1>");
效果很清晰:输出了我喜欢的玄幻小说之一《仙逆》的主旨
设置浏览器解码格式时也可以这么写,但是没必要,不推荐
response.setHeader("Content-Type", "text/html;charset=UTF-8");
重定向
重定向也可以跳转页面,它是浏览器发送2次请求,浏览器地址栏会发生变化。最终实现的页面跳转发生在浏览器端。
//由服务器通知浏览器再次发送请求跳转到重定向的路径
response.sendRedirect("success.html");
响应浏览器的3种方式
1.响应浏览器数据
2.请求转发
3.重定向
总结:业务逻辑处理成功使用重定向,业务逻辑处理失败使用请求转发
以下来自我自己的总结,在新的页面中有操作且有数据要带过去展示的话用请求转发,有操作但是没有数据带过去的情况下,用重定向。没有操作没有数据带过去的单纯跳转页面用转发。
补充:
有操作有数据也可以使用重定向, 这时你只要将数据存入到session中也是可以的.
没有操作没有数据带过去用 重定向和内部转发 都可以.用转发是因为转发可以访问WEB-INF目录下的资源
请求转发和重定向区别:
区别一:
转发时地址栏不变,即显示的是servlet地址,浏览器只发送一次请求,最终页面跳转发生在服务器端;重定向时地址栏改变,即显示最终重定向的地址,浏览器只发送2次请求,最终页面跳转发生在浏览器端区别二:
WEB-INF下的页面具有隐藏性、安全性,浏览器不能直接访问,只有服务器才能访问,即只有请求转发才能访问到,重定向不能访问到。以后大部分情况,把页面放在WEB-INF下。不会把css,js放在WEB-INF下区别三:
请求转发可以访问请求域中的数据,重定向不可以。
那是因为转发是浏览器发送的一次请求,request对象是同一个。重定向发送2次请求,2次请求对应2个request对象
登录失败,需要把错误信息共享在请求域中,这是因为另外俩种域对象太大了,所以业务逻辑处理失败使用转发。
相对路径和绝对路径
相对路径:指目标资源相对于当前位置的路径
绝对路径:
- static web中,绝对路径指目标资源在磁盘上的路径
- web application中,绝对路径指目标资源在服务器上的路径
相对路径的缺点对应绝对路径的优点 :
1、相对路径跟目标资源的位置和当前的位置有关,其中任何一个位置发生变化,则相对路径失效
2、相对路径跟目标资源的位置和当前的位置有关,在不同的位置访问同一个资源,没有统一的访问路径
3、相对路径在请求转发中不靠谱,因为相对地址会发生变化
对第3条的理解:在请求转发到的页面中,由于请求转发是浏览器发送的一次请求,因此地址栏中的地址不变,即访问的是servlet的地址,因此当前位置发生了变化,从而影响到页面中的相对路径
web application的绝对路径
很简单:就是”/“开头的路径。但是这个“/”分为服务器解析和浏览器解析
服务器解析的绝对路径中,/表示"http://localhost:8080/上下文路径"下开始访问
浏览器解析的绝对路径中,/表示"http://localhost:8080"下开始访问
服务器解析的绝对路径的2种情况:①web.xml中使用的绝对路径,②请求转发到的绝对路径
如url-pattern标签中的"/" <url-pattern>/ServletMM</url-pattern>
浏览器解析的绝对路径的情况:①html页面中标签设置的绝对路径,② 重定向到的绝对路径
html页面中标签绝对路径3种处理方式
由于是浏览器所解析的绝对路径,所以缺失了上下文路径,有3种处理方式
方式1、手动添加上下文路径
方式2、base标签
方式3、将web应用的上下文路径设置为"/"
第二种方式:
<base href="/day05_web/">
href里有俩个"/",后面那个"/"为什么写在base里,因为base标签不能作用于绝对路径的(以"/"开头的路径)
第三种方式:
"/" 由浏览器和服务器解析的绝对路径就是一样的了,实际项目就是这么用的
重定向到的绝对路径的处理方式:
在重定向到绝对路径前拼接request.getContextPath();
System.out.println("上下文路径: "+request.getContextPath());
//重定向由浏览器解析,要加上下文路径
response.sendRedirect(request.getContextPath() + "/test.html");
浏览器重定向后展示的页面
控制台输出上下文路径为: