HTTP协议
概念:
Hyper Text Transfer Protocol 超文本传输协议
传输协议:
定义了,客户端和服务器端通信时,发送数据的格式
特点:
- 基于
TCP/IP
的高级协议 - 默认端口号:
80
- 基于请求/响应模型的:一次请求对应一次响应
- 无状态的:每次请求之间相互独立,不能交互数据
历史版本:
1.0
:每一次请求响应都会建立新的连接1.1
:复用连接
request
运算
字符串格式:
1 | POST /login.html HTTP/1.1 |
请求行
请求方式 请求url
请求协议/版本GET /login.html HTTP/1.1
请求方式:
HTTP
协议有7
中请求方式,常用的有2
种
GET
:- 请求参数在请求行中,在
url
后。 - 请求的
url
长度有限制的 - 不太安全
- 请求参数在请求行中,在
POST
:- 请求参数在请求体中
- 请求的
url
长度没有限制的 - 相对安全
请求头:
客户端浏览器告诉服务器一些信息
请求头名称: 请求头值
常见的请求头:
User-Agent
:浏览器告诉服务器,我访问你使用的浏览器版本信息- 可以在服务器端获取该头的信息,解决浏览器的兼容性问题
Referer
:http://localhost/login.html告诉服务器,我(当前请求)从哪里来?
作用:
防盗链:
统计工作:
请求空行
空行,就是用于分割POST
请求的请求头和请求体的。
请求体(正文):
- 封装POST请求消息的请求参数的
Request对象
request对象和response对象的原理
request和response对象是由服务器创建的。我们来使用它们
request对象是来获取请求消息,response对象是来设置响应消息
request对象继承体系结构:
1 | ServletRequest -- 接口 |
request功能:
获取请求消息数据
获取请求行数据
1 | GET /day14/demo1?name=zhangsan HTTP/1.1 |
方法:
获取请求方式 :
GET
String getMethod()
获取虚拟目录:
/day14
String getContextPath()
获取Servlet路径:
/demo1
String getServletPath()
获取
get
方式请求参数:name=zhangsan
String getQueryString()
获取请求
URI
:/day14/demo1
String getRequestURI():
/day14/demo1
StringBuffer getRequestURL()
:http://localhost/day14/demo1
URL
:统一资源定位符 : http://localhost/day14/demo1 中华人民共和国URI
:统一资源标识符 : /day14/demo1 共和国获取协议及版本:
HTTP/1.1
String getProtocol()
获取客户机的IP地址:
String getRemoteAddr()
示例:
1 | package com.uestc.web.servlet02; |
获取请求头数据
方法:
String getHeader(String name):
通过请求头的名称获取请求头的值
Enumeration<String> getHeaderNames():
获取所有的请求头名称
示例1:打印所有的请求头的名称以及对于的值
1 | package com.uestc.web.servlet02; |
示例2:
1 | "/demo01"}) ({ |
获取请求体数据:
请求体:只有POST请求方式,才有请求体,在请求体中封装了POST请求的请求参数
步骤:
获取流对象
BufferedReader getReader():
获取字符输入流,只能操作字符数据ServletInputStream getInputStream():
获取字节输入流,可以操作所有类型数据,在文件上传知识点后讲解再从流对象中拿数据
示例:
- 首先创建
regist.html
1 |
|
- 然后创建
RequestDemo01.java
文件
1 | "/requestDemo01") ( |
- 启动tomcat服务器,在浏览区中访问
http://localhost:8080/servlet02/regist.html
其他功能:
获取请求参数通用方式:
不论get
还是post
请求方式都可以使用下列方法来获取请求参数
String getParameter(String name):
根据参数名称获取参数值 username=zs&password=123示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21"/requestDemo01") (
public class RequestDemo01 extends HttpServlet{
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//get 获取请求参数
//根据参数的名称获取参数值
String username=req.getParameter("username");
System.out.println("get");
System.out.println(username);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//post 获取请求参数
//根据参数的名称获取参数值
String username=req.getParameter("username");
System.out.println("post");
System.out.println(username);
}
}
String[] getParameterValues(String name):
根据参数名称获取参数值的数组hobby=xx&hobby=game
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13//servlet类
"/requestDemo01") (
public class RequestDemo01 extends HttpServlet{
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//post 获取请求参数
//根据参数名称获取参数值的数组
String [] hobbies=req.getParameterValues("hobby");
for(String hobby:hobbies){
System.out.println(hobby);
}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<!-- regist.html-->
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册页面</title>
</head>
<body>
<form action="/servlet02/requestDemo01" method="post">
<input type="text" placeholder="请输入用户名" name="username"><br>
<input type="text" placeholder="请输出密码" name="password"><br>
<input type="checkbox" name="hobby" value="game">游戏
<input type="checkbox" name="hobby" value="study">学习
<input type="submit" type="注册">
</form>
</body>
</html>
Enumeration<String> getParameterNames():
获取所有请求的参数名称示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15"/requestDemo01") (
public class RequestDemo01 extends HttpServlet{
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//post 获取请求参数
//根据参数名称获取参数值的数组
Enumeration<String> parameterNames=req.getParameterNames();
while(parameterNames.hasMoreElements()){
String name=parameterNames.nextElement();
System.out.println(name);
String value=req.getParameter(name);
System.out.println(value);
System.out.println("---------------------------");
}
}Map<String,String[]> getParameterMap():
获取所有参数的map集合示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18"/requestDemo01") (
public class RequestDemo01 extends HttpServlet{
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//post 获取请求参数
//根据参数名称获取参数值的数组
Map<String, String []> map=req.getParameterMap();
Set<String> set=map.keySet();
for(String name:set){
String [] values=map.get(name);
System.out.println(name);
for(String value:values){
System.out.println(value);
}
System.out.println("--------------");
}
}
}
中文乱码问题:
get
方式:tomcat 8
已经将get
方式乱码问题解决了post
方式:会乱码- 解决:在获取参数前,设置
request
的编码request.setCharacterEncoding("utf-8");
- 解决:在获取参数前,设置
1.2242 请求转发:
一种在服务器内部的资源跳转方式
步骤:
通过
request
对象获取请求转发器对象:RequestDispatcher
1
getRequestDispatcher(String path)
使用
RequestDispatcher
对象来进行转发:1
forward(ServletRequest request, ServletResponse response)
特点:
- 浏览器地址栏路径不发生变化
- 只能转发到当前服务器内部资源中。
- 转发是一次请求
示例:
新建RequestDemo02.java
1 | "/requestDemo02") ( |
1.2243 共享数据:
域对象:
一个有作用范围的对象,可以在范围内共享数据
request域:
代表一次请求的范围,一般用于请求转发的多个资源中共享数据
方法:
void setAttribute(String name,Object obj):
存储数据Object getAttitude(String name):
通过键获取值void removeAttribute(String name):
通过键移除键值对获取
ServletContext
:ServletContext getServletContext()
示例:
1 | "/requestDemo02") ( |
1 | "/requestDemo01") ( |
案例1:用户登录
用户登录案例需求:
编写
login.html
登录页面
username
&password
两个输入框使用
Druid
数据库连接池技术,操作mysql
day14数据库中user表
使用
JdbcTemplate
技术封装JDBC
登录成功跳转到
SuccessServlet
展示:登录成功!用户名,欢迎您
登录失败跳转到
FailServlet
展示:登录失败,用户名或密码错误
开发步骤
- 创建项目,导入
html
页面,配置文件,jar
包
导入jar
包之后需要Add as Library
创建数据库环境
1
2
3
4
5
6
7CREATE DATABASE day14;
USE day14;
CREATE TABLE USER(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(32) UNIQUE NOT NULL,
password VARCHAR(32) NOT NULL
);
创建包
com.uestc.domin
,创建类User
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43package com.uestc.domin;
/**
* 用户的实体类
*/
public class User {
private int id;
private String username;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}创建包
com.uestc.util
,编写工具类JDBCUtils`1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45package com.uestc.util;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* JDBC工具类,使用Durid连接池
*/
public class JDBCUtils {
private static DataSource ds;
static {
try {
//1.加载配置文件
Properties pro=new Properties();
//使用classLoader加载配置文件,获取字节输入流
InputStream is=JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
//2.初始化连接池对象
ds=DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取连接池对象
*/
public static DataSource getDataSource(){
return ds;
}
/**
* 获取连接Connection对象
*/
}创建包
com.uestc.dao
,创建类UserDao
,提供login
方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30package com.uestc.dao;
import com.uestc.domin.User;
import com.uestc.util.JDBCUtils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
/**
*操作数据库中User表的类
*/
public class UserDao {
//生命JDBCTemplate对象共用
private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());
/**
* 登陆方法
* @param loginUser 只有用户名和密码
* @return user包含用户全部数据
*/
public User login(User loginUser){
//1.编写sql
String sql="select * from user where username=? and password=?";
//2.调用query方法
User user=template.queryForObject(sql,
new BeanPropertyRowMapper<User>(User.class),
loginUser.getUsername(),loginUser.getPassword());
return user;
}
}单元测试
login
方法,新建包com.uestc.test
, 创建UserDaoTest
类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17package com.uestc.test;
import com.uestc.dao.UserDao;
import com.uestc.domin.User;
import org.junit.Test;
public class UserDaoTest {
public void testLogin(){
User loginUser=new User();
loginUser.setUsername("liufei");
loginUser.setPassword("123456");
UserDao dao=new UserDao();
User user=dao.login(loginUser);
System.out.println(user);
}
}
编写
cn.uestc.web.servlet.LoginServlet
类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47package com.uestc.web.servlet;
import com.uestc.dao.UserDao;
import com.uestc.domin.User;
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;
"/loginServlet") (
public class LoginServlet extends HttpServlet{
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.设置编码
req.setCharacterEncoding("utf-8");
//2.获取请求参数
String username=req.getParameter("username");
String password=req.getParameter("password");
//3.封装user对象
User loginUser=new User();
loginUser.setUsername(username);
loginUser.setPassword(password);
//4.调用UserDao的login的方法
UserDao dao=new UserDao();
User user=dao.login(loginUser);
//5.判断user
if(user==null){
//登录失败
req.getRequestDispatcher("/failServlet").forward(req,resp);
}else{
//登录成功
//存储数据
req.setAttribute("user",user);
//转发
req.getRequestDispatcher("/successServlet").forward(req,resp);
}
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}编写
FailServlet
和SuccessServlet
类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27//FailServlet类
package com.uestc.web.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;
"/failServlet") (
public class FailedServlet extends HttpServlet{
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//给页面写一句话
//设置编码
resp.setContentType("text/html;charset=utf-8");
//输出
resp.getWriter().write("登录失败, 用户名或密码错误");
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32//SuccessServlet类
package com.uestc.web.servlet;
import com.uestc.domin.User;
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;
"/successServlet") (
public class SuccessServlet extends HttpServlet{
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//给页面写一句话
//获取request域中共享的user对象
User user=(User)req.getAttribute("user");
if(user!=null){
//设置编码
resp.setContentType("text/html;charset=utf-8");
//输出
resp.getWriter().write("登录成功!"+user.getUsername()+"欢迎您!");
}
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}login.html
中form
表单的action
路径的写法1
虚拟目录+Servlet的资源路径
示例:
![image-20201018151952299](C:\Users\Liu Fei\AppData\Roaming\Typora\typora-user-images\image-20201018151952299.png)
![image-20201018152115095](C:\Users\Liu Fei\AppData\Roaming\Typora\typora-user-images\image-20201018152115095.png)
BeanUtils
工具类,简化数据封装首先导入
beanUtils
的jar
包 然后使用
beanUtils
![image-20201018154652738](C:\Users\Liu Fei\AppData\Roaming\Typora\typora-user-images\image-20201018154652738.png)
BeanUtils工具类
BeanUtils
用于封装JavaBean
的
JavaBean
:标准的Java
类, 用于封装数据
- 类必须被public修饰
- 必须提供空参的构造器
- 成员变量必须使用private修饰
- 提供公共setter和getter方法
注意的成员变量和属性的区别:
属性:setter
和getter
方法截取后的产物
例如:getUsername()
–> Username
–> username
有时候属性和成员变量不相同
方法:
setProperty()
getProperty()
populate(Object obj , Map map)
:将map集合的键值对信息,封装到对应的JavaBean
对象中
示例:
response
响应消息:服务器端发送给客户端的数据
响应消息的数据格式
字符串格式:
1 | #响应字符串格式 |
响应行
组成:
协议/版本 响应状态码 状态码描述
响应状态码:
服务器告诉客户端浏览器本次请求和响应的一个状态。
状态码都是3位数字
状态码分类:
1xx
:服务器就收客户端消息,但没有接受完成,等待一段时间后,发送1xx多状态码2xx
:成功。代表:200
3xx
:重定向。代表:302
(重定向),304
(访问缓存)4xx
:客户端错误。代表:
404
(请求路径没有对应的资源)405
:请求方式没有对应的doXxx
方法
5xx
:服务器端错误。代表:500
(服务器内部出现异常)
响应头:
格式:
头名称: 值
常见的响应头:
头名称:
Content-Type
:服务器告诉客户端本次响应体数据格式以及编码格式Content-disposition
:服务器告诉客户端以什么格式打开响应体数据值:
in-line
: 默认值,在当前页面内打开attachment;filename=xxx
:以附件形式打开响应体。文件下载
响应空行
响应体:
传输的数据
Response对象
功能:设置响应消息
设置响应行
格式:HTTP/1.1 200 ok
设置状态码:setStatus(int sc)
设置响应头:
setHeader(String name, String value)
设置响应体:
使用步骤:
获取输出流
字符输出流:
PrintWriter getWriter()
字节输出流:
ServletOutputStream getOutputStream()
使用输出流,将数据输出到客户端浏览器
案例:
重定向:资源跳转的方式
代码实现:
1 | //1. 设置状态码为302 |
创建
ResponseDemo01
Servlet类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31package com.uestc.web.servlet;
import com.sun.org.apache.xpath.internal.SourceTree;
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;
/**
* 重定向
* 访问/responseDemo01,会自动跳转到/responseDemo02
*/
"/responseDemo01") (
public class ResponseDemo01 extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("responseDemo01启动。。。");
//1.设置状态码302
resp.setStatus(302);
//设置响应头location
resp.setHeader("location","/servlet03/responseDemo02");
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
}创建
ResponseDemo02
Servlet类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21package com.uestc.web.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;
"/responseDemo02") (
public class ResponseDemo02 extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("responseDemo02启动。。。");
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
}
简单的重定向方法:
1 | response.sendRedirect("/day15/responseDemo2"); |
1.4311 forward 和 redirect 区别
1.43111 重定向的特点: redirect
- 地址栏发生变化
- 重定向可以访问其他站点(服务器)的资源
- 重定向是两次请求。不能使用request对象来共享数据
1.43112 转发的特点:forward
- 转发地址栏路径不变
- 转发只能访问当前服务器下的资源
- 转发是一次请求,可以使用request对象来共享数据
1.4312 路径写法:
路径分类
相对路径:通过相对路径不可以确定唯一资源
- 如:
./index.html
- 不以
/
开头,以.
开头路径
- 不以
规则:找到当前资源和目标资源之间的相对位置关系
./
:当前目录../
: 后退一级目录- 如:
绝对路径:通过绝对路径可以确定唯一资源
- 如:http://localhost/day15/responseDemo2 /day15/responseDemo2
- 以
/
开头的路径
规则:判断定义的路径是给谁用的?判断请求将来从哪儿发出
给
客户端浏览器
使用:需要加虚拟目录
(项目的访问路径)建议:虚拟目录动态获取:
request.getContextPath()
如
<a>
,<form>
重定向
…给
服务器
使用:不需要加虚拟目录转发路径
服务器输出字符数据到浏览器
步骤:
获取字符输出流
输出数据
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24package com.uestc.web.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;
"/responseDemo03") (
public class ResponseDemo03 extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取字符输出流
PrintWriter pw=resp.getWriter();
//2.输出数据
pw.write("<h1>hello response</h2>");
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
}
乱码问题:
1. `PrintWriter pw = response.getWriter()`;获取的流的默认编码是`ISO-8859-1`
2. 设置该流的默认编码
3. 告诉浏览器响应体使用的编码
1 | package com.uestc.web.servlet; |
服务器输出字节数据到浏览器
步骤:
获取字节输出流
输出数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25package com.uestc.web.servlet;
import javax.servlet.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;
"/responseDemo04") (
public class ResponseDemo04 extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
//1.获取字节输出流
ServletOutputStream sos=resp.getOutputStream();
//2.输出数据
sos.write("你好".getBytes("utf-8"));
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
}
验证码
本质:图片
目的:防止恶意表单注册
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64package com.uestc.web.servlet;
import javax.imageio.ImageIO;
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.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
"/checkCode") (
public class CheckCodeServlet extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int width=100;
int height=50;
//1.创建对象,在内存中的图片(验证码图片对象)
BufferedImage image=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
//2.美化图片
//2.1 背景填充
//获取画笔对象
Graphics g=image.getGraphics();
//设置画笔颜色
g.setColor(Color.PINK);
//填充颜色
g.fillRect(0,0,width,height);
//2.2 画边框
g.setColor(Color.BLUE);
g.drawRect(0,0,width-1,height-1);
String str="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
//生成随机角标
Random rd=new Random();
for(int i=0;i<4;i++){
int index=rd.nextInt(str.length());
//获取字符
char ch=str.charAt(index);
//2.3 写验证码
g.drawString(ch+"",(width/5)*(i+1),25);
}
//2.4 画干扰线
//生成随机坐标点
for(int i=0;i<5;i++){
int x1=rd.nextInt(width);
int y1=rd.nextInt(height);
int x2=rd.nextInt(width);
int y2=rd.nextInt(height);
g.drawLine(x1,y1,x2,y2);
}
//3.将图片输出到页面展示
ImageIO.write(image,"jpg",resp.getOutputStream());
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
}
ServletContext对象
概念:
代表整个web应用,可以和程序的容器(服务器)来通信
获取:
通过
request
对象获取1
request.getServletContext();
通过
HttpServlet
获取1
this.getServletContext();
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18"/servletContextDemo1") (
public class ServletContextDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//通过request对象获取
ServletContext context1=req.getServletContext();
//通过HttpServlet获取
ServletContext context2=this.getServletContext();
System.out.println(context1);
System.out.println(context2);
System.out.println(context1.equals(context2));
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
}
功能:
获取MIME类型:
MIME类型:在互联网通信过程中定义的一种文件数据类型
格式: 大类型/小类型 text/html
image/jpeg
获取:
1 | String getMimeType(String file) |
示例:
1 | "/servletContextDemo1") ( |
域对象:共享数据
1 | 1. setAttribute(String name,Object value) |
ServletContext
对象范围:所有用户所有请求的数据
示例:
新建
servletContextDemo1.java
,通过ServletContext
域对象赋值1
2
3
4
5
6
7
8
9
10
11
12
13
14"/servletContextDemo2") (
public class ServletContextDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context=this.getServletContext();
String msg=(String)context.getAttribute("msg");
System.out.println(msg);
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
}新建
servletContextDemo2.java
,获取ServletContext
域对象的值1
2
3
4
5
6
7
8
9
10
11
12
13
14"/servletContextDemo2") (
public class ServletContextDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context=this.getServletContext();
String msg=(String)context.getAttribute("msg");
System.out.println(msg);
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
}
获取文件的真实(服务器)路径
方法:
1 | String getRealPath(String path) |
示例: 想要获取文件的真实路径(区别与工作空间的目录)
1 | "/servletContextDemo3") ( |
案例 文件下载
需求
- 页面显示超链接
- 点击超链接后弹出下载提示框
- 完成图片文件下载
分析:
超链接指向的资源如果能够被浏览器解析,则在浏览器中展示,如果不能解析,则弹出下载提示框。不满足需求
任何资源都必须弹出下载提示框
使用响应头设置资源的打开方式:
1
content-disposition:attachment;filename=xxx
步骤
定义页面,编辑超链接
href
属性,指向Servlet
,传递资源名称filenam
定义
Servlet
- 获取文件名称
- 使用字节输入流加载文件进内存
- 指定response的响应头: content-disposition:attachment;filename=xxx
- 将数据写出到response输出流
示例代码:
1 | package com.uestc.web.download; |
中文乱码问题
解决思路:
获取客户端使用的浏览器版本信息
根据不同的版本信息,设置filename的编码方式不同
步骤:
新建utils工具类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24package com.uestc.web.utils;
import sun.misc.BASE64Encoder;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class DownLoadUtils {
public static String getFileName(String agent, String filename) throws UnsupportedEncodingException {
if (agent.contains("MSIE")) {
// IE浏览器
filename = URLEncoder.encode(filename, "utf-8");
filename = filename.replace("+", " ");
} else if (agent.contains("Firefox")) {
// 火狐浏览器
BASE64Encoder base64Encoder = new BASE64Encoder();
filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
} else {
// 其它浏览器
filename = URLEncoder.encode(filename, "utf-8");
}
return filename;
}
}解决乱码问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54package com.uestc.web.download;
import com.uestc.web.utils.DownLoadUtils;
import javax.servlet.ServletContext;
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.FileInputStream;
import java.io.IOException;
"/downloadServlet") (
public class DownloadServlet extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取请求参数,文件名称
String filename=req.getParameter("filename");
//2.使用字节输入流加载文件进内存
//2.1 找到文件服务器路径
ServletContext context=this.getServletContext();
String realpath=context.getRealPath("/img/"+filename);
//2.2 用字节流关联
FileInputStream fis=new FileInputStream(realpath);
//3.设置response的响应头
//3.1设置相应头类型:contend-type
//获取文件的mimeType
String minType=context.getMimeType(filename);
resp.setHeader("content-type",minType);
//解决中文文件名问题
//1.获取user-agent请求头
String agent=req.getHeader("user-agent");
//2.使用工具类方法编码文件名即可
filename=DownLoadUtils.getFileName(agent,filename);
//3.2 设置相应头的打开方式:contend-disposition
resp.setHeader("content-disposition","attachment;filename="+filename);
//4.将输入流的数据写出到输出流中
ServletOutputStream sos=resp.getOutputStream();
byte [] buff=new byte[1024*8];
int len=0;
while ((len=fis.read(buff))!=-1){
sos.write(buff,0,len);
}
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
}