文章目录
- JavaWeb - 02
- 一、Servlet
- 1. 简介
- 2. HelloServlet
- 3. Servlet 原理
- 4. Mapping 原理
- 二、ServletContext
- 1. 共享数据
- 2. 获取初始化参数
- 3. 请求转发
- 4. 读取资源文件
- 三、HttpServletResponse
- 1. 方法介绍
- 2. 应用:下载文件
- 3. 应用:创建验证码
- 4. 应用:重定向
- 5. 总结
- 四、HttpServletRequest
- 1. 获取前端传递的参数
- 2. 请求转发
- 注意:
JavaWeb - 02
一、Servlet
1. 简介
Servlet 是 Sun 公司开发动态 Web 的一门技术,在这些 API 中提供了一个接口就是:Servlet,开发一个 Servlet 程序需要两个步骤:
- 编写一个类,实现 Servlet 接口;
- 把开发好的 java 类部署到 Web 服务器中。
把实现了 Servlet 接口的 Java 程序叫做 Servlet。
2. HelloServlet
- 创建一个普通的 Maven 项目,注意在
Settings
中修改 Maven 地址,并删除src
文件夹。
- 在 pom 文件中导入用到的 jar 包
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
</dependency>
注意:在 Maven 仓库中下载,
groupId
为路径,artifactId
为 jar 包名,version
为版本。
- 建立 Module 模块(子项目)
注意:父项目中的 jar 包,子项目可以直接使用。
- Maven 环境优化(2 步)
第一步:修改子项目中 webapp.WEB-INF
中的 web.xml
配置文件(可以用 apache-tomcat-8.5.85\webapps\ROOT\WEB-INF
中的 web.xml
配置文件替换),修改原因:因为是直接用 Maven 模板,版本太低,用新版本。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"
metadata-complete="true">
</web-app>
第二步:将 Maven 的结构搭建完整:在子项目的 main
中建立 java
以及 resources
文件夹,并标记功能。
- 编写一个 Servlet 程序(3 步)
第一步:刷新子项目的 pom.xml
文件,可以创建一个新的 Servlet,并重写 doPost 和 doGet 方法。
public class HelloServlet extends HttpServlet {
// 由于 get 或者 post 都是请求实现的不同方式,可以相互调用,业务逻辑都一样
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter writer = response.getWriter(); // 响应流
writer.println("Hello, Servlet!");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
注意:由于 get 或者 post 都是请求实现的不同方式,可以相互调用,业务逻辑都一样。
第二步:在 web.xml
中编写 Servlet 的映射,因为我们写的是 Java 程序,但是要通过浏览器访问,而浏览器需要连接 Web 服务器,所以我们需要在 Web 服务器中注册我们写的 Servlet,给一个浏览器能够访问的路径。
<!-- 注册 Servlet -->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.Sun3285.servlet.HelloServlet</servlet-class>
</servlet>
<!-- Servlet 的请求路径 -->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
注意:
- servlet-name 可以随便起,但上下要一致;
- servlet-class 是在 Web 服务器中注册我们写的 Servlet(Web 服务器 – Java 程序);
- url-pattern 是 Servlet 的请求路径,浏览器连接 Web 服务器(Web 服务器 – 浏览器)。
第三步:配置 Tomcat:注意配置项目发布的路径。
- 启动测试
注意:请求
s1
进入主页index.jsp
,再请求/hello
进入web.xml
中找url-pattern > servlet-name > servlet-class
,然后进入自己编写的 Java 程序HelloServlet.java
。
3. Servlet 原理
Servlet 原理(Web 服务器 – Java 程序实现的过程)
Web 服务器在收到浏览器请求之后,会进行如图所示过程。
注意:自己的实现类重写方法作用:
- 接受并处理请求;
- 给出响应的信息。
4. Mapping 原理
- 一个 Servlet 的请求可以指定一个或多个映射路径。
<!-- 映射路径 hello1 和 hello2 都对应同一个 Servlet 的请求 -->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
- 一个 Servlet 的请求可以指定通用映射路径。
<!-- 用通配符 * -->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
注意:指定了固有的映射路径优先级最高,如果找不到就会走通用的映射路径。
- 可以自定义后缀实现请求映射。
<!-- 用通配符 * -->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>*.Sun3285</url-pattern>
</servlet-mapping>
注意:此时在 mapping 中
*
前面不能加项目映射的路径/
,如:/hello/*.Sun3285
,而/hello.Sun3285
是正确的。
二、ServletContext
Web 在启动时,会为每个 Web 程序都创建一个对应的 ServletContext 对象,代表了当前的 Web 应用。
注意:每个 Web 工程只有一个 ServletContext 对象,可以有多个 Servlet。
1. 共享数据
在 Servlet 中保存的数据,可以在另外一个 Servlet 中拿到。
方法名 | 说明 |
---|---|
void setAttribute(String var1, Object var2) | 以键值对的形式保存数据 |
Object getAttribute(String var1) | 根据键获取数据 |
- 放置数据的类
ServletContext context = this.getServletContext();
String name = "Sun3285"; // 数据
context.setAttribute("username", name); // 将数据保存在 ServletContext 中
- 读取数据的类
ServletContext context = this.getServletContext();
String name = (String) context.getAttribute("username");
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
response.getWriter().println("用户名为:" + name);
注意:放置数据和读取数据中得到的 ServletContext 对象为同一个。
- 映射
<servlet>
<servlet-name>setu</servlet-name>
<servlet-class>com.Sun3285.servlet.OneServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>setu</servlet-name>
<url-pattern>/setu</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>getu</servlet-name>
<servlet-class>com.Sun3285.servlet.TwoServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>getu</servlet-name>
<url-pattern>/getu</url-pattern>
</servlet-mapping>
- 测试访问结果:先进行 setu,再进行 getu
2. 获取初始化参数
方法名 | 说明 |
---|---|
String getInitParameter(String var1) | 获取初始化参数 |
注意:方法由 ServletContext 对象调用。
3. 请求转发
方法名 | 说明 |
---|---|
RequestDispatcher getRequestDispatcher(String var1) | 请求转发,参数为转发的请求路径,如 /hello |
例如:
// 请求转发
RequestDispatcher requestDispatcher = context.getRequestDispatcher("/hello");
requestDispatcher.forward(request, response); // 调用 forward 实现请求转发,最后结果为获取了 /hello 路径的内容
注意:请求转发与重定向区别。
- 相同点:页面都会实现跳转。
- 不同点:请求转发时,URL 不会产生变化,状态码为 307;重定向时,URL 会发生改变,状态码为 302。
4. 读取资源文件
方法名 | 说明 |
---|---|
InputStream getResourceAsStream(String var1) | 产生一个资源流 |
- 先准备一个 Properties 类型的文件
username = Sun3285
password = 123456
注意:
Properties
文件最好放在resources
目录下,最后生成在target
文件的classes
文件下;main
文件下的java
和resources
运行后都被打包到了同一路径下,即classes
,俗称类路径 classpath。
- 读取资源文件
ServletContext context = this.getServletContext();
InputStream is = context.getResourceAsStream("/WEB-INF/classes/aa.properties");
Properties prop = new Properties();
// 把要读取的属性文件以流的形式加载进去
prop.load(is);
String username = prop.getProperty("username"); // 获取属性
String password = prop.getProperty("password");
response.getWriter().println(username + " : " + password);
注意:读取资源文件需要一个文件流,用 ServletContext 对象来产生,其中路径是相对路径,从当前 Web 应用开始。
三、HttpServletResponse
Web 服务器接收到客户端的 Http 请求,针对这个请求,会分别创建一个代表客户端请求的 HttpServletRequest 对象和一个代表响应的 HttpServletResponse 对象。
- HttpServletRequest :获取客户端请求过来的参数;
- HttpServletResponse :给客户端响应的一些信息。
1. 方法介绍
HttpServletResponse 继承了 ServletResponse。
- 负责向浏览器发送数据的方法
ServletOutputStream getOutputStream() throws IOException;
PrintWriter getWriter() throws IOException;
- 负责向浏览器发送响应头的方法
void setCharacterEncoding(String var1);
void setContentLength(int var1);
void setContentLengthLong(long var1);
void setContentType(String var1);
void setDateHeader(String var1, long var2);
void addDateHeader(String var1, long var2);
void setHeader(String var1, String var2);
void addHeader(String var1, String var2);
void setIntHeader(String var1, int var2);
void addIntHeader(String var1, int var2);
- 设置响应的状态码
int SC_OK = 200;
int SC_NOT_FOUND = 404;
int SC_INTERNAL_SERVER_ERROR = 500;
int SC_BAD_GATEWAY = 502;
void setStatus(int var1);
HttpServletResponse 对象除了可以向浏览器输出消息外,还可以下载文件、创建验证码以及重定向。
2. 应用:下载文件
下载文件的步骤:
- 获取下载文件的路径和文件名;
- 设置让浏览器能够支持下载;
- 获取下载文件的输入流,创建缓冲区,文件拷贝。
// - 获取下载文件的路径和文件名
String realPath = "F:\\studying\\javastudy\\javaweb\\javaweb-03-servlet\\response\\src\\main\\resources\\涛涛.txt";
String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);
System.out.println("下载文件的路径为:" + realPath);
System.out.println("下载文件的名称为:" + fileName);
// - 设置让浏览器能够支持下载
response.setHeader("Content-Disposition","attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));
// response.setCharacterEncoding("utf-8");
// response.setContentType("text/html");
// - 获取下载文件的输入流,创建缓冲区,文件拷贝
InputStream is = new FileInputStream(realPath);
OutputStream os = response.getOutputStream();
InputStream bis = new BufferedInputStream(is);
OutputStream bos = new BufferedOutputStream(os);
byte[] buffer = new byte[1024];
int len;
while ((len = bis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
bos.flush();
}
bos.close();
bis.close();
注意:
realPath.substring(realPath.lastIndexOf("\\") + 1);
为获取文件名的常用方法;response.setHeader("Content-Disposition","attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));
是设置浏览器能够支持下载,后面的URLEncoder.encode(fileName, "utf-8")
可以使下载的文件名为 UTF-8 格式不乱码,如果没有这行代码,浏览器会直接显示文件内容,而不会下载;- 文件拷贝用字节缓冲输入流 + 字节缓冲输出流 + 以字节数组读取的组合;
- 这里的输出流是 response 得到的输出流。
3. 应用:创建验证码
创建验证码步骤:
- 在内存中创建一个图片;
- 告诉浏览器,这个请求用图片的方式打开;
- 把图片写给浏览器。
response.setHeader("refresh", "3"); // 刷新
// 在内存中创建一个图片
BufferedImage image = new BufferedImage(110, 30, BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D) image.getGraphics(); // 得到图片,g 相当于画笔
g.setColor(Color.green); // 设置图片的背景颜色
g.fillRect(0, 0, 110, 30);
g.setColor(Color.red); // 给图片写数字
g.setFont(new Font(null, Font.BOLD, 20)); // 粗体,字号 20
g.drawString(makeNum(),10,20); // 写入随机数
// 告诉浏览器,这个请求用图片的方式打开
response.setContentType("image/jpg");
response.setHeader("Cache-Control", "no-cache"); // 去除网站的缓存
response.setHeader("Pragma", "no-cache");
// 把图片写给浏览器
ImageIO.write(image, "jpg", response.getOutputStream());
生成 8 位随机数
// 生成 8 位的随机数
public String makeNum() {
Random r = new Random();
String num = String.valueOf(r.nextInt(99999999)); // 生成随机数
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 8-num.length(); i++) {
sb.append(r.nextInt(9));
}
String num1 = sb.toString(); // 补齐 8 位
return num + num1;
}
4. 应用:重定向
// 重定向
response.sendRedirect("/r/image");
注意:重定向的时候一定要注意路径问题,否则 404。
相当于
response.setHeader("Location", "/r/image"); // 设置跳转地址
response.setStatus(302); // 设置状态码
5. 总结
response 对象的方法使用
方法 | 说明 |
---|---|
response.getWriter() | 以字符的形式向浏览器输出消息 |
response.getOutputStream() | 以字节的形式向浏览器输出消息 |
response.setContentType(“text/html”) | 告诉浏览器用什么方式打开,如文本(text/html)、图片(image/jpg) 等 |
response.setCharacterEncoding(“utf-8”) | 设置编码格式 |
response.setHeader(“Content-Disposition”,“attachment;filename=” + URLEncoder.encode(fileName, “utf-8”)) | 浏览器下载文件 |
response.setHeader(“refresh”, “x”) | 浏览器 x 秒刷新一次 |
response.setHeader(“Cache-Control”, “no-cache”) | 浏览器去缓存 |
response.setHeader(“Pragma”, “no-cache”) | 浏览器去缓存 |
response.sendRedirect(“跳转地址”) | 重定向,跳转地址需要从项目名开始 |
response.setHeader(“Location”, “跳转地址”) | 设置跳转地址 |
response.setStatus(302) | 设置状态码 |
四、HttpServletRequest
HttpServletRequest 代表客户端的请求,用户通过 Http 协议访问服务器,Http 请求中的所有信息会被封装到 HttpServletRequest 中,通过这个 HttpServletRequest 的方法,获得客户端的所有信息。
1. 获取前端传递的参数
调用方法 | 说明 |
---|---|
request.getParameter() | 获得一个参数的值 |
request.getParameterValues() | 获得多个参数的值 |
- 删除原来的
index.jsp
文件,重新建立,并写前端内容。
注意:
${pageContext.request.contextPath}/login
表示当前路径/login
。
- 通过调用方法获取前端传递的参数。
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
String username = request.getParameter("username");
String password = request.getParameter("password");
String[] hobbies = request.getParameterValues("hobbies");
System.out.println("=============================");
System.out.println("username : " + username);
System.out.println("password : " + password);
System.out.println(Arrays.toString(hobbies));
System.out.println("=============================");
- 效果
2. 请求转发
调用方法 | 说明 |
---|---|
request.getRequestDispatcher(“/转发路径”).forward(request, response) | 请求转发 |
注意:这里的
/
代表当前的 Web 应用,转发路径中不用再写项目名,因为转发是项目内部资源跳转。而重定向需要写项目名。
- 建立跳转的页面
success.jsp
。
- 请求转发
request.getRequestDispatcher("/success.jsp").forward(request, response);
- 效果
注意:
-
this 指当前类的对象。
-
点击
clean
可以清除生成的target
文件。
random.nextInt(max)
表示生成 [0,max] 之间的随机数。- 请求转发和重定向的地址都是浏览器导航栏的路径。