服务器温习笔记(二)Tomcat和HttpServlet

http协议

什么是http协议

什么是http协议,http英文全称为hyper text transfer protocol即超文本传输协议,何为传输协议呢?传输协议是指客户端和服务器端通信时,双方发送数据的格式
http的特点:

  1. http是基于TCP/IP的高级协议。
  2. 默认端口号:80。
  3. 基于请求/响应模型的:一次请求对应一次响应。
  4. 无状态响应:每次请求之间相互独立,不能交互数据。

历史版本

1.0 : 每一次请求响应都会建立新的链接。
1.1: 复用连接。

Request和Response概述

  1. request和response对象是由服务器创建的。我们来使用它们。
  2. 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

浏览器需要告诉服务器,从哪里开始发起请求。
作用:

  1. 防盗链
  2. 做统计工作

请求体(正文)

封装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
  1. 获取请求方式 :GET
    String getMethod()
  2. (*)获取虚拟目录: /servlet
    String getContextPath()
  3. 获取Servlet路径: /test01
    String getServletPath()
  4. 获取get方式请求参数:username=xueshanfeitian
    String getQueryString()
  5. (*)获取请求URI:虚拟目录/servlet路径 /servlet/test01
    String getRequestURI(): /servlet/test01
    StringBuffer getRequestURL() :http://localhost/servlet/test01
    URL:统一资源定位符 :http://localhost/servlet/test01
    URI:统一资源标识符 : /servlet/test01
  6. 获取协议及版本:HTTP/1.1
    String getProtocol()
  7. 获取客户机的IP地址:
    String getRemoteAddr()
    Notes: URI范围大于URL范围

获取请求头数据

方法:
String getHeader(String name):通过请求头的名称获取请求头的值
Enumeration getHeaderNames():获取所有的请求头名称

获取请求体数据

请求体:只有POST请求方式,才有请求体,在请求体中封装了POST请求的请求参数

  1. 获取流对象
    BufferedReader getReader():获取字符输入流,只能操作字符数据
    ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据
    在文件上传知识点后讲解
  2. 再从流对象中拿数据

其他功能

  1. 获取请求参数
    String getParameter(String name):根据参数名称获取参数值 username=zs&password=123
    String[] getParameterValues(String name):根据参数名称获取参数值的数组 多用于复选框 hobby=xx&hobby=game
    Enumeration<String> getParameterNames():获取所有请求的参数名称
    Map<String,String[]> getParameterMap():获取所有参数的map集合
    在请求参数时可能会出现中文乱码
    get方式: tomcat8已经将get方式的乱码问题解决了。
    post方式: 会乱码
    解决:在获取参数签,设置request的编码 request.setCharacterEncoding(“utf-8”)。
  2. 请求转发
    一种在服务器内部跳转方式。
    步骤:
    1)通过request对象获取请求转发器对象: RequestDispatcher getRequestDispatcher(String path)
    2)通过RequestDispatcher对象来进行转发:forward(ServletRequest request, ServletResponse response)
  3. 共享数据
    域对象:一个有作用范围的对象,可以在范围内共享数据
    request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据(也就是在转发的情况下可以用request域来请求对象)
    方法:
  1. void setAttribute(String name,Object obj):存储数据。
    2)Object getAttitude(String name):通过键获取值。
  2. void removeAttribute(String name):通过键移除键值对。
  1. 获取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
组成

协议/版本 响应状态码 状态码描述

  1. 状态码都是3位数字
  2. 分类:
    1xx:服务器就收客户端消息,但没有接受完成,等待一段时间后,发送1xx多状态码
    2xx:成功。代表:200
    3xx:重定向。代表:302(重定向),304(访问缓存)
    4xx:客户端错误。
    代表:
    404(请求路径没有对应的资源)
    405:请求方式没有对应的doXxx方法(没有对应的doPost方法或者doGet方法)
    5xx:服务器端错误。代表:500(服务器内部出现异常)
响应状态码

服务器告诉客户端浏览器本次请求和响应的一个状态。

响应头

  1. 格式:头名称: 值
  2. 常见的响应头:
    1)Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式
    2)Content-disposition:服务器告诉客户端以什么格式打开响应体数据
    取值:
    in-line:默认值,在当前页面内打开
    attachment;filename=xxx:以附件形式打开响应体。文件下载

响应空行

分割响应头和响应体的空行

响应体

服务器发送给浏览器的数据资源
如:

<html>
<head>
	<title>$Title$</title>
</head>
 <body>
	......
 </body>
</html>

还有其他图片等资源信息。

Response 对象

该对象主要是用于设置响应消息

设置响应行

  1. 格式:HTTP/1.1 200 ok
  2. 设置状态码:setStatus(int sc)

设置响应头:

setHeader(String name, String value)

设置响应体:

使用步骤:

  1. 获取输出流
    字符输出流:PrintWriter getWriter()
    字节输出流:ServletOutputStream getOutputStream()
  2. 使用输出流,将数据输出到客户端浏览器

服务器

重定向和转发

转发

转发图解

在这里插入图片描述
转发代码:

req.getRequestDispatcher("/HttpServlet04Request").forward(req,resp);

转发特点

1)浏览器地址栏路径不发生变化。
2)只能转发到当前服务器内部资源中。
3)转发是一次请求,可以通过转发来实现request对象共享

重定向

重定向图解

在这里插入图片描述
重定向原始代码

resp.setStatus(302);
resp.setHeader("location","/servlet/HttpServlet06Request");

重定向改进后的代码

resp.sendRedirect("/servlet/HttpServlet06Request");

上述两种重定向代码在本质上是相同的。

重定向特点

  1. 重定向是浏览器地址栏会发生变化
  2. 重定向可以访问其他(服务器的资源)站点
  3. 重定向有两次请求

重定向和转发对比在这里插

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)

作为域对象

  1. setAttribute(String name,Object value)
  2. getAttribute(String name)
  3. 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的

要求

  1. 类必须被public修饰
  2. 必须提供空参的构造器
  3. 成员变量必须使用private修饰
  4. 提供公共setter和getter方法

概念

成员变量:
属性:setter和getter方法截取后的产物
例如:getUsername() --> Username–> username

方法

  1. setProperty()
  2. getProperty()
  3. populate(Object obj , Map map):将map集合的键值对信息,封装到对应的JavaBean对象中。

猜你喜欢

转载自blog.csdn.net/xueshanfeitian/article/details/109483799
今日推荐