2.3.3 Servlet, 生命周期, 体系结构, xml配置, 请求和响应对象, 转发与重定向, ServletContext共享数据

目录

一 Servlet概述

二 Servlet快速入门

2.1 案例需求:编写一个普通的java类,通过浏览器可以访问

2.2 servlet执行原理

三 Servlet生命周期

3.1 生命周期相关

3.1.1 思想介绍

3.1.2 代码演示

四 Servlet体系结构

4.1 GenericServlet

4.2 HttpServlet

五 url-pattern的配置方式

5.1 Servlet映射多个url

5.2 url映射模式

六 Request对象

6.1 request对象概述

6.2 获取请求行信息

6.3 获取请求头信息

6.4 获取请求体信息(请求参数)【重点】

6.5 请求转发

6.6 域对象(共享数据)

七 Response对象

7.1 概述

7.2 设置Http响应消息

7.3 响应重定向

7.4 响应中文

八 ServletContext

8.1 概述

8.2 域对象(共享数据)

8.3 获取资源在服务器的真实地址

8.4 获取全局的配置参数

8.5 获取文件MIME类型

8.6 案例:统计网站的访问次数


一 Servlet概述

servlet= server+applet :运行在服务器端的java程序。
Servlet是一个接口,一个类要想通过浏览器被访问到,那么这个类就必须直接或间接的实现Servlet接口

作用
接收请求,处理逻辑,响应结果

二 Servlet快速入门

2.1 案例需求:编写一个普通的java类,通过浏览器可以访问

步骤分析:

① 创建web项目
② 编写普通java类,实现servlet接口
③ 在web.xml配置url-pattern
④ 部署web项目
⑤ 启动测试

编写java类

package com.lg.servlet;

import javax.servlet.*;
import java.io.IOException;

/**
 * @author CH
 * @date 2020/11/19 10:51
 */
public class QuickServlet implements Servlet {


    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    /*
        对外提供服务的方法, tomcat会调用servlet中的service方法, 执行具体的业务逻辑
        servletRequest: 请求对象, 借助该对象获取请求参数
        servletResponse: 响应对象, 借助该对象向浏览器响应一些数据
     */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("servlet入门成功了...");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}

编写XML配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!--配置QuickSerlvet
           servlet-name : 当前配置的servlet起一个别名(名称)
           servlet-class: 编写的就是配置的servlet的全限定类名
      -->
    <servlet>
        <servlet-name>QuickServlet</servlet-name>
        <servlet-class>com.lg.servlet.QuickServlet</servlet-class>
    </servlet>


    <!--
        servlet-mapping:给servlet设置一个映射地址
            servlet-name:给指定名称的servlet来配置映射地址
            url-pattern:具体该serlvet的映射地址(访问路径) *必须以/开头
    -->
    <servlet-mapping>
        <servlet-name>QuickServlet</servlet-name>
        <url-pattern>/quickServlet</url-pattern>
    </servlet-mapping>

</web-app>


项目部署后访问网址idea的tomcat控制台会打印

2.2 servlet执行原理

三 Servlet生命周期

3.1 生命周期相关

3.1.1 思想介绍

生命周期:指的是 一个对象从生(创建)到死(销毁)的一个过程

// 1. servlet对象创建时,调用此方法
public void init(ServletConfig servletConfig);
// 2. 用户访问servlet时,调用此方法
public void service(ServletRequest servletRequest, ServletResponse
servletResponse);
// 3. servlet对象销毁时,调用此方法
public void destroy();

3.1.2 代码演示

① LifeServlet

package com.lg.life;

import javax.servlet.*;
import java.io.IOException;

/**
 * @author CH
 * @date 2020/11/19 12:46
 */
public class LifeServlet implements Servlet {

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("LifeServlet的init方法执行了,该对象被创建完成了...");
    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("LifeServlet的service方法执行了,执行了具体的业务逻辑...");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {
        System.out.println("LifeServlet的destroy方法执行了,该对象被销毁了...");
    }
}

② 配置web.xml

<!--LifeSerlvet-->
    <servlet>
        <servlet-name>LifeSerlvet</servlet-name>
        <servlet-class>com.lg.life.LifeServlet</servlet-class>

        <!--配置上该标签,serlvet就会在启动服务器的时候去完成实例化,并进行初始化操作
            标签内部需要写数值  正整数 1-3在tomcat的web.xml被使用了,所以建议从4开始使用
        -->
        <load-on-startup>4</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>LifeSerlvet</servlet-name>
        <url-pattern>/LifeSerlvet</url-pattern>
    </servlet-mapping>

 <!--配置上该标签,serlvet就会在启动服务器的时候去完成实例化,并进行初始化操作
            标签内部需要写数值  正整数 1-3在tomcat的web.xml被使用了,所以建议从4开始使用
        -->
        <load-on-startup>4</load-on-startup>

* 创建
1)默认情况下

        用户第一次访问时,创建servlet,执行init方法

2)修改创建时机
        <load-on-startup></load-onstartup>
        正数:4-N 【服务器启动时,创建】
                补充:Tomcat的web.xml里有1,3 所以推荐4-n
        负数(默认值):-1 【用户第一次访问时,创建】

* 运行(提供服务)
        用户每次访问时,都执行service方法

* 销毁
        服务器正常关闭时,销毁servlet,执行destroy方法
```

笔试题:请描述下servlet的生命周期:
        答案:servlet是一个单实例多线程的,默认情况下,第一次请求来的时候,才会对该servlet进行实例化,并执行初始化init方法,随后再执行service方法完成业务处理,当每一次请求发送过来,都会重新开启一个线程,来执行servlet中的service方法,当服务器关闭或者servlet被移除的时候,会执行destory方法

四 Servlet体系结构

4.1 GenericServlet

① 编写普通java类,继承GenericServlet抽象类

package com.lagou.servlet;

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

public class ServletDemo1 extends GenericServlet {

    @Override
    public void init() throws ServletException {
        super.init();
        System.out.println("ServletDemo1的初始化方法执行了..");
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("ServletDemo1 extends GenericServlet...");
    }


    @Override
    public void destroy() {
        super.destroy();
        System.out.println("ServletDemo1的销毁方法执行了");
    }
}

② 配置web.xml

<!--ServletDemo1-->
    <servlet>
        <servlet-name>ServletDemo1</servlet-name>
        <servlet-class>com.lagou.servlet.ServletDemo1</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ServletDemo1</servlet-name>
        <url-pattern>/servletDemo1</url-pattern>
    </servlet-mapping>

4.2 HttpServlet

① 编写前端html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>login</title>
</head>
<body>
<h3>用户登录</h3>
<form action="http://localhost:8080/servlet_demo/servletDemo2" method="get">
  <input type="submit" value="提交表单..">
</form>
</body>
</html>

② 编写普通java类,继承HttpServlet抽象类, 重写doGet和doPost

package com.lagou.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class ServletDemo2 extends HttpServlet {


    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("ServletDemo2中的doGet方法执行了...");

    }


    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("ServletDemo2中的doPost方法执行了...");
    }
}

③ 配置web.xml

<!--ServletDemo2-->
    <servlet>
        <servlet-name>ServletDemo2</servlet-name>
        <servlet-class>com.lagou.servlet.ServletDemo2</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ServletDemo2</servlet-name>
        <url-pattern>/servletDemo2</url-pattern>
    </servlet-mapping>

五 url-pattern的配置方式

5.1 Servlet映射多个url

5.2 url映射模式

配置 url地址取值可以是:

1. 精确匹配(掌握)
         /servletDemo3         如:   localhost:8080/项目路径/servletDemo3

2. 目录匹配
         /aa/*        只要是aa目录下的都可以访问

3. 后缀匹配
         *.xxx 例如:*.do          是要后缀名是 .do 都可以访问

<!--
    只要浏览器符合目录匹配规则,都可以访问到这个servlet:
      /aa/abc
      /aa/asadfasdf
-->
<servlet>
  <servlet-name>ServletDemo4</servlet-name>
  <servlet-class>com.lagou.servlet.QuickServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>ServletDemo4</servlet-name>
  <url-pattern>/aa/*</url-pattern>
</servlet-mapping>
<!--
      只要浏览器符合后缀匹配规则,都可以访问到这个servlet
        aa.do
        bb.do
        xx.do
-->
<servlet>
  <servlet-name>ServletDemo5</servlet-name>
  <servlet-class>com.lagou.servlet.QuickServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>ServletDemo5</servlet-name>
  <url-pattern>*.do</url-pattern>
</servlet-mapping>

六 Request对象

6.1 request对象概述

  • 用户通过浏览器访问服务器时,Tomcat将HTTP请求中所有的信息都封装在Request对象中
  • 作用:开发人员可以通过request对象方法,来获取浏览器发送的所有信息.

6.2 获取请求行信息

* 例如:
        GET /servlet_demo/requestDemo1 HTTP/1.1
* 相关API:
1. 获取请求方式    GET【掌握】
        String    getMethod() 

2. 获取项目虚拟路径(项目名)   /servlet_demo【掌握】
        String    getContextPath() 

3. 获取URL      http://localhost:8080/servlet_demo/requestDemo1
        统一资源定位符(确定某一个地址) 中华人民共和国
        StringBuffer    getRequestURL() 

4. 获取协议和版本号 HTTP/1.1
        String    getProtocol()

5. 获取客户端ip
        String    getRemoteAddr()

package com.lagou.request;


import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class RequestDemo1 extends HttpServlet {


    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 演示request对象获取请求行信息
        System.out.println("请求方式:" + request.getMethod());
        System.out.println("虚拟路径:" + request.getContextPath());
        System.out.println("URL:" + request.getRequestURL());
        System.out.println("协议和版本:" + request.getProtocol());
        System.out.println("客户端IP地址:"+ request.getRemoteAddr());
    }


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

6.3 获取请求头信息

* 例如:
        Host: 127.0.0.1:8080
* 相关API:
1. 获取知道请求头名称对应的值,注:名称不区分大小写

        String    getHeader(String name) 
2. 获取所有请求头的名称
        Enumeration<String>    getHeaderNames() 
        注:是Iterator前身

package com.lagou.request;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

public class RequestDemo2 extends HttpServlet {


    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
          // 获取请求头信息
        // 获取指定的头信息 Host
        String host = request.getHeader("Host");
        System.out.println("指定的请求头信息Host是: " + host);

        // 先获取到所有的请求头名称
        Enumeration<String> headerNames = request.getHeaderNames();
        //遍历
        while (headerNames.hasMoreElements()){
            // 请求头名称
            String name = headerNames.nextElement();
            // 根据名称获取值
            String value = request.getHeader(name);

            System.out.println("请求头" + name + "的信息是: " + value);
        }
    }

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

6.4 获取请求体信息(请求参数)【重点....】

不论get还是post请求方式,都可以使用下列方法来获取请求参数

* 参数
username=jack&password=123&hobby=drink&hobby=perm

* API
1. 获取指定参数名的值 username=jack

String     getParameter(String name)

2. 获取指定参数名的值数组 hobby=drink&hobby=perm
String[]     getParameterValues(String name)

3. 获取所有参数名和对应值数组,参数名 name(key),值数组 value,封装map集合
Map<String,String[]>    getParameterMap()

* 中文乱码【重点】
        get:在tomcat8及以上版本,内部URL编码(UTF-8)
        post:编码解码不一致,造成乱码现象
                客户端(浏览器)编码:UTF-8
                服务器默认   解码:ISO-8859-1 拉丁文

                指定解码:void setCharacterEncoding(String env)
                       注:这哥们必须在方法内,行首

 ①创建一个表单

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

<h3>get方式提交表单:</h3>
  <form action="/servlet_demo/requestDemo3" method="get">
      用户:<input type="text" name="username"><br>
      密码:<input type="password" name="password"><br>
      爱好:
        <input type="checkbox" name="hobby" value="smoking"/> 抽烟
        <input type="checkbox" name="hobby" value="drink"/> 喝酒
        <input type="checkbox" name="hobby" value="perm"/> 烫头

      <input type="submit" value="get提交">
  </form>

<h3>post方式提交表单:</h3>
  <form action="/servlet_demo/requestDemo3" method="post">
      用户:<input type="text" name="username"><br>
      密码:<input type="password" name="password"><br>
      爱好:
      <input type="checkbox" name="hobby" value="smoking"/> 抽烟
      <input type="checkbox" name="hobby" value="drink"/> 喝酒
      <input type="checkbox" name="hobby" value="perm"/> 烫头

      <input type="submit" value="post提交">
  </form>

</body>
</html>

② 编写java 的HttpServlet, 重写doGet doPost

package com.lagou.request;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;

public class RequestDemo3 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
        
        // 获取表单提交的请求参数
        String username = request.getParameter("username");

        System.out.println("用户名:" + username);

        // 获取爱好这样的多个value的数组类型
        String[] hobbies = request.getParameterValues("hobby");
        System.out.println( Arrays.toString(hobbies));

        // 获取所有的请求参数的key和value  String:表单中的name属性值   String[]:请求参数的value值
        Map<String, String[]> parameterMap = request.getParameterMap();
        parameterMap.forEach((k,v)->{
            System.out.println(k + "=" + Arrays.toString(v));
        });
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
        // 设置解码为UTF-8 ,解决post中文乱码问题
        // 下面的语句必须放在首行
        request.setCharacterEncoding("UTF-8");   //可以放到get中
        doGet(request, resp);                   //让doGet方法中业务逻辑执行
    }
}

6.5 请求转发

一种在服务器内部的资源跳转方式

* API
1. 通过reqeust对象,获得转发器对象

        RequestDispatcher getRequestDispatcher(String path)      //要跳转到的z

2. 通过转发器对象,实现转发功能
        void forward(ServletRequest request, ServletResponse response) 

* 请求转发特点
        浏览器:发了一次请求
        地址栏:没有发生改变
        只能转发到服务器内部资源....

* 链式编程
        request.getRequestDispatcher("/bServlet").forward(reqeust,response)

① 编写AServlet转发信息给BServlet ,  getRequestDispatcher, 

package com.lagou.request;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class AServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {

        System.out.println("AServlet中功能上执行了");

        // 请求转发到Bservelt String path: 写的就是要跳转的资源路径
    /*    // 1.获取到转发器对象
        RequestDispatcher requestDispatcher = request.getRequestDispatcher("https://www.baidu.com/");

        // 2.借助转发器对象进行真正的请求转发
        requestDispatcher.forward(request,resp);*/

        // 链式编程
        request.getRequestDispatcher("/bServlet").forward(request,resp);
    }

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

② 编写BServlet接收AServlet转发的信息  

package com.lagou.request;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class BServlet extends HttpServlet {


    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 从request域中取出数据
        String hanbao = (String) req.getAttribute("hanbao");
        System.out.println(hanbao);
       
        // 向request域中设置数据
        request.setAttribute("hanbao","香辣鸡腿堡");

        System.out.println("BServlet中功能下执行了");
    }

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

③ 配置xml文件 

    <!--ASerlvet-->
    <servlet>
        <servlet-name>ASerlvet</servlet-name>
        <servlet-class>com.lagou.request.AServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ASerlvet</servlet-name>
        <url-pattern>/aServlet</url-pattern>
    </servlet-mapping>

    <!--BSerlvet-->
    <servlet>
        <servlet-name>BSerlvet</servlet-name>
        <servlet-class>com.lagou.request.BServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>BSerlvet</servlet-name>
        <url-pattern>/bServlet</url-pattern>
    </servlet-mapping>

6.6 域对象(共享数据)

域对象:一个有作用范围的对象,可以在范围内共享数据
request域:代表一次请求的范围,一般用于一次请求中转发的多个资源中共享数据

package com.lagou.request;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class AServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {

        System.out.println("AServlet中功能上执行了");

        // 向request域中设置数据
        request.setAttribute("hanbao","香辣鸡腿堡");

        // 链式编程
        request.getRequestDispatcher("/bServlet").forward(request,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}
package com.lagou.request;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class BServlet extends HttpServlet {


    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 从request域中取出数据
        String hanbao = (String) req.getAttribute("hanbao");
        System.out.println(hanbao);

        System.out.println("BServlet中功能下执行了");
    }

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

七 Response对象

7.1 概述

response对象表示web服务器给浏览器返回的响应信息
作用:开发人员可以使用response对象的方法,设置要返回给浏览器的响应信息

Response体系结构

ServletResponse 接口
        |
HttpServletResponse 接口
        |
org.apache.catalina.connector.ResponseFacade 实现类(由tomcat提供的)

7.2 设置Http响应消息

响应行

响应头

响应体【重点】

7.3 响应重定向

需求:用户访问AServlet后,服务器告诉浏览器重定向到BServlet

步骤分析

* 方式一
        // 1.设置状态码

                response.setStatus(302);
        // 2.设置响应头 Location
                response.setHeader("Location","重定向网络地址");
* 方式二
        // 1.response这哥们封装专门处理重定向的方法

                response.sendRedirect("重定向网络地址");

重定向特点

1. 地址栏会发生改变
2. 重定向是二次请求, 每次请求都会创建request对象
3. 重定向是客户端(浏览器)行为,可以跳转到服务器外部资源...
4. 不能使用request域共享数据

package com.lagou.response;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class CServlet extends HttpServlet {


    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        System.out.println("访问到了CSerlvet,接下来重定向到DServlet");

        // 设置重定向
      /*  resp.setStatus(302);
        resp.setHeader("Location","dServlet");*/

        // 设置重定向 方式二:常用, 重点掌握
        resp.sendRedirect("https://www.lagou.com/");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
package com.lagou.response;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class DServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        System.out.println("DServlet执行了.....");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
<!--CSerlvet-->
    <servlet>
        <servlet-name>CServlet</servlet-name>
        <servlet-class>com.lagou.response.CServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>CServlet</servlet-name>
        <url-pattern>/cServlet</url-pattern>
    </servlet-mapping>


    <!--DSerlvet-->
    <servlet>
        <servlet-name>DSerlvet</servlet-name>
        <servlet-class>com.lagou.response.DServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>DSerlvet</servlet-name>
        <url-pattern>/dServlet</url-pattern>
    </servlet-mapping>

请求转发与重定向的区别

1. 哪个对象
        转发(request对象的方法)

                request. getRequestDispatcher("/bServlet"). forward(request,response);

        重定向(response对象的方法)
                response. sendRedirect("/day10_response/bServlet ");

2. 几次请求
        转发

                地址栏: 没有改变
                浏览器: 发了一次请求
                服务器: 只有一对请求和响应对象
                发生的位置: 服务器

        重定向
                地址栏: 发生了改变
                浏览器: 发了两次请求
                服务器: 有两对请求和响应对象
                发生的位置: 浏览器
3. 小结
        写法

                转发("/servlet资源路径") 服务器内部行为
                重定向 ("/虚拟路径(项目名)/servlet资源路径") 浏览器外部行为

        使用场景(重点掌握)
                如果需要传递数据(request域),使用转发
                如果不需要传递数据(request域),使用重定向

7.4 响应中文


需求

向页面输出中文数据没有乱码

步骤分析

1. 通过response获取字符输出流
        PrintWriter pw = response.getWriter();

2. 通过字符输出输出文本
        pw.write("中文....");

 解决中文乱码

1. 指定服务器响应编码方式
       response.setCharacterEncoding("GBK");

2. 统一浏览器和服务器编码
       response.setContentType("text/html;charset=utf-8");

package com.lagou.response;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class EncodeServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 设置编码时,一定要写在首行
        //resp.setCharacterEncoding("GBK");

        // 统一浏览器和服务器编码
        resp.setContentType("text/html;charset=utf-8");

        // 向页面输出中文
        PrintWriter writer = resp.getWriter();
        writer.write("中文..");
    }
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
<!--EncodeServlet-->
    <servlet>
        <servlet-name>EncodeServlet</servlet-name>
        <servlet-class>com.lagou.response.EncodeServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>EncodeServlet</servlet-name>
        <url-pattern>/encodeServlet</url-pattern>
    </servlet-mapping>

八 ServletContext

8.1 概述

web容器(tomcat)在启动时,它会为每个web项目承建一个对应的ServletContext对象
它代表:当前web项目

主要作用

1. 域对象(共享数据)
2. 获取资源在服务器的真实地址
3. 获取全局的配置参数
4. 获取文件MIME类型

获取ServletContext对象

1. 通过request对象获得
        ServletContext sc = request.getServletContext();
2. 继承HttpServlet后,可以直接调用
        ServletContext sc = this.getServletContext();

8.2 域对象(共享数据)

在当前项目范围内,共享数据(多个servlet都可以获取)

1. 存储数据
        void setAttribute(String name,Object value)
2. 获取数据
        Object getAttribute(String name)
3. 删除数据
        void removeAttribute(String name)

package com.lagou.servletContext;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class OneServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 向servletContext域对象中存入数据
        //  ServletContext servletContext1 = this.getServletContext(); 因为继承了HttpServlet, 所以下面的也可
        ServletContext servletContext = req.getServletContext();

        servletContext.setAttribute("user","jack");     // 如果two比one先执行, 那么two中获取user时结果为null
        System.out.println("OneServlet中存入了数据....");

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
package com.lagou.servletContext;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class TwoServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 从servletContext域中取出数据
        String user = (String) req.getServletContext().getAttribute("user");

        System.out.println("TwoServlet中取出的数据为" + user); // 如果two比one先执行, 那么two中获取user时结果为null

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
<!--OneSerlvet-->
    <servlet>
        <servlet-name>OneServlet</servlet-name>
        <servlet-class>com.lagou.servletContext.OneServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>OneServlet</servlet-name>
        <url-pattern>/oneServlet</url-pattern>
    </servlet-mapping>

    <!--TwoSerlvet-->
    <servlet>
        <servlet-name>TwoServlet</servlet-name>
        <servlet-class>com.lagou.servletContext.TwoServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>TwoServlet</servlet-name>
        <url-pattern>/twoServlet</url-pattern>
    </servlet-mapping>

生命周期

1. 何时创建?
         项目加载时,创建

2. 何时销毁?
         项目卸载时,销毁

3. 作用范围?
         与项目共存亡(多个servlet都可以操作它)

8.3 获取资源在服务器的真实地址

可以实现web项目的移植性...动态获取文件真实路径

package com.lagou.servletContext;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class RealpathServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 获取lagou.jpg文件的真实路径
        ServletContext servletContext = req.getServletContext();
        // 使用getRealPath方法
        String realPath = servletContext.getRealPath("/img/lagou.jpg");
        System.out.println(realPath);
    }


    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
<!--RealpathServlet-->
    <servlet>
        <servlet-name>RealpathServlet</servlet-name>
        <servlet-class>com.lagou.servletContext.RealpathServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>RealpathServlet</servlet-name>
        <url-pattern>/realpathServlet</url-pattern>
    </servlet-mapping>

8.4 获取全局的配置参数

读取web.xml配置文件中标签信息,实现参数和代码的解耦(多个servlet都可以获取)

<!--全局配置参数:所有的servlet都可以读取...-->
    <context-param>
        <param-name>encode</param-name>
        <param-value>UTF-8</param-value>
    </context-param>
package com.lagou.servletContext;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class OneServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // servletContext获取到全局配置参数
        String encode = req.getServletContext().getInitParameter("encode");
        System.out.println("获取到的全局配置参数-"+ encode);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
package com.lagou.servletContext;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class TwoServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String encode = req.getServletContext().getInitParameter("encode");
        System.out.println("获取到的全局配置参数-"+ encode);
    }

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

8.5 获取文件MIME类型

在互联网通信过程中定义的一种文件数据类型格式
格式: 大类型/小类型 例如: text/html image/jpeg

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

  <a href="/servlet_demo/mimeServlet?fileName=a.jpg">获取文件的mime类型</a>

</body>
</html>
package com.lagou.servletContext;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MimeServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 获取指定文件的mime类型
        // servlet_demo/mimeServlet?fileName=a.jpg
        // 获取请求参数
        String fileName = req.getParameter("fileName");

        // 获取文件的mime类型
        String mimeType = req.getServletContext().getMimeType(fileName);
        resp.getWriter().write(fileName + "----" + mimeType);

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
<!--MimeServlet-->
    <servlet>
        <servlet-name>MimeServlet</servlet-name>
        <servlet-class>com.lagou.servletContext.MimeServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MimeServlet</servlet-name>
        <url-pattern>/mimeServlet</url-pattern>
    </servlet-mapping>

8.6 案例:统计网站的访问次数

需求  显示你是第几位访问此网站..

package com.lagou.servletContext;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class CountServlet extends HttpServlet {


    @Override
    public void init() throws ServletException {
        // 向servletContext域中存入变量count,并且初始值为0
        // 必须在web.xml中设置启动服务器就自动实例化的 load-on-startup 标签
        this.getServletContext().setAttribute("count",0);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

       //1. 设置响应编码
        resp.setContentType("text/html;charset=utf-8");

       //2. 向页面响应信息
        resp.getWriter().write("<h1>拉勾博客</h1>");

        //3.进行servletContext域中的取值   取  加  存    0
        // 取
        Integer count = (Integer) this.getServletContext().getAttribute("count");
        // 加
        count++;
        resp.getWriter().write("<dev>你是,第"+ count + "位访问此网站的人....</dev>");
        // 存
        this.getServletContext().setAttribute("count",count);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
<!--CountServlet-->
    <servlet>
        <servlet-name>CountServlet</servlet-name>
        <servlet-class>com.lagou.servletContext.CountServlet</servlet-class>
        <load-on-startup>4</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>CountServlet</servlet-name>
        <url-pattern>/countServlet</url-pattern>
    </servlet-mapping>

猜你喜欢

转载自blog.csdn.net/chengh1993/article/details/109801504