服务器温习笔记(二)Tomcat和HttpServlet
http协议
什么是http协议
什么是http协议,http英文全称为hyper text transfer protocol即超文本传输协议,何为传输协议呢?传输协议是指客户端和服务器端通信时,双方发送数据的格式。
http的特点:
- http是基于TCP/IP的高级协议。
- 默认端口号:80。
- 基于请求/响应模型的:一次请求对应一次响应。
- 无状态响应:每次请求之间相互独立,不能交互数据。
历史版本
1.0 : 每一次请求响应都会建立新的链接。
1.1: 复用连接。
Request和Response概述
- request和response对象是由服务器创建的。我们来使用它们。
- request对象是来获取请求消息,response对象是来设置响应消息。
Request
请求消息概述
请求消息是指将各类请求消息按照http协议封装后的数据包,该数据包由浏览器发出请求并发送到目标服务器,这个过程就是请求消息的过程。
请求消息格式组成
请求行
请求方式 请求url 请求协议/版本
GET /servlet/form01.html HTTP/1.1
请求方式:
HTTP协议7种请求方式,常用的有2种。
GET:
1.请求参数在请求行中,在url后。
2.url长度有限制。
3.不太安全。
POST:
1.请求参数在请求体中。
2.url长度没有限制。
3.相对安全。
请求头
客户端(浏览器)告诉服务器浏览器的基本信息。
请求头名称: 请求头值。
常见的请求头。
Host: localhost
//请求头的浏览器发送给服务器的信息
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36
......
通过请求头,服务器可以知晓客户端浏览器信息,便于提高浏览器的兼容性。
Referer: http://localhost/servlet/form01.html
浏览器需要告诉服务器,从哪里开始发起请求。
作用:
- 防盗链
- 做统计工作
请求体(正文)
封装POST请求消息的请求体的
请求空行
空行,就是用于分割POST请求的请求头,和请求体的。
请求体
封装POST请求消息的请求参数的。
消息格式
POST /servlet/test01 HTTP/1.1
Host: localhost
Connection: keep-alive
Content-Length: 61
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://localhost
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Sec-Fetch-Site: same-origin Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: document Referer: http://localhost/servlet/form01.html Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Cookie: JSESSIONID=6EC7D4F934BF301660549B84431B5DFC; Idea-a7480d3b=af5d3764-107c-43e1-8355-7701d0e9e648 //参数格式 username=xueshanfeitian&%E6%8F%90%E4%BA%A4=%E6%8F%90%E4%BA%A4
请求消息格式图解
Request对象继承体系结构
request 功能
获取请求行数据
POST /servlet/test01 HTTP/1.1
Interface:HttpServletRequest
方法:
http://localhost/servlet/test01?username=xueshanfeitian
- 获取请求方式 :GET
String getMethod() - (*)获取虚拟目录: /servlet
String getContextPath() - 获取Servlet路径: /test01
String getServletPath() - 获取get方式请求参数:username=xueshanfeitian
String getQueryString() - (*)获取请求URI:虚拟目录/servlet路径 /servlet/test01
String getRequestURI(): /servlet/test01
StringBuffer getRequestURL()//localhost/servlet/test01
URL:统一资源定位符 :http://localhost/servlet/test01
URI:统一资源标识符 : /servlet/test01 - 获取协议及版本:HTTP/1.1
String getProtocol() - 获取客户机的IP地址:
String getRemoteAddr()
Notes: URI范围大于URL范围
获取请求头数据
方法:
String getHeader(String name):通过请求头的名称获取请求头的值
Enumeration getHeaderNames():获取所有的请求头名称
获取请求体数据
请求体:只有POST请求方式,才有请求体,在请求体中封装了POST请求的请求参数
- 获取流对象
BufferedReader getReader():获取字符输入流,只能操作字符数据
ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据
在文件上传知识点后讲解 - 再从流对象中拿数据
其他功能
- 获取请求参数
String getParameter(String name):
根据参数名称获取参数值 username=zs&password=123String[] getParameterValues(String name):
根据参数名称获取参数值的数组 多用于复选框 hobby=xx&hobby=gameEnumeration<String> getParameterNames()
:获取所有请求的参数名称Map<String,String[]> getParameterMap()
:获取所有参数的map集合
在请求参数时可能会出现中文乱码
get方式: tomcat8已经将get方式的乱码问题解决了。
post方式: 会乱码
解决:在获取参数签,设置request的编码 request.setCharacterEncoding(“utf-8”)。 - 请求转发
一种在服务器内部跳转方式。
步骤:
1)通过request对象获取请求转发器对象: RequestDispatcher getRequestDispatcher(String path)
2)通过RequestDispatcher对象来进行转发:forward(ServletRequest request, ServletResponse response) 共享数据
域对象:一个有作用范围的对象,可以在范围内共享数据
request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据(也就是在转发的情况下可以用request域来请求对象)
方法:void setAttribute(String name,Object obj):存储数据。
2)Object getAttitude(String name):通过键获取值。void removeAttribute(String name):通过键移除键值对。
获取ServletContext
ServletContext getServletContext();
Response
响应消息典例
HTTP/1.1 200 OK
Bdpagetype: 2
Bdqid: 0xc4f9613f00050ec6
Cache-Control: private
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html;charset=utf-8
Date: Thu, 05 Nov 2020 08:44:02 GMT
Expires: Thu, 05 Nov 2020 08:44:01 GMT
Server: BWS/1.1
Set-Cookie: BDSVRTM=448; path=/
Set-Cookie: BD_HOME=1; path=/
Set-Cookie: H_PS_PSSID=32816_1424_32705_32961_32919; path=/; domain=.baidu.com
Strict-Transport-Security: max-age=172800
Traceid: 1604565842019070260214193482623845994182
X-Ua-Compatible: IE=Edge,chrome=1
Transfer-Encoding: chunked
<html>
<head>
<title>$Title$</title>
</head>
<body>
......
</body>
</html>
响应消息格式
响应行
HTTP/1.1 200 OK
组成
协议/版本 响应状态码 状态码描述
- 状态码都是3位数字
- 分类:
1xx:服务器就收客户端消息,但没有接受完成,等待一段时间后,发送1xx多状态码
2xx:成功。代表:200
3xx:重定向。代表:302(重定向),304(访问缓存)
4xx:客户端错误。
代表:
404(请求路径没有对应的资源)
405:请求方式没有对应的doXxx方法(没有对应的doPost方法或者doGet方法)
5xx:服务器端错误。代表:500(服务器内部出现异常)
响应状态码
服务器告诉客户端浏览器本次请求和响应的一个状态。
响应头
- 格式:头名称: 值
- 常见的响应头:
1)Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式
2)Content-disposition:服务器告诉客户端以什么格式打开响应体数据
取值:
in-line:默认值,在当前页面内打开
attachment;filename=xxx:以附件形式打开响应体。文件下载
响应空行
分割响应头和响应体的空行
响应体
服务器发送给浏览器的数据资源
如:
<html>
<head>
<title>$Title$</title>
</head>
<body>
......
</body>
</html>
还有其他图片等资源信息。
Response 对象
该对象主要是用于设置响应消息
设置响应行
- 格式:HTTP/1.1 200 ok
- 设置状态码:setStatus(int sc)
设置响应头:
setHeader(String name, String value)
设置响应体:
使用步骤:
- 获取输出流
字符输出流:PrintWriter getWriter()
字节输出流:ServletOutputStream getOutputStream() - 使用输出流,将数据输出到客户端浏览器
服务器
重定向和转发
转发
转发图解
转发代码:
req.getRequestDispatcher("/HttpServlet04Request").forward(req,resp);
转发特点
1)浏览器地址栏路径不发生变化。
2)只能转发到当前服务器内部资源中。
3)转发是一次请求,可以通过转发来实现request对象共享
重定向
重定向图解
重定向原始代码
resp.setStatus(302);
resp.setHeader("location","/servlet/HttpServlet06Request");
重定向改进后的代码
resp.sendRedirect("/servlet/HttpServlet06Request");
上述两种重定向代码在本质上是相同的。
重定向特点
- 重定向是浏览器地址栏会发生变化
- 重定向可以访问其他(服务器的资源)站点
- 重定向有两次请求
" class="reference-link">重定向和转发对比
response输出信息
response输出字符数据
输出代码:
//需要用utf-8来设置处理的编码方式
// resp.setCharacterEncoding("utf-8");
//告诉浏览器需要用UTF-8来进行解码
// resp.setHeader("content-type","text/html;charset=utf-8");
// resp.setHeader("content-type","text/html;charset=utf-8");
resp.setContentType("text/html;charset=utf-8");
PrintWriter pw = resp.getWriter();
pw.write("<h1>晓鹏hello java & python </h1>");
notes: 一定要用注意乱码格式,需要服务器输出文件编码格式和浏览器解析的编码格式一致。
reponse输出字节数据
resp.setContentType("text/html;charset=utf-8");
ServletOutputStream os = resp.getOutputStream();
os.write("你好!!!".getBytes("utf-8"));
通过上面的过程就可以就可以向浏览器输出字节流。
验证码
验证码的本质是一张图片,简单的验证码可以采用
验证码生成代码:
@WebServlet(value = "/CheckCode01Servlet")
public class CheckCode01Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
final int width = 150;
final int height = 50;
System.out.println("-----------http CheckCode01Servlet---------------");
//1. 创建一个对象,在内存中图片
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
//2. 美化图片
Graphics graphics = bufferedImage.getGraphics();
//填充颜色
graphics.setColor(Color.pink);
graphics.fillRect(0,0,width,height);
//花边框
graphics.setColor(Color.BLUE);
graphics.drawRect(0,0,width-2,height-2);
String str ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
// 生成随机交表
Random rm = new Random();
for (int i = 1; i <= 6; i++) {
int index = rm.nextInt(str.length());
char c = str.charAt(index);
graphics.drawString(c+"",width/7*i,height/2);
}
graphics.setColor(Color.GREEN);
//随机生成坐标点
for (int i = 0; i < 10; i++) {
int x1 = rm.nextInt(width);
int x2 = rm.nextInt(width);
int y1 = rm.nextInt(height);
int y2 = rm.nextInt(height);
graphics.drawLine(x1,y1,x2,y2);
}
//3. 将图片输出到页面展示
boolean jpg = ImageIO.write(bufferedImage, "jpg", resp.getOutputStream());
}
}
页面代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>check code</title>
<script>
window.onload=function () {
var img = document.getElementById("checkCode");
img.onclick=function () {
var date = new Date();
img.src="/servlet/CheckCode01Servlet?"+date;
}
var change = document.getElementById("changeCheckCode");
change.onclick=function ( ) {
var date = new Date();
img.src="/servlet/CheckCode01Servlet?"+date;
}
}
</script>
</head>
<body>
<img src="/servlet/CheckCode01Servlet" id="checkCode" >
<a href="" id="changeCheckCode">看不清 换一张?</a>
</body>
</html>
测试结果:
ServletContext对象
ServletContext简介
Defines a set of methods that a servlet uses to communicate with its servlet container, for example, to get the MIME type of a file, dispatch requests, or write to a log file.
ServletContext本质是一个接口,它代表整个Web应用,可以和程序的容器(服务器)来通信。
ServletContext获取
通过 request对象获取
request.getServletContext();
通过HttpServlet获取
//通过HttpServletRequest
ServletContext servletContext = req.getServletContext();
//通过HttpServlet获取该对象
ServletContext servletContext1 = this.getServletContext();
ServletContext功能
获取MIME类型
MIME类型:在互联网通信过程中定义的一种文件数据类型
格式: 大类型/小类型 text/html image/jpeg
获取
String getMimeType(String file)
作为域对象
- setAttribute(String name,Object value)
- getAttribute(String name)
- removeAttribute(String name)
ServletContext对象范围:所有用户所有请求的数据
notes: 但一般情况下,尽量少点用ServletContext来做数据共享,该对象面向范围大,生命周期长,安全性较差,内存压力会变大.
获取文件的真实路径
String getRealPath(String path)
String b = context.getRealPath("/b.txt");//web目录下资源访问
System.out.println(b);
String c = context.getRealPath("/WEB-INF/c.txt");//WEB-INF目录下的资源访问
System.out.println(c);
String a = context.getRealPath("/WEB-INF/classes/a.txt");//src目录下的资源访问
System.out.println(a);
文件下载案例
html代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/filedownload/downloadServlet?filename=2.jpg" type="" >图片1</a>
<br/>
<a href="/filedownload/downloadServlet?filename=001.mp4">视频1</a>
<br/>
<a href="/filedownload/downloadServlet?filename=九尾.jpg">视频1</a>
</body>
</html>
后台代码:
@WebServlet("/downloadServlet")
public class DownLoadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取请求参数,文件名称
String filename = req.getParameter("filename");
//2.使用字节输入流加载文件进内存
//3.找到文件服务器路径
ServletContext servletContext = req.getServletContext();
String realPath = servletContext.getRealPath("/img/" + filename);
//4.用字节流关联
FileInputStream fileInputStream = new FileInputStream(realPath);
//5 设置response的响应头
String mineType = servletContext.getMimeType(filename);
resp.setHeader("content-type",mineType);
//解决中文问题
String agent = req.getHeader("user-agent");
String fileName = DownLoadUtils.getFileName(agent, filename);
//5.1 设置响应头content-type
resp.setHeader("content-disposition","attachment;filename="+fileName);
//6 将输入流的数据写出到输出流中
ServletOutputStream outputStream = resp.getOutputStream();
byte[] buff = new byte[1024 * 8];
int len =0;
while ((len=fileInputStream.read(buff))!=-1){
outputStream.write(buff,0,len);
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
}
工具类:
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;
}
}
文件组织目录:
notes:用其他电脑访问本机一定要注意关闭服务器防火墙
NetSh Advfirewall set allprofiles state off #关闭防火墙
Netsh Advfirewall show allprofiles #查看防火墙状态
所有文件下载正常。
BeautifulUtils 工具类用法
用于封装JavaBean的
要求
- 类必须被public修饰
- 必须提供空参的构造器
- 成员变量必须使用private修饰
- 提供公共setter和getter方法
概念
成员变量:
属性:setter和getter方法截取后的产物
例如:getUsername() —> Username–> username
方法
- setProperty()
- getProperty()
- populate(Object obj , Map map):将map集合的键值对信息,封装到对应的JavaBean对象中。
还没有评论,来说两句吧...