Servlet

1 主要内容

请添加图片描述

2. IDEA的使用

IDEA 全称 IntelliJ IDEA,由JetBrains公司开发,是java编程语言开发的集成环境。在业界被公认为最

好的java开发工具,尤其在智能代码助手、代码自动提示、重构、J2EE支持、各类版本工具(git、svn

等)、JUnit、CVS整合、代码分析、 创新的GUI设计等方面的功能可以说是超常的。

2.1. IDEA的特色功能

  • 智能选取
  • 丰富的导航模式
  • 历史记录功能
  • 编码辅助
  • 灵活的排版功能
  • 代码检查
  • 完美的自动代码完成
  • 版本控制的支持

2.2. IDEA的基本设置

使用IDEA时,可以对它进行一些简单的设置,通过设置用户的偏好设置,可提高使用者的体验感。

2.3. IDEA常用快捷键

快捷键作用
Alt+Insert生成代码(如get, set方法,构造函数等)
Alt+↑/ ↓在方法间快速定位
Alt+【F3】查找相同文本,并高亮显示
Ctrl+B快速打开光标处的类或方法
Ctrl+J自动代码(main方法)
Ctrl+N查找类
Ctrl+Y删除行
Ctrl+D复制行
Ctrl+O重写方法
Ctrl+E最近打开的文件
Ctrl+F查找文本
Ctrl+R替换文本
Ctrl+P方法参数提示
Ctrl+/单行注释//
Ctrl+Shift+/多行注释/* */
Ctrl+Shift+N查找文件
Ctrl+Alt+L格式化代码
Ctrl+Shift+↑/ ↓代码向上/向下移动
Shift+F6重构-重命名

3. HTTP协议

HTTP 协议(Hypertext Transfer Protocol, 超文本传输协议),是一个客户端请求和响应的标准协

议,这个协议详细规定了浏览器和万维网服务器之间互相通信的规则。用户输入地址和端口号之后就可

以从服务器上取得所需要的网页信息。

通信规则规定了客户端发送给服务器的内容格式,也规定了服务器发送给客户端的内容格式。客户端

发送给服务器的格式叫"请求协议";服务器发送给客户端的格式叫"响应协议"。

在浏览器中 F12可查看

3.1. 浏览器中的书写格式

服务器端资源需要通过浏览器进行,此时由浏览器将我们给出的请求解析为满足 HTTP 协议的格式并

发出。我们发出的请求格式需要按照浏览器规定的格式来书写,在浏览器中书写格式如下:

在这里插入图片描述

当浏览器获取到信息以后,按照特定格式解析并发送即可。接收到服务器端给出的响应时,也按照

HTTP 协议进行解析获取到各个数据,最后按照特定格式展示给用户

3.2. HTTP协议的特点

  1. 支持客户/服务器模式。
  2. 简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的 有 GET、

POST。每种方法规定了客户与服务器联系的类型不同。由于 HTTP 协议简单,使得HTTP服务器的

程序规模小,因而通信速度很快。

  1. 灵活:HTTP 允许传输任意类型的数据对象。传输的类型由Content-Type加以标记。
  2. 无连接:无连接是表示每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答

后,即断开连接。采用这种方式可以节省传输时间。

HTTP1.1 版本后支持可持续连接。通过这种连接,就有可能在建立一个 TCP 连接后,发送请求并得到

回应,然后发送更多的请求并得到更多的回应.通过把建立和释放 TCP 连接的开销分摊到多个请求

上,则对于每个请求而言,由于 TCP 而造成的相对开销被大大地降低了。而且, 还可以发送流水

线请求,也就是说在发送请求 1 之后的回应到来之前就可以发送请求 2.也可以认为,一次连接发送

多个请求,由客户机确认是否关闭连接,而服务器会认为这些请求分别来自不同的客户端。

  1. 无状态:HTTP 协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着

如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送 的数据量增大。另一方

面,在服务器不需要先前信息时它的应答就较快。

3.3. HTTP之URL

HTTP(超文本传输协议)是一个基于请求与响应模式的、应用层的协议,常基于 TCP 的连接方式,

绝大多数的 Web 开发,都是构建在 HTTP 协议之上的 Web 应用。

HTTP URL (URL 是一种特殊类型的 URI,包含了用于查找某个资源的足够的信息)的格式 如下:

http://host[:port]/[abc_path] 
http://IP(主机名/域名):端口/访问的资源路径
  • http 表示要通过 HTTP 协议来定位网络资源;
  • host 表示合法的 Internet 主机域名或 者 IP 地址;
  • port 指定一个端口号,为空则使用缺省端口 80;
  • abs_path 指定请求资源的 URI; 如果 URL 中没有给出 abs_path,那么当它作为请求 URI 时,必

须以“/”的形式给出,通常 这个工作浏览器自动帮我们完成。

3.4. HTTP 请求

HTTP 请求由三部分组成,分别是:请求行、请求头、请求正文。

通过chrome浏览器, F12 —> Network查看。

Get 请求(没有请求体)

Post 请求

请求行以一个方法符号开头,以空格分开,后面跟着请求的 URI 和协议的版本。

格式如下:Method Request-URI HTTP-Version CRLF

Method 表示请求方法;

Request-URI 是一个统一资源标识符;

HTTP-Version 表示请 求的 HTTP 协议版本;

CRLF 表示回车和换行;

3.5. HTTP 响应

在接收和解释请求消息后,服务器返回一个 HTTP 响应消息。HTTP 响应也是由三个部分组成,分别

是:状态行、消息报头、响应正文。

3.6. 消息头

HTTP 消息由客户端到服务器的请求和服务器到客户端的响应组成。请求消息和响应消息都是由开始

行(对于请求消息,开始行就是请求行,对于响应消息,开始行就是状态行), 消息报头(可选),空

行(只有 CRLF 的行),消息正文(可选)组成。

每一个报头域都是由 名字+“:”+空格+值 组成,消息报头域的名字是大小写无关的。

请求头

请求报头允许客户端向服务器端传递请求的附加信息以及客户端自身的信息。

Referer:该请求头指明请求从哪里来 。

如果是地址栏中输入地址访问的都没有该请求头 地址栏输入地址,通过请求可以看到,此时多了

一个 Referer 的请求头,并且后面的值 为该请求从哪里发出。比如:百度竞价,只能从百度来的才

有效果,否则不算;通常用来做统计工作、 防盗链。

响应头

响应报头允许服务器传递不能放在状态行中的附加响应信息,以及关于服务器的信息和 对 Request

URI 所标识的资源进行下一步访问的信息。

Location:Location响应报头域用于重定向接受者到一个新的位置。

  • Location响应报头域,常用在更换域名的时候。
response.sendRedirect("http://www.baidu.com");
  • Refresh:自动跳转(单位是秒),可以在页面通过meta标签实现,也可在后台实现。
<meta http-equiv="refresh" content="3;url=http://www.baidu.com">

4. Tomcat服务器

4.1. 什么是Tomcat

Tomcat 是一个符合 JavaEE WEB 标准的最小的 WEB 容器,所有的 JSP 程序一定要有 WEB 容器的支

持才能运行,而且在给定的 WEB 容器里面都会支持事务处理操作。

Tomcat 是由 Apache 提供的(www.apache.org)提供的可以用安装版和解压版,安装版可以在服务

中出现一个 Tomcat 的服务,免安装没有,开发中使用免安装版。 Tomcat 简单的说就是一个运行 Java

的网络服务器,底层是 Socket 的一个程序,它也是 JSP 和 Servlet 的一个容器。 Tomcat 是 Apache 软

件基金会(Apache Software Foundation)的 Jakarta 项目中的一个核心项目,由 Apache、Sun和其

他一些公司及个人共同开发而成。

由于有了 Sun 的参与和支持,最新的 Servlet 和 JSP 规范总是能在 Tomcat 中得到体现。因为

Tomcat 技术先进、性能稳定,而且免费,因而深受 Java 爱好者的喜爱并得到了部分软件开发商的认

可,成为目前比较流行的 Web 应用服务器

Tomcat 服务器是一个免费的开放源代码的 Web 应用服务器,属于轻量级应用服务器, 在中小型系

统和并发访问用户不是很多的场合下被普遍使用,是开发和调试 JSP 程序的首选。 对于一个初学者来

说,可以这样认为,当在一台机器上配置好 Apache 服务器,可利用它响应 HTML(标准通用标记语言

下的一个应用)页面的访问请求。实际上 Tomcat 部分是 Apache 服务器的扩展,但它是独立运行的,

所以当你运行 tomcat 时,它实际上作为一个与 Apache 独立的进程单独运行的。

当配置正确时,Apache 为 HTML 页面服务,而 Tomcat 实际上是在运行 JSP 页面和 Servlet。另外,

Tomcat 和 IIS 等 Web 服务器一样,具有处理 HTML 页面的功能,另外它还是 一个 Servlet 和 JSP 容

器,独立的 Servlet 容器是 Tomcat 的默认模式。不过,Tomcat 处理静态 HTML 的能力不如 Apache

服务器。目前 Tomcat 最新版本为 9.0。

4.2. 安装Tomcat

运行 Tomcat 需要 JDK 的支持【Tomcat 会通过 JAVA_HOME 找到所需要的 JDK】。 安装就是解压缩

过程。启动 Tomcat,能访问则算安装好了

  1. 解压Tomcat8的压缩包

  2. 启动 Tomcat (在 tomcat 的安装目录下的 bin 目录 使用命令行启动 tomcat)

    startup.bat启动,shutdown.bat关闭

  3. 服务器启动成功

    1. Tomcat默认占用端口8080。(注意端口冲突问题) 
    2. 如果需要使用服务器,启动成功后,该启动窗口不要关闭。
    
  4. 打开浏览器,输入http://localhost:8080/ 访问

  5. 调用 shutdown 命令关闭Tomcat服务器

4.3. Tomcat目录结构

  1. bin:启动和关闭 tomcat 的 bat 文件
  2. conf:配置文件server.xml 该文件用于配置 server 相关的信息,比如 tomcat 启动的端口号,配

置主机(Host) ;web.xml 文件配置与 web 应用(web 应用相当于一个 web站点);tomcat

user.xml 配置用户名密码和相关权限

  1. lib:该目录放置运行 tomcat 运行需要的 jar 包
  2. logs:存放日志,当我们需要查看日志的时候,可以查询信息
  3. webapps:放置我们的 web 应用
  4. work 工作目录:该目录用于存放 jsp 被访问后生成对应的 server 文件和.class 文件

4.4. IDEA配置Tomcat

  1. 在settings下的Build里选择 “Appliction Servers”,点击右侧的 “+” 号,选择 “Tomcat Server”
  2. 设置 Tomcat 的安装目录。Tomcat Home选到bin目录的上一级,Tomcat base directory会自动填充,与上一个相同。
  3. 配置Tomcat服务器完成,点击右上角的 "Add Configurations ",打开 “Run/Debug Configurations” 窗口点击左上角的 “+” 号,选择 "Tomcat Server"Local插件配置,

在这里插入图片描述

如果下面出现红色提醒,可以直接点击Fix在Deployment去设置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qGRY0if1-1650469084467)(E:\program\安装资料\笔记工具\Markdown\Pictures\java中级\07 servlet\Tomcat\idea配置Tomcat02.png)]

5. Servlet的实现

Servlet 是 Server 与 Applet 的缩写,是服务端小程序的意思。使用 Java 语言编写的服务器端程序,

可以生成动态的 WEB 页,Servlet 主要运行在服务器端,并由服务器调用执行, 是一种按照 Servlet 标

准来开发的类。 是 SUN 公司提供的一门用于开发动态 Web 资源的技术。(言外之意:要实现 web 开

发,需要实现 Servlet 标准)

Servlet 本质上也是 Java 类,但要遵循 Servlet 规范进行编写,没有 main()方法,它的创建、使用、

销毁都由 Servlet 容器进行管理(如 Tomcat)。(言外之意:写自己的类,不用写 main 方法,别人自动

调用)

Servlet 是和 HTTP 协议是紧密联系的,其可以处理 HTTP 协议相关的所有内容。这也是 Servlet 应用

广泛的原因之一。

提供了 Servlet 功能的服务器,叫做 Servlet 容器,其常见容器有很多,如 Tomcat, Jetty, WebLogic

Server, WebSphere, JBoss 等等。

5.1. 创建Web项目

选择 “File” —> “New” —> “Project”,同上

5.2. Servlet的实现

5.2.1. 新建类
  1. 创建普通 java类

  2. 遵循servlet标准(继承 HttpServlet)

    pom.xml中添加(https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api/3.1.0)

    <dependencies>
        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>3.1.0</version>
          <scope>provided</scope>
        </dependency>
      </dependencies>
    
    1. 重写service方法(当前Servlet 类被访问时自动调用service方法)ctrl+o
    2. 设置对外访问的路径 (设置@WebServlet(“/路径”))

    注解可以设置多个(name无用)

    @WebServlet(name="Servlet01",value={"/ser01",'/ser001'})
    @WebServlet(name="Servlet01",urlPatterns={"/ser01",'/ser001'})
    

项目结构如下:

5.2.2 发布项目并启动服务

到此,需要编写和配置的地方已经完成,项目已经完整了,但是如果需要外界能够访问, 还需要将项

目发布到服务器上并运行服务器,配置Tomcat,在浏览器查看结果.

5.3. Servlet的工作流程
  1. 通过请求头获知浏览器访问的是哪个主机
  2. 再通过请求行获取访问的是哪个一个web应用
  3. 再通过请求行中的请求路径获知访问的是哪个资源
  4. 通过获取的资源路径在配置中匹配到真实的路径,
  5. 服务器会创建servlet对象,(如果是第一次访问时,创建servlet实例,并调用init方法进行初始化

操作)

  1. 调用service(request, response)方法来处理请求和响应的操作
  2. 调用service完毕后返回服务器 由服务器讲response缓冲区的数据取出,以http响应的格式发送给

浏览器

5.4. Servlet的生命周期

Servlet没有 main()方法,不能独立运行,它的运行完全由 Servlet 引擎来控制和调度。 所谓生命周

期,指的是 servlet 容器何时创建 servlet 实例、何时调用其方法进行请求的处理、 何时并销毁其实例的

整个过程。

  • 实例和初始化时机

当请求到达容器时,容器查找该 servlet 对象是否存在,如果不存在,则会创建实例并进行初始

化。

  • 就绪/调用/服务阶段

有请求到达容器,容器调用 servlet 对象的 service()方法,处理请求的方法在整个生命周期中可以被

多次调用; HttpServlet 的 service()方法,会依据请求方式来调用 doGet()或者 doPost()方法。但

是, 这两个 do 方法默认情况下,会抛出异常,需要子类去 override。

  • 销毁时机

当容器关闭时(应用程序停止时),会将程序中的 Servlet 实例进行销毁。

上述的生命周期可以通过 Servlet 中的生命周期方法来观察。在 Servlet 中有三个生命周 期方法,

不由用户手动调用,而是在特定的时机有容器自动调用,观察这三个生命周期方法 即可观察到

Servlet 的生命周期。

init 方法,在 Servlet 实例创建之后执行(证明该 Servlet 有实例创建了)

service 方法,每次有请求到达某个 Servlet 方法时执行,用来处理请求(证明该Servlet 进行服务了)

destroy 方法,Servlet 实例销毁时执行(证明该 Servlet 的实例被销毁了)

 /**
 * 创建Servlet
 *      1.创建普通 java类
 *      2.遵循servlet标准(继承 HttpServlet)
 *      3.重写service方法(当前Servlet 类被访问时自动调用service方法)
 *      4.设置对外访问的路径 (设置@WebServlet("/路径"))
 *
 */
@WebServlet("/ser02")
public class Servlet02 extends HttpServlet {
     /**
     * Servlet被实例化后(初始化),service方法可以被多次调用
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
  
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         System.out.println("服务调用了...");
    }

   
    /**
     * 当资源被访问时自动调用初始化方法
     *      调用时只执行一次
     */
    @Override
    public void init() throws ServletException {
        System.out.println("初始化");
    }


    /**
     * 当服务器关闭时自动调用销毁方法
     *      服务器关闭时只执行一次
     */
    @Override
    public void destroy() {
        System.out.println("销毁");//初始化,服务调用了...,服务调用了...,服务调用了...,销毁
    }
}

Servlet 的生命周期,简单的概括这就分为四步:servlet 类加载–>实例化–>服务–>销毁。

在这里插入图片描述

  1. Web Client 向 Servlet 容器(Tomcat)发出 Http 请求
  2. Servlet 容器接收 Web Client 的请求
  3. Servlet 容器创建一个 HttpServletRequest 对象,将 Web Client 请求的信息封装到这个对象 中
  4. Servlet 容器创建一个 HttpServletResponse 对象
  5. Servlet 容器调HttpServlet 对象service 方法,把 Request 与 Response 作为参数,传给

HttpServlet

  1. HttpServlet 调用 HttpServletRequest 对象的有关方法,获取 Http 请求信息
  2. HttpServlet 调用 HttpServletResponse 对象的有关方法,生成响应数据
  3. Servlet 容器把 HttpServlet 的响应结果传给 Web Client

6. HttpServletRequest对象

HttpServletRequest 对象:主要作用是用来接收客户端发送过来的请求信息,例如:请求的参数,发

送的头信息等都属于客户端发来的信息,service()方法中形参接收的是 HttpServletRequest 接口的实例

化对象,表示该对象主要应用在 HTTP 协议上,该对象是由 Tomcat 封装好传递过来。

HttpServletRequest 是 ServletRequest 的子接口,ServletRequest 只有一个子接口,就是

HttpServletRequest。既然只有一个子接口为什么不将两个接口合并为一个?

从长远上讲:现在主要用的协议是 HTTP 协议,但以后可能出现更多新的协议。若以后想要支持这种

新协议,只需要直接继承 ServletRequest 接口就行了。

在 HttpServletRequest 接口中,定义的方法很多,但都是围绕接收客户端参数的。但是怎么拿到该对

象呢?不需要,直接在 Service 方法中由容器传入过来,而我们需要做的就是取出对象中的数据,进行

分析、处理。

6.1. 接收请求

6.1.1. 常用方法

方法

在这里插入图片描述

6.1.2. 获取请求参数

方法

  • getParameter(name)获取指定名称的参数,返回字符串
  • getParameterValues(String name)获取指定名称参数的所有参数值,返回数组
6.1.3 实例

http://localhost:8080/sw/ser03?uname=za&hobby=bb

@WebServlet("/ser03")
public class Servlet03 extends HttpServlet {
    /**
     * Servlet被实例化后(初始化),service方法可以被多次调用
     * @param request
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
        // 获取客户端请求的完整URL (从http开始,到?前面结束)
        String url = request.getRequestURL().toString();
        System.out.println("获取客户端请求的完整URL:" + url);
        //  获取客户端请求的部分URL (从站点名开始,到?前面结束)
        String uri = request.getRequestURI();
        System.out.println("获取客户端请求的部分URI:" + uri);
        // 获取请求行中的参数部分
        String queryString = request.getQueryString();
        System.out.println("获取请求行中的参数部分:" + queryString);
        // 获取客户端的请求方式
        String method = request.getMethod();
        System.out.println("获取客户端的请求方式:" + method);
        // 获取HTTP版本号
        String protocol = request.getProtocol();
        System.out.println("获取HTTP版本号:" + protocol);
        // 获取webapp名字 (站点名)
        String webapp = request.getContextPath();
        System.out.println("获取webapp名字:" + webapp);

        // 获取指定名称的参数,返回字符串
        String uname = request.getParameter("uname");
        System.out.println("uname的参数值:" + uname);
        // 获取指定名称参数的所有参数值,返回数组
        String[] hobbys = request.getParameterValues("hobby");
        System.out.println("获取指定名称参数的所有参数值:" + Arrays.toString(hobbys));
    }
}

获取客户端请求的完整URL:http://localhost:8080/sw/ser03
获取客户端请求的部分URI:/sw/ser03
获取请求行中的参数部分:uname=za&hobby=bb
获取客户端的请求方式:GET
获取HTTP版本号:HTTP/1.1
获取webapp名字:/sw
uname的参数值:za
获取指定名称参数的所有参数值:[bb]

6.2. 请求乱码问题

由于现在的 request 属于接收客户端的参数,所以必然有其默认的语言编码,主要是由于在解析过程

中默认使用的编码方式为 ISO-8859-1(此编码不支持中文),所以解析时一定会出现乱码。要想解决这种

乱码问题,需要设置 request 中的编码方式,告诉服务器以何种方式来解析数据。或者在接收到乱码数

据以后,再通过相应的编码格式还原。

方式一:

request.setCharacterEncoding("UTF-8");

这种方式只针对 POST 有效(必须在接收所有的数据之前设定)

方式二:

new String(request.getParameter(name).getBytes("ISO-8859-1"),"UTF-8");

借助了String 对象的方法,该种方式对任何请求有效,是通用的。

Tomcat8起,以后的GET方式请求是不会出现乱码的。

6.3. 请求转发

请求转发,是一种服务器的行为,当客户端请求到达后,服务器进行转发,此时会将请求对象进行保

存,地址栏中的 URL 地址不会改变,得到响应后,服务器端再将响应发送给客户端,从始至终只有一个

请求发出。

实现方式如下,达到多个资源协同响应的效果。

request.getRequestDispatcher(url).forward(request,response);
request.getRequestDispatcher("req_attr.jsp").forward(request,resp);

6.4. request作用域

通过该对象可以在一个请求中传递数据,作用范围:在一次请求中有效,即服务器跳转有效。

// 设置域对象内容 
request.setAttribute(String name, String value); 
request.setAttribute("msg","登录成功");
// 获取域对象内容 
request.getAttribute(String name); 
// 删除域对象内容 
request.removeAttribute(String name);

request 域对象中的数据在一次请求中有效,则经过请求转发,request 域中的数据依然存在,则在

请求转发的过程中可以通过 request 来传输/共享数据。

 		   //设置作用域数据
            request.setAttribute("msg","登录成功");
            //请求转发
           request.getRequestDispatcher("req_attr.jsp").forward(request,resp);

<%--
  Created by IntelliJ IDEA.
  User: 龙
  Date: 2022/4/19
  Time: 15:01
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%=request.getAttribute("msg")%>
</body>
</html>

7. HttpServletResponse对象

Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的 request 对象

代表响应的 response 对象。

request 和 response 对象代表请求和响应:获取客户端数据,需要通过 request 对象;向客户端输

出数据,需要通过 response 对象

HttpServletResponse 的主要功能用于服务器对客户端的请求进行响应,将 Web 服务器处理后的结

果返回给客户端。service()方法中形参接收的是 HttpServletResponse 接口的实例化对象,这个对象中

封装了向客户端发送数据、发送响应头,发送响应状态码的方法。

7.1. 响应数据

接收到客户端请求后,可以通过 HttpServletResponse 对象直接进行响应,响应时需要获取输出流。

有两种形式:

getWriter() 获取字符流**(只能响应回字符)**

getOutputStream() 获取字节流**(能响应一切数据)**

响应回的数据到客户端被浏览器解析。

注意:两者不能同时使用。

@WebServlet("/ser01")
public class Servlet01 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //resp.setHeader("content-type","text/html;charset=UTF-8"); // html,加入不乱码
        //resp.setContentType("text/html;charset=UTF-8");//也不乱码
        //获取字符流
        PrintWriter writer = resp.getWriter();
        writer.write("zs");//zs
        writer.write("张三");//乱码
        writer.flush();
        writer.close();
        //字节流
        /*ServletOutputStream os = resp.getOutputStream();
        os.write("zs".getBytes());//zs
        os.write("张三".getBytes());//张三
        os.flush();
        os.close();*/

    }
}

7.2. 响应乱码问题

在响应中,如果我们响应的内容中含有中文,则有可能出现乱码。这是因为服务器响应的数据也会经

过网络传输,服务器端有一种编码方式,在客户端也存在一种编码方式,当两端使用的编码方式不同时

则出现乱码。

getWriter()的字符乱码

对于 getWriter()获取到的字符流,响应中文必定出乱码,由于服务器端在进行编码时默认会使用 ISO-

8859-1 格式的编码,该编码方式并不支持中文。

要解决该种乱码只能在服务器端告知服务器使用一种能够支持中文的编码格式,比如我们通常用

的"UTF-8"。

两端指定编码后,乱码就解决了。一句话:保证发送端和接收端的编码一致

// 设置服务端的编码 
response.setCharacterEncoding("UTF-8"); 
// 设置客户端的响应类型及编码 
response.setHeader("content-type","text/html;charset=UTF-8"); 
// 得到字符输出流 
PrintWriter writer = response.getWriter(); writer.write("<h2>你好</h2>");

以上两端编码的指定也可以使用一句替代,同时指定服务器和客户端

response.setContentType("text/html;charset=UTF-8");

7.3. 重定向

重定向是一种服务器指导,客户端的行为。客户端发出第一个请求,被服务器接收处理后,服务器会

进行响应,在响应的同时,服务器会给客户端一个新的地址(下次请求的地址

response.sendRedirect(url);),当客户端接收到响应后,会立刻、马上、自动根据服务器给的新地址

发起第二个请求,服务器接收请求并作出响应,重定向完成。

从描述中可以看出重定向当中有两个请求存在,并且属于客户端行为。

// 重定向跳转到index.jsp 
response.sendRedirect("index.jsp");

7.4. 请求转发与重定向的区别

response 重定向  request请求转发之间的区别
1.请求转发是服务端行为,重定向是客户端行为
2.请求转发地址栏不发生改变,重定向会发生改变
3.请求转发地址栏发送 1次请求,重定向会发送 2次请求
4.请求转发的数据(requset)可以共享,重定向不共享数据
5.请求转发的起始路径是从当前项目开始的,所以不能跳转到百度以及外网
  重定向的起始路径是http://开始的,所以跳转到百度以及外网

8. Cookie对象

Cookie是浏览器提供的一种技术,通过服务器的程序能将一些只须保存在客户端,或者在客户端进行

处理的数据,放在本地的计算机上,不需要通过网络传输,因而提高网页处理的效率,并且能够减少服

务器的负载,但是由于 Cookie 是服务器端保存在客户端的信息, 所以其安全性也是很差的。例如常见

的记住密码则可以通过 Cookie 来实现。

有一个专门操作Cookie的类 javax.servlet.http.Cookie。随着服务器端的响应发送给客户端,保存

在浏览器。当下次再访问服务器时把Cookie再带回服务器。

Cookie 的格式:键值对用“=”链接,多个键值对间通过“;”隔开。

8.1. Cookie的创建和发送

通过 new Cookie(“key”,“value”);来创建一个 Cookie 对象,要想将 Cookie 随响应发送到客户端,需

要先添加到 response 对象中,response.addCookie(cookie);此时该 cookie 对象则随着响应发送至了

客户端。在浏览器上可以看见。

		// 创建Cookie对象
        Cookie cookie = new Cookie("uname","张三");
        // 发送Cookie对象
        resp.addCookie(cookie);

右键检查,Application,Cookies

8.2. Cookie的获取

在服务器端只提供了一个 getCookies()的方法用来获取客户端回传的所有 cookie 组成的一个数组,如

果需要获取单个 cookie 则需要通过遍历,getName()获取 Cookie 的名称,getValue()获取 Cookie 的

值。

 		// 获取Cookie数组
        Cookie[] cookies = req.getCookies();
        // 判断数组是否为空
        if (cookies != null && cookies.length > 0){
            for(Cookie cookie:cookies){
                if("uname".equals(cookie.getName())){
                    System.out.println(cookie.getValue());
                }
            }
        }

8.3. Cookie设置到期时间

除了 Cookie 的名称和内容外,我们还需要关心一个信息,到期时间,到期时间用来指定该 cookie 何

时失效。默认为当前浏览器关闭即失效。我们可以手动设定 cookie 的有效时间(通过到期时间计算),

通过 setMaxAge(int time);方法设定 cookie 的最大有效时间,以秒为单位。

到期时间的取值

  • 负整数

    若为负数,表示不存储该 cookie。

    cookie 的 maxAge 属性的默认值就是-1,表示只在浏览器内存中存活,一旦关闭浏览器窗口,那

    么 cookie 就会消失。

  • 正整数

    若大于 0 的整数,表示存储的秒数。

    表示 cookie 对象可存活指定的秒数。当生命大于 0 时,浏览器会把 Cookie 保存到硬盘上,就算

    关闭浏览器,就算重启客户端电脑,cookie 也会存活相应的时间。

  • 若为 0,表示删除该 cookie。

    cookie 生命等于 0 是一个特殊的值,它表示 cookie 被作废!也就是说,如果原来浏览器已经保存

    了这个 Cookie,那么可以通过 Cookie 的 setMaxAge(0)来删除这个 Cookie。 无论是在浏览器内

    存中,还是在客户端硬盘上都会删除这个 Cookie。

 		// 创建Cookie对象
        Cookie cookie1 = new Cookie("uname","张三");
        Cookie cookie2 = new Cookie("age","20");
        Cookie cookie3 = new Cookie("job","shanghai");
        //设置到期时间
        cookie1.setMaxAge(-2);
        cookie2.setMaxAge(0);
        cookie3.setMaxAge(1*24*60*60);
        // 发送Cookie对象
        resp.addCookie(cookie1);//有,关掉浏览器就没了
        resp.addCookie(cookie2);//没有
        resp.addCookie(cookie3);//有,关掉浏览器还有

        Cookie cookie = new Cookie("uname", "null");
        cookie.setMaxAge(0);
        resp.addCookie(cookie);//cook01的没有了

8.4. Cookie的注意点

  1. Cookie保存在当前浏览器中。

    在一般的站点中常常有记住用户名这样一个操作,该操作只是将信息保存在本机上,换电脑以后这

    些信息就无效了。而且 cookie 还不能跨浏览器。

  2. Cookie存中文问题

    Cookie 中不能出现中文,如果有中文则通过 URLEncoder.encode()来进行编码,获取时通过

    URLDecoder.decode()来进行解码。

 		// 通过 URLEncoder.encode()来进行编码
        String name = URLEncoder.encode("姓名");
        // 创建Cookie对象
        Cookie cookie1 = new Cookie(name,"张三");


        //设置到期时间
        cookie1.setMaxAge(-2);

        // 发送Cookie对象
        resp.addCookie(cookie1);
 		// 获取Cookie数组
        Cookie[] cookies = req.getCookies();
        // 判断数组是否为空
        if (cookies != null && cookies.length > 0){
            for(Cookie cookie:cookies){
                /*if("uname".equals(cookie.getName())){
                    System.out.println(cookie.getValue());
                }*/
                // 获取时通过 URLDecoder.decode()来进行解码
                String name = URLDecoder.decode(cookie.getName());
                System.out.println(name);
            }
        }
  1. 同名Cookie问题

    如果服务器端发送重复的Cookie那么会覆盖原有的Cookie。

  2. 浏览器存放Cookie的数量

    不同的浏览器对Cookie也有限定,Cookie的存储有是上限的。Cookie是存储在客户端(浏览器)

    的,而且一般是由服务器端创建和设定。后期结合Session来实现回话跟踪。

8.5. Cookie的路径

Cookie的setPath设置cookie的路径,这个路径直接决定服务器的请求是否会从浏览器中加载某些

cookie。

**情景一:**当前服务器下任何项目的任意资源都可获取Cookie对象


**情景二:**当前项目下的资源可获取Cookie对象 (默认不设置Cookie的path)

**情景三:**指定项目下的资源可获取Cookie对象

**情景四:**指定目录下的资源可获取Cookie对象

如果我们设置path,如果当前访问的路径包含了cookie的路径(当前访问路径在cookie路径基础上要

比cookie的范围小)cookie就会加载到request对象之中。

cookie的路径指的是可以访问该cookie的顶层目录,该路径的子路径也可以访问该cookie。

总结:当访问的路径包含了cookie的路径时,则该请求将带上该cookie;如果访问路径不包含 cookie路径,则该请求不会携带该cookie。

9. HttpSession对象

HttpSession对象是 javax.servlet.http.HttpSession 的实例,该接口并不像 HttpServletRequest 或

HttpServletResponse 还存在一个父接口,该接口只是一个纯粹的接口。这因为 session 本身就属于

HTTP 协议的范畴。

对于服务器而言,每一个连接到它的客户端都是一个 session,servlet 容器使用此接口创建 HTTP 客

户端和 HTTP 服务器之间的会话。会话将保留指定的时间段,跨多个连接或来自用户的页面请求。一个

会话通常对应于一个用户,该用户可能多次访问一个站点。可以通过此接口查看和操作有关某个会话的

信息,比如会话标识符、创建时间和最后一次访问时间。在整个 session 中,最重要的就是属性的操

作。

session 无论客户端还是服务器端都可以感知到,若重新打开一个新的浏览器,则无法取得之前设置

的 session,因为每一个 session 只保存在当前的浏览器当中,并在相关的页面取得。

Session 的作用就是为了标识一次会话,或者说确认一个用户;并且在一次会话(一个用户的多次请

求)期间共享数据。我们可以通过 request.getSession()方法,来获取当前会话的 session 对象。

// 如果session对象存在,则获取;如果session对象不存在,则创建 
HttpSession session = request.getSession();

9.1. 标识符 JSESSIONID

Session 既然是为了标识一次会话,那么此次会话就应该有一个唯一的标志,这个标志就是

sessionId。

每当一次请求到达服务器,如果开启了会话(访问了 session),服务器第一步会查看是否从客户端

回传一个名为 JSESSIONID 的 cookie,如果没有则认为这是一次新的会话,会创建 一个新的 session 对

象,并用唯一的 sessionId 为此次会话做一个标志。如果有 JESSIONID 这 个cookie回传,服务器则会根

据 JSESSIONID 这个值去查看是否含有id为JSESSION值的session 对象,如果没有则认为是一个新的会

话,重新创建一个新的 session 对象,并标志此次会话; 如果找到了相应的 session 对象,则认为是之

前标志过的一次会话,返回该 session 对象,数据达到共享。

这里提到一个叫做 JSESSIONID 的 cookie,这是一个比较特殊的 cookie,当用户请求服务器时,如果

访问了 session,则服务器会创建一个名为 JSESSIONID,值为获取到的 session(无论是获取到的还是

新创建的)的 sessionId 的 cookie 对象,并添加到 response 对象中,响应给客户端,有效时间为关闭

浏览器。

所以 Session 的底层依赖 Cookie 来实现。

浏览器和后台其中有一个关了,就会开启新会话

		 // 如果session对象存在,则获取;如果session对象不存在,则创建
        HttpSession session = req.getSession();
        String id = session.getId();
        System.out.println(id);//JSESSIONID	AA558BD0F793D5EC4DA53D4B3BDEF965
    }

9.2. session域对象

Session 用来表示一次会话,在一次会话中数据是可以共享的,这时 session 作为域对象存在,可以

通过 setAttribute(name,value) 方法向域对象中添加数据,通过 getAttribute(name) 从域对象中获取

数据,通过 removeAttribute(name) 从域对象中移除数据。

当浏览器访问后台时,默认携带jsessionID,只有前台后台的JsessionID存在并且一致时才能接着会话

// 获取session对象 
HttpSession session = request.getSession(); 
// 设置session域对象 
session.setAttribute("uname","admin");
// 获取指定名称的session域对象 
String uname = (String) request.getAttribute("uname"); 
// 移除指定名称的session域对象 
session.removeAttribute("uname");
		//cook07
		// 如果session对象存在,则获取;如果session对象不存在,则创建
        HttpSession session = req.getSession();
        // 设置session域对象
        session.setAttribute("uname","张三");
        
        //cook06
        // 如果session对象存在,则获取;如果session对象不存在,则创建
        HttpSession session = req.getSession();
        String id = session.getId();
        System.out.println(id);//AA558BD0F793D5EC4DA53D4B3BDEF965
        // 获取指定名称的session域对象
        String uname = (String) session.getAttribute("uname");
        System.out.println(uname);

数据存储在 session 域对象中,当 session 对象不存在了,或者是两个不同的 session 对象时,数据

也就不能共享了。这就不得不谈到 session 的生命周期。

9.3. session对象的销毁

9.3.1. 默认时间到期

当客户端第一次请求 servlet 并且操作 session 时,session 对象生成,Tomcat 中 session 默认的存

活时间为 30min,即你不操作界面的时间,一旦有操作,session 会重新计时。

那么 session 的默认时间可以改么?答案是肯定的。

可以在 Tomcat 中的 conf 目录下的 web.xml 文件中进行修改。

<!-- session 默认的最大不活动时间。单位:分钟。 -->
<session-config> 
	<session-timeout>30</session-timeout>
</session-config>
9.3.2. 自己设定到期时间

当然除了以上的修改方式外,我们也可以在程序中自己设定 session 的生命周期,通过

session.setMaxInactiveInterval(int) 来设定 session 的最大不活动时间,单位为秒。

// 获取session对象
HttpSession session = request.getSession(); 
// 设置session的最大不活动时间 
session.setMaxInactiveInterval(15); // 15秒

当然我们也可以通过 getMaxInactiveInterval() 方法来查看当前 Session 对象的最大不活动时间。

// 获取session的最大不活动时间 
int time = session.getMaxInactiveInterval();
9.3.3. 立刻失效

或者我们也可以通过 session.invalidate() 方法让 session 立刻失效

// 销毁session对象 
session.invalidate();
9.3.4. 关闭浏览器

从前面的 JESSIONID 可知道,session 的底层依赖 cookie 实现,并且该 cookie 的有效时间为关闭浏

览器,从而 session 在浏览器关闭时也相当于失效了(因为没有 JSESSION 再与之对应)。

9.3.5. 关闭服务器

当关闭服务器时,session 销毁。

Session 失效则意味着此次会话结束,数据共享结束。

10. ServletContext对象

每一个 web 应用都有且仅有一个ServletContext 对象,又称 Application 对象,从名称中可知,该对

象是与应用程序相关的。在 WEB 容器启动的时候,会为每一个 WEB 应用程序创建一个对应的

ServletContext 对象。

该对象有两大作用,第一、作为域对象用来共享数据,此时数据在整个应用程序中共享; 第二、该对

象中保存了当前应用程序相关信息。例如可以通过 getServerInfo() 方法获取当前服务器信息 ,

getRealPath(String path) 获取资源的真实路径等。

10.1. ServletContext对象的获取

获取 ServletContext 对象的途径有很多。比如

 		//创建servletContext对象的方式
 		//通过 request 对象获取
        ServletContext servletContext = request.getServletContext();
        // 通过 session 对象获取
        ServletContext servletContext1 = request.getSession().getServletContext();
        //通过 servletConfig 对象获取,在 Servlet 标准中提供了 ServletConfig 方法
        ServletContext servletContext2 = getServletConfig().getServletContext();
        //直接获取,Servlet 类中提供了直接获取 ServletContext 对象的方法
        ServletContext servletContext3 = getServletContext();

常用方法

// 获取项目存放的真实路径 
String realPath = request.getServletContext().getRealPath("/"); 
// 获取当前服务器的版本信息 
String serverInfo = request.getServletContext().getServerInfo()
// 获取项目存放的真实路径
System.out.println(servletContext.getRealPath("/"));
// 获取当前服务器的版本信息
System.out.println(servletContext3.getServerInfo());

10.2. ServletContext域对象

ServletContext 也可当做域对象来使用,通过向 ServletContext 中存取数据,可以使得整个应用程序

共享某些数据。当然不建议存放过多数据,因为 ServletContext 中的数据一旦存储进去没有手动移除将

会一直保存。

// 获取ServletContext对象 
ServletContext servletContext = request.getServletContext();
// 设置域对象 
servletContext.setAttribute("name","zhangsan"); 
// 获取域对象 
String name = (String) servletContext.getAttribute("name"); 
// 移除域对象 
servletContext.removeAttribute("name")

Servlet的三大域对象

  1. request域对象

    在一次请求中有效。请求转发有效,重定向失效。

  2. session域对象

    在一次会话中有效。请求转发和重定向都有效,session销毁后失效。

  3. servletContext域对象

    在整个应用程序中有效。服务器关闭后失效。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值