一.Servlet生命周期
- 初始化
- 提供服务
- 销毁
1.测试生命周期
Java
package com.demo.servlet;
import javax.servlet.*;
import java.io.IOException;
public class LifeServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("Servlet init");
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException {
System.out.println("Servlet service");
}
@Override
public void destroy() {
System.out.println("Servlet destroy");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public String getServletInfo() {
return null;
}
}
2.初始化:init()
(1)默认情况
- 默认情况下,第一次被请求的时候初始化,初始化在整个生命中只有一次
(2)设置初始化时间
-
某种原因,导致第一次请求时初始化很慢,这时就可以修改Servlet的初始化时间
-
使用其值为大于等于0的整数时,该Servlet就会在服务器启动时初始化,初始化在整个生命中只有一次
3.提供服务:service()
- 生命周期中会提供n次
4.销毁:destroy()
- 服务器关闭时自动销毁,生命周期中只有一次
二.Servlet的映射路径
1.web.xml配置
(1)标签
- 的子标签,用于给Servlet配置访问路径
(2)注意
- 路径最前面加上/,代表根目录
- 路径中可以出现文件夹的,如/user/test/urlServlet
(3)示例
- http://localhost:8888/day02_war_exploded/user/test/lifeServlet
- http://localhost:8888/day02_war_exploded/user/life.html
2.模块前端文件的访问路径
- 访问文件时,只需要关注自己创建的目录,自动生成的不管
- 访问Servlet时,照着url-pattern设置的值来找
3.Servlet3.0注解配置
(1)使用前提
- Servlet3.0和JDK1.5及以后的版本才能使用
(2)使用
(3)注意
-
同一个Servlet,要么使用web.xml文件配置,要么使用注解配置,但是不能使用两种方式同时配置
-
注解中的参数有name、serviceName;若是只写name参数,可以省略key值,只写value;除此之外要写key-value的形式
三.Servlet请求对象
1.HttpServletRequest接口
- 请求对象
- 父接口:ServletRequest
- 包含请求行,请求头和请求体
2.请求行
(1)包含
- 请求方式
- 请求的资源
- 协议及其版本
(2)获取信息
Java
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println(req.getMethod());
System.out.println(req.getRequestURL());
System.out.println(req.getRequestURI());
System.out.println(req.getServerName());
System.out.println(req.getServerPort());
}
3.请求头
(1)获取信息
Java
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String value1 = req.getHeader("Host");
System.out.println(value1);
Enumeration<String> names = req.getHeaderNames();
while (names.hasMoreElements()) {
String name = names.nextElement();
String value = req.getHeader(name);
System.out.println(name+":"+value);
}
}
4.请求体
- 就是请求的数据,也就是Servlet中获取的参数
(1)Servlet中获取请求的数据的方法
- request.getParameter("name属性的值");返回值类型为String
- request.getParameterValues("name属性的值");返回值类型为String[]
(2)示例
Java
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
String gender = req.getParameter("gender");
String hobbies[] = req.getParameterValues("hobbies");
System.out.println(username+","+password+","+gender+","+ Arrays.toString(hobbies));
}
5.Servlet获取参数乱码问题
(1)问题
- 中文乱码,Servlet的默认编码集是ISO-8859-1(纯英文)
- 页面输入中文进行提交,会乱码
(2)解决方案
四.文件上传
- 就是在指定的位置复制出一个跟源文件一模一样的文件
1.页面编写
- 表单的method属性的值必须是pos
- 表单上加上enctype,值为multipart/form-data
2.Servlet
- 在Servlet上加上@MultipartConfig
3.Post方法编写
- 不同浏览器上传文件的路径不一样
- 绝对路径(不带盘符)
- 文件名+文件类型后缀
Java
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//设置请求体编码集
req.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
String gender = req.getParameter("gender");
String hobbies[] = req.getParameterValues("hobbies");
System.out.println(username+","+password+","+gender+","+ Arrays.toString(hobbies));
//文件相关处理
//获取用户提交的文件对象
Part part = req.getPart("photo");
//指定上传路径
String path = "d://upload";
//判断该路径是否存在
File file = new File(path);
if (!file.exists()) {
//不存在则创建
file.mkdirs();
}
//获取上传的文件的名字
String fileName = part.getSubmittedFileName();
//在指定位置创建指定文件
part.write(path+"/"+fileName);
}
五.Servlet响应对象
1.HttpServletResponse接口
- 服务器响应对象
- 父接口:ServletResponse
- 包含响应行,响应头和响应体。
2.响应行
- 包含协议及其版本,状态码
(1)状态码
状态码 | 说明 |
---|---|
1** | 请求已到达服务器,但未完成,需要再次请求 |
2** | 请求已到达服务器,并且已完成 |
3** | 服务器内部资源重定向 |
4** | 资源找不到 |
5** | 服务器内部异常,代码异常 |
200 | 成功 |
404 | 找不到,原因:路径有问题 |
500 | 代码有问题,90%以上都是空指针 |
(2)设置状态码
Java
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setStatus(404);
}
3.响应头
响应头key | value |
---|---|
Location | 这个头通常配合302状态码使用,它用于告诉浏览器你去找谁。 |
Server | 告诉浏览器,服务器的类型 |
Content-Encoding | 服务器通过这个头,告诉浏览器,回送的数据采用的压缩格式。 |
Content-Length | 0 |
Content-Language | zh-cn |
Content-Type | 这个头用于告诉浏览器,回送数据的类型 |
Last-Modified | 这个头用于告诉浏览器,数据的最后修改时间 |
Transfer-Encoding | 用于通知浏览器,数据是以分块形式回送的 |
Cache-Control | no-cache 通知浏览器不要缓存 |
Refresh | 1;url=http://www.it315.org 隔多少秒以后,让当前页面去访问哪个地址(例如网页登陆成功后,跳回原来的界面,就是用的这个头) |
Content-Disposition | attachment;filename=aaa.zip 和下载相关,通知浏览器以附件的形式下载服务器发送过去的数据 |
Set-Cookie | SS=Q0=5Lb_nQ; path=/search 和cookie相关的头 |
ETag | W/"83794-1208174400000" 和cookie相关的头 |
Expires | -1 通知浏览器是否缓存当前资源:如果这个头的值是一个以毫秒为单位值,则通知浏览器缓存资源到指定的时间点;如果值是0或-1,则通知浏览器禁止缓存 |
Pragma | no-cache 通知浏览器是否缓存资源 |
Connection | close/Keep-Alive 是否继续保持连接 |
Date | Tue, 11 Jul 2000 18:23:51 GMT 当前响应的时间 |
(1)Location的使用
java
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setStatus(302);
resp.setHeader("location","http://www.baidu.com");
}
(2)Refresh的使用
Java
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setHeader("refresh","2;url=http://www.qidian.com");
}
4.响应体
- 响应的数据,会将HTML,text等信息返回给客户端。
(1)响应数据传递方式
- 响应数据需要通过流来传递,response自带两个输出流
- 这两个流不能同时使用
Java
ServletOutputStream out = response.getOutputStream();//字节流
PrintWriter out = response.getWriter();//字符流
(2)示例
Java
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.print("<h1>今天天气不错</h1>");
out.close();
}
六.文件下载
1.创建下载文件的页面
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="responseServlet">下载</a>
</body>
</html>
2.添加测试图片操作
-
去除原来的 exploded
-
重新添加exploded
3.Servlet编写代码
- 下载的源文件直接放在src目录下
Java
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//告诉浏览器,以附件的形式打开数据
resp.setHeader("Content-Disposition","attachment;filename=erha.png");
//输入流读取文件
//this.getClass().getClassLoader().getResourceAsStream("gouza.png")用于快速的获取src当中问文件对象流
InputStream in = this.getClass().getClassLoader().getResourceAsStream("gouza.png");
//输出流写文件
ServletOutputStream out = resp.getOutputStream();
//边读边写
byte[] b = new byte[1024];
int len = 0;
while ((len = in.read(b)) != -1) {
out.write(b,0,len);
}
out.close();
in.close();
}
七.请求转发与重定向
1.Servlet进行跳转的方式
跳转方式 | 方法 |
---|---|
请求转发 | request.getRequestDispatcher("跳转的文件路径").forward(request,response); |
重定向 | response.sendRedirect("跳转的文件路径"); |
2.请求转发
(1)请求转发概述
- 服务器行为,客户端不知道整个操作在服务器中到底处理了多少次,所以地址栏不会发生改变
- 整个过程中只发送了一个请求,所以request对整个转发过程中所有的Servlet是共享的
- 请求转发的是那种数据提交方式,那么第二个servlet也是该方式,出form表单和超链接
(2)创建FirstServlet
Java
package com.demo.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("/firstServlet")
public class FirstServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("进入FirstServlet");
req.setAttribute("color","red");
System.out.println(req.getAttribute("color"));
req.getRequestDispatcher("secondServlet").forward(req,resp);
}
}
(3)创建SecondServlet
Java
package com.demo.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("/secondServlet")
public class SecondServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("进入SecondServlet");
System.out.println(req.getAttribute("color"));
}
}
(4)index.html,点击测试跳转
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="firstServlet">测试请求转发</a>
</body>
</html>
(5)结果
3.重定向
(1)重定向概述
- 客户端行为,客户端向FirstServlet发送请求,FirstServlet给了客户端响应告诉客户端去找SecondServlet,客户端向SecondServlet发送请求
- 地址栏会变,request不共享
(2)创建FirstServlet
Java
package com.demo.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("/firstServlet")
public class FirstServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("进入FirstServlet");
req.setAttribute("color","red");
System.out.println(req.getAttribute("color"));
resp.sendRedirect("secondServlet");
}
}
(3)创建SecondServlet
Java
package com.demo.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("/secondServlet")
public class SecondServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("进入SecondServlet");
System.out.println(req.getAttribute("color"));
}
}
(4)测试
4.请求转发与重定向的区别
请求转发 | 重定向 | |
---|---|---|
发出位置 | 服务器行为 | 客户端行为 |
地址栏内容 | 地址栏不会发生改变 | 地址栏会发生改变 |
请求次数 | 只有一次请求 | 至少两次请求 |
request共享 | equest是共享的 | request不共享的 |
转发效率 | 高 | 较低 |
发送范围 | 只能在当前模块中进行 | 可以跳转到其他模块的作用域容器对象:作用域里面的作为容器的对象 |
--------------------------------------------------------: |
| 发出位置 | 服务器行为 | 客户端行为 |
| 地址栏内容 | 地址栏不会发生改变 | 地址栏会发生改变 |
| 请求次数 | 只有一次请求 | 至少两次请求 |
| request共享 | equest是共享的 | request不共享的 |
| 转发效率 | 高 | 较低 |
| 发送范围 | 只能在当前模块中进行 | 可以跳转到其他模块的作用域容器对象:作用域里面的作为容器的对象 |