目标
- 请求对象Request
- 响应对象Response
- 转发与重定向
- ServletContext
- 域对象
request是在创建Servlet实例时由Tomcat容器自动创建并交给Servlet的service方法,从而为我们提供请求服务。
ServletRequest 接口
↑继承
HttpServletRequest 子接口
接收客户端的请求,获取请求中的信息。除了可以获取请求中携带的数据之外,还可以获取比如主机地址、端口、请求方式、项目名称等一系列信息。
请求分类:
请求行、请求头、请求体。
1.请求行
请求行中,我们可以通过request对象的相应方法获取到比如协议名、服务名、端口号、项目名称、请求方式、参数列表等信息。
http
localhost
8080
get/post
get:url?name=zhangsan&age=23
post:form data 打包数据
http://localhost:8080/day12/reqline
案例:
package com.ujiuye.servlet;
import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/reqline") public class ReqLineServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取请求行的信息 String scheme = req.getScheme(); System.out.println(scheme);//http String serverName = req.getServerName();//localhost int serverPort = req.getServerPort();//8080 String contextPath = req.getContextPath();//day12 System.out.println(serverName+"==="+serverPort+"===="+contextPath); //动态拼接服务器地址 String url = scheme+"://"+serverName+":"+serverPort+contextPath; System.out.println(url);
//请求方式 String method = req.getMethod();//get/post String queryString = req.getQueryString();//name=zhangsan&age=23&sex=1 System.out.println(method+"====="+queryString); } } |

2.请求头
请求头是当前对用户发送的数据的描述信息。
请求头信息在请求的时候不需要程序员手动添加,是浏览器发送的时候已经处理好的。
如果想查看请求头信息,也可以在Servlet中通过getHeader方法获取。

方法名 | 描述 |
String getHeader(String name) | 根据请求头的名称获取请求头信息 |
Enumeration getHeaderNames() | 返回此请求包含的所有头名称的枚举 |
案例:


3.请求体
请求体就是请求中携带的数据,也就是我们需要获取的参数。
获取请求参数的方法:
方法名 | 描述 |
String getParameter(String name) | 根据参数名获取参数值 |
String[] getParameterValues(String name) | 根据参数名获取参数值(可以是多个值) |
Map<String,String[]> getParameterMap() | 获取所有参数的map集合 |
案例1:getParameter和getParameterValues
package com.ujiuye.servlet;
import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/reqbody") public class ReqBodyServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //处理中文乱码问题 //1.请求乱码 req.setCharacterEncoding("utf-8"); //2.响应乱码 resp.setContentType("text/html;charset=utf-8"); //获取页面提交的数据 String sname = req.getParameter("sname"); String sex = req.getParameter("sex"); String age = req.getParameter("age"); String degree = req.getParameter("degree"); //由于复选框可以选多个值,所以这里用返回数组方法 String[] hobbies = req.getParameterValues("hobby"); String mark = req.getParameter("mark"); System.out.println(sname); System.out.println(sex); System.out.println(age); System.out.println(degree); System.out.println(mark); System.out.println("===================================="); for (String hobby : hobbies) { System.out.println(hobby); } } } |
案例2:getParameterMap
Map<String, String[]> map = req.getParameterMap(); Set<String> keys = map.keySet(); for (String key : keys) { System.out.println(key); } System.out.println("===================================="); for (String key : keys) { System.out.println(key+"-----"+ Arrays.toString(map.get(key))); } |
4.乱码处理
Get:
默认编码编码类型是:Tomcat8之前的版本,默认编码格式是iso-8859-1,从Tomcat8版本之后默认编码改为UTF-8,所以如果是Tomcat8及以上版本就不需要进行转码处理,如果是Tomcat7及之前版本可以使用以下方法进行转码:
String name = request.getParameter("name");
String encodingName=new String(name.getBytes("iso-8859-1"),"utf-8");
Post:
支持多种编码类型,application/x-www-form-urlencoded 或 multipart/form-data。可以使用以下方法进行转码:
request.setCharacterEncoding("utf-8");
在这里顺便说一下响应的乱码处理方法,后面我们还会详细讲解:
response.setContentType("text/html;charset=utf-8");
response.setContentType(“image/jpeg");
response是在创建Servlet实例时由Tomcat容器自动创建并交给Servlet的service方法,从而为我们提供响应服务。
ServletResponse 接口
↑继承
HttpServletResponse 子接口
针对页面发送的请求做出数据响应,向页面输出信息,包括文本、图片、视频等。
响应分类:
响应行、响应头、响应体。
1. 响应行
响应行中包含的信息:可以通过开发者模式F12-Network查看

由上图可知, 响应行中包含协议和状态码
1)HTTP协议
HTTP/1.1 表示使用的是HTTP协议,且版本号为1.1
HTTP协议的特点:
1.简单快速。客户端向服务器请求服务时,只需要传送请求方法和路径。
2.灵活。HTTP协议允许传送任意格式的数据。正在传输的类型由,content-type标明。
3.无状态。是指协议对于每次请求的处理没有记忆能力,它不知道之前是否已经访问过,不保留访问痕迹。主要目的是为了保证数据传输的安全性。
HTTP的版本:
0.9版本:只能传输一些简单的文本信息。
1.0版本:该协议对每一次请求/响应建立并拆除一次连接。短连着,每一次请求和响应结束后,连接状态断开。

1.1版本:由于1.0版本是短连接模式,每次请求响应结束后,连接就断开,所以速度比较慢的。1.1版本中做了一些改进,实现了长连接。

问题:如何(在什么情况下)断开长连接状态?
能过设置过期时间来自动关闭。

2.0版本:解决了1.1.版本中一次请求必须等待响应结束后再次发出请求的问题,在2.0版本中一次可以发送多个请求,同时做出多个响应。
HTTPS 的全称是Hyper Text Transfer Protocol over Secure Socket Layer ,是以安全为目标的HTTP通道,简单的讲是HTTP的安全版本,即HTTP下加入SSL层,简称HTTPS。
2)状态码

几中常见的状态码:
200 表示响应成功
404 表示请求资源找不到
出现的原因:
1.浏览器访问路径错误
2.tomcat服务未开启,项目没有部署到tomcat服务器中
3.你要访问的页面资源在WEB-INF文件夹中,无法访问
500 表示服务器端代码出错,可以通过控制台查看异常消息。
2.响应头
当我们在浏览器中打开network工具时,每一次的请求响应数据,都可以被捕捉到,而在内容中Response Headers 中的内容就是当前这一次请求响应的响应头信息。


设置响应头信息可以通过以下两种方法:
response.setHeader("Content-Type", "text/html;charset=utf-8");
response.addHeader("Content-Type", "text/html;charset=utf-8");
response.setContentType("text/html;charset=utf-8");
二者的区别:
response.setHeader(String name, String value);一个关键字对应一个值,如果设置了多个值,则会覆盖。
response.addHeader(String name, String value);一个关键字可以对应多个值。
在实际开发中,同一个响应头信息只会对应一个值,所以在使用时一般没什么区别。
使用setHeader()设置效果:

使用addHeader()设置效果:


3.响应体
响应的数据就是响应体。响应对象response在返回数据、响应数据的时候,会将一些HTML、text、流数据等信息通过响应主体返回给页面,而响应体绝大多数都是文本类型。
响应数据需要通过流来进行数据传输,而response自带的流有两个:
response.getWriter() ==> PrintWriter 输出文本信息的字符流
response.getOutputStream ==> ServletOutputStream 输出字节信息,比如图片、音频、视频
注意:这两个流不能同时存在。
响应一个表格到页面:

代码:
package com.ujiuye.servlet;
import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter;
@WebServlet("/respbody") public class RespBodyServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=utf-8"); //resp.getWriter().print("今天天气不错"); //响应表格 PrintWriter out = resp.getWriter(); out.print("<table border='1px' width='400px'><tr><th>姓名</th><th>年龄</th><th>性别</th></tr>"); out.print("<tr><td>张三</td><td>23</td><td>男</td></tr>"); out.print("<tr><td>李四</td><td>24</td><td>男</td></tr>"); out.print("<tr><td>王五</td><td>24</td><td>女</td></tr>"); out.print("</table>"); } } |
(一)转发与重定向原理
转发和重定向是实现页面间跳转的主要方式。
具体实现方式:
请求转发:request.getRequestDispatcher("url").forward(request, response);
重定向:response.sendRedirect("url");
请求转发的原理:
转发是服务器行为,对于客户端来讲并不知道在服务器端经历了几次处理后才返回的结果,所以客户端地址栏不会发生改变,转发是在一次请求范围内,所以请求域request的信息是可以共享的。

重定向的工作原理:
重定向是客户端行为,当客户端浏览器向AServlet发送一个请求,经过处理后向客户端做出响应,这个响应就是向服务器再次发送新的请求,去请求BServlet,而这个新请求的地址将为浏览器做出第二次响应,此时浏览器地址栏会发生改变,由于一次请求/响应结束后,request对象会自动销毁,所以两次请求的request对象并非同一个,所以两次请求域中的数据信息不会共享。由此可见,重定向是做了两次请求和响应。

(二)转发与重定向区别【面试题】
1、发生位置不同,转发是在服务器行为,重定向是客户端行为
2、转发浏览器地址栏不发生改变,重定向地址栏变
3、转发是一次请求一次响应,重定向至少是两次请求两次响应
4、转发时request作用域的数据可共享,而重定向时request作用域的数据不能共享
5、跳转语句不同:
(1)转发:request.getRequestDispatcher("url").forward(request, response);
(2)重定向:response.sendRedirect("url");
6、转发速度要高于重定向,因为是在服务器内部完成
7、转发的url一定是本web应用范围内,而重定向可以是任意url。
(一)概述
当 Tomcat 启动时,Tomcat 会为每个 Web 应用创建一个唯一的 ServletContext 对象代表当前的 Web 应用,该对象封装了当前 Web 应用的所有信息。可以利用该对象获取整个Web 应用程序的初始化信息、读取资源文件等。它与Servlet是一对多的关系,其内部封装的信息可以被同一web应用内的所有Servlet共享。
获取方式两种:
1. request.getServletContext();
2. this.getServletContext();
1.获取MIME类型
MIME类型:
在互联网中通信过程中定义的一种文件数据类型
格式:
大类型/小类型 如 text/html text/xml image/jpeg image/png
获取方法:
String getMimeType(String file)
2.获取文件的真实路径
获取文件的真实路径方法:
getRealPath("web下的资源路径"); getRealPath(“source/face5.jpg”)
获取资源路径并转化成流:
InputStream is = getResourceAsStream("source/a.jpg");
案例:
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取ServletContext对象 ServletContext context = this.getServletContext(); //获取文件的mime类型 String mimeType = context.getMimeType("a.jpg"); System.out.println(mimeType); //获取资源的真实路径 String realPath = context.getRealPath("source/face5.jpg"); System.out.println(realPath); //获取资源对应的输入流对象 URL url = context.getResource("source/face5.jpg"); System.out.println(url); InputStream is = context.getResourceAsStream("source/face5.jpg"); System.out.println(is); } |

域对象:有作用域的对象就是域对象。域对象可以用来存值并在不同组件(serlvet/jsp)之间进行传递,域对象限制了数据的访问范围,其值会随着对象的消失而消失。Servlet中提供了两个域对象:
1、request 作用域的值是在一次请求范围内有效(周期短)。
2、ServletContext是一个全局作用域对象,在整个Web应用内都有效(周期长)。
作用域对象有三个方法:
setAttribute(String,object) 向域对象中存值
getAttribute(“name”) 根据name获取值
removeAttribute(“name”) 根据name移除
总结:request作用域仅限于一次请求范围内可以实现信息的共享,一次请求结束,request对象消失,内部的值也随之消失,周期短,但效率高,不会占用过多的内存资源;而ServletContext是一个全局作用域对象,整个web项目的所有组件(Servlet、jsp)共享信息,周期长,可用来保存所有web组件之间需要共享的信息。它在tomcat服务器启动时创建,关闭时销毁。
(1)使用a标签可以下载文件,但具有局限性,如果能被浏览器识别的文件格式会直接打开显示,如果浏览器无法识别,则进行下载。

- 后台下载
分析:
- 从服务器上使用流读到计算机内存 inputStream
- 从计算机内存写到本地 outputStream

重点:设置响应头Content-Disposition,以附件的形式下载,并指导下后文件名。
response.setHeader("Content-Disposition", "attachment;filename=" + filename);
package com.ujiuye.servlet;
import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream;
@WebServlet("/download") //在 html 里 href 里?前的地址值 public class DownLoadServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1.获取文件名 String filename = req.getParameter("filename"); //2.设置响应头 resp.setHeader("content-disposition","attachment;filename="+new String(filename.getBytes("utf-8"),"iso-8859-1")); //3.创建文件输入流 InputStream is = req.getServletContext().getResourceAsStream("source/"+filename); //4.创建文件输出流 ServletOutputStream os = resp.getOutputStream(); //5.读写文件过程 byte []data = new byte[1024]; int len = -1; while ((len = is.read(data))!=-1){ os.write(data,0,len); } //6.关闭流 is.close(); os.close(); } } |
解决中文文件名问题:

- 创建学生表的javabean

- dao层创建StudentDao继承BaseDao
package com.ujiuye.dao;
import com.ujiuye.bean.Student;
public class StudentDao extends BaseDao<Student> { //添加方法 public int addStudent(Student student){ String sql = "INSERT INTO student(sname,sex,age,degree,pic,mark)VALUES(?,?,?,?,?,?)"; return myupdate(sql,student.getSname(),student.getSex(),student.getAge(),student.getDegree(),student.getPic(),student.getMark()); } } |
- 在service层创建StudentService

- servlet中创建StudentServlet
package com.ujiuye.servlet;
import com.ujiuye.bean.Student; import com.ujiuye.service.StudentService;
import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter;
@WebServlet("/student") public class StudentServlet extends HttpServlet { private StudentService ss = new StudentService(); @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //处理乱码 req.setCharacterEncoding("utf-8"); resp.setContentType("text/html;charset=utf-8"); //获取页面传递过来数据 String sname = req.getParameter("sname"); String sex = req.getParameter("sex"); String age = req.getParameter("age"); String degree = req.getParameter("degree"); String pic = req.getParameter("pic"); String mark = req.getParameter("mark"); //封装学生对象 Student stu = new Student(sname,sex,Integer.parseInt(age),degree,pic,mark); //调用service层的添加方法 int row = ss.addStudent(stu); PrintWriter out = resp.getWriter(); //判断 if(row > 0){ out.print("添加成功"); }else{ out.print("添加失败"); } } } |
页面addstudent.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>添加学员</title> <style> span{ color: red; font-size: 12px; } </style> </head> <body> <form id="login" action="student" method="POST"> <table border="1px" cellpadding="10px" cellspacing="0" align="center" width="500px"> <caption><h2>添加新学员</h2></caption> <tr> <td>姓名</td> <td> <input type="text" name="sname"> </td> </tr> <tr> <td>性别</td> <td> <input type="radio" name="sex" value="男" checked>男 <input type="radio" name="sex" value="女">女 </td> </tr> <tr> <td>年龄</td> <td> <input type="text" name="age"> </td> </tr> <tr> <td>学历</td> <td> <select name="degree"> <option value="0">==请选择==</option> <option value="专科">专科</option> <option value="本科">本科</option> <option value="硕士">硕士</option> <option value="博士">博士</option> </select> </td> </tr> <tr> <td>头像</td> <td> <input type="file" name="pic"> </td> </tr> <tr> <td>备注</td> <td> <textarea name="mark" rows="4" cols="40"></textarea> </td> </tr> <tr align="center"> <td colspan="2"> <input type="submit" value="添加"> <input type="reset" value="取消"> </td> </tr> </table> </form> </body> </html> |
注意:

