对Servlet的学习

本文详细介绍了Servlet的概述、快速入门、执行原理、生命周期、方法、注解配置及其继承体系。同时,讲解了HTTP请求消息的概念、特点、历史版本、数据格式,包括请求行、请求头、请求体等。此外,还探讨了Request对象的原理、获取请求数据的方法,以及Response对象的使用,包括重定向、服务器输出数据到浏览器以及验证码的生成。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.Servlet

1.概述

运行在服务器端的java小程序

图解:

在这里插入图片描述

  • Servlet是一个接口,定义了Java类被Tomcat识别的规则。
  • Servlet的开发就是实现Servlet接口,重写里面的方法。

2.快速入门

  • 步骤
    • 创建JavaEE项目
    • 定义一个类,实现Servlet接口
    • 实现接口中的抽象方法
    • 配置Servlet
  • 在刚才创建的web工程的src目录中创建包 org.wdzl.web.servlet,并创建一个类ServletDemo
  • 实现Servlet接口

注意:实现接口时会发现,找不到依赖

  • 解决办法

    • File —> Project Structure

    在这里插入图片描述

    • 选择 Library

      在这里插入图片描述

    • 选择 Tomcat 8.5.61—> Add Selected

在这里插入图片描述

1.service方法

//提供服务的方法
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
    System.out.println("Hello Servlet");//写一条输出语句即可
}

2.配置Servlet

为什么要配置Servlet?

因为浏览器要访问动态资源是要通过URL,而URL 如何要和Servlet对应上,就是我们接下来要做的事情。

web.xml中配置

<!-- 配置Servlet -->
<servlet>
    <servlet-name>demo1</servlet-name>
    <servlet-class>org.wdzl.web.servlet.ServletDemo</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>demo1</servlet-name>
    <!-- 访问Servlet的虚拟路径 -->
    <url-pattern>/demo1</url-pattern>
</servlet-mapping>

配置好后通过localhost/demo1进行访问即可

3 servlet执行原理

在这里插入图片描述

执行原理

  1. 服务器接收到浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径
  2. 查找web.xml文件,是否有对应的<url-pattern>
  3. 如果有,则会找到对应的servlet-class全类名
  4. tomcat将对应的字节码文件加载到内存中,并创建该类的对象
  5. 调用方法

4 Servlet的方法 和 生命周期

  1. 生命周期

    • 被创建:执行init方法,只执行一次
    • 提供服务: 执行service方法,执行多次
    • 被销毁:执行destroy,只执行一次
  2. 方法

/**
 *  初始化的方法
 *  在Servlet被创建时执行,只会执行一次
 * @param servletConfig
 * @throws ServletException
 */
@Override
public void init(ServletConfig servletConfig) throws ServletException {
    System.out.println("init...");
}
   
/**
 * 获取ServletConfig对象
 * ServletConfig:Servlet的配置对象
 * @return
 */
@Override
public ServletConfig getServletConfig() {
    return null;
}
   
/**
 * 提供服务方法
 * 每次Servlet被访问时执行,执行多次。
 * @param servletRequest
 * @param servletResponse
 * @throws ServletException
 * @throws IOException
 */
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
    System.out.println("Hello Servlet");
}
   
/**
 * 获取Servlet的一些信息,版本,作者等
 * @return
 */
@Override
public String getServletInfo() {
    return null;
}
   
/**
 * 销毁的方法
 * 在Servlet销毁或在服务器正常关闭时,被执行一次
 */
@Override
public void destroy() {
    System.out.println("destroy...");
}

5 Servlet方法详解

  1. init():

    • 初始化的时机可以改变

    image-20210116095734091

    image-20210116095734091

    • Servlet是单例模式,多个用户访问可能存在线程安全问题
      • 解决:使用Servlet时,尽量不要在Servlet中使用成员变量 ,即使定义了成员变量,也不要有修改值的操作。

6 注解配置

配置文件方式配置比较麻烦,3.0之后的版本支持注解方式,比较方便

  • 步骤:
    1. 创建JavaEE项目,选择3.0以上版本,可以不创建web.xml
    2. 定义一个类,实现Servlet接口
    3. 重写方法
    4. 在类上使用注解进行配置
  • 准备工作:重新创建一个,这次不勾选 Create web.xml

img

  1. 定义一个类,实现Servlet接口,重写方法
  2. 在类上使用注解进行配置

image-20210116112625361

  1. 注解 WebServlet
属性名类型描述
nameString指定Servlet 的 name 属性,等价于 <servlet-name>。如果没有显式指定,则该 Servlet 的取值即为类的全限定名。
valueString[]该属性等价于 urlPatterns 属性。两个属性不能同时使用。使用时可以省略属性名。
urlPatternsString[]指定一组 Servlet 的 URL 匹配模式。等价于<url-pattern>标签。
loadOnStartupint指定 Servlet 的加载顺序,等价于 <load-on-startup>标签。
initParamsWebInitParam[]指定一组 Servlet 初始化参数,等价于<init-param>标签。
asyncSupportedboolean声明 Servlet 是否支持异步操作模式,等价于<async-supported> 标签。
descriptionString该 Servlet 的描述信息,等价于 <description>标签。
displayNameString该 Servlet 的显示名,通常配合工具使用,等价于 <display-name>标签。

7 小常识:

  1. 工作空间项目 和 tomcat部署的web项目 并不是一个项目

tomcat部署位置:CATALINA_BASE\work

工作空间项目位置:项目右键

  1. WEB-INFO目录下的资源不能被浏览器直接访问

8 Servlet 继承体系结构

7.8 Servlet 继承体系结构

查询API 我们了解一下Servlet的继承体系结构:

					Servlet 接口

							 |

​ GenericServlet 抽象类

​ |

​ HttpServlet 抽象类

  • GenericServlet 抽象类

    • 它将Servlet接口中的其他方法都做了空实现,只留下了service()方法作为抽象方法
  • HttpServlet 抽象类

    • 该抽象类是对Http协议的一种封装,可以简化操作。

在这里插入图片描述

9 HttpServlet

  • 使用步骤
    1. 定义类,继承HttpServlet
    2. 重写doGet()/doPost()
  • 查看源码,理解原理

HttpServlet 中的 service()方法

image-20210116160343347

service()继续往下翻

因为Http有7种请求方式,我们只需要关注常用的两个 Get 和 Post

image-20210116160428838

  • get()方式效果演示
  1. 新建一个ServletDemo2
@WebServlet("/demo2")
public class ServletDemo2 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...");
    }
}
  1. 启动服务,直接用浏览器请求该Servlet

注意:浏览器默认访问方式是GET() 方式

  • post() :方式
  1. post方式需要借助Html的``标签
<body>    
    <form action="demo2" method="post">        
        <input type="text" name="username">       
        <input type="submit" value="登录">    
    </form>
</body>

10 urlPatterns()

  1. 一个Servlet可以匹配多个访问路径

注解源码:

image-20210116170103681

urlPatterns 的数据类型是String类型的数组,就表示 该servlet可以设置多个访问路径

演示案例:

@WebServlet(urlPatterns = {"/a","/a2","/a3"})
public class ServletDemo3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("ServletDemo3 doGet()....");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("ServletDemo3 doPost()....");
    }
}
  1. 路径定义规则
    • 路径匹配:/xxx
    • 目录结果匹配:/xxx/xxx
    • 扩展名匹配:*.xxx

案例:

//@WebServlet("/aa/bb") 通过/aa/bb 访问
//@WebServlet("/aa/*") 通过/aa/任意字符 访问
//@WebServlet("/*") 通过/任意字符访问
@WebServlet("*.do")
public class ServletDemo4 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("demo4 doGet()");
    }

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

2. HTTP - 请求消息

2.1 概念

超文本传输协议:Hyper Text Transfer Protocol 超文本传输协议

2.2 特点

  1. 基于TCP/IP的高级协议:安全的
  2. 默认端口号:80
  3. 基于请求/相应模型:一次请求对应一次相应

图示:

img

  1. 无状态的:每次请求之间相互独立,不能交互数据

2.3 历史版本

演示:使用火狐浏览器

我们访问baidu首页一共发送了几次请求?实际访问百度主页会发送很多次请求,因为主页的每一个图片,文本内容都是一次请求

  1. 1.0:每一次请求响应都会建立新的连接
  2. 1.1:复用连接,请求连接不会立马释放,会保留一段时间,如果在时间内该链接还有数据进行传输,就会复用该连接。

3.请求消息- 数据格式

数据格式

  1. 请求行
  2. 请求头
  3. 请求空行
  4. 请求体JSP + Servlet

演示案例:使用post()演示案例结合火狐浏览器查看数据格式

img

3.1 请求行

  • 格式:请求方式 请求URL 请求协议/版本号

结合演示案例得出案例种请求行的信息:

GET  /demo/login.html  HTTP/1.1
  • **请求方式:**Http共有7种请求方式,常用的有2种

    • GET

      1. 请求参数在请求行中,在URL后

        image-20210116214119197

      2. 请求的URL长度是有限制的

      3. 不安全

    • POST

      1. 请求参数在请求体中
      2. 请求的URL长度没有限制
      3. 相对安全
  • 请求URL

    • GET
      1. URL可能携带参数
    • POST
      1. URL不携带参数

3.2 请求头

请求头内容就是浏览器告诉服务器自身的一些信息。

  • 格式:请求头名称 : 请求头值 ,请求头值,……

结合演示案例得出案例种请求行的信息:

Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
Origin: http://localhost:8080
Connection: keep-alive
Referer: http://localhost:8080/demo/login.html
Cookie: JSESSIONID=EA1651C97732902D299C5CD859AE1647; Idea-e44921c1=1d14f60c-0164-4cc4-9ed0-2d9d05535a13
Upgrade-Insecure-Requests: 1

常见的请求头

  • Host:发送请求的主机

  • User-Agent: 浏览器告诉服务器,当前浏览器的版本信息

    • 可以在服务器端获取浏览器版本信息,来解决浏览器兼容问题(原因:静态页面的解析都是浏览器自己完成的。这就造成了相同的内容,在不同浏览器中可能出现不同的样式。)
  • Accept: 浏览器告诉服务器自己支持的数据格式

  • Referer:告诉服务器当前请求从哪里来

    • 作用:
      1. 防盗链
      2. 统计工作
  • Connection:keep-alive (现在都使用的HTTP 1.1 所以该头信息被省略)

3.3 请求空行

  • 空行:用于分割请求头 和请求体

3.4 请求体(正文)

封装POST 请求信息的请求参数

GET方式种没有请求体,我们可以看表单提交后的效果

image-20210116212753552

  • 参数 = 对应的值
  1. 请求消息-格式:
POST /demo/demo2 HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
Origin: http://localhost:8080
Connection: keep-alive
Referer: http://localhost:8080/demo/login.html
Cookie: JSESSIONID=EA1651C97732902D299C5CD859AE1647; Idea-e44921c1=1d14f60c-0164-4cc4-9ed0-2d9d05535a13
Upgrade-Insecure-Requests: 1

username=hahaha

4. Request 对象

4.1 Request 和 Response 对象的原理

  1. request 和 response对象是由服务器创建,我们使用即可
  2. request对象是用来获取请求信息,response对象用设置相应信息

4.2 Request继承体系

查询API

ServletRequest – 接口

| 继承

HttpServletRequest – 接口

| 实现(service中打印request对象)

org.apache.catalina.connector.RequestFacade – 在tomcat中实现

image-20210116234832122

4.3 获取请求消息数据

4.3.1获取请求行数据

我们根据请求行数据格式分析需要的方法

GET /demo/demo2 HTTP/1.1

  • 获取请求方式:GET

    String getMethod()

  • 获取虚拟目录(常用): /demo

    String getContextPath()

  • 获取Servlet路径: /demo2

    String getServletPath()

  • 获取get方式请求参数:name=zhangsan

    String getQueryString()

  • 获取请求URI(常用): /demo/demo2

    String getRequestURI(): /demo/demo2

    StringBuffer getRequestURL() :http://localhost:8080/demo/demo2

  • 获取协议及版本:HTTP/1.1

    String getProtocol()

  • 获取客户机的IP地址:

    String getRemoteAddr()

演示案例:

@WebServlet("/req")
public class RequestDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          //获取请求方式
        String method = req.getMethod();
        System.out.println(method);
         // 获取虚拟目录
        String contextPath = req.getContextPath();
        System.out.println(contextPath);
        // 获取Servlet路径
        String servletPath = req.getServletPath();
        System.out.println(servletPath);
        // 获取get方式的请求参数
        String queryString = req.getQueryString();
        System.out.println(queryString);
        // 获取URI
        String requestURI = req.getRequestURI();
        StringBuffer requestURL = req.getRequestURL();
        System.out.println(requestURI);
        System.out.println(requestURL);

        // 获取协议版本
        String protocol = req.getProtocol();
        System.out.println(protocol);
        //返回用户ip
        String remoteAddr = req.getRemoteAddr();
        System.out.println(remoteAddr);
    }

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

4.3.2 获取请求头数据
  • String getHeader(String name):通过请求头的名称获取请求头的值(常用)
    • Enumeration getHeaderNames():获取所有的请求头名称* Enumeration 相当于迭代器,API中有说

演示案例1:获取所有请求头数据

@WebServlet("/req2")
public class RequestDemo2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         //获取所有请求头名称
        Enumeration<String> headerNames = req.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            //获取请求头的键
            String name = headerNames.nextElement();
            //获取请求头的值
            String value = req.getHeader(name);
            System.out.println(name + "--" + value);

        }

    }

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

    }
}

演示案例2:获取用户浏览器信息

@WebServlet("/req3")
public class RequestDemo3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         //获取UserAgent
        String agent = req.getHeader("user-agent");//请求头的key不区分大小写
        if (agent.contains("QQBrowser")) {
            //因为我们无法处理浏览器兼容问题,所以我们用一个输出语句代替处理
            System.out.println("您用的是QQ浏览器");
        } else if (agent.contains("Firefox")) {
            System.out.println("您用的是火狐浏览器");
        }
    }

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

    }
}

通过不同浏览器访问servlet可以有不同的效果

演示案例3:获取referer

@WebServlet("/req4")
public class RequestDemo4 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         //获取Referer
        String referer = req.getHeader("referer");
        System.out.println(referer);
        if (referer.contains("/demo")) {
            System.out.println("播放音乐");
            //等学了response之后就可以把输出语句中的内容显示到网页中

        } else {
            System.out.println("滚");
        }
    }

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

    }
}

注意:如果直接通过/demo/req4 访问这个Servlet,就相当于直接自己访问自己,referer 的值是null,所以我们需要在index.jsp中加一个超链接,控制跳转

4.3.4 获取请求体数据
  • 请求体:只有POST方式有请求体。在请求体中封装了POST请求的请求参数
  • 步骤:
    1. 获取流对象
      • BufferedReader getReader() : 获取字符输入流,只能操作字符数据
      • ServletInputStream getInputStream() : 获取字节输入流,它可以操作所有类型数据(文件上传时讲解)
    2. 从流中获取数据

演示案例:

创建regist.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册页面</title>
</head>
<body>
<form action="/demo/req5" method="post">
    用户名:<input type="text" placeholder="请输入用户名" name="username"><br>
    密码:<input type="password" placeholder="请输入密码" name="username"><br>
    <input type="submit" value="注册">
</form>
</body>
</html>

创建servlet

@WebServlet("/req5")
public class RequestDemo5 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取请求消息体
        //1. 获取字符流
        BufferedReader br = req.getReader();
        //2.读取数据
        String line = null;
        while ((line = br.readLine()) != null) {
            System.out.println(line);//username=aaa&username=aaa
        }
    }
}

4.3.4 其他方法

这些方法是由前面基础方法衍生出来的一些通用方法,更方便使用

1.获取请求参数对象(GET/POST都能用)
  • String getParameter(String name): 根据参数名称获取参数值
  • String[] getParameterValues(String name): 根据参数名称获取参数值的数组(多用于复选框)例如:hobby=java &hobby=c
  • Enumeration getParameterNames():获取所有请求的参数名称
  • Map getParameterMap():获取所有参数的map集合

POST中文乱码解决:

//在获取参数前,设置req编码集
req.setCharacterEncoding("utf-8");

2. 请求转发
  • **概述:**一种在服务器内部的资源跳转方式。

简单理解服务器内部的资源跳转:一个服务器中有多个Servelt,多个Servlet分工协作完成用户的一个请求,这多个Servlet间数据的交换,就是资源跳转

  • 步骤
    1. 通过request对象 获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
    2. 使用转发器对象进行转发:forward(ServletRequest request, ServletResponse response)
4. 获取ServletContext对象
  • 方法:ServletContext getServletContext()

5.HTTP-相应消息

  1. 请求消息:客户端发送给服务器端的数据

数据格式:

  1. 相应消息:服务器端相应客户端的数据

数据格式:

  1. 相应行
  2. 相应头
  3. 相应空行
  4. 相应体体

5.1 响应消息的字符串格式:

通过获取浏览器 F12 查看 格式

图示:

image-20210121021150868

HTTP/1.1 200 OK //响应行
// ****************************** 响应头 *****************************
Bdpagetype: 1
Bdqid: 0x86f2f3e6001eefab
Cache-Control: private
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html;charset=utf-8
Date: Wed, 20 Jan 2021 18:07:52 GMT
Expires: Wed, 20 Jan 2021 18:07:52 GMT
Server: BWS/1.1
Set-Cookie: BDSVRTM=12; path=/
Set-Cookie: BD_HOME=1; path=/
Set-Cookie: H_PS_PSSID=33425_33430_33344_33286_33395_33398_33334_26350; path=/; domain=.baidu.com
Strict-Transport-Security: max-age=172800
Traceid: 161116607205735506029724102714616377259
X-Ua-Compatible: IE=Edge,chrome=1
Transfer-Encoding: chunked
// ****************************** 响应头结束 *****************************

//响应空行
//响应体:就是整个页面的内容(包括:html,css,js, 及数据)

5.2 响应行

  1. 组成:

协议/版本 响应状态码 响应码描述

  1. 状态码:

状态码都是3位数字 服务器告诉客户端本次 请求 和 响应的状态

  • 分类

    1. 1xx - 服务器接收客户端消息,但是没有接收完成。等待一段时间后,发送1xx状态码,询问客户端是否继续发送消息
    2. 2xx:成功。代表码:200
    3. 3xx: 重定向。资源跳转的方式。代表码:302-重定向 ,304-访问缓存
    • 重定向:比如你要访问ServletA, A说它做不了,让你访问B,然后浏览器接收到A的相应之后,会自动的访问ServletB,就相当于你一次回车进行了两次请求。
    1. 4xx: 客户端错误。比如访问路径有问题,没有对应资源 ,就会报404。
    2. 5xx: 服务器端错误。 如果服务器代码出现异常就会报500

5.3 响应头

  1. 组成:

    头名称 :值

  2. 常见响应头:

    • Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式
    • Content-disposition:服务器告诉客户端以什么格式打开响应体数据。如果没有设置就使用默认值。
      1. 值:
        • in-line:默认值,在当前页面内打开
        • attachment ; filename=xxx:以附件形式打开响应体。即文件下载 filename执行下载文件名称

6. Response 对象

6.1 概述

Response 对象是用来设置响应消息的

  • 设置响应行

    • 设置状态码:setStatus( int sc) - sc 为状态码
  • 设置响应头

    • setHeader(String name , String value)
  • 设置响应体:

    • 步骤:
      1. 获取输出流
        • 字节输出流:ServletOutputStream getOutputStream()
        • 字符输出流: PrintWriter() getWriter()
      2. 使用输出流将数据输出到客户端浏览器

    我们通过下面4个小案例来讲解上述内容

  1. 完成重定向
  2. 服务器输出字符数据到浏览器
  3. 服务器输出字节数据到浏览器
  4. 验证码

6.2 重定向

图解:

img

步骤:

1.  设置状态码为302
2.  设置响应头Location

简化操作:

由于 302 和 location为固定参数,所以将重定向简化为方法:sendRedirect(“/虚拟路径/资源路径”)

演示案例:responseDemo 通过重定向 访问 responseDemo2

responseDemo

/**
 *  重定向演示案例
 */
@WebServlet("/responseDemo")
public class ResponseDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("responseDemo 被访问");
        //设置状态码
        resp.setStatus(302);
        //设置响应头
        resp.setHeader("location","/book/responseDemo2");

        //重定向简单的方法实现:因为 302 和 location是固定的。
        resp.sendRedirect("/book/responseDemo2");
    }
}

responseDemo2

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

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

重定向的特点:

  • 转发的特点:forward
    1. 地址栏 路径不变
    2. 转发只能访问当前服务器下的资源
    3. 转发是一次请求 可以使用request对象共享数据
  • 重定向的特点:redirect
    1. 地址栏发生变化
    2. 可以访问其他服务器的资源
    3. 重定向是两次请求,不可以使用request对象共享数据
  • 面试题: forward 和 redirect 的区别

路径写法:

  • 路径分类

    • 相对路径:找到当前资源和目标资源之间的相对位置关系

      • ./ 开头
      • ../ 表示上一级目录
    • 绝对路径:通过绝对路径可以确定唯一资源

      • /开头。因为当前项目中 localhost:8080/虚拟路径都是统一的,所以可以省略为 /
      • 判断路径给谁用
        1. 浏览器用,要加虚拟目录 。例子:重定向
        2. 服务器用,不用加虚拟目录。例子:转发
      • 使用request.getContextPath()动态获取项目虚拟路径,这样即便是修改项目虚拟目录,我们之前写的重定向方法也不会失效。

      image-20210121231141215

      image-20210121231141215

6.3 服务器输出字符数据到浏览器

演示案例:

/**
 * 响应字符数据到浏览器
 */
@WebServlet("/responseDemo3")
public class ResponseDemo3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取流
        PrintWriter writer = resp.getWriter();
        //输出字符
       // writer.write("Hello Response");
        //输出html标签
        writer.write("<h1>Hello Response</h1>");
        writer.write("你好 response");//乱码
     
    }
}

演示案例2:处理中文乱码

/**
 *   处理中文乱码
 */
@WebServlet("/res4")
public class ResponseDemo4 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        /*
         分析:中文乱码问题
         qq浏览器查看网页源码:默认编码集GBK
         输出流通过tomcat获取。编码集应该是ISO-8859-1
         */
        //解决中文乱码
        //1. 获取流之前设置编码集
        //resp.setCharacterEncoding("GBK");
        /*
        但是仅仅设置输出流的编码集,万一用户的编码集被修改不是默认的GBK呢?
        我们可以使用相应头content-type,告诉浏览器本次相应的编码格式,浏览器读取到后,就会使用相应的编码
         */
        //设置响应头的同时也设置了本身的编码集,所以resp.setCharacterEncoding()可以省略不写
        //resp.setHeader("content-type","text/html;charset=utf-8");

        //简单的方法设置编码
        resp.setContentType("text/html;charset=utf-8");

        //获取流
        resp.getWriter().write("哈哈哈哈");
    }
}

6.4 服务器输出字节数据到浏览器

演示案例:

/**
 *   服务器相应字节数据:
 *      一般这种方法我们不用在输出字符上,而是用在输出图片上,比如说验证码。
 */
@WebServlet("/res5")
public class ResponseDemo5 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");

        ServletOutputStream outputStream = resp.getOutputStream();
        outputStream.write("你好".getBytes("utf-8"));

    }
}

6.5 验证码

**本质:**它是一张图片

**目的:**提高安全性,防止恶意注册等操作。

**方式:**随机生成

本次案例做的是比较初级的验证码:在内存中随机生成验证码

演示案例:

  1. 后台生成图片
import javax.imageio.ImageIO;
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.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

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

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       //1.创建一个对象,代表内存中的一张图片(空白画布)
        int width = 100;
        int height = 50;
        /*
        new BufferedImage(参数1,参数2,参数3)
        参数1:宽
        参数2:高
        参数3:图片类型 -常用 BufferedImage.TYPE_INT_RGB
         */
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        //2.美化图片,让它变成我们想要的样子
        //2.1 填充背景色
        Graphics g = image.getGraphics();//获取画笔工具
        g.setColor(Color.ORANGE);//设置画笔颜色
        g.fillRect(0,0,width,height);//填充一个矩形

        //2.2 画边框
        g.setColor(Color.green);//设置画笔颜色
//        g.drawRect(0, 0, 100, 50);//因为边框本身占一个像素,所以右边和下边的边框会超出
        g.drawRect(0,0,width-1,height-1);

        //2.3 验证码所有可能出现的字符
        String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        //2.4 获取随机数根据随机数取字符
        for (int i = 1; i <= 4; i++) {
            int index = new Random().nextInt(str.length());
            char ch = str.charAt(index);
            //2.5 写验证码
            g.drawString(ch+"",width/5*i,height/2);
        }

        //2.6 画干扰线
        g.setColor(Color.BLUE);
        //两点确定一条线,一条线由x,y左边的组成。一共画十条
        for (int i = 0; i < 10; i++) {
            int x1 = new Random().nextInt(width);
            int x2 = new Random().nextInt(width);
            int y1 = new Random().nextInt(height);
            int y2 = new Random().nextInt(height);
            g.drawLine(x1,x2,y1,y2);
        }

        //3. 将图片输出到页面展示
        ImageIO.write(image, "jpg", resp.getOutputStream());
    }
}

  1. 前端页面展示验证码,并通过单击改变验证码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册页面</title>
    <script>
        window.onload=function (){
            //获取图片标签对象
         var img = document.getElementById("checkCode");
         //绑定单击时间
            img.onclick = function () {
                //获取时间戳,为了让浏览器不读取缓存图片
                var date = new Date().getTime();
                //重新请求
                img.src="/book/code?"+date;
            };
        }

    </script>
</head>
<body>
<input type="text" name="username">
    <img id="checkCode" src="/book/code"/>看不清,换一张
</body>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值