javaweb学习(day06-servlet)

一、基本介绍

1 官方文档

  • 地址: https://tomcat.apache.org/tomcat-8.0-doc/servletapi/index.html
  • Servlet Tomcat 的关系: 一句话, Tomcat 支持 Servlet
  • 【假如单独使用Servlet就失去了意义】

2 为什么会出现 Servlet 

  • 提出需求: 请用你现有的html css javascript,开发网站,比如可以让用户留言/购物/, 你能搞定吗?【不能,无法操作数据库】
  •  引入我们动态网页(能和用户交互)技术 ===> Servlet
  • Java Web 技术体系的流程图改造说明(细化).[整体的概念] 

 

3 什么是 Servlet 

  • Servlet 在开发动态 WEB 工程中,得到广泛的应用,掌握好 Servlet 非常重要了, Servlet()SpringMVC 的基础

 Servlet(java 服务器小程序),它的特点:

  • 他是由服务器端调用和执行的(一句话:是Tomcat解析和执行)
  • 他是用java语言编写的, 本质就是Java
  • 他是按照Servlet规范开发的(除了tomcat->Servlet weblogic->Servlet)
  • 功能强大,可以完成几乎所有的网站功能(在以前,我们老程员,使用Servlet开发网站) 术栈要求高

 4 Servlet JavaWeb 项目位置

 二、Servlet 基本使用

1 Servlet 开发方式说明 

  • servlet3.0 前使用 web.xml , servlet3.0 版本以后(包括 3.0)支持注解, 同时支持 web.xml
  •  如何查看 servlet 版本[如图]
  • 讲解 SpringBoot 时,我们用注解方式, 从 ssm , springboot 后面全部使用注解 
  • 这专门讲 servlet, 为让大家更清晰知道 servlet 使用原理, 老师用配置方式(说明,原生Servlet 在项目中使用很少)
  •  不管使用哪种方式,本质都一样

2 快速入门- 手动开发 Servlet 

2.1 需求说明 

  • 开发一个 HelloServlet 
  • 当浏览器 访问 http://localhost:8080/web 应用名/helloServlet 时,后台输出 "hi HelloServelt"

 2.2 具体步骤

  • 编写类HelloServlet去实现 Servlet 接口
  • 实现 service 方法,处理请求,并响应数据 
  • web.xml 中去配置 servlet 程序的访问地址

2.3 演示 

  • 创建hspedu_servlet JavaWeb工程,并配置好Tomcat 
  •  添加servlet-api.jar(tomcat/lib) 到工程, 因为servlet.jar 不是jdk自带的, 要引入
  • src 下 包 com.hspedu.servlet.HelloServlet.java ,并实现Servlet接口 
package com.hspedu.servlet;

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

/*
解读
1. 开发一个Servlet需要实现Servlet接口
2. 实现Servlet接口的方法
 */
public class HelloServlet implements Servlet {
    /**
     * 1. 初始化servlet
     * 2. 当创建HelloServlet实例时,会调用init方法
     * 3. 该方法只会被调用一次
     * @param servletConfig
     * @throws ServletException
     */
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        //System.out.println("init...~~~");
    }

    /**
     * 返回
     * @return ServletConfig 也就是返回Servlet的配置
     */
    @Override
    public ServletConfig getServletConfig() {

        return null;
    }

    /**
     * 1. service方法处理浏览器的请求(包括get/post)
     * 2. 当浏览器每次请求servlet时,就会调用一次servlet
     * 3. 当tomcat调用该方法时,会把http请求的数据封装成实现了ServletRequest的对象
     * 4. 通过ServletRequest对象,可以得到用户提交的数据
     * 5. ServletRequest对象可以用于返回数据给Tomcat->浏览器
     * @param servletRequest
     * @param servletResponse
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        //System.out.println("HelloServlet 被访问" + servletRequest.getClass());
        // 类型转换(因为它有 getMethod()方法)
        HttpServletRequest httpServletRequest = (HttpServletRequest)
                servletRequest;
        // 获取请求的方式
        String method = httpServletRequest.getMethod();
        if ("GET".equals(method)) {
            doGet();
        } else if ("POST".equals(method)) {
            doPost();
        }
    }

    /**
     * 处理浏览器 get 请求
     */
    public void doGet() {
        System.out.println("处理 get 请求");
    }
    /**
     * 处理浏览器 post 请求
     */
    public void doPost() {
        System.out.println("处理 post 请求");
    }
    /**
     * 返回servlet的信息
     * @return
     */
    @Override
    public String getServletInfo() {

        return null;
    }

    /**
     * 该方法在servlet被销毁时被调用
     */
    @Override
    public void destroy() {
        System.out.println("destroy 被调用...");
    }
}
  •  web.xml配置HelloServlet:HelloServlet 提供对外访问地址

 通过浏览器访问HelloServlet ,看是否正确(记住要redeploy[] 或者 restart[])

 3 浏览器调用 Servlet 流程分析

 

4 Servlet 生命周期 

  • 主要有三个方法 

  • 示意图 

4.1 初始化阶段

Servlet 容器 ( 比如 : Tomcat) 加载 Servlet ,加载完成后, Servlet 容器会创建一个 Servlet 实例
并调用 init() 方法, init() 方法只会调用一次 , Servlet 容器在下面的情况装载 Servlet

 

4.2 处理浏览器请求阶段(service 方法) 

4.3 终止阶段 destory 方法(体现 Servlet 完整的生命周期)

5 GET POST 请求的分发处理 

开发 Servlet, 通常编写 doGetdoPost 方法。来对表单的 get post 请求进行分发处理 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册</title>
</head>
<body>
    <h1>注册用户</h1>
    <form action="http://localhost:8080/servlet/helloServlet" method="post">
        u: <input type="text" name="username"/><br><br>
        <input type="submit" value="注册用户"/>
    </form>
</body>
</html>

 修改了helloservlet.java代码

package com.hspedu.servlet;

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

/*
解读
1. 开发一个Servlet需要实现Servlet接口
2. 实现Servlet接口的方法
 */
public class HelloServlet implements Servlet {
    /**
     * 1. 初始化servlet
     * 2. 当创建HelloServlet实例时,会调用init方法
     * 3. 该方法只会被调用一次
     * @param servletConfig
     * @throws ServletException
     */
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("init...~~~");
    }

    /**
     * 返回
     * @return ServletConfig 也就是返回Servlet的配置
     */
    @Override
    public ServletConfig getServletConfig() {

        return null;
    }

    /**
     * 1. service方法处理浏览器的请求(包括get/post)
     * 2. 当浏览器每次请求servlet时,就会调用一次servlet
     * 3. 当tomcat调用该方法时,会把http请求的数据封装成实现了ServletRequest的对象
     * 4. 通过ServletRequest对象,可以得到用户提交的数据
     * 5. ServletRequest对象可以用于返回数据给Tomcat->浏览器
     * @param servletRequest
     * @param servletResponse
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        //System.out.println("HelloServlet 被访问" + servletRequest.getClass());
        // 类型转换(因为它有 getMethod()方法)
        //思考->从 servletRequest 对象来获取请求方式->
        //1. ServletRequest 没有得到提交方式的方法
        //2. ServletRequest 看看 ServletRequest 子接口有没有相关方法
        //3. 小技巧:ctrl+alt+b => 可以看到接口的子接口和实现子类
        //4. 把 servletReqeust 转成 HttpServletRequest 引用
        //5. 仍然是 Java 基础的 OOP
        HttpServletRequest httpServletRequest = (HttpServletRequest)
                servletRequest;
        // 获取请求的方式
        String method = httpServletRequest.getMethod();
        if ("GET".equals(method)) {
            doGet();
        } else if ("POST".equals(method)) {
            doPost();
        }
    }

    /**
     * 处理浏览器 get 请求
     */
    public void doGet() {
        System.out.println("处理 get 请求");
    }
    /**
     * 处理浏览器 post 请求
     */
    public void doPost() {
        System.out.println("处理 post 请求");
    }
    /**
     * 返回servlet的信息
     * @return
     */
    @Override
    public String getServletInfo() {

        return null;
    }

    /**
     * 该方法在servlet被销毁时被调用
     */
    @Override
    public void destroy() {
        System.out.println("destroy 被调用...");
    }
}

6 通过继承 HttpServlet 开发 Servlet

  • 在实际项目中,都是使用继承 HttpServlet 类开发 Servlet 程序,更加方便 

  • 通过继承 HttpServlet 开发一个 HiServlet
  • 当浏览器 访问 http://localhost:8080/web 应用名/hiServlet 时,后台输出 "hi HiServelt" 

具体的开发步骤 

编写HiServlet类

package com.hspedu.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 HiServlet extends HttpServlet {
    //重写httpServlet的doGet和doPost方法

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("HiServlet doGet()...");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("HiServlet doPost()...");
    }
}

 配置web,xml

7 IDEA 开发 Servlet 程序 

  • 编手动开发 Servlet 需要程序员自己配置 Servlet ,比较麻烦,在工作中,直接使用 IDEA Servlet 会更加方便
  • 应用实例

 

 8 Servlet 注意事项和细节

  • Servlet 是一个供其他 Java 程序(Servlet 引擎)调用的 Java 类,不能独立运行
  • 针对浏览器的多次 Servlet 请求,通常情况下,服务器只会创建一个 Servlet 实例对象, 也就是说 Servlet 实例对象一旦创建,它就会驻留在内存中,为后续的其它请求服务,直至 web 容器退出/或者 redeploy web 应用,servlet 实例对象才会销毁 【示意图】

  • Servlet 的整个生命周期内,init 方法只被调用一次。而对每次请求都导致 Servlet 擎调用一次 servlet service 方法。
  • 对于每次访问请求,Servlet 引擎都会创建一个新的 HttpServletRequest 请求对象和一个新的 HttpServletResponse 响应对象,然后将这两个对象作为参数传递给它调用的 Servletservice()方法,service 方法再根据请求方式分别调用 doXXX 方法
  • 如果在<servlet>元素中配置了一个<load-on-startup>元素,那么 WEB 应用程序在启动时, 会装载并创建 Servlet 的实例对象、以及调用 Servlet 实例对象的 init()方法, 老师聊聊(时发送邮件的服务/自动启动->完成任务)

 三、Servlet - 注解方式

1 快速入门 

  • 编写类OkServlet去继承HttpServlet
  • 注解方式配置OkServlet, 一个Servlet支持配置多个urlPattern
package com.hspedu.servlet.annotation;

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;

/**
 * 注解方式来配置
 * 1.@WebServlet 是一个注解=》java基础
 * 2.@WebServlet源码
         *  @Target({ElementType.TYPE})
         * @Retention(RetentionPolicy.RUNTIME)
         * @Documented =》
         * public @interface WebServlet {
         *     String name() default "";
         *
         *     String[] value() default {};
         *
         *     String[] urlPatterns() default {};
         *
         *     int loadOnStartup() default -1;
         *
         *     WebInitParam[] initParams() default {};
         *
         *     boolean asyncSupported() default false;
         *
         *     String smallIcon() default "";
         *
         *     String largeIcon() default "";
         *
         *     String description() default "";
         *
         *     String displayName() default "";
 *  3.  urlPatterns对应web,xml的<url-pattern></url-pattern>
 *  4. {"/ok1","/ok2"}可以给OkServlet配置多个url-pattern
 *  5. 相当于这个@WebServlet(urlPatterns = {"/ok1","/ok2"})代替了web.xml的配置
 *  6。浏览器可以这样访问OKServlet时,可以http://localhost:8080/servlet/ok1或者
 *  http://localhost:8080/servlet/ok1
 * }
 */
@WebServlet(urlPatterns = {"/ok1","/ok2"})
public class OkServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("注解方式 OKServlet doGet()");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("注解方式 OKServlet doPost()");
    }
}

 2 Servlet urlPattern 配置

 2.1 精确匹配

 2.2 目录匹配

2.3 扩展名匹配

2.4 任意匹配 

 2.5 注意事项和使用细节

  • Servlet 配置了 "/", 会覆盖 tomcat DefaultServlet, 当其他的 utl-pattern 都匹配 不 上 时 , 都 会 走 这 个 Servlet, 这 样 可 以 拦 截 到 其 它 静 态 资 源 , 比 如D:\hspedu_javaweb_temp\hspedu_servlet\web\hi.html [举例]
  • Servelt 配置了 "/*", 表示可以匹配任意访问路径 
  • 提示: 建议不要使用 / /* , 建议尽量使用精确匹配 
  • 优先级遵守: 精确路径 > 目录路径 > 扩展名路径 > /* > /

四、WEB 开发通信协议-HTTP 协议

1.什么是 HTTP 协议

  • 超文本传输协议(HTTPHyperText Transfer Protocol)是互联网上应用广泛的一种网络协议。 是工作在 tcp/ip 协议基础上的,所有的 WWW 文件都遵守这个标准
  • http1.0 短连接 http1.1 长连接 

  • http TCP/IP 协议的一个应用层协议,http 也是我们 web 开发的基础

快速入门 HTTP 协议 

 

http 请求 hi.html UML 时序图 

 3 页面请求的一个问题(分析)

  • 创建 D:\idea_java_projects\hspedu_servlet\web\http\test.html 页面 

  •  当访问 test.html 页面时, 问浏览器发出几次 http 请求?

        答:一共 3  

 

HTTP 请求包分析(GET) 

 4.1案例说明

  • 创建 D:\idea_java_projects\hspedu_servlet\web\http\login.html 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户登录</title>
</head>
<body>
<!--给我们的LoginServlet发出Get请求,提交表单-->
    <h1>用户登录</h1>
    <form action="http://localhost:8080/http/loginServlet" method="get">
        u: <input type="text" name="username"/><br/>
        p: <input type="password" name="pwd"/><br/>
        <input type="submit" value="用户登录"> <input type="reset" value="清空">
    </form>
</body>
</html>

  • 创 建 D:\hspedu_javaweb_temp\hspedu_servlet\src\com\hspedu\http\LoginServlet.java
  • 并完成配置【添加web框架,导包,配置Tomcat,设置web.xml】
package com.hspedu.http.servlet;

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

public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)  {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //输出一句话,返回给浏览器
        //1 通过response获取流程
        //2 为了让浏览器显示中文,需要告诉浏览器编码是utf-8
        //(1) 回送数据设置编码 (2)text/html这个是MIME告诉浏览器返回的数据
        //是text类型下的html格式数据【MIME类型 大类型/小类型】(3)charset=utf-8数据编码

        //小小细节:编码设置一定要在得到流-response.getWriter()之前

        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer=response.getWriter();
        writer.print("<h1>登录成功</h1>");

        //为了确保数据返回,可以把flush()和close()
        //程序员有强迫症,flush方法表示为了将缓存的数据进行刷新
        writer.flush();
        //close表示为了及时释放资源
        writer.close();
    }
}

4.2 抓包测试分析

 5 HTTP 请求包分析(POST)

5.1 HTTP POST 请求方式案例 

  • 修改 login.html, 将提交方式改成 post 

  • 修改 D:\idea_java_projects\hspedu_servlet\src\com\hspedu\http\LoginServlet.java

 5.2 完成测试, HTTP 请求包分析(POST)

说明 : %E9%9F%A9%E9%A1%BA%E5%B9%B3 url 编码 , 在服务端会自动解码 .
试一把 http://tool.chinaz.com/tools/urlencode.aspx

6 GET 请求 POST 请求分别有哪些? 

6.1 GET 请求有哪些 

 6.2 POST 请求有哪些

form 标签 method=post

6.3 HTTP 请求中怎样选择 Get Post 方式

在大部分情况下,我们不需要考虑这个问题,因为业务本身就会自动区别,
比如你要显示图片,引入 css/js 这个天然的就是 get 请求,比如你登录,发帖,上传文
件, 你就会使用 post( 感情的自然流露 )

 

 7 HTTP 响应包分析

7.1 HTTP 响应包括 3 个部分

7.2 HTTP 响应包分析图

常用的状态码说明 

 8.1 302 状态码使用

新建一个servlet

package com.hspedu.http.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 T1 extends HttpServlet {
    //这里我们把doPost和doGet进行合并处理
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //如果有一个请求来,重定向到hi.html
        //(1)返回302状态码 (2)响应头Location:/hi.html
        response.sendRedirect("/http/hi.html");
    }

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

 

测试抓包

 8.2 304 状态码

 9 MIME 类型

9.1 MIME 介绍

        MIME 是 HTTP 协议中数据类型。 MIME 的英文全称是 "Multipurpose Internet Mail
Extensions" 多功能 Internet 邮件扩充服务。 MIME 类型的格式是 " 大类型/小类型 "
并与某一种文件的扩展名相对应
        在响应包的Content-Type 就有指定 , 如图

9.2 常见的 MIME 类型 

五、ServletConfig 

1 ServletConfig 基本介绍

  • ServletConfig 类是为 Servlet 程序的配置信息的类
  • Servlet 程序和 ServletConfig 对象都是由 Tomcat 负责创建
  • Servlet 程序默认是第 1 次访问的时候创建,ServletConfig Servlet 程序创建时,就创建一个对应的 ServletConfig 对象

2 ServletConfig 类能干什么

  • 获取 Servlet 程序的 servlet-name 的值
  • 获取初始化参数 init-param
  • 获取 ServletContext 对象

3 ServletConfig 应用实例 

3.1 需求 

3.2 示意图 

3.3 代码实现 

DBServlet.java

package com.hspedu.servlet;

import javax.servlet.ServletConfig;
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 DBServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //合二为一
        //获取web.xml的用户名跟密码
        //DBServlet的父类GenericServlet有getServletConfig()
        ServletConfig servletConfig = getServletConfig();
        String username = servletConfig.getInitParameter("username");
        String pwd = servletConfig.getInitParameter("pwd");
        System.out.println("初始化参数username: "+username);
        System.out.println("初始化参数pwd: "+pwd);
         




    }

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

 配置web.xml

六、ServletContext 

1 为什么需要 ServletContext 

  • 先看一个需求: 如果我们希望统计某个 web 应用的所有 Servlet 被访问的次数,怎么?
  • 方案 1-DB

  •  方案 2-ServletContext

 2 ServletContext 基本介绍

  • ServletContext 是一个接口,它表示 Servlet 上下文对象
  • 一个 web 工程,只有一个 ServletContext 对象实例
  • ServletContext 对象 是在 web 工程启动的时候创建,在 web 工程停止的时销毁
  • ServletContext 对象可以通过 ServletConfig.getServletContext 方法获得对 ServletContext 对象的引用,也可以通过 this.getServletContext()来获得其对象的引用。
  • 由于一个 WEB 应用中的所有 Servlet 共享同一个 ServletContext 对象,因此 Servlet 对象之间可以通过 ServletContext 对象来实现多个 Servlet 间通讯ServletContext 对象通常也被称之为域对象。【示意图】

 3 ServletContext 可以做什么

  • 获取 web.xml 中配置的上下文参数 context-param [信息和整个 web 应用相关,而不是属于某个 Servlet]
  • 获取当前的工程路径,格式: /工程路径 =》 比如 /servlet
  • 获 取 工 程 部 署 后 在 服 务 器 硬 盘 上 的 绝 对 路 径 ( 比如:D:\hspedu_javaweb\servlet\out\artifacts\servlet_war_exploded)
  • Map 一样存取数据, 多个 Servlet 共享数据

应用实例 1 

4.1 需求 

  • 获取 web.xml 中配置的上下文参数 context-param
  • 获取当前的工程路径,格式: /工程路径
  • 获取工程部署后在服务器硬盘上的绝对路径

4.2 代码实现 

新建servlet

package com.hspedu.servlet.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 ServletContext_ extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取web.xml的context-parameter

        //1.获取到ServletContext对象
        ServletContext servletContext = getServletContext();
        //2.获取参数
        String website = servletContext.getInitParameter("website");
        String company = servletContext.getInitParameter("company");
        System.out.println("website="+website);
        System.out.println("company"+company);
        //获取工程路径
        String contextPath = servletContext.getContextPath();
        System.out.println("工程路径="+contextPath);
        //获取项目发布后真正的工作路径
        // /表示我们的项目发布后的根路径
        String realPath = servletContext.getRealPath("/");
        System.out.println("真正工作路径="+realPath);



    }

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

 配置web.xml

应用实例 2 

5.1 需求

  • 完成一个简单的网站访问次数计数器:

  • 使用 Chrome 访问 Servlet01, 每访问一次,就增加 1 访问次数,在后台输出,并将结果返回给浏览器显示
  • 使用火狐访问 Servlet02,每访问一次,就增加 1 访问次数,在后台输出,并将结果返回给浏览器显示

5.2 代码实现 

新建两个servlet

package com.hspedu.servlet.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;
import java.io.PrintWriter;

public class OrderServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //先获取到ServletContext对象
        ServletContext servletContext = getServletContext();
        System.out.println("OrderServlet servletContext= "+servletContext +" 运行类型 "+servletContext.getClass());

        //从servletContext获取visit_count属性 k-v
        Object visit_count = servletContext.getAttribute("visit_count");

        //判断visit_count是否为空
        if(visit_count==null){
            servletContext.setAttribute("visit_count",1);
            visit_count=1;
        }else {
            //取出visit_count属性的值+1
           visit_count= Integer.parseInt(visit_count+"") +1;
           //放回servletContext
            servletContext.setAttribute("visit_count",visit_count);


        }
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print("<h1>网站访问的次数是 "+visit_count +"</h1>");
        writer.flush();
        writer.close();


    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }
}
package com.hspedu.servlet.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;
import java.io.PrintWriter;

public class PayServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //先获取到ServletContext对象
        ServletContext servletContext = getServletContext();
        System.out.println("PayServlet servletContext= "+servletContext +" 运行类型 "+servletContext.getClass());

        //从servletContext获取visit_count属性 k-v
        Object visit_count = servletContext.getAttribute("visit_count");

        //判断visit_count是否为空
        if(visit_count==null){
            servletContext.setAttribute("visit_count",1);
            visit_count=1;
        }else {
            //取出visit_count属性的值+1
            visit_count= Integer.parseInt(visit_count+"") +1;
            //放回servletContext
            servletContext.setAttribute("visit_count",visit_count);


        }
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print("<h1>网站访问的次数是 "+visit_count +"</h1>");
        writer.flush();
        writer.close();

    }

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

配置web.xml

七、HttpServletRequest 

1 HttpServletRequest 介绍 

  • HttpServletRequest 对象代表客户端的请求
  • 当客户端/浏览器通过 HTTP 协议访问服务器时,HTTP 请求头中的所有信息都封装在这个对象中
  • 通过这个对象的方法,可以获得客户端这些信息

2 HttpServletRequest 类图 

3 HttpServletRequest 常用方法 

4 HttpServletRequest 应用实例 

4.1 需求 

  • 说明: 在一个表单提交数据给 Servlet , 然后在 Servlet 通过 HttpServletRequest对象获取相关数据

 4.2 代码实现

创建 D:\idea_java_projects\hspedu_servlet\web\register_request.html 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册</title>
</head>
<body>
<h1>注册用户</h1>
<form action="http://localhost:8080/servlet/requestMethods" method="post">
    u: <input type="text" name="username"/><br><br>
    p: <input type="password" name="pwd"/><br><br>
    选择你喜欢的老师:
    <input type="checkbox" name="hobby" value="hsp">韩顺平
    <input type="checkbox" name="hobby" value="lh">老韩
    <input type="checkbox" name="hobby" value="spls">顺平老师<br/><br/>
    <input type="submit" value="注册用户"/>
</form>
</body>
</html>

创建servlet

package com.hspedu.servlet.httpservletrequest;

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 HttpServletRequestMethods extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //使用request对象获取相关数据
        System.out.println("HttpServletRequestMethods doPost被调用");
        /***********************************
         * 获取和 http 请求头相关信息
         ***********************************/
        System.out.println("请求的资源路径 URI= " + request.getRequestURI());
        //http://主机/uri
        System.out.println(" 请 求 的 统 一 资 源 定 位 符 ( 绝 对 路 径 ) URL= " +
                request.getRequestURL());
        System.out.println("请求的客户端 ip 地址= " + request.getRemoteAddr());//本地就是 127.0.01
                //思考题:如发现某个 ip 在 10s 中,访问的次数超过 100 次,就封 ip
        //实现思路:1 用一个集合 concurrentHashmap[ip:访问次数] 2[线程/定时扫描]3 做成处理

        // 获取 http 请求头的信息,可以指定其他,比如 User-Agent , Host 等待 就举一个例子
        System.out.println("http 请求头 HOST= " + request.getHeader("Host"));
        // 说 明 , 如 果 我 们 希 望 得 到 请 求 的 头 的 相 关 信 息 , 可 以 使 用
        request.getHeader("请求头字段");
        System.out.println("该请求的发起地址是= " + request.getHeader("Referer"));
        // 请获取访问网站的浏览器是什么?
        String userAgent = request.getHeader("User-Agent");
        System.out.println("User-Agent= " + userAgent);
        // 取出 FireFox, 取出最后
        String[] s = userAgent.split(" ");
        System.out.println("浏览器=" + s[s.length - 1].split("\\/")[0]);
        //课堂练习: 要求同学们取出 Windows NT 10.0 和 Win64
        // 主要是 Get / Post
        System.out.println("http 请求方式~= " + request.getMethod());
        /***********************************
         * 获取和请求参数相关信息, 注意要求在返回数据前,获取参数
         ***********************************/

        //1. 获取表单的数据[单个数据]
        //username=tom&pwd=&hobby=hsp&hobby=spls
        String username = request.getParameter("username");
        String pwd = request.getParameter("pwd");
        //2. 获取表单一组数据
        String[] hobbies = request.getParameterValues("hobby");
        System.out.println("username= " + username);
        System.out.println("pwd= " + pwd);
        //增强 for 循环的快捷键 iter->回车即可 , 能使用快捷键,就使用快捷键
        for (String hobby : hobbies) {
            System.out.println("hobby=" + hobby);
        }

    }

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

配置web.xml

5 HttpServletRequest 注意事项和细节 

  • 获 取 doPost 参 数 中 文 乱 码 解 决 方 案 , 注 意 setCharacterEncoding("utf-8") 要 写 在 request.getParameter()

  • 注意:如果通过 PrintWriter writer, 有返回数据给浏览器,建议将获取参数代码写在 writer.print() 之前,否则可能获取不到参数值(doPost)
  • 处理 http 响应数据中文乱码问题 

 

八、请求转发 

1 为什么需要请求转发 

  • 目前我们学习的都是一次请求,对应一个 Servlet, 如图 

  • 但是在实际开发中,往往业务比较复杂,需要在一次请求中,使用到多个 Servlet 完成一个任务(Servlet , 流水作业) 如图:

 2 请求转发说明

  • 实现请求转发:请求转发指一个 web 资源收到客户端请求后,通知服务器去调用另外 一个 web 资源进行处理
  • HttpServletRequest 对象(也叫 Request 对象)提供了一个 getRequestDispatcher 方法,该 方法返回一个 RequestDispatcher 对象,调用这个对象的 forward 方法可以实现请求转发
  • request 对象同时也是一个域对象,开发人员通过 request 对象在实现转发时,把数据 通过 request 对象带给其它 web 资源处理

 3 实现请求转发

 4 请求转发应用实例

4.1 需求说明 

如果是 tom,提示为管理员,其它是普通用户 

 4.2 代码实现

4.2.1 登陆页面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
    <form action="http://localhost:8080/servlet/checkServlet" method="post">
        u: <input type="text" name="username"><br>
        <input type="submit" value="登录">
    </form>
</body>
</html>
4.2.2 创建servlet
package com.hspedu.servlet.request;

import javax.servlet.RequestDispatcher;
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 CheckServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("CheckServlet 被调用 ----");
        //根据用户来确定该用户是什么身份
        String username = request.getParameter("username");
        //注意,如果是同一个request对象(请求转发),那么可以在不同的servlet使用getParameter
        if("tom".equals(username)){
            //分配
            request.setAttribute("role","管理员");
        }else {
            request.setAttribute("role","普通用户");
        }
        //获取分发器

        //解读 1. /manageServlet 写的是 要转发的 servlet 的 url
        // 2. / 会被解析成 /servlet
        // 3. forward(request, response) 表示把当前 servlet 的 request 对象和response 对象,传递给下一个 servlet 使用
        RequestDispatcher requestDispatcher = request.getRequestDispatcher("/manageServlet");
        requestDispatcher.forward(request,response);


    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }
}
package com.hspedu.servlet.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.io.PrintWriter;

public class ManageServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("ManageServlet 被调用 ----");
        String username = request.getParameter("username");
        String role = (String) request.getAttribute("role");
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print("用户名:"+username+"<br/>");
        writer.print("角色:"+role+"<br/>");

        writer.flush();
        writer.close();



    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }
}
4.2.3 配置web.xml

九、HttpServletResponse 

1 HttpServletResponse 介绍 

  • 每次 HTTP 请求,Tomcat 会创建一个 HttpServletResponse 对象传递给 Servlet 程序去使用。
  • HttpServletRequest 表示请求过来的信息,HttpServletResponse 表示所有响应的信息, 如果需要设置返回给客户端的信息,通过 HttpServletResponse 对象来进行设置即可

 

2 HttpServletResponse 类图 

3 向客户端返回数据方法 

  • 字节流 getOutputStream(); 常用于下载(处理二进制数据)
  • 字符流 getWriter(); 常用于回传字符串 
  • (细节:)两个流同时只能使用一个。 使用了字节流,就不能再使用字符流,反之亦然,否则就会报错

4 向客户端返回数据注意事项和细节

处理中文乱码问题-方案 1

 处理中文乱码问题-方案 2

十、请求重定向 

1 请求重定向介绍 

  • 请求重定向指:一个 web 资源收到客户端请求后,通知客户端去访问另外一个 web资源,这称之为请求重定向
  • 请求重定向原理示意图 

 

2 请求重定向应用实例 

2.1 需求 

  • 演 示 请 求 重 定 向 的 使 用 当 访 问 DownServlet 下 载 文 件 , 重 定 向 到 DownServletNew 下载文件

 

2.2 实现 

创建html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>下载文件</title>
</head>
<body>
    <h1>下载文件</h1>
    <a href="http://localhost:8080/servlet/downServlet">下载天龙八部</a>
</body>
</html>

创建servlet

package com.hspedu.servlet.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 DownServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//        System.out.println("DownServlet 被调用");
//        //编码
//        response.setContentType("application/x-tar;charset=utf-8");
//        PrintWriter writer=response.getWriter();
//        writer.print("ok");
//        writer.flush();
//        writer.close();

        //1. 因为请求重定向 是将请求返回给 Location: /downServletNew
        //2. 所以浏览器来解析 /downServletNew, 而不是服务端解析
        //3. 会以当前浏览器的地址栏的 主机+/downServletNew 也就是http://localhost:8080
        response.sendRedirect("/servlet/downServletNew");

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }
}
package com.hspedu.servlet.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 DownServletNew extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("DownServletNew 被调用");
        //编码
        response.setContentType("application/x-tar;charset=utf-8");
        PrintWriter writer=response.getWriter();
        writer.print("ok");
        writer.flush();
        writer.close();
    }

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

记得配置web.xml哦

请求重定向注意事项和细节 

  • 最佳应用场景:网站迁移,比如原域名是 www.hsp.com 迁移到 www.hsp.cn ,但是百度抓取的还是原来网址.
  • 浏览器地址会发生变化,本质是两次 http 请求.
  • 不能共享 Request 域中的数据,本质是两次 http 请求,会生成两个 HttpServletRequest 对象
  • 不能重定向到 /WEB-INF 下的资源
  • 可以重定向到 Web 工程以外的资源, 比如 到 www.baidu.com 在前面的案例演示
  • 重定向有两种方式, 推荐使用第 1 .

 

  • 动态获取到 application context

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜菜小林然

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值