一.本次笔记小目标
理解几个常用对象的意义和作用
掌握几种请求的发出方式
掌握数据的发送和接收方式
掌握跳转方式
掌握乱码的解决
二.请求的方式
要访问服务器首先需要由客户端主动发出请求,在实际的操作中,我们可以通过多种方式向服务器发起请求。
1. 地址栏输入------->2. 超链接------->3. Form 表单------->4. ajax------>5. 请求转发------>6. 重定向
1. 地址栏输入 | 在浏览器地址栏直接输入要访问的地址即可 |
2. 超链接 | 如:<a href=”http://www.shsxt.com”>尚学堂</a> |
3. Form 表单 | 当需要向服务器发送请求,并且传输一些用户输入的数据时,我们优先选择form 表单的方式发起请求。 |
4. ajax | 通过 ajax 发起的请求,属于异步请求,能实现局部刷新的效果,是一种比较常用的请求方式。通过 jQuery 中的 ajax(),get(),post(),getJSON()等方法都能发送请求. |
5. 请求转发 | 通过服务器内部将请求进行一次转发,可以请求到其他资源 |
6. 重定向 | 服务器通过给定一个新资源的地址,响应会客户端后,客户端自动再次发送一个请求到新资源的地址处。 |
三.HttpServletRequest 对象
1.小小介绍一波
HttpServletRequest 对象:主要作用是用来接收客户端发送过来的请求信息,例如:请求的参数,发送的头信息等都属于客户端发来的信息, service()方法中形参接收的是 HttpServletRequest 接口的实例化对象,表示该对象主要应用在HTTP 协议上,该对象是由 Tomcat 封装好传递过来。
HttpServletRequest 是 ServletRequest 的子接口, ServletRequest 只有一个子接口,以后可能出现更多新的协议。若以后想要支持这种新协议,只需要直接继承 ServletRequest 接口就行了。
2.开场show
a.常用方法
b.获取请求头
c.获取客户端请求参数(客户端提交的数据)
getParameter(name)方法经常使用,给个小星星
package com.shsxt.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@SuppressWarnings("serial")
public class Servlet01 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 常用方法
// 得到请求的完整路径(从http开始到?之前)
String requestURL = request.getRequestURL() + "";
System.out.println("得到请求的完整路径:" + requestURL);
// 得到请求部分资源路径(从端口后开始到?结束)
String requestURI = request.getRequestURI();
System.out.println("得到请求部分资源路径:" + requestURI);
// 得到请求的参数(从?开始到最后的字符串)
String queryString = request.getQueryString();
System.out.println("得到请求的参数:" + queryString);
// 得到请求的方式 GET/POST
String method = request.getMethod();
System.out.println("得到请求的方式:" + method);
// 得到请求协议的版本号
String protocol = request.getProtocol();
System.out.println("得到请求协议的版本号:" + protocol);
// 获取项目的站点名
String contextPath = request.getContextPath();
System.out.println("获取项目的站点名:" + contextPath);
// 获取请求头
// 获取单个指定请求头(请求头 不区分大小写)
String header = req.getHeader("HOST");
System.out.println("获取单个指定请求头:" + header);
// 获取所有请求头的名称集合
Enumeration<String> enumerations = req.getHeaderNames();
while(enumerations.hasMoreElements()) {
System.out.println("获取所有请求头的名称集合: " + enumerations.nextElement());
}
}
}
}
package com.shsxt.servlet;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@SuppressWarnings("serial")
public class Servlet03 extends HttpServlet{
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取请求参数(客户端提交到后台的参数)
// 获取指定参数
String uname = req.getParameter("uanme");
System.out.println("获取指定参数:"+ uname);
// 获取指定参数的所有值
String[] hobby = req.getParameterValues("hobby");
for (String string : hobby) {
System.out.println("获取指定参数的所有值:" + string);
}
// 获取所有请求参数的名称集合
Enumeration<String> enumeration = req.getParameterNames();
while(enumeration.hasMoreElements()){
System.out.println("获取所有请求参数的名称集合: " + enumeration.nextElement());
}
// 获取所有的请求参数和值的map对象
Map<String, String[]> map = req.getParameterMap();
for (String key : map.keySet()) {
System.out.println("key: " + key);
for (String string : map.get(key)) {
System.out.println("value:" + string);
}
}
}
}
3. 请求乱码解决
由于现在的 request 属于接收客户端的参数,所以必然有其默认的语言编码,主要是由于在解析过程中默认使用的编码方式为 ISO-8859-1(此编码不支持中文),所以解析时一定会出现乱码。要想解决这种乱码问题,需要设置 request 中的编码方式,告诉服务器以何种方式来解析数据。或者在接收到乱码数据以后,再通过相应的编码格式还原。
方法1:
这种方式只针对 POST 有效(必须在接收所有的数据之前设定)
方法2:
借助了 String 对象的方法,该种方式对任何请求有效,是通用的。Tomcat8 起,以后的 GET 方式请求是不会出现乱码的。
package com.shsxt.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@SuppressWarnings("serial")
public class Servlet04 extends HttpServlet{
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 请求乱码解决
/**
* Tomcat7及以下版本 Tomcat8版本及以上
* GET请求 会 不会(不会乱码的不需要处理)
* 1、new String(req.getParameter("str").getBytes("ISO-8859-1"), "UTF-8");
*
* POST请求 会 会
* 1、req.setCharacterEncoding("UTF-8"); 1、req.setCharacterEncoding("UTF-8");
* 2、new String(req.getParameter("str").getBytes("ISO-8859-1"), "UTF-8");
*/
/*// 处理请求乱码(只针对POST请求)
req.setCharacterEncoding("UTF-8");
// 接收参数
String name = req.getParameter("uname");
System.out.println(name);*/
// GET请求乱码解决 (Tomcat8及以上版本不能使用,否则会乱码)
String str = new String(req.getParameter("str").getBytes("ISO-8859-1"), "UTF-8");
System.out.println(str);
System.out.println(req.getParameter("str1"));
}
}
4. 请求转发
请求转发,是一种服务器的行为,当客户端请求到达后,服务器进行转发,此时会将请求对象进行保存,地址栏中的 URL 地址不会改变,得到响应后,服务器端再将响应发送给客户端, 从始至终只有一个请求发出。 实现方式如下,达到多个资源协同响应的效果.
5. request 作为域对象
通过该对象可以在一个请求中传递数据,作用范围: 在一次请求中有效,即服务器跳转有效。
request.setAttribute():设置域对象内容; request.getAttribute(String name):获取域对象内容; request.removeAttribute(String name): 删除域对象内容。
request 域对象中的数据在一次请求中有效,则经过请求转发, request 域中的数据依然 存在,则在请求转发的过程中可以通过 request 来传输/共享数据。
package com.shsxt.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@SuppressWarnings("serial")
public class Servlet06 extends HttpServlet{
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// POST请求处理乱码
req.setCharacterEncoding("UTF-8");
// 接收参数
String name = req.getParameter("uname");
// 设置request作用域
req.setAttribute("uname", name);
req.setAttribute("upwd", "admin");
req.setAttribute("sex", true);
// 获取request作用域中的值
String uname = (String) req.getAttribute("uname");
String upwd = (String) req.getAttribute("upwd");
boolean sex = (boolean) req.getAttribute("sex");
System.out.println("Servlet06 : " + uname + "," + upwd + "," + sex);
// 删除request指定域对象的值
req.removeAttribute("upwd");
// 请求转发
req.getRequestDispatcher("s07").forward(req, resp);
}
}
四.HttpServletResponse 对象
1.开场白
Web 服务器收到客户端的 http 请求,会针对每一次请求,分别创建一个用于代表请求的 request 对象和代表响应的 response 对象。
request 和 response 对象代表请求和响应:获取客户端数据,需要通过request 对象; 向客户端输出数据,需要通过 response 对象。
HttpServletResponse 的主要功能用于服务器对客户端的请求进行响应,将Web 服务器处理后的结果返回给客户端。 service()方法中形参接收的是HttpServletResponse 接口的实例化对象,这个对象中封装了向客户端发送数据、发送响应头,发送响应状态码的方法。
2.对象个人show时间
个人小星星:setContentType(Sreing ContenType)
package com.shsxt.web;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@SuppressWarnings("serial")
public class Servlet01 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 添加指定的响应头 addHeader在设置响应头时,如果响应头已存在,不改变原来的响应头的值,会再次添加一个信息
resp.addHeader("uname", "zhansgan");
//resp.addHeader("uname", "zs");
// 设置指定响应头 setHeader在设置响应头时,如果响应头已存在,会将原来的响应头覆盖
resp.setHeader("uname", "lisi");
// refresh 自动跳转或刷新页面
// resp.setHeader("refresh", "3;url=http://www.shsxt.com");
// 设置一个错误状态码
// resp.sendError(404);
// 设置一个错误状态码和错误信息
// resp.sendError(404,"由于颜值过低,无法访问!");
// 设置响应的MIME类型
//resp.setHeader("content-Type", "text/html;charset=UTF-8");
// 两种流互斥,不能同时使用
// 字符输出流
/*PrintWriter pw = resp.getWriter();
pw.write("<h1>Hello World!</h1>");
pw.write("<h2>Hello World!</h2>");
pw.close();
*/
/*resp.setCharacterEncoding("UTF-8");
resp.setHeader("content-Type", "text/html");*/
// 设置响应类型和编码
resp.setContentType("text/html;charset=UTF-8");
// 字节输出流
ServletOutputStream out = resp.getOutputStream();
out.write("<h1>Hello World!</h1>".getBytes());
out.write("<h1>你好!</h1>".getBytes());
out.close();
}
}
3. 刷新和页面自动跳转
a.所有头信息都是随着请求和回应自动发送到服务器端(客户端),在response 中一个比 较常用的头信息就是刷新的指令,可以完成定时刷新的功能。
resp.setHeader("refresh","2");
b.对于刷新的头信息,除了定时的功能外,还具备了定时跳转的功能,可以让一个页面定时跳转到一个指定的页面。 (已经注册成功,两秒后跳转到登陆页面)
response.setHeader("refresh","3;URL=ok.html");
c.但是这种跳转不是万能的,有时候根本就无法进行跳转操作,返回后刷新不会跳转;对于这种定时跳转的头信息,也可以采用 HTML 的方式进行设置, HTML本身也可以设 置头信息。 (客户端跳转).
4. 数据响应
接收到客户端请求后,可以通过 HttpServletResponse 对象直接进行响应,响应时需要获取输出流,有两种形式 getWriter()获取字符流(只能响应回字符);getOutputStream()获取字节流(能响应一切数据)。响应回的数据到客户端被浏览器解析。 注意:两者不能同时使用。
5. 乱码解决
a.getWriter()的字符乱码
对于 getWriter()获取到的字符流,响应中文必定出乱码,由于服务器端在进行编码时默认会使用 ISO-8859-1 格式的编码,该编码方式并不支持中文。所以要解决该种乱码只能在服务器端告知服务器使用一种能够支持中文的编码格式,比如我们通常用的“UTF-8” resp.setCharacterEncoding("UTF-8");,此时还只完成了一半的工作,要保证数据正确显示,还需要指定客户端的解码方式resp.setHeader("content-type", "text/html;charset=UTF-8");,和服务器一致。两端指定编码后,乱码就解决了。 一句话: 保证发送端和接收端的编码一致.
以上两端编码的指定也可以使用一句替代,同时指定服务器和客户端
resp.setContentType("text/html;charset=utf-8");
b.getOutputStream()字节乱码
对于 getOutputStream()方式获取到的字节流,响应中文时,由于本身就是传输的字节, 所以此时可能出现乱码,也可能正确显示.无论如何我们都应该准确掌握服务器和客户端使用的是那种编码格式,以确保数据正确显示。 指定客户端和服务器使用的编码方式一致即可 。
同样也可以使用一句替代
resp.setContentType("text/html;charset=utf-8");
总结: 要想解决响应的乱码,只需要保证使用支持中文的编码格式。并且保证服务器端 和客户端使用相同的编码方式即可。
6. 响应图片
值得注意的是,在客户端解析资源时默认是以文本(text/html)的形式,当响应图片时 需要指定响应头信息,告知客户端响应内容为图片形式,使用一种叫做 MIME 类型的东西来指定。 MIME 类型见 Tomcat 的 web.xml 文件。
定义某一个扩展名和某一个 MIME Type 做对应,包 含两个子元素:
<extension></extension> 扩展名的名称
<mime-type></mime-type> MIME 格式
package com.shsxt.web;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@SuppressWarnings("serial")
public class Servlet02 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置图片的响应类型
resp.setContentType("image/jpeg;charset=UTF-8");
// 得到服务器的真实路径
String realPath = req.getServletContext().getRealPath("/");
System.out.println(realPath);
// 得到图片的路径
String filePath = realPath + "service.jpg";
// 通过图片路径得到file对象
File file = new File(filePath);
// 判断file对象是否存在,并且是一个标准文件
if (file.exists() && file.isFile()) {
// 得到输出流
ServletOutputStream out = resp.getOutputStream();
// 得到file对象的输入流
InputStream in = new FileInputStream(file);
byte[] bytes = new byte[1024];
int len = 0;
while((len = in.read(bytes)) != -1) {
out.write(bytes, 0, len);
}
in.close();
out.close();
} else {
resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().write("<h1>文件不存在!</h1>");
}
}
}
7. 重定向跳转
重定向是一种服务器指导,客户端的行为。客户端发出第一个请求,被服务器接收,经过处理服务器进行响应,与此同时,服务器给客户端一个地址(下次请求的地址 resp.sendRedirect("url");),当客户端接收到响应后, 立刻、马上、自动根据服务器 给的地址进行请求的发送第二个请求,服务器接收请求并作出响应,重定向完成。从描述中可以看出重定向当中有两个请求存在,并且属于客户端行为。 实现方式如下:
请求转发和重定向比较:
package com.shsxt.web;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@SuppressWarnings("serial")
public class Servlet03 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Servlet03...");
// 重定向跳转
/**
* 1、地址栏的路径会发生改变
* 2、重定向存在两次请求,request作用域只在一次请求中有效,重定向后request作用域失效
* 3、重定向时/代表的含义:http://localhost:8080
* 4、可以重定向到任何地址
*/
req.setAttribute("uname", "zhangsan");
//req.getRequestDispatcher("s04").forward(req, resp);
// 如果同时设置了两个跳转 java.lang.IllegalStateException: Cannot call sendRedirect() after the response has been committed
// resp.sendRedirect("s04");
//resp.sendRedirect("/sr04/s04");
// resp.sendRedirect("http://localhost:8080/sr04/s04");
resp.sendRedirect("http://www.baidu.com");
// resp.sendRedirect("/s04"); // HTTP Status 404 - /s04
}
}
五.请求时的路径问题
相对路径:
书写路径时,无论是哪类请求相对路径都是相对当前资源的路径书写格式 : 直接 从 当前路径 开始写 , 目录前不 加任何 符 号 ; a.html, html/b.html“/”代表的是 http://主机|IP:端口/站点名
绝对路径:
使用绝对路径时则有两种方式,以 http://开头,或者以/开头,但是注意:只有客户端跳转才能使用 http://这种方式, 此时需要写出资源的完整路径;另一种以/开头的绝对路径,则是绝对到端口后,例如本机则是: http://localhost:8080此时则是 / 代表以上一串字符。 /helloworld/a.html http://localhost:8080/helloworld/a.html
现在对于我们来说,只有请求转发属于服务器跳转,其他都是客户端跳转。通过观察地址栏状态也可判定跳转类型(请求类型),地址栏不变服务器端跳转;地址栏改变客户端跳转。
六.乱码问题总结
字符集过滤器
请求乱码:
GET请求 POST请求
Tomcat8及以上版本 不会乱码,不需要处理 会乱码,需要处理
request.setCharacterEncoding("UTF-8");
Tomcat7及以下版本 会乱码 会乱码 request.setCharacterEncoding("UTF-8");
new String(request.getParameter(name).getBytes("ISO-8859-1"),"UTF-8")(通用)
响应乱码:
response.setContentType("text/html;charset=UTF-8")