目录
request与response对象简介
Request:获取请求的数据
Response:设置响应数据
@WebServlet(value = "/demo3")
public class servletdemo3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
resp.setHeader("content-type","text/html;charset=utf-8");
resp.getWriter().write("<h1>"+name+",欢迎你!</h1>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
比如上面这段代码,获取到了用户请求中的name参数,然后再在响应的数据中输出欢迎name的操作
Request对象
继承体系
获取请求数据
请求的数据一般分为三部分:请求行、请求头、请求体
对于请求行,我们可以获取请求行消息的方法如下:
String method = req.getMethod();//获取请求方式
System.out.println(method);
String contextPath = req.getContextPath();//获取虚拟目录(项目访问路径//)
System.out.println(contextPath);
StringBuffer requestURL = req.getRequestURL();//获取URL
System.out.println(requestURL.toString());
String requestURI = req.getRequestURI();//获取URI
System.out.println(requestURI);
String queryString = req.getQueryString();//获取请求参数
System.out.println(queryString);
我们在地址栏输入
运行结果为:
对于请求头,我们有比如获取user-agent(浏览器版本)
String header = req.getHeader("user-agent");//获取浏览器版本
System.out.println(header);
对于请求体,也就是Post方法下会将传入的参数放入请求体中,对于请求体中的数据,tomcat提供了字节流与字符流的方法来获取参数:
request通用方式获取请求参数
我们发现如果客户端是get消息,那么我们需用getQueryString的方法来获取参数,而如果是post的消息,我们需要用getHeader来获取请求参数,而且还需需要进入到不同的doget和dopost两个方法中去处理获取请求参数,这样会稍显麻烦,所以我们需要用到一些通用的方式来获取请求参数。
我们首先获取到请求的方法,然后可以做一个判断,当时get请求时我们使用getQueryString,并且将值传入到params中,如果是post请求那么我们将使用getHeader方法并且将参数放到getHeader。
同时,对于获取到的参数,tomcat提供了上图的三个方法,来分别获取所有参数map集合、根据名称获取参数值(是一个数组)、根据名称获得参数值。
实验:
先写一个req.html,请求方式为get
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/demo1/req2" method="get">
<input type="text" name="username"><br>
<input type="text" name="pwd"><br>
<input type="checkbox" name="hobby" value="1">篮球
<input type="checkbox" name="hobby" value="2">足球
<br>
<input type="submit">
</form>
</body>
</html>
再写一个doGet方法来获取请求参数:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("this is doGet");
Map<String, String[]> parameterMap = req.getParameterMap();
for(String key : parameterMap.keySet()){
System.out.print(key + ":");
String[] values = parameterMap.get(key);
for (String value : values){
System.out.print(value + " ");
}
System.out.println();
}
}
在浏览器页面输入表单信息后,浏览器显示get请求:
在服务器端可以看到获取到了用户输入为:
对于POST的请求方法,我们可以直接在doPost中书写如下代码:
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
this.doGet(req,resp);
}
这样就简化了我们处理不同请求方法的代码书写
Request请求中文乱码问题--POST
我们request请求中如果有中文,那么会出现乱码的情况:
那么针对post的请求中有中文的情况,我们应该如果处理?因为post从底层读取数据的方法是getreader(),ISO-8859-1标准和页面的utf-8不匹配出现乱码,我们需要修改读取数据流的编码方式:
req.setCharacterEncoding("UTF-8");
但是以上的办法对于get请求是没有办法的,因为get是通过getQueryString来获取参数的
Request请求中文乱码问题--GET
GET请求乱码原因分析
浏览器的传输不支持中文,所以浏览器的网页首先通过utf-8的编码形式将中文转化为URL编码进行传输。随后TOMCAT在接受到数据之后又会对收到的URL进行解码,如果解码的方式也是utf-8的话,那么是不会发生乱码问题的,但是tomcat的getquerystring的底层代码是写死的,采用的是ISO-8859-1来进行解码,所以产生了Get请求中有中文乱码的现象
URL编码
虽然我们在参数输入的地方可以看到是中文,但是这时谷歌浏览器做的优化,看底层的消息头,我们发现张三这个字符被转化为了URL编码:
那么我们应该怎么做?
首先tomcat8之后的版本已经解决这个问题,get请求的中文参数不会乱码。
还有一种方法就是找寻两个编码之间的关系,无论是utf-8还是iso的编码,他们底层都是二进制数,只是由于编码解码的方式造成了乱码,我们可以这样做:
String name = req.getParameter("username");
byte[] bytes = name.getBytes(StandardCharsets.ISO_8859_1);
String s = new String(bytes, StandardCharsets.UTF_8);
System.out.println(s);
先将ISO_8859_1编码的数据转化为字节数组,然后将重新编码为utf-8来解决这一问题
请求转发
演示:
我们新建一个demo4代码如下:
System.out.println("this is demo4");
req.getRequestDispatcher("/req5").forward(req,resp);
新建一个demo5如下:
System.out.println("this is demo5");
然后我们运行我们的服务器,请求req4的数据后可以发现打印了两句话,说明req4的请求处理后又转到了req5这个资源当中
当然有时候我们两个资源之间需要资源共享,第一个资源处理了一部分的请求后,会将处理的数据交给第二个资源继续处理,所以request对象提供了以下三个方法:
演示:
输出:
特点
Response对象
Response对象来设置响应数据
功能介绍
Response对象完成重定向
演示:
@WebServlet(value = "/resp1")
public class respDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setStatus(302);
resp.setHeader("Location","/demo1/resp2");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
我们新建一个resp1的资源,然后什么都不做,重定向让浏览去去访问resp2的资源:
@WebServlet(value = "/resp2")
public class respDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("i am resp2");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
在浏览器中我们发现,当访问了resp1的资源后,地址栏发生了变化:
并且在控制台成功输出:
平时我们还可以将重定向的代码简化书写为:
resp.sendRedirect("/demo1/resp2");
同时我们在浏览器的网络中能看到产生了两次请求,浏览器在接受到302的状态码后知道了想要的资源不在resp1中,而location中有我将要访问的地址:
特点
路径问题
可以看到我们重定向转发和request请求转发的时候,我们对应的路径是不一样的,request转发我们没有加虚拟路径,而重定向的时候我们加载了虚拟路径:
那么原则应该是这样的
练习:
那么为了能够动态的获取虚拟目录,我们有这样一个方法利用getContextPath:
String contextPath = req.getContextPath();
响应字符数据
演示:
@WebServlet(value = "/resp3")
public class respDemo3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取字符输入流
PrintWriter writer = resp.getWriter();
writer.write("hello");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
输出:
并且我们在网络调试工具中也能看到响应的消息:
那么我们先显示中文应该怎么样做呢?如果我们直接在write中写入中文,肯定会乱码,因为默认的是iso的编码,这个时候我们就需要通过以下方法来设置编码格式了:
stContentType();
在这个方法中,我们还可以设置让浏览器知道我们写入的数据应该用什么文本解析,比如我们想写入HTML让浏览器能够解析,并且是中文,可以这样做:
resp.setContentType("text/html;charset=utf-8");
//获取字符输入流
PrintWriter writer = resp.getWriter();
writer.write("<h1>你好</h1>");
注意
我们无需释放write资源,因为write资源是跟随resp对象的产生而产生的,在响应结束后,服务器会自动回收,无需我们手动关闭。
响应字节数据
演示:
我们演示的目标是将一张D盘的图片a.jpg显示在我们的浏览器页面上,首先我们要将图片的字节消息读取出来:
FileInputStream fileInputStream = new FileInputStream("d://1.jpg");
随后我们需要通过Response对象获得字节输出流:
ServletOutputStream outputStream = resp.getOutputStream();
为了将输出流和输入流接起来,我们加载IO工具类,此工具类是apche提供的io工具类:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.2</version>
</dependency>
随后我们做字节流的copy:
IOUtils.copy(fileInputStream,outputStream);
fileInputStream.close();
运行效果: