Servlet 相关内容

news2024/11/15 14:07:30

1. Servlet

1.1 Servlet概述

 Servlet 是 SUN 公司提供的一套规范,名称就叫 Servlet 规范,它也是 JavaEE 规范之一,可以通过API来学习。目前在Oracle官网中的最新版本是JavaEE8,该网址中介绍了JavaEE8的一些新特性。当然,我们可以通过访问官方API,学习和查阅里面的内容。

1.2 Servlet详解

  • Servlet是一个运行在 web 服务端的 java 小程序,用于接收和响应客户端的请求,基于 Http 协议

  • 要想实现 Servlet 功能,可以实现 Servlet 接口,继承 GenericServlet 或者 HttpServlet

  • 核心方法:任何客户端请求每次请求时都会执行 service 方法

1.3 servlet版本对应

截止到目前,最新的 Servlet 版本是 6.1

下表列出了各种主要 Servlet 版本其对应的 Java 版本和 Tomcat 版本。

 1.4 Servlet 主要做的工作

  • 允许程序猿注册一个类, 在 Tomcat 收到某个特定的 HTTP 请求的时候, 执行这个类中的一些代码。

  • 帮助程序猿解析 HTTP 请求,把 HTTP 请求从一个字符串解析成一个 HttpRequest 对象。

  • 帮助程序猿构造 HTTP 响应,程序猿只要给指定的 HttpResponse 对象填写一些属性字段, Servlet 就会自动的按照 HTTP 协议的方式构造出一个 HTTP 响应字符串, 并通过 Socket 写回给客户端。简而言之, Servlet 是一组 Tomcat 提供的 API, 让程序猿自己写的代码能很好的和 Tomcat 配合起来, 从 而更简单的实现一个 web app。而不必关注 Socket, HTTP协议格式, 多线程并发等技术细节, 降低了 web app 的开发门槛, 提高了开发效率。 我们只需要关注生成响应的这个过程。

2 Servlet快速入门

2.1 servlet编写步骤

  1. 前期准备-创建JavaWeb工程

  2. 编写一个普通类继承GenericServlet并重写service方法

  3. 在web.xml配置Servlet

  4. 部署并启动

  5. 浏览器测试运行

2.1.1 创建Javaweb工程

Servlet 快速上手教程(上)_赵同学&的博客-CSDN博客

2.1.2 创建servlet类

第一步,pom文件添加jar包

<dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
    </dependency>

最新版本使用下方的 

<dependencies>
    <dependency>
        <groupId>jakarta.servlet</groupId>
        <artifactId>jakarta.servlet-api</artifactId>
        <version>6.0.0</version>
    </dependency>
</dependencies>

第二步,创建servlet类继承GenericServlet

/*
 * Copyright (c) 2017, 2023, zxy.cn All rights reserved.
 *
 */
package cn.zxy.controller;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;

/**
 * <p>Description:</p>
 * <p>Class:</p>
 * <p>Powered by zxy On 2023/6/25 13:57 </p>
 *
 * @author zxy [zxy06291@163.com]
 * @version 1.0
 * @since 17
 */
public class FirstServlet extends GenericServlet {

    @Override
    public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
        System.out.println("执行了firstServlet里面的service方法。。。。");
    }
}

2.1.3 编写web.xml配置文件

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <!--servlet核心的配置-->
  <servlet>
    <servlet-name>firstServlet</servlet-name>
    <!--必须全类名-->
    <servlet-class>cn.zxy.controller.FirstServlet</servlet-class>
  </servlet>
  <!--servlet映射 一个url路径-->
  <servlet-mapping>
    <servlet-name>firstServlet</servlet-name>
    <url-pattern>/first</url-pattern>
  </servlet-mapping>

  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

2.1.4 部署tomcat并启动

点击run选择Edit 或者直接点击右上角小锤子也可以

配置添加tomcat文件

 2.1.5 浏览器url地址输入

2.2 Servlet执行过程分析

我们通过浏览器发送请求,请求首先到达Tomcat服务器,由服务器解析请求URL,然后在部署的应用列表中找到我们的应用。接下来,在我们的应用中找应用里的web.xml配置文件,在web.xml中找到FirstServlet的配置,找到后执行service方法,最后由FirstServlet响应客户浏览器。整个过程如下图所示:

一句话总结执行过程:

浏览器——>Tomcat服务器——>我们的应用——>应用中的web.xml——>FirstServlet——>响应浏览器

2.3 继承Httpservlet使用案例

继承 HttpServlet ,它是 jakarta.servlet.http 包下的一个抽象类,是 GenericServlet 的子类。

如果我们选择继承 HttpServlet 时,只需要重写 doGet 和 doPost 方法,不要覆盖 service 方法。使用此种方式,表示我们的请求和响应需要和 HTTP 协议相关,是通过 HTTP 协议来访问的。那么每次请求和响应都符合 HTTP 协议的规范。

请求的方式是 HTTP 协议所支持的方式(目前我们只知道 GET 和 POST ,而实际 HTTP 协议支持7种请求方式,GET POST PUT DELETE TRACE OPTIONS HEAD )。

2.3.1 在入门案例的工程中创建一个Servlet继承HttpServlet


public class servletDemo01 extends HttpServlet {

}

web.xml配置文件:

<servlet>
    <servlet-name>servletDemo01</servlet-name>
    <servlet-class>com.by.web.ServletDemo01</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>servletDemo01</servlet-name>
    <url-pattern>/servletDemo01</url-pattern>
</servlet-mapping>

第二步:部署项目并测试访问

当我们在地址栏输入servletDemo01的访问URL时,出现了访问错误,状态码是405。提示信息是:方法不允许。

 第三步:分析原因

得出HttpServlet的使用结论:

我们继承了HttpServlet,需要重写里面的doGet和doPost方法来接收get方式和post方式的请求。

为了实现代码的可重用性,我们只需要在doGet或者doPost方法中一个里面提供具体功能即可,而另外的那个方法只需要调用提供了功能的方法。

2.3.2 响应行详解

响应行:HTTP/1.1 200 OK

内容说明
HTTP/1.1使用协议的版本。
200响应状态码
OK状态码描述

常用状态码介绍:

状态码说明
200一切都OK>
302/307请求重定向(客户端行为,两次请求,地址栏发生改变)
304请求资源未发生变化,使用缓存
404请求资源未找到
405用来访问本页面的 HTTP 谓词不被允许(方法不被允许)请求方式不对
500服务器错误

2.4 Servlet使用细节

2.4.1 Servlet生命周期

生命周期是指事物从创建到毁灭的过程。

Servlet 也有生命周期,Servlet 的生命周期就是 Servlet 从创建到销毁的过程。Servlet 的生命周期由 Servlet 容器管理,主要分为以下 3 个阶段。

  1. 初始化阶段

  2. 运行时阶段

  3. 销毁阶段

2.4.2 初始化阶段

Servlet 初始化是其生命周期的第一个阶段,也是其他阶段的基础。只有完成了初始化,Servlet 才能处理来自客户端的请求。

Servlet 初始化阶段分为 2 步:

  1. 加载和实例化 Servlet;

  2. 调用 init() 方法进行初始化。

  3. 加载和实例化 Servlet

Servlet 容器负责加载和实例化 Servlet。当容器启动或首次请求某个 Servlet 时,容器会读取 web.xml 或 @WebServlet 中的配置信息,对指定的 Servlet 进行加载。加载成功后,容器会通过反射对 Servlet 进行实例化。

因为 Servlet 容器是通过 Java 的反射 API 来创建 Servlet 实例的,需要调用 Servlet 的默认构造方法(default constructor,即不带参数的构造方法),所以在编写 Servlet 类时,不能只提供一个带参数的构造方法。

1.调用 init() 方法进行初始化

加载和实例化完成后,Servlet 容器调用 init() 方法初始化 Servlet 实例。

初始化的目的:让 Servlet 实例在处理请求之前完成一些初始化工作,例如建立数据库连接,获取配置信息等。

在 Servlet 的整个生命周期内,init() 方法只能被调用一次。

初始化期间,Servlet 实例可以通过 ServletConfig 对象获取在 web.xml 或者 @WebServlet 中配置的初始化参数。

2.4.3 运行时阶段

运行时阶段是 Servlet 生命周期中最重要的阶段。Servlet 容器接收到来自客户端请求时,容器会针对该请求分别创建一个 ServletRequst 对象和 ServletResponse 对象,将它们以参数的形式传入 service() 方法内,并调用该方法对请求进行理处。

2.4.4 销毁阶段

当 Servlet 容器关闭、重启或移除 Servlet 实例时,容器就会调用 destory() 方法,释放该实例使用的资源,例如:关闭数据库连接,关闭文件的输入流和输出流等,随后该实例被 Java 的垃圾收集器所回收。

对于每个 Servlet 实例来说,destory() 方法只能被调用一次。

2.5 Servlet 生命周期执行流程

Servlet 生命周期流程如下图所示。

在 Servlet 的整个生命周期中,创建 Servlet 实例、init() 方法和 destory() 方法都只执行一次。当初始化完成后,Servlet 容器会将该实例保存在内存中,通过调用它的 service() 方法,为接收到的请求服务。

总结:

servlet对象只会创建一次,销毁一次,所以Servlet对象只有一个实例,如果一个对象实例在应用中是唯一的存在,那么就被称为单例。

2.5.1代码演示:

@Override
public void init() throws ServletException {
    System.out.println("servlet创建并初始化成功");
}
​
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    System.out.println("接收客户端的请求。。。");
}
​
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    doGet(req,resp);
}
​
@Override
public void destroy() {
    System.out.println("对象已销毁。。。。");
}

2.6 虚拟路径匹配规则

Servlet 虚拟路径匹配规则有以下 4 种:

  1. 完全路径匹配 /demo

  2. 目录匹配 /demo/*

  3. 扩展名匹配 *.do

  4. 缺省匹配(默认匹配) / /*

下面我们以 servletDemo 为例,分别介绍 4 种规则。

匹配规则使用规则虚拟路径可访问的URL
完全路径匹配 (精确匹配)以/开始,不能包含通配符*。 必须完全匹配/myServlet /user/myServlet /product/index.actionhttp://localhost:8080/servletDemo/myServlet http://localhost:8080/servletDemo/user/myServlet http://localhost:8080/servletDemo/product/index.action
目录匹配以/字符开头,并以/*结尾的字符串。 用于路径匹配/user/*http://localhost:8080/servletDemo/user/aaa http://localhost:8080/servletDemo/aa
扩展名匹配以通配符*.开头的字符串。 用于扩展名匹配*.do *.action *.jsphttp://localhost:8080/servletDemo/user.do http://localhost:8080/servletDemo/myServlet.action http://localhost:8080/servletDemo/bb.jsp
缺省匹配(默认匹配)映射路径为/,表示这个 Servlet 为当前应用的缺省 Servlet 或默认 Servlet,默认处理无法匹配到虚拟路径的请求。/可以匹配任意请求 URL

注意:目录匹配和扩展名匹配无法混合使用,即 /rest/*.do 这种写法是不正确的。

2.6.1 匹配优先级

Servlet 虚拟路径的匹配优先级顺序为:全路径匹配(精确匹配)> 目录匹配 > 扩展名匹配 > 缺省匹配(默认匹配)。

2.6.2 多路径映射

  • 我们可以给一个Servlet配置多个访问映射,从而根据不同的请求路径来实现不同的功能。

  • 场景分析:

    • 如果访问访问的资源路径是/vip 商品价格打9折

    • 如果访问访问的资源路径是/Cvip 商品价格打5折

    • 如果访问访问的资源路径是其他 商品价格不打折

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //1、定义商品价格
    int money=1000;
    //2、获取浏览器访问路径
    String path = req.getRequestURI();
     path = path.substring(path.lastIndexOf("/"));
    //判断路径
    if("/vip".equals(path)){
        System.out.println("商品原价是="+money+"优惠后的价格是="+(money * 0.9));
    }else if ("/cvip".equals(path)){
        System.out.println("商品原价是="+money+"优惠后的价格是="+(money * 0.5));
    }else{
        System.out.println("您不是会员您的商品原价是="+money);
    }
​
}

web.xml配置

<servlet>
    <servlet-name>ServletDemo02</servlet-name>
    <servlet-class>com.by.web.ServletDemo02</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ServletDemo02</servlet-name>
    <url-pattern>/demo02/*</url-pattern>
</servlet-mapping>

3 TomCat介绍

3.1 称服务器

服务器的概念非常的广泛,它可以指代一台特殊的计算机(相比普通计算机运行更快、负载更高、价格更贵),也可以指代用于部署网站的应用。我们这里说的服务器,其实是web服务器,或者应用服务器。它本质就是一个软件,一个应用。作用就是发布我们的应用(工程),让用户可以通过浏览器访问我们的应用。

常见的应用服务器,请看下表:

服务器名称说明
weblogic实现了javaEE规范,重量级服务器,又称为javaEE容器
websphereAS实现了javaEE规范,重量级服务器。
JBOSSAS实现了JavaEE规范,重量级服务器。免费的。
Tomcat实现了jsp/servlet规范,是一个轻量级服务器,开源免费。

3.2 Tomcat下载

Servlet 快速上手教程(上)_赵同学&的博客-CSDN博客

4 ServletConfig

4.1 ServletConfig概述

4.1.1 基本概念

是 Servlet 的配置参数对象,在 Servlet 规范中,允许为每个 Servlet 都提供一些初始化配置。所以,每个 Servlet 都有一个自己的 ServletConfig 。它的作用是在 Servlet 初始化期间,把一些配置信息传递给 Servlet 。

4.1.2 生命周期

由于它是在初始化阶段读取了 web.xml 中为 Servlet 准备的初始化配置,并把配置信息传递给Servlet,所以生命周期与 Servlet 相同。这里需要注意的是,如果 Servlet 配置了 <load-on-startup>1</load-on-startup>,那么 ServletConfig 也会在应用加载时创建。

4.2 ServletConfig的使用

4.2.1 如何配置

需要使用 <servlet> 标签中的 <init-param> 标签来配置。

Servlet 的初始化参数都是配置在 Servlet 的声明部分的。并且每个 Servlet 都支持有多个初始化参数,并且初始化参数都是以键值对的形式存在的。接下来,我们看配置示例:

<!--配置servletDemo02-->
    <servlet>
        <servlet-name>servletDemo02</servlet-name>
        <servlet-class>com.by.web.ServletDemo02</servlet-class>
        <!--配置初始化参数-->
        <init-param>
<!--            用于获取初始化参数的key-->
            <param-name>name</param-name>
            <!--初始化参数的值-->
            <param-value>张三</param-value>
        </init-param>
        <init-param>
            <param-name>servletInfo</param-name>
            <param-value>this is Demo02</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>servletDemo02</servlet-name>
        <url-pattern>/servletDemo02</url-pattern>
    </servlet-mapping>

4.2.3 ServletConfig 接口参数

javax.servlet 包提供了一个 ServletConfig 接口,该接口中提供了以下方法。

返回值类型方法功能描述
StringgetInitParameter(String name)根据初始化参数名 name,返回对应的初始化参数值。
Enumeration<String>getInitParameterNames()返回 Servlet 所有的初始化参数名的枚举集合,如果该 Servlet 没有初始化参数,则返回一个空的集合。
ServletContextgetServletContext()返回一个代表当前 Web 应用的 ServletContext 对象。
StringgetServletName()返回 Servlet 的名字,即 web.xml 中 <servlet-name> 元素的值。

代码演示输出

//创建一个servletConfig对象
 private ServletConfig servletConfig;
​
@Override
    public void init(ServletConfig config) throws ServletException {
       this.servletConfig=config;
    }
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  //输出servletConfig的值
    System.out.println(servletConfig);
    //获取servlet名字
    String servletName = servletConfig.getServletName();
    System.out.println("servlet的名字是="+servletName);
    //获取自定以name名字
    String name = servletConfig.getInitParameter("name");
    System.out.println("自定义的名字是="+name);
    Enumeration<String> enumer = servletConfig.getInitParameterNames();
    while (enumer.hasMoreElements()) {
        //取出每个names值
        String names = enumer.nextElement();
        //根据key获取Value值
        String value = servletConfig.getInitParameter(names);
        System.out.println("name= "+names+"  value= "+value);
    }
    //获取servletContext对象
    ServletContext servletContext = servletConfig.getServletContext();
    System.out.println(servletContext);
}

5. ServletContext接口详解

Servlet 容器启动时,会为每个 Web 应用(web下的每个目录都是一个 Web 应用)创建一个唯一的 ServletContext 对象,该对象一般被称为“Servlet 上下文”。

ServletContext 对象的生命周期从 Servlet 容器启动时开始,到容器关闭或应用被卸载时结束。

Web 应用中的所有 Servlet 共享同一个 ServletContext 对象,不同 Servlet 之间可以通过 ServletContext 对象实现数据通讯,因此 ServletContext 对象也被称为 Context 域对象。

域对象是服务器在内存上创建的存储空间,该空间用于不同动态资源(例如 Servlet、JSP)之间传递与共享数据。

5.1 域对象概念

域对象的概念,它指的是对象有作用域,即有作用范围。

域对象的作用,域对象可以实现数据共享。不同作用范围的域对象,共享数据的能力不一样。

在Servlet规范中,一共有4个域对象。今天我们讲解的ServletContext就是其中一个。它也是我们接触的第一个域对象。它是web应用中最大的作用域,叫application域。每个应用只有一个application域。它可以实现整个应用间的数据共享功能。

5.2 ServletContext配置

ServletContext 既然被称之为应用上下文对象,所以它的配置是针对整个应用的配置,而非某个特定 Servlet 的配置。它的配置被称为应用的初始化参数配置。

配置的方式,需要在<web-app>标签中使用<context-param>来配置初始化参数。具体代码如下:

<!--配置应用初始化参数-->
<context-param>
    <!--用于获取初始化参数的key值-->
    <param-name>namespace</param-name>
    <!--用于获取初始化参数的value值-->
    <param-value>小李子</param-value>
</context-param>
<!--每个应用初始化参数都需要用到context-param标签-->
<context-param>
    <param-name>globalEncoding</param-name>
    <param-value>UTF-8</param-value>
</context-param>

5.3 ServletContext常用的方法

返回值类型方法功能描述
StringgetInitParameter(String name)根据初始化参数名 name,返回对应的初始化参数值。
stringgetContextPath()获取虚拟目录
stringgetRealPath(String name)根据虚拟目录获取应用部署的磁盘绝对路径
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   //创建上下文对象
    ServletContext context=getServletContext();
    //获取全局配置的globalEncoding
    String glo = context.getInitParameter("globalEncoding");
    System.out.println(glo);
    //获取虚拟目录
    String pa = context.getContextPath();
    System.out.println("虚拟目录是"+pa);
    //根据虚拟目录获取应用部署的磁盘绝对路径
    //获取c.txt文件的绝对路径
    String c = context.getRealPath("/WEB-INF/c.txt");
    System.out.println(c);

    //向域对象中存储数据
   // context.setAttribute("username","zhangsan");
    context.removeAttribute("username");
}

5.4 ServletContext常用方法

实现共享数据的方法

返回值方法名说明
voidsetAttribute(String name, Object value);向应用域对象中存储数据
objectgetAttribute(String name);通过名称获取应用对象中存储的数据
voidremoveAttribute(String name);通过名称删除应用域对象中的数据

6 注解开发入门案例

6.1 删除web.xml

直接编写代码就好了

@WebServlet("/webDemo")
public class WebServletDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("servlet 注解执行完成");
    }
}

@WebServlet注解

在 Servlet 中,web.xml 扮演的角色十分的重要,它可以将所有的 Servlet 的配置集中进行管理,但是若项目中 Servelt 数量较多时,web.xml 的配置会变得十分的冗长。这种情况下,注解(Annotation)就是一种更好的选择。

为了简化 Servlet 的配置,Servlet 3.0 中增加了注解支持,例如:@WebServlet、@WebInitParm 、@WebFilter 和 @WebLitener 等,这使得 web.xml 从 Servlet 3.0 开始不再是必选项了。下面我们对 @WebServlet 进行介绍。

@WebServlet 注解的属性

@WebServlet 用于将一个类声明为 Servlet,该注解会在部署时被容器处理,容器根据其具体的属性配置将相应的类部署为 Servlet。该注解具有下表给出的一些常用属性。

属性名类型标签描述是否必需
nameString<servlet-name>指定 Servlet 的 name 属性。 如果没有显式指定,则取值为该 Servlet 的完全限定名,即包名+类名。
valueString[ ]<url-pattern>该属性等价于 urlPatterns 属性,两者不能同时指定。 如果同时指定,通常是忽略 value 的取值。
urlPatternsString[ ]<url-pattern>指定一组 Servlet 的 URL 匹配模式。
loadOnStartupint<load-on-startup>指定 Servlet 的加载顺序。
initParamsWebInitParam[ ]<init-param>指定一组 Servlet 初始化参数。
descriptionString<description>指定该 Servlet 的描述信息。
displayNameString<display-name>指定该 Servlet 的显示名。

7 Request&Response

7.1 HttpServletResponse响应对象概述

在 Servlet API 中,定义了一个 HttpServletResponse 接口,它继承自 ServletResponse 接口。HttpServletResponse 对象专门用来封装 HTTP 响应消息,简称 response 对象。

Servlet 容器会针对每次请求创建一个 response 对象,并把它作为参数传递给 Servlet 的 service 方法。Servlet 处理请求后,会将响应信息封装到 response 对象中,并由容器解析后返回给客户端。

7.2 关于响应

响应,它表示了服务器端收到请求,同时也已经处理完成,把处理的结果告知用户。指的就是服务器把请求的处理结果告知客户端,在B/S架构中,响应就是把结果带回浏览器。

响应对象,顾名思义就是用于在JavaWeb工程中实现上述功能的对象。

7.2.1 响应行相关的方法

当 Servlet 返回响应消息时,需要在响应消息中设置状态码。因此,HttpServletResponse 接口定义了发送状态码的方法,如下表。

返回值类型方法描述
voidsetStatus(int status)用于设置 HTTP 响应消息的状态码,并生成响应状态行。
voidsendError(int sc)用于发送表示错误信息的状态码。

7.2.2 响应头相关的方法

HttpServletResponse 接口中定义了一系列设置 HTTP 响应头字段的方法,如下表所示。

返回值类型方法描述
voidsetHeader (String name,String value)用于设置响应头字段,其中,参数 name 用于指定响应头字段的名称,参数 value 用于指定响应头字段的值。
voidaddIntHeader(String name,int value)用于增加值为 int 类型的响应头字段,其中,参数 name 用于指定响应头字段的名称,参数 value 用于指定响应头字段的值,类型为 int。
voidsetIntHeader(String name, int value)用于设置值为 int 类型的响应头字段,其中,参数 name 用于指定响应头字段的名称,参数 value 用于指定响应头字段的值,类型为 int。
voidsetContentType(String type)用于设置 Servlet 输出内容的 MIME 类型以及编码格式。
voidsetCharacterEncoding(String charset)用于设置输出内容使用的字符编码。

7.2.3 响应体相关的方法

由于在 HTTP 响应消息中,大量的数据都是通过响应消息体传递的。

因此 ServletResponse 遵循以 I/O 流传递大量数据的设计理念,在发送响应消息体时,定义了两个与输出流相关的方法。

返回值类型方法描述
ServletOutputStreamgetOutputStream()用于获取字节输出流对象。
PrintWritergetWriter()用于获取字符输出流对象。

7.3 响应对象的使用示例

7.3.1 响应-字节流输出及乱码问题

@WebServlet("/respDemo")
public class RespDemo01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //获取字节流对象
        ServletOutputStream so = resp.getOutputStream();
        //准备一个消息
        String str="字节输出流";
        resp.setContentType("text/html;charset=utf-8");
        //通过字节输出
        so.write(str.getBytes("utf-8"));

    }

7.3.2 响应-字符流输出中文问题

@WebServlet("/respDemo2")
public class RespDemo02 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1、获取字符流对象
        PrintWriter writer = resp.getWriter();
        //2、设置响应正文的字符集
        resp.setContentType("text/html;charSet=UTF-8");
        //3、编写预留文字
        String str="使用字符流输出信息";
        //4、响应输出到控制台
        writer.write(str);
    }

7.3.3 设置响应消息头定时刷新

/*
 * Copyright (c) 2017, 2023, zxy.cn All rights reserved.
 *
 */
package cn.zxy.web;

import com.sun.net.httpserver.HttpServer;

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;

/**
 * <p>Description:</p>
 * <p>Class:</p>
 * <p>Powered by zxy On 2023/6/25 17:23 </p>
 *
 * @author zxy [zxy06291@163.com]
 * @version 1.0
 * @since 17
 */
@WebServlet("/respDemo02")
public class RespDemo02 extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charSet=utf-8");

        String str="3秒后跳转到别的页面去";
        PrintWriter writer =resp.getWriter();
        writer.write(str);
        //设置跳转
        resp.setHeader("Refresh","3,URL=/login.jsp");
        //重定向的数据不能共享 因为发送了两次请求
        Object username = req.getAttribute("username");
        System.out.println(username);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

7.3.4请求重定向:注意地址栏发生改变。

  • 请求重定向:客户端的一次请求到达后,发现需要借助其他servlet来实现功能

  • 特点:浏览器地址栏发生改变,发送两次请求,请求域对象中不能共享数据,可以重定向到其他服务器

  • 重定向实现原理

    • resp.setStatus(302);

  • 设置响应的资源路径(响应到哪里去,通过响应消息头location来指定)

    • resp.setHeader("location","/ReqResp/respdemo");

  • 响应对象方法:

    • sendRedirect(String name): 指定重定向

使用示例:

/*
 * Copyright (c) 2017, 2023, zxy.cn All rights reserved.
 *
 */
package cn.zxy.web;

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;

/**
 * <p>Description:</p>
 * <p>Class:</p>
 * <p>Powered by zxy On 2023/6/25 21:20 </p>
 *
 * @author zxy [zxy06291@163.com]
 * @version 1.0
 * @since 17
 */
@WebServlet("/respDemo03")
public class RespDemo03 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("RespDemo03 已经开始执行。。。");
        resp.setContentType("text/html;charSet=utf-8");
//        //1、设置状态码
//        resp.setStatus(302);
//        // 2、设置响应的资源路径
//        resp.setHeader("location","/respDemo02");
        //重定向
        String contextPath = req.getContextPath();
        //  System.out.println(contextPath);
        resp.sendRedirect(contextPath+"/respDemo02");
        req.setAttribute("username","zhangsan");

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

另一个类:

/*
 * Copyright (c) 2017, 2023, zxy.cn All rights reserved.
 *
 */
package cn.zxy.web;

import com.sun.net.httpserver.HttpServer;

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;

/**
 * <p>Description:</p>
 * <p>Class:</p>
 * <p>Powered by zxy On 2023/6/25 17:23 </p>
 *
 * @author zxy [zxy06291@163.com]
 * @version 1.0
 * @since 17
 */
@WebServlet("/respDemo02")
public class RespDemo02 extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charSet=utf-8");

        String str="3秒后跳转到别的页面去";
        PrintWriter writer =resp.getWriter();
        writer.write(str);
        //设置跳转
        resp.setHeader("Refresh","3,URL=/login.jsp");
        //重定向的数据不能共享 因为发送了两次请求
        Object username = req.getAttribute("username");
        System.out.println(username);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

7.3.5 响应和消息头组合应用-文件下载

文件下载的思路:

1.获取文件路径

2.把文件读到字节输入流中

3.设置响应消息头支持的类型

4.告知浏览器,以下载的方式打开(告知浏览器下载文件的MIME类型)

5.使用响应对象的字节输出流输出到浏览器上

6.循环读写

7.释放资源

/*
 * Copyright (c) 2017, 2023, zxy.cn All rights reserved.
 *
 */
package cn.zxy.web;

import javax.servlet.ServletConfig;
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;

/**
 * <p>Description:</p>
 * <p>Class:</p>
 * <p>Powered by zxy On 2023/6/25 21:20 </p>
 *
 * @author zxy [zxy06291@163.com]
 * @version 1.0
 * @since 17
 */
@WebServlet("/respDemo04")
public class RespDemo04 extends HttpServlet {
    public ServletConfig servletConfig;

    @Override
    public void init(ServletConfig config) throws ServletException {
        this.servletConfig=config;
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1 获取文件路径
        ServletContext context = servletConfig.getServletContext();
        String realPath = context.getRealPath("/WEB-INF/image/q1.jpg");
        //2 把文件读取到字节输入流当中
        FileInputStream in=new FileInputStream(realPath);
        /*
            content-Type: 消息支持的类型 字符流
        application/octet-stream : 消息的参数,应用的类型是字节流的模式
         */
        resp.setHeader("content-Type","application/octet-stream");
        //3 告知浏览器以下载的方式打开
        /*
            content-Disposition 内容处理方式
            attachment;filename 附件形式处理 指定的文件名字
         */
        resp.setHeader("content-Disposition","attachment;filename=q1.jpg");
        //4 指定输出流
        ServletOutputStream out = resp.getOutputStream();
        byte[] bytes=new byte[1024];
        int len;
        while ((len=in.read(bytes))!=-1){
            out.write(bytes,0,len);
        }
        in.close();
        out.close();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/684173.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C语言初阶】带你轻松玩转所有常用操作符(2) ——赋值操作符,单目操作符

君兮_的个人主页 勤时当勉励 岁月不待人 C/C 游戏开发 Hello,这里是君兮_&#xff0c;今天给大家带来的是有关操作符的第二部分内容&#xff0c;废话不多说&#xff0c;咱们直接开始吧&#xff01; 在正式开始之前&#xff0c;我们还是借助一张思维导图帮助大致简单回忆一下有…

Docker-compose的使用

目录 Docker-compose 简介 docker-compose的安装 docker-compose.yaml文件说明 compose的常用命令 总结 Docker-compose 简介 Docker-compose 是用于定义和运行多容器的 Docker 应用程序的工具。可以使用YAML文件来配置应用程序的服务。&#xff08;通俗讲是可以通过yml文…

LeetCode108-将有序数组转换为二叉搜索树

题目来源 108. 将有序数组转换为二叉搜索树 - 力扣&#xff08;LeetCode&#xff09; 题目 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵高度平衡 二叉搜索树。 高度平衡二叉树是一棵满足「每个节点的左右两个子树的高度差的…

智慧地下采矿,“像素游戏”智能呈现

在这个像素世界里&#xff0c;我们需要一个智能地下采矿可视化综合管理平台&#xff0c;来帮助我们管理和监控地下采矿全流程。 图扑软件依托自主研发的 HT for Web 产品&#xff0c;结合三维定制化渲染、动态模拟、物理碰撞、5G、物联网、云计算及大数据等先进技术&#xff0c…

从零开始理解Linux中断架构(8)---执行上下文之CPU上下文

1 CPU上下文的来由 CPU上下文是切换任务到CPU时需要保存和恢复的CPU寄存器。ARM64需要保存的寄存器如下图所示 X19-X29作为CPU上下文的依据是什么? 实际上这里使用了一个隐含的事实:Linux所有的任务切换都是在内核中__switch_to函数中进行的,当前任务通过__…

KubeSphere 社区双周报 | OpenFunction 发布 v1.1.1 | 2023.6.9-6.22

KubeSphere 社区双周报主要整理展示新增的贡献者名单和证书、新增的讲师证书以及两周内提交过 commit 的贡献者&#xff0c;并对近期重要的 PR 进行解析&#xff0c;同时还包含了线上/线下活动和布道推广等一系列社区动态。 本次双周报涵盖时间为&#xff1a;2023.6.9-6.22。 …

Elisp之定时器run-with-timer、run-with-idle-timer、run-at-time 区别(二十二)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

libevent(11)libevent中的循环和退出函数

一、libevent基本原理介绍 一个 event_base 对象相当于一个 Reactor 实例&#xff08;不了解Reactor的读者可自行查询相关文章&#xff09;。libevent默认情况下是单线程的&#xff0c;每个线程有且只有一个event_base&#xff0c;对应一个struct event_base结构体以及附于其上…

由于找不到msvcp120.dll无法继续执行代码怎么办?

msvcp120.dll是微软软件包的一部分。它是一个库文件&#xff0c;可用于支持软件运行时&#xff0c;msvcp120.dll的作用是提供计算机程序所需的标准库&#xff0c;msvcp120.dll还负责管理堆内存、线程和异常处理函数等。在使用windows编写的应用程序中&#xff0c;通常需要使用此…

android 如何分析应用的内存(八)——malloc debug

android 如何分析应用的内存&#xff08;八&#xff09; 接上文&#xff0c;介绍六大板块中的第三个————malloc调试和libc回调 上一篇文章中&#xff0c;仅仅是在分配和释放的时候&#xff0c;拦截对应的操作。而不能进一步的去检查内存问题。比如&#xff1a;释放之后再…

深入理解Android Jetpack Compose的Box

Box是一个提供了一种快速、简便的方式来对其子元素进行层叠布局的布局组件。 一、什么是Box? 二、如何使用Box? 三、Box中的contentAlignment属性 四、使用Modifier在Box内进行更复杂的布局 一、什么是Box? 在Compose中&#xff0c;Box是一个简单的布局组件&#xff0c…

如何写出高效、准确的会议记录?

在企业或组织中&#xff0c;会议是一种常见的沟通和决策方式。作为参会人员之一&#xff0c;撰写一份高效、准确的会议记录显得尤为重要。会议记录不仅记录了会议的主题、议题和讨论结果&#xff0c;还能帮助参与者回顾会议过程、梳理思路、明确职责&#xff0c;同时也为后续工…

快速入门JavaScript异步编程:从回调到async/await的跨越

文章目录 I. 介绍异步编程的背景和基本概念本文主要讨论JavaScript中的异步编程 II. 回调函数回调函数的定义、作用以及使用场景回调地狱的问题及解决方案 III. PromisePromise的定义、作用以及使用场景Promise的状态及状态转换Promise的链式调用和错误处理 IV. async/awaitasy…

深度学习之目标检测Fast-RCNN模型算法流程详解说明(超详细理论篇)

1.Fast-RCNN论文背景 2. Fast-RCNN算法流程 3.Fast R-CNN 问题和缺点 这篇以对比RCNN来说明&#xff0c;如果你对RCNN网络没太熟悉&#xff0c;可访问这链接&#xff0c;快速了解&#xff0c;点下面链接 深度学习之目标检测R-CNN模型算法流程详解说明&#xff08;超详细理论篇…

合宙Air724UG Cat.1模块硬件设计指南--原理图设计注意事项

在设计原理时注意以下几点&#xff1a; 严格按照模块硬件手册设计原理图 1.调试接口&#xff1a; 调试务必留出usb&#xff08;烧录脚本&#xff0c;升级用&#xff09; ,1.8v&#xff08;开机标志&#xff09;&#xff0c;uboot&#xff08;强制烧录用&#xff09;测试点&…

软件测试面试,大厂上岸究竟有什么秘诀?

最后&#xff0c;总结一下个人认为比较重要的知识点&#xff1a;接口自动化测试 &#xff1a;测试框架&#xff0c;多个有关联的接口的用例编写&#xff0c;用例的组织及存储&#xff0c;接口测试的覆盖率&#xff0c;RESTAssured 的封装等。UI 自动化测试 &#xff1a;iOS 和 …

Web自动化测试之滑动验证码的解决方案

目录 滑动验证破解思路 案例讲解 实现代码 运行效果&#xff1a; 根据传入滑块&#xff0c;和背景的节点&#xff0c;计算滑块的距离 滑动滑块进行验证 总结&#xff1a; 在Web自动化测试的过程中&#xff0c;经常会被登录的验证码给卡住&#xff0c;不知道如何去通过验证…

Prompt不等于编程,“提示词工程师”淘汰程序员也是伪命题

Original 李建忠 李建忠研思 最近ChatGPT及基于大语言模型&#xff08;Large Language Model&#xff0c;以下简写为LLM&#xff09;的Github Copilot等工具出来之后&#xff0c;在软件开发领域也带来了非常大的震撼。著名的观点有Fixie创始人、前Google工程总监Matt Welsh在AC…

解决onblur()失去焦点事件在刚登陆页面(尚未有任何操作)时就触发的问题

文章目录 一、原始错误&#xff1a;1.1 原始代码1.2 访问页面&#xff08;仅访问页面&#xff0c;不进行任何操作&#xff09; 二、解决错误2.1 解决办法2.2 再次访问页面2.2.1 输入错误格式2.2.2 输入正确格式 最近笔者在编写代码时遇到刚访问页面&#xff0c;什么都没有操作&…

JavaWeb学习笔记-1

学习路线 Web开发–介绍&#xff08;画大饼&#xff09; 什么是Web&#xff1f; Web&#xff1a;全球广域网&#xff0c;也成为万维网&#xff0c;能通过浏览器访问的网站 Web网站的工作流程 网站大致是由三个部分组成的 第一部分就是我们能看到的网页程序&#xff0c;也叫做…