Servlet

Servlet,第1张

Servlet

Servlet
  • 1、介绍
    • 1.1、什么是 Servlet
    • 1.2、自定义类直接实现 Servlet 程序
      • 1.2.1、url 地址到 Servlet 程序的访问过程
      • 1.2.2、Servlet 的生命周期
      • 1.2.3、GET 和 POST 请求的分发处理
    • 1.3、自定义类继承已有的实现子类 HttpServlet
    • 1.7、使用 IDEA 自定义类继承 HttpServlet
    • 1.8、Servlet 类的继承体系
  • 2、ServletConfig、ServletContext
    • 2.1、ServletConfig 类
      • ServletConfig 类的三大作用:
      • 注意点:
    • 2.2、ServletContext 类
      • ServletContext 类的四个作用
  • 3、HTTP 协议
    • 3.1、请求的 HTTP 协议格式
      • 3.1.1、GET 请求
      • 3.1.2、POST 请求
      • 3.1.3、常用请求头的说明
      • 3.1.4、常用请求
    • 3.2、响应的 HTTP 协议格式
      • 3.2.1、常用的响应码说明
      • 3.2.2、MIME 类型说明
      • 谷歌浏览器如何查看 HTTP 协议
  • 4、HttpServletRequest 类
    • 4.1、常用方法
    • 4.2、如何获取请求参数
    • 4.3、请求的转发getRequestDispatcher()
    • 4.4、base 标签的作用
    • 4.5、Web 中的相对路径和绝对路径
    • 4.6、web 中 / 斜杠的不同意义
  • 5、HttpServletResponse 类
    • 5.1、两个输出流的说明
    • 5.2、如何往客户端回传数据
    • 5.3、响应的乱码解决
    • 5.4、请求重定向sendRedirect()

导入源码

Tomcat 配置

1、介绍 1.1、什么是 Servlet
  • Servlet 是 JavaEE 规范之一。规范就是接口
  • Servlet 就 JavaWeb 三大组件之一。三大组件分别是:Servlet 程序、Filter 过滤器、Listener 监听器
  • Servlet 是运行在服务器上的一个 java 小程序,它 可以接收客户端发送过来的请求,并响应数据给客户端
1.2、自定义类直接实现 Servlet 程序
  1. 编写一个类去实现 Servlet 接口
  2. 实现 service 方法,处理请求,并响应数据
  3. 到 web.xml 中去配置 servlet 程序的访问地址

编写 Hello 类去实现 Servlet 接口
实现 service 方法
service 方法是专门用来处理请求和响应的

(没啥特别的,就是实现接口,并重写方法)

public class Hello implements Servlet {
    public Hello() {
        System.out.println("1、构造器");
    }

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("2、执行 init 初始化方法");
    }
    @Override
    public ServletConfig getServletConfig() {
        return null;
    }
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("3、service方法   ========>>>    hello servlet");
    }
    @Override
    public String getServletInfo() {
        return null;
    }
    @Override
    public void destroy() {
        System.out.println("4、执行 destroy 销毁方法");
    }
}

web.xml 中去配置 servlet 程序的访问地址



    
    
        
        Hello
        
        com.atguigu.servlet.Hello
    
    
    
        
        Hello
        
        /aba
    

注意:

  1. 首先,在 web.xml 中有两个大标签
    1. servlet 标签给 Tomcat 配置 Servlet 程序
    2. servlet-mapping 标签给 servlet 程序配置访问地址
  2. 在 servlet 标签中
    1. servlet-name 标签是给 Servlet 程序起一个别名(一般是类名)
    2. servlet-class 是 Servlet 程序的全类名,即自定义的实现 Servlet 接口的类的全名
  3. 在 servlet-mapping 标签中
    1. servlet-name 标签的作用是告诉服务器,我当前配置的地址给哪个 Servlet 程序使用,所以这里填写的内容要和 servlet 标签中的 servlet-name 标签内容保持一致
    2. url-pattern 标签配置访问地址,记得要有斜杠 /
      / 斜杠在服务器解析的时候,表示地址为:http://ip:port/工程路径
      /hello 表示地址为:http://ip:port/工程路径/hello
      这里的 /hello 在硬盘中没有实际位置,只是客户端通过该标签就可以访问到自定义类对应的 Servlet 程序

然后运行
先点击该工程的 Tomcat ,再点击三角形的运行按钮

在d出来的浏览器页面,在链接地址后面 加上 刚刚设置的访问地址

运行的结果会输出在 IDEA 控制台

经常会碰到几个问题:

  1. url-pattern 中配置的路径没有以斜杠开头

  2. servlet-name 配置的值不存在
    就是指在 servlet-mapping 标签中给的程序名一定要与 上一个标签中给 程序起的别名保持一致

  3. servlet-class 标签的全类名配置错误
    此种情况浏览器会正常d出,但是会报错

1.2.1、url 地址到 Servlet 程序的访问过程


客户端拿到 ip:port 定位到哪个电脑的哪个线程,通过工程路径得到工程

根据 web.xml 里面的 servlet-mapping 标签得到访问地址和地址配置给哪个 servlet 程序

根据程序名在 servlet 标签中找到全类名,找到类,再得到类里面重写的 service 方法

1.2.2、Servlet 的生命周期

1、执行 Servlet 构造器方法
2、执行 init 初始化方法
3、执行 service 方法
4、执行 destroy 销毁方法

第一、二步,是在第一次访问,的时候创建 Servlet 程序会调用
第三步,每次访问都会调用
第四步,在 web 工程停止的时候调用

第一次执行得到如下:

刷新浏览器得到如下,可见非第一次访问仅执行 service 方法

点击 IDEA 的停止执行

1.2.3、GET 和 POST 请求的分发处理

在学习 HTML 的时候,知道提交表单的时候,有两种请求方式 GET 、POST

但是在自定义实现 Servlet 接口的类中,只有一个 service 方法,有时候需要不同的请求方式去做不同的事情,此时就需要进行请求的分发处理

通过 F4 ,可以发现 ServletRequest 是接口,为了调用其子类中的getMethod()方法,强转为 HttpServletRequest 类型

service() 方法体如下

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("3、service方法   ========>>>    hello servlet");
        HttpServletRequest ser = (HttpServletRequest) servletRequest;
        //获取请求的类型
        String method = ser.getMethod();
        //System.out.println(method);   //输出就是GET
        if("GET".equals(method)){
            doget();
        }else if("POST".equals(method)){
            dopost();
        };
    }
    //将不同请求方式做的不同事情全部封装进方法内
    public void doget(){System.out.println("GET方式");}
    public void dopost(){System.out.println("POST方式");}

下面介绍的是怎么实现之前学习的表单提交,提交到这里给定的工程
同时验证输出语句 System.out.println(method);

现在写一个页面,来验证getMethod()方法能够返回请求的方式

1、创建文件
注意是在 web 的文件夹下 写页面

2、写一个表单,提交按钮
注意这里 提交的地址需要是在最开始 web.xml 中设定的 url-pattern 的地址




3、运行
注意运行的时候只需要在跳转的 链接后面加上文件名

4、执行结果:
页面提交一次,service 方法就会执行一次

1.3、自定义类继承已有的实现子类 HttpServlet

通过继承已经实现 Servlet 的 HttpServlet 类的方式去实现 Servlet 程序

一般在实际项目开发中,都是使用继承 HttpServlet 类的方式去实现 Servlet 程序
1、编写一个类去继承 HttpServlet 类
2、根据业务需要重写 doGet 或 doPost 方法
3、到 web.xml 中的 加 一个配置 Servlet 程序和访问地址的 *** 作

编写一个类,并重写方法

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("继承方式的 doGet 方法");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("继承方式的 doPost 方法");
    }
}

加 一个配置 Servlet 程序和访问地址的 *** 作

    
        HelloServlet
        com.atguigu.servlet.HelloServlet
    
    
        HelloServlet
        /hello
    

执行

使用 exp.html 文件




执行结果:

页面提交一次,service 方法就会执行一次

1.7、使用 IDEA 自定义类继承 HttpServlet

在包名上右击


IDEA 会创建好类
继承了 HttpServlet
提供了doPost和doGet的重写
提供了 web.xml 文件中的 标签

需要手动补上标签

1.8、Servlet 类的继承体系

2、ServletConfig、ServletContext 2.1、ServletConfig 类

ServletConfig 类从类名上来看,就知道是 Servlet 程序的配置信息类

Servlet 程序和 ServletConfig 对象都是由 Tomcat 负责创建,我们负责使用

Servlet 程序默认是第一次访问的时候创建,ServletConfig 是每个 Servlet 程序创建时,就创建一个对应的 ServletConfig 对象

Tomcat 有几个提供可以使用 ServletConfig 对象的位置:
1、将对象传给了init(ServletConfig servletConfig)方法,我们可以通过重写此方法,实现调用
2、在doPost和doGet的重写方法中,可以使用方法getServletConfig(),返回的是一个ServletConfig 类的对象

ServletConfig 类的三大作用:

(都是通过实例化对象调用)

  1. 可以获取 Servlet 程序的别名 servlet-name 的值
    servletConfig.getServletName()
  2. 获取初始化参数 init-param
    servletConfig.getInitParameter("参数名")
  3. 获取 ServletContext 对象
    servletConfig.getServletContext()

初始化参数 init-param
要先配置,才有该参数
在 web.xml 文件中的 标签里面进行配置

是呈现 键值对式的,一个参数名对应一个参数值
可以有多个 init-param


	Hello
	com.atguigu.servlet.Hello
      
	
	
		
		username
		
		root
	

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("2、执行 init 初始化方法");
        System.out.println(servletConfig.getServletName());
        System.out.println(servletConfig.getInitParameter("username"));
        System.out.println(servletConfig.getServletContext());
    }
注意点:
  1. servletconfig仅作用于单个servlet程序
    在创建servlet程序的时候,会创建一个对应的 servletconfig ,有一个一一对应的关系,包括servletconfig对应servlet程序在web.xml中配置的相关信息。所以在这个自定义类下的servletconfig对象无法访问另一个自定义类下的init-param,因为servlet程序程序不同
  2. 因为父类的 init 方法中有一句 this.config = config;,该句给父类的 config 属性进行了赋值,否则拿到的 config 就是 null值的。
    在子类重写了同名方法时,如果没有使用 super.init(config),那么子类重写的方法就会覆盖父类方法,父类方法得不到执行,那么 config 就是null 值的
    那这样在使用方法getServletConfig()的时候,就会返回一个 null 值
public class HelloServlrt extends HttpServlet {
    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("重写的方法init");
    }
	@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("继承方式的 doGet 方法");
        ServletConfig servletConfig = getServletConfig();
        System.out.println(servletConfig);   //null
    }
}

2.2、ServletContext 类

什么是 ServletContext?

  • ServletContext 是一个接口,它表示 Servlet 上下文对象
  • 一个 web 工程,只有一个 ServletContext 对象实例
  • ServletContext 对象是一个域对象
  • ServletContext 是在 web 工程部署启动的时候创建。在 web 工程停止的时候销毁。

什么是域对象?
域对象,是可以像 Map 一样存取数据的对象,叫域对象
这里的域指的是存取数据的 *** 作范围,整个 web 工程

ServletContext 类的四个作用
  1. 获取 web.xml 中配置的上下文参数 context-param
    servletContext.getInitParameter("参数名")

context-param 参数也是类似于参数 init-param是一个键值对的对应关系 但是不同于 参数 init-param,context-param 参数是声明在 web.xml 文件中的 标签外面,供一整个 web工程进行共享使用 所以同一个工程下的多个自定义类都可以去访问context-param 参数

  1. 获取当前的工程路径,格式: /工程路径
    context.getContextPath()

其实就是 Tomcat 配置页面的 Application context

  1. 获取工程部署后在服务器硬盘上的绝对路径
    context.getRealPath("/")

这里的参数 “ 斜杠 ”
获取到的路径实际上就是 IDEA 代码中,该 web 工程下的 web 文件夹的路径

  1. 像 Map 一样存取数据

此处解释 idea 中获取的工程路径一直都是 /工程路径:
在 IDEA 中,实际上是复制了tomcat部分文件夹,然后使用第二种 web 工程部署方式,即创建 工程路径.xml 配置文件(此处默认已将工程路径名称更改为工程名一致,所以同样是 工程名.xml), 配置文件中指明了工程在硬盘中的实际位置
访问的时候直接访问配置文件的位置即可http://localhost:8080/工程路径

1、获取 web.xml 中配置的上下文参数 context-param
该参数是定义在标签外面


    HelloServlrt
    com.atguigu.servlet.HelloServlrt


    HelloServlrt
    /hello



    age
    18



    username
    123

在同一个 web 工程下的不同类(即在不同 servlet 程序中),都可以访问上下文参数 context-param

public class HelloServlrt extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("继承方式的 doGet 方法");
        ServletContext servletContext = getServletConfig().getServletContext();
        System.out.println(servletContext.getInitParameter("age"));   //18
    }
}
public class HelloServlet3 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("另一个自定义类中");
        ServletContext servletContext = getServletConfig().getServletContext();
        System.out.println(servletContext.getInitParameter("age"));
    }
}

2、获取当前的工程路径

@Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    ServletContext servletContext = getServletConfig().getServletContext();
    System.out.println(servletContext.getContextPath());    ///servlet
}

3、获取工程部署后在服务器硬盘上的绝对路径

@Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    ServletContext servletContext = getServletConfig().getServletContext();
    //获取工程部署后在服务器硬盘上的绝对路径
    // "/"斜杠被服务器解析地址为:http://ip:port/工程名/ ,映射到 IDEA 代码的 web 目录
    System.out.println(servletContext.getRealPath("/"));
    //F:workspaceJavaWebJavaWeboutartifactsservlet_war_exploded
}

获取当前的工程路径/servlet
获取工程部署后在服务器硬盘上的绝对路径
F:workspaceJavaWebJavaWeboutartifactsservlet_war_exploded

在 IDEA 运行 web 工程的时候,会加载一个地址
Using CATALINA_base: "C:UsersASUS.IntelliJIdea2019.2systemtomcatTomcat_8_0_50_JavaWeb_3"

这里是IDEA整合Tomcat的时候复制了的部分文件,在在里面部署 web工程的方法就是在 conf 目录 Catalinalocalhost 下创建配置文件,文件里面指向的真实工程地址就是上面的F盘文件
而配置文件的名称就是上面获取当前的工程路径的名称servlet

这里的绝对路径F:...对应的就是工程下面的 web 文件夹

所以如果要访问web文件夹里面其他内容的路径,只需要在 斜杠 后面加上文件名即可
("工程下 imgs 目录 1.jpg 的绝对路径是:" + context.getRealPath("/imgs/1.jpg")

4、ServletContext 像 Map 一样存取数据
在父类中封装了方法getServletContext()来获取 ServletContext 对象

一个 web 工程,只有一个 ServletContext 对象实例
在不同的 servlet 程序里面,打印 ServletContext 对象,得到的是一致的地址值,说明 ServletContext 对象是整个 web 工程共有的

@Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    ServletContext context = getServletContext();
    System.out.println("一个servlet程序里的"+context);
}
public class HelloServlet3 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("另一个自定义类中");
        ServletContext context = getServletContext();
        System.out.println("另一个servlet程序里的"+context);
    }
}


因为不同的 servlet 程序共有一个 ServletContext 对象,所以里面存放的数据是不同的 servlet 程序共有的

@Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    ServletContext context = getServletContext();
    //设置数据之前
    System.out.println("设置数据之前"+context.getAttribute("key1"));
    //设置数据
    context.setAttribute("key1","value1");
    //设置数据之后访问
    System.out.println("设置数据之后"+context.getAttribute("key1"));
}
public class HelloServlet3 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("另一个自定义类中");
        ServletContext context = getServletContext();
        //不同的servlet程序中访问数据
        System.out.println("另一个自定义类中"+context.getAttribute("key1"));
    }
}


而 ServletContext 是在 web 工程部署启动的时候创建,在 web 工程停止的时候销毁(web工程的重新部署、重启就是销毁)
所以里面存放的数据也会随着重新部署而销毁,如果没有重新部署,就会一直存在

3、HTTP 协议

什么是 HTTP 协议?
协议是指双方,或多方,相互约定好,大家都需要遵守的规则,叫协议

HTTP 协议,就是指,客户端和服务器之间通信时,发送的数据,需要遵守的规则,叫 HTTP 协议

HTTP 协议中的数据又叫报文

3.1、请求的 HTTP 协议格式

客户端给服务器发送数据叫请求
服务器给客户端回传数据叫响应

请求又分为 GET 请求,和 POST 请求两种

3.1.1、GET 请求
  1. 请求行
    请求的方式 GET
    请求的资源路径 [+?+请求参数]
    请求的协议的版本号 HTTP/1.1
  2. 请求头
    key : value 键值对组成
    不同的键值对,表示不同的含义

3.1.2、POST 请求
  1. 请求行
    请求的方式 POST
    请求的资源路径 [+?+请求参数] 中括号为可选内容
    请求的协议的版本号 `HTTP/1.1
  2. 请求头
    key : value `
    不同的请求头,表示不同的含义
  3. 空行
  4. 请求体 ---->>> 就是发送给服务器的数据

3.1.3、常用请求头的说明

Accept: 表示客户端可以接收的数据类型
Accpet-Languege: 表示客户端可以接收的语言类型
User-Agent: 表示客户端浏览器的信息
Host: 表示请求时的服务器 ip 和端口号

3.1.4、常用请求

大部分情况下都是 get 请求的方式

GET 请求有哪些:

  1. form 标签 method=get
  2. a 标签
  3. link 标签引入 css
  4. script 标签引入 js 文件
  5. img 标签引入图片
  6. iframe 引入 html 页面
  7. 在浏览器地址栏中输入地址后敲回车

POST 请求有哪些:
8. form 标签 method=post

3.2、响应的 HTTP 协议格式
  1. 响应行
    1. 响应的协议和版本号
    2. 响应状态码
    3. 响应状态描述符
  2. 响应头
    key : value
    不同的响应头,有其不同含义
  3. 空行
  4. 响应体 ---->>> 就是回传给客户端的数据

3.2.1、常用的响应码说明

200 表示请求成功
302 表示请求重定向
404 表示请求服务器已经收到了,但是你要的数据不存在(请求地址错误)
500 表示服务器已经收到请求,但是服务器内部错误(代码错误int i = 12/0)

3.2.2、MIME 类型说明

MIME 是 HTTP 协议中的数据类型

MIME 的英文全称是"Multipurpose Internet Mail Extensions" 多功能 Internet 邮件扩充服务

MIME 类型的格式是“大类型/小 类型”,并与某一种文件的扩展名相对应。

常见的 MIME 类型:


谷歌浏览器如何查看 HTTP 协议


火狐浏览器如何查看 HTTP 协议:

4、HttpServletRequest 类

每次只要有请求进入 Tomcat 服务器,Tomcat 服务器就会把请求过来的 HTTP 协议信息解析好封装到 Request 对象中。 然后传递到 service 方法(doGet 和 doPost)中给我们使用。我们可以通过 HttpServletRequest 对象,获取到所有请求的 信息

HttpServletRequest 对象是 Tomcat 创建的,每次请求就会创建一个,请求过后,就会销毁

4.1、常用方法 方法描述getRequestURI()获取请求的资源路径getRequestURL()获取请求的统一资源定位符(绝对路径)getRemoteHost()获取客户端的 ip 地址getHeader()获取请求头getParameter()获取请求的参数getParameterValues()获取请求的参数(多个值的时候使用)getMethod()获取请求的方式 GET 或 POSTsetAttribute(key, value);设置域数据getAttribute(key);获取域数据getRequestDispatcher()获取请求转发对象
@Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //getRequestURI()	获取请求的资源路径
    System.out.println("URI ==> "+req.getRequestURI());   //URI ==> /servlet/hello
    //getRequestURL()	获取请求的统一资源定位符(绝对路径)
    System.out.println("URL ==> "+req.getRequestURL());   //URL ==> http://localhost:8080/servlet/hello
    //getRemoteHost()	获取客户端的 ip 地址
    
    System.out.println("客户端的 ip 地址 ==> "+req.getRemoteHost());  //客户端的 ip 地址 ==> 127.0.0.1
    //getHeader()	获取请求头
    System.out.println("请求头User-Agent ==> "+req.getHeader("User-Agent")); 
    //getMethod()	获取请求的方式 GET 或 POST
    System.out.println("请求的方式 ==> "+req.getMethod());  //请求的方式 ==> GET
}

getRemoteHost() 获取客户端的 ip 地址

在 IDEA 中,使用 localhost 访问时,得到的客户端 ip 地址是 ===>>> 127.0.0.1
在 IDEA 中,使用 127.0.0.1 访问时,得到的客户端 ip 地址是 ===>>> 127.0.0.1
在 IDEA 中,使用 真实 ip 访问时,得到的客户端 ip 地址是 ===>>> 真实的客户端 ip 地址

当将Tomcat上网址交给同局域网内的其他电脑访问时,这里可以得到已访问电脑的 ip 地址

4.2、如何获取请求参数
@Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //getParameter()	获取请求的参数,参数只有一个值
    String username = req.getParameter("username");
    String password = req.getParameter("password");
    System.out.println("用户名:" + username);
    System.out.println("密码:" + password);
    //getParameterValues()	获取请求的参数(多个值的时候使用)
    String[] hobbies = req.getParameterValues("hobby");
    System.out.println("兴趣:" + Arrays.asList(hobbies));
}

在浏览器页面输入参数信息

在 IDEA 输出请求参数

Get 请求的中文乱码解决
一般 get 请求没有中文乱码

// 获取请求参数 
String username = req.getParameter("username"); 

//1 先以 iso8859-1 进行编码 
//2 再以 utf-8 进行解码 
username = new String(username.getBytes("iso-8859-1"), "UTF-8");

在 Post 请求里面容易出现中文乱码的问题

POST 请求的中文乱码解决

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // 设置请求体的字符集为 UTF-8,从而解决 post 请求的中文乱码问题
    // 要在获取请求参数之前才有效,只要有一个请求参数的语句在前面,此句就无效
    req.setCharacterEncoding("UTF-8");
    System.out.println("---------doPost方法-----------");


    String username = req.getParameter("username");
    String password = req.getParameter("password");
    System.out.println("用户名:" + username);
    System.out.println("密码:" + password);
    String[] hobbies = req.getParameterValues("hobby");
    System.out.println("兴趣:" + Arrays.asList(hobbies));
}

注意:
设置请求体的字符集要在所有的获取请求参数语句之前才有效

4.3、请求的转发getRequestDispatcher()

请求转发是指,服务器收到请求后,从一次资源跳转到另一个资源的 *** 作叫请求转发

Servlet1 代码

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // 获取请求的参数(办事的材料)查看
    String username = req.getParameter("username");
    System.out.println("在 Servlet1(柜台 1)中查看参数(材料):" + username);

    // 给材料 盖一个章,并传递到 Servlet2(柜台 2)去查看
    //setAttribute()这里的数据时web工程下所有servlet程序共有的
    req.setAttribute("key1","柜台 1 的章");

    // 问路:Servlet2(柜台 2)怎么走
    //请求转发必须要以斜杠开头,/ 斜杠表示地址为:http://ip:port/工程名/ , 映射到 IDEA 代码的 web 目录
    //这里填写的是Servlet2的
    RequestDispatcher requestDispatcher = req.getRequestDispatcher("/servlet2");

    // 带着参数数据走向 Sevlet2(柜台 2)
    requestDispatcher.forward(req,resp);
}

Servlet2 代码

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // 获取请求的参数(办事的材料)查看
    String username = req.getParameter("username");
    System.out.println("在 Servlet2(柜台 2)中查看参数(材料):" + username);

    // 查看 柜台 1 是否有盖章
    Object key1 = req.getAttribute("key1");
    System.out.println("查看章:" + key1);

    // 处理自己的业务
    System.out.println("Servlet2 处理自己的业务 ");
}

执行


注意:

  1. 虽然是从一个程序转发到第二个程序,但是浏览器的网址没有发生变化

  2. 请求转发是在一次请求中的

  3. 因为在一次请求中只会产生一个请求对象,在一个请求对象里面存储的数据是多个 servlet 程序都可以访问到的
    setAttribute(key, value);设置域数据
    getAttribute(key);获取域数据

  4. WEB-INF 文件夹是受服务器保护的,如果将定义的 html 文件放到该目录下,是无法访问的

  5. 但是请求转发可以转到 WEB-INF 文件夹内
    req.getRequestDispatcher("/WEB-INF/abc.html")

  6. 请求转发无法转到外网,因为访问的地址是该工程下

4.4、base 标签的作用

a文件


    
    a


这里是first下second下的a.html
跳转到首页index.jsp

首页文件

  
这里是首页
跳转到first下second下的a.html
请求HelloServlet3转发到a.html

执行请求转发的 HelloServlet3

public class HelloServlet3 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("经过了HelloServlet3,走向first下second下的a.html");
        RequestDispatcher requestDispatcher = request.getRequestDispatcher("/first/second/a.html");
        requestDispatcher.forward(request,response);
    }
}


a.html里面有超链接可以直接从a.html页面跳转到首页,因为是相对路径,相对于当前的a.html页面

如果要使用HelloServlet3执行请求的转发的方式,实现首页和a.html页面之间的跳转
(即从首页的超链接跳转到HelloServlet3,HelloServlet3执行请求转发方法,转到a.html页面,再点击a.html页面的超链接回到首页)
前面一步是不会出问题的,要注意的是请求转发之后,从a.html页面的超链接回到首页

因为请求转发浏览器网址是不会变的,所以此时虽然是a.html页面,但网址是http://localhost:8080/servlet/hello3

而a.html页面里面的路径是相对路径,相对于当前页面去跳转到首页,但是当前页面的网址是http://localhost:8080/servlet/hello3,所以这里无法通过请求转发的方式跳转到首页

此时就需要使用 base 标签,让a.html页面的相对路径永远只参照自己的路径,而不会随着网址的变化而变化

base 标签设置页面相对路径工作时参照的地址, href 属性就是参考的地址值
下面是添加了 base 标签的 a.html
属性的地址值里面的a.html可以省略,只要写到了文件所在目录的位置即可


    
    a
    


这里是first下second下的a.html
跳转到首页index.jsp
4.5、Web 中的相对路径和绝对路径

在实际开发中,路径都使用绝对路径,而不简单的使用相对路径。
1、绝对路径
2、base+相对

4.6、web 中 / 斜杠的不同意义

在 web 中 / 斜杠 是一种绝对路径

/ 斜杠 如果被浏览器解析,得到的地址是:1http://ip:port/1

斜杠

/ 斜杠 如果被服务器解析,得到的地址是:http://ip:port/工程路径,同时就是 IDEA 代码中的web 文件夹

1、/servlet1 
2、servletContext.getRealPath(“/”); 
3、request.getRequestDispatcher(“/”);

特殊情况:
response.sendRediect(“/”);把斜杠发送给浏览器解析。得到 http://ip:port/

5、HttpServletResponse 类

HttpServletResponse 类和 HttpServletRequest 类一样。每次请求进来,Tomcat 服务器都会创建一个 Response 对象传递给 Servlet 程序去使用。

HttpServletRequest 表示请求过来的信息,HttpServletResponse 表示所有响应的信息

我们如果需要设置返回给客户端的信息,都可以通过 HttpServletResponse 对象来进行设置

5.1、两个输出流的说明

字节流 getOutputStream(); 常用于下载(传递二进制数据)
字符流 getWriter();常用于回传字符串(常用)

两个流同时只能使用一个 。 使用了字节流,就不能再使用字符流,反之亦然,否则就会报错

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    response.getOutputStream();
    response.getWriter();
}

5.2、如何往客户端回传数据

实现往客户端回传字符串 数据

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //往客户端回传字符串数据
    PrintWriter printWriter = response.getWriter();
    printWriter.write("回传");
}


打印中文有乱码

5.3、响应的乱码解决

方案一(不推荐 使用):

    //设置字符集为 UTF-8
    response.setCharacterEncoding("UTF-8");
    //通过设置响应头数据,将浏览器的字符集更改为 UTF-8
    response.setHeader("Content-Type", "text/html; charset=UTF-8");

方案二 (推荐) :
注意一定要在获取流对象之前调用才有效

 // 它会同时设置服务器和客户端都使用 UTF-8 字符集,还设置了响应头
 // 此方法一定要在获取流对象之前调用才有效 
 resp.setContentType("text/html; charset=UTF-8");

5.4、请求重定向sendRedirect()

请求重定向,是指客户端给服务器发请求,然后服务器告诉客户端说。我给你一些地址。你去新地址访问。叫请求重定向(因为之前的地址可能已经被废弃)

Servlet1的代码

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    System.out.println("曾到此一游===> 这里是过时的旧店铺");

    //设置响应状态码 302 ,表示重定向,(已搬迁)
    resp.setStatus(302);
    // 设置响应头,说明 新的地址在哪里
    resp.setHeader("Location", "http://localhost:8080/servlet/servlet2");
}

Servlet2的代码

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    resp.getWriter().write("welcome to Servlet2!!!");
}

执行
浏览器输入http://localhost:8080/servlet/servlet1

注意:

  1. 运行的时候是通过旧店铺的网址去访问,执行之后浏览器网址会发生变化
  2. 进行了两次请求,访问了两个网址,所以请求域里面的数据也不能共享,因为是两个请求对象
  3. 不能访问 WEB-INF
  4. 但是能访问到外网,因为直接是指向了一个完整的网址

请求重定向的第一种方案:

// 设置响应状态码 302 ,表示重定向,(已搬迁) 
resp.setStatus(302); 
// 设置响应头,说明 新的地址在哪里 
resp.setHeader("Location", "http://localhost:8080");

请求重定向的第二种方案 (推荐):

resp.sendRedirect("http://localhost:8080");

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5676320.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存