HttpServletResponse
常见的用法主要有:
- 发送响应码
- sendError(int num):发送错误码num,其中错误码是4和5类状态码
- sendError(int num,String msg):发送错误码,提示信息为msg.
- setStatus(int num):发送状态码num,其中这些状态码是1,2,3类状态码
- 设置响应头
- setHeader(header,value):设置响应头,它的值为value,这是单值的,即这个响应头只有单个值。(这是最常用的).例如我们设置Location来实现重定向.
public class AServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*//发送重定向之后,同时需要设置对应的响应头Location,其中对应的值就是我们需要
//重定向的URL
resp.setStatus(302);//发送状态码,表示重定向
resp.setHeader("Location","/response/BServlet");*/
//可以调用sendRedirect()来代替上面的2行代码,从而实现它的重定向
System.out.println("this is AServlet!!!!");
resp.sendRedirect("/response/BServlet");
}
}
public class BServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
设置响应编码,如果不设置的话,那么下面发送的数据就会出现乱码。因为
服务端默认是iso编码,而客户端是gbk,所以我们需要调用setCharacterEncoding来
设置可以识别中文的编码,例如utf-8或者gbk,但是设置utf-8同样出现乱码,因为
此时服务端和客户端的编码依旧是不一样的。所以还需要通知客户端,服务端使用的编码
因此可以利用setHeader("Content-Type","text/html;charset=utf-8")来,通过设置
Content-Type响应头,一方面执行了setCharacterEncoding("utf-8")来设置服务端的编码,
同时会告诉客户端,服务端所使用的编码,这样客户端就会自动使用对应的编码了.
而setHeader("Content-Type","text/html;charset=utf-8")的快捷方式为
setContentType("text/html;charset=utf-8");
*/
response.setContentType("text/html;charset=utf-8");
System.out.println("这是我们重定向的BServlet!!!!");
response.getWriter().println("这是我们重定向的BServlet!!!");
}
}
这时候我们一旦在浏览器地址栏上面输入localhost:8080/response/AServlet,回车之后,就会发现地址栏变成了localhost:8080/response/BServlet,并且输出了在BServlet类中发送的实体数据 。测试结果如下:
同时我们可以设置Refresh响应头,这个响应头相当于定向重定向的,可以设置多少秒之后就会重定向到新的Servlet中.例如下面的代码:
public class CServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
/*设置给AServlet发送请求的时候,AServlet的响应编码*/
response.setContentType("text/html;charset=utf-8");
response.getWriter().println("这是AServlet!");
response.setHeader("Refresh","5;/request/BServlet");
}
}
测试结果位:
- addHeader(header,value):设置响应头,它的值不只是value,它是一个多值的,即这个响应头有多个值
- setIntHeader(header,value):设置int类型的响应头,它的值为value,它是单值的,即一个响应头只有一个值。
- addIntHeader(header,value):设置int类型的响应头,它的值不只是value,它是多值的。
- setDateHeader(header,value):设置毫秒类型(即long类型的)的响应头,同样这是一个单值的。
- addDateHeader(header,value):设置毫秒类型的多值的响应头
⭐通过上面,我们可以知道,只要是set开头的,那么响应头就是单值的,因为我们新的值就会覆盖掉原来的值,但是add开头的,那么响应头就是多值的,给这个响应头再添加值。
-
获取对应的流,通过流来发送实体数据
- getWriter():获取字符流PrintWriter,然后可以调用println(msg)来发送实体数据
- getOutputStream():获取字节流,然后调用write方法来发送实体数据.
- 值得注意的是,不可以同时出现getWriter和getOutputStream,否则就会发送异常IllegalStateException
public class EServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8");//设置响应编码为utf-8,同时告诉给客户端,服务端的编码 response.getWriter().println("这是使用getWriter发送的数据!"); response.getOutputStream().write("这是使用getOutputStream发送实体数据".getBytes()); } }
测试结果为:
HttpServletRequest
常见的用法有:
-
getMethod():来获取对应的请求方法
-
getRemoteAddr():来获取客户端的ip地址
-
getHeader():获取请求头的数据,例如通过获取User-Agent请求头,我们就可以获取客户端的操作系统,以及浏览器等信息.
-
获取地址栏URL中的相关数据
- getScheme():获取所使用的协议
- getServerName():获取服务器的名字
- getServerPort():获取服务点所使用的端口
- getContextPath():获取项目路径
- getServletPath():获取Servlet的路径
- getQueryString():获取请求参数,URL中?后面的一些列字符串
- getRequestURI():即项目路径 + Servlet路径
- getRequestURL():即URL中?前面的一系列字符串
public class AServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1、调用getMethod来获取请求方法 PrintWriter writer = resp.getWriter(); String method = req.getMethod(); writer.println("getMethod() = " + method); //2、调用getRemoteAddr()来获取远程客户主机的ip地址 String remoteAddr = req.getRemoteAddr(); writer.println("getRemoteAddr() = " + remoteAddr); //3、获取URL上的相关信息 String scheme = req.getScheme();//调用getScheme来获取协议 writer.println("getScheme() = " + scheme); //调用getServerName()来获取服务器的名字 String serverName = req.getServerName(); writer.println("getServerName() = " + serverName); //调用getServerPort()来获取服务器的端口号 writer.println("getServerPort() = " + req.getServerPort()); //调用getContextPath来获取项目名 writer.println("getContextPath() = " + req.getContextPath()); //调用getServletPath来获取Servlet名字 writer.println("getServletPath = " + req.getServletPath()); //调用getQueryString来获取参数,注意的是,如果参数的值是个中文,那么这时候会发生乱码 String queryString = req.getQueryString(); writer.println("getQueryString() = " + queryString); //调用getRequestURI来获取URI(即web.xml中的url) writer.println("getRequestURI() = " + req.getRequestURI()); //调用getRequestURL来获取URL,即浏览器上面的URL中?前面一系列字符串 writer.println("getRequestURL() = " + req.getRequestURL()); } }
测试结果:
-
获取请求参数对应的值
- String getParameter(target):获取请求参数target的值
- String[ ] getParameterValues(target):获取请求参数target的所有值。这是针对的是多值的参数,例如复选框
- Enumeration getParameters():获取所有请求参数的名字
- Map<String,String[ ]> getParameterMap():获取所有的请求参数以及对应的值。
public class DServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*
通过超链接来获取请求参数,也即是GET请求
此时超链接所在的页面是一个UTF-8的,那么这时候发送请求的参数中含有中文
那么request调用响应的方法来获取这个参数的值,由于服务器的编码是iso的,那么
必然会发生了乱码。所以需要在获取值之后,用iso进行回编,然后在用utf-8进行重编
*/
String value = req.getParameter("xxx");//调用getParameter(target)表示获取参数target的值
//服务器的默认编码为iso,那么我们需要先将iso的编码形式回退,然后在重编
byte[] bytes = value.getBytes("iso-8859-1");
//重建对应的编码形式
String value1 = new String(bytes,"utf-8");
System.out.println("xxx的value为:" + value1);
String yyy = req.getParameter("yyy");
//回退,然后在重编
byte[] bytes1 = yyy.getBytes("iso-8859-1");
String yyy1 = new String(bytes1, "utf-8");
System.out.println("yyy的value为: " + yyy1);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*
使用Post请求的时候,直接利用req调用对应方法来获取参数的值,那么出现乱码的时候,
所以在调用getParameter等方法之前,执行req.setCharacterEncoding设置编码
*/
req.setCharacterEncoding("utf-8");//需要用req来设置对应的编码
Enumeration<String> parameterNames = req.getParameterNames();
while(parameterNames.hasMoreElements()){
String parameter = parameterNames.nextElement();
//调用getParameter(name)来获取name参数的值
System.out.println(parameter + ": " + Arrays.toString(req.getParameterValues(parameter)));
}
//调用方法getParameterMap()来获取所有的参数,并且返回的值是一个String[],因为
//这些参数中有可能含有多个值,例如下面的hobby就是多值的
Map<String, String[]> parameterMap = req.getParameterMap();
for(Map.Entry<String,String[]> entry: parameterMap.entrySet()){
String name = entry.getKey();
String[] value = entry.getValue();
System.out.println(name + ": " + Arrays.toString(value));
}
}
}
对应的html页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><!--设置了解码的形式为UTF-8-->
<title>login.html</title>
</head>
<body>
<a href="/request/DServlet?xxx=张三&yyy=李四">通过链接来提交表单</a><br>
<form action="/request/DServlet" method="post">
姓 名: <input type="text" name="username"><br>
密 码: <input type="password" name="password"><br>
爱 好: <input type="checkbox" name="hobby" value="足球">足球
<input type="checkbox" name="hobby" value="篮球">篮球
<input type="checkbox" name="hobby" value="乒乓球">乒乓<br>
<input type="submit" value="登录">
</form>
</body>
</html>
所以一开始,直接在地址栏上输入:localhost:8080/login.html来到我们上面html代码页面,然后点击表单提交,或者超链接体,测试结果为:
- 请求转发和请求包括
首先request对象调用getRequestDispatcher(“新的Servlet”),获取RequestDispatcher对象dispatcher
然后dispatcher调用forward进行请求转发,调用include进行请求包括。
请求转发:
public class EServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置响应编码
response.setContentType("text/html;charset=utf-8");
//1、response调用getRequestDispatcher对象,从而获取调度对象
RequestDispatcher other = request.getRequestDispatcher("/request/FServlet");
//2、其他的Servlet调用forward进行转发请求,调用include方法进行转发包括
//3、进行转发请求之前,利用response获取对应的流对象,然后书写对应的响应头和实体数据
response.setHeader("aaa","AAA");//当前Servlet中设置响应头,再进行请求转发,那么在新的Servlet不会清空当前Servlet设置的响应头,这就是留头
//发送响应数据
PrintWriter pw = response.getWriter();
/*
如果在EServlet中写这样的实体数据,然后在进行转发请求,那么并不会
发送留头不流体的情况。
for(int i = 0; i < 1024 * 24 + 1; ++i){
pw.write("this is EServlet");
}*/
pw.write("这是发送请求转发和包括的EServlet");//EServlet中发送实体数据,之后进行请求转发,那么新的Servlet就会清空当前Servlet中发送的实体数据,这就是不留体。
other.forward(request,response);
}
}
public class FServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//演示转发请求和转发包括
//书写对应的实体数据,这时候并没有设置响应编码,所以如果输出的是中文,会发生乱码
response.setContentType("text/html;charset=utf-8");//设置响应编码
System.out.println("this is FServlet");
response.setHeader("aaa","BBB");
PrintWriter writer = response.getWriter();
writer.println("这是请求转发和包括的FServlet");
}
}
测试结果:
如果在上面的EServlet中,进行的是请求包括,即other.include(request,response),那么对应的测试结果为:
所以上面2张图片可以知道,请求转发拥有留头不留体的特征,而请求包括则留头又留体。
- 请求转发和重定向的区别
1、请求转发中地址栏并没有发生变化,而重定向的地址栏则发生了变化。也即是说请求转发中客户端只发送了1次请求,请求转发中的多个Servlet使用同一个请求,而重定向中则客户端发送了多个请求。
2、请求转发中只能向当前项目的其他Servlet进行转发,而重定向则可以向其他项目的Servlet进行重定向。
3、因为请求转发中多个Servlet使用的是同一个请求,而重定向则需要客户端发送多个请求,所以请求转发的效率比重定向的要高。
编码问题
编码问题主要分为了响应编码和请求编码以及URL编码.
- 响应编码
由于服务端一般使用的是iso编码,而客户端则一般使用的是gbk编码。此时iso不可以识别中文,所以发送出去的数据是乱码,然后又因为服务端和客户端的编码不同,乱码会更加严重。
所以服务端需要通过setCharacterEncoding(encode)来设置服务端的编码为encode,例如setCharacterEncoding(“utf-8”)来设置服务端的编码为utf-8,
虽然utf-8,gbk是可以识别中文的,但是如果服务端的编码是utf-8,那么会因为两个端点的编码不同而导致乱码。所以服务端需要告知客户端自己使用的编码。所以服务端通过setHeader(“Content-Type”,“text/html;charset=utf-8”),这个语句不仅可以设置服务端的编码为utf-8,同时告诉了客户端服务端所使用的编码为utf-8,那么客户端就会自动使用对应得编码进行解码了,这样就不会出现乱码了。
而setHeader(“Context-Type”,“text/html;charset=utf-8”)的快捷方式为:setContentType(“text/html;charset=utf-8”); - 请求编码
请求主要分为 页面中的超链接和表单进行提交数据、地址栏URL这2中情况。
而对于第一种情况,我们首先通过浏览器发送请求,才会得到一个页面。而这个页面(html文件)是utf-8的编码,尽管响应头中并没有Content-Type:text/html;utf-8,但是这个html文件中的语句已经设置了当前的页面的编码是utf-8了。那么通过超链接,或者表单发送出去的都是utf-8编码。而此时由于服务端使用的编码是iso,从而会发生乱码。
所以分2种情况:- GET请求(即超链接):
首先需要利用iso-8859-1进行回编,然后再利用utf-8进行重编 - POST请求:
直接利用request.setCharacterEncoding(“utf-8”),然后再获取对应参数的值即可.但是需要保证再设置编码之后才可以获取对应参数的值,否则,如果在设置编码之前,调用了getParameter获取参数的值的话,那么哪怕有写了setCharacterEncoding,也不会生效的。
- GET请求(即超链接):
public class BServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1、调用getParameter来获取对应参数的值
String xxx = request.getParameter("xxx");
String yyy = request.getParameter("yyy");
//2、利用iso进行回编
byte[] bytes = xxx.getBytes("iso-8859-1");
byte[] bytes1 = yyy.getBytes("iso-8859-1");
//3、利用utf-8进行重编
xxx = new String(bytes, "utf-8");
yyy = new String(bytes1,"utf-8");
System.out.println("xxx的值为: " + xxx);
System.out.println("yyy的值为: " + yyy);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
对于post请求,只需要将调用setCharacterEncoding为
utf-8,然后就可以直接获取对应参数的值了,注意是request来调用setCharacterEncoding,而不是response
但是需要注意的是,需要保证request调用setCharacterEncoding放在getParameter的前面
*/
request.setCharacterEncoding("utf-8");
String username = request.getParameter("username");
String[] hobbies = request.getParameterValues("hobby");
System.out.println(username);
System.out.println(Arrays.toString(hobbies));
}
}
对应的encoding.html文件(在web目录下):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><!--设置客户端页面编码的形式为UTF-8-->
<title>encoding.html</title>
</head>
<body>
<a href="/encoding/BServlet?xxx=张三&yyy=李四">通过链接来提交表单</a><br>
<form action="/encoding/BServlet" method="post">
姓 名: <input type="text" name="username" value="王五"><br>
密 码: <input type="password" name="password" value="123di"><br>
爱 好: <input type="checkbox" name="hobby" value="足球">足球
<input type="checkbox" name="hobby" value="篮球">篮球
<input type="checkbox" name="hobby" value="乒乓">乒乓<br>
<input type="submit" value="登录">
</form>
</body>
</html>
测试结果:
- URL编码
什么是URL编码,是客户端和服务端之间为了网络安全的编码,例如localhost:8080/username=张三&address=北京,这时候将参数的值能够完全显示出来,显然很容易被窃取数据,安全性不高,所以就出现了URL编码,它的作用就是将中文转成%后面跟随2位的16进制。
URLEncoder.encode(String string,code);//code是对应的编码。调用encode实现URL编码
URLDecoder.decode(String string,decode);//code是对应的编码。调用decode实现URL解码