JavaWeb-01(web基本概念、Tomcat、Http、Servlet)

1.基本概念

1.1 web开发

  1. web是网页的意思,表示我们可以从网站上取得一定的资源
  2. 静态web:
    • html、css
    • 提供给所有人看的数据,数据始终不会发生变化
  3. 动态web:
    • 几乎所有的网站都是动态的
    • 提供给所有人看的数据,数据始终会发生变化。每个人在不同的时间、地点看到的信息各不相同
    • 常用技术栈:Serblet/JSP, ASP, PHP
    • 在java中动态web资源开发的技术统称为javaWeb

1.2 web应用程序

  1. web应用程序:可以提供浏览器访问的程序
    • 如xxx.html……多个web资源整合起来,这些资源可以被外界访问,对外界提供服务。
    • 能够被访问到的任何一个资源或者页面,都存在于这个世界的某一台计算机上
    • URL
    • 这些统一的web资源会被放在同一个文件夹下,这就是一个web应用程序,依赖于Tomcat(服务器)去访问
    • 一个web应用由多部分组成(静态web、动态web)
      • html、css、js
      • jsp、servlet
      • java程序
      • jar包
      • 配置文件(properties)
  2. web应用程序编写完毕后,若想提供给外界访问,需要一个服务器来统一管理

1.3 静态web

  • *.htm、 *.html是网页的后缀,若服务器上一直存在这些东西,就可以直接通过网络进行读取。
  • 流程如下:在这里插入图片描述
  • 静态web的缺点:
    • web页面无法更新,所有用户看到的页面相同
      • 轮播图,点击特效:伪动态(使用javaScript实现)
    • 无法和数据库交互,数据无法持久化,用户无法交互

1.4 动态web

  • 页面可以动态展示,每个用户看到的页面都不一样。web页面展示的效果因人而异。
  • 流程如下在这里插入图片描述
  • 缺点:若服务器的动态web资源出错,就需要重新编写后台程序并且重新发布,代价会有点大
  • 优点:
    • web页面可以动态更新,每个用户看到的页面都不一样
    • 可以和数据库交互,可以做数据持久化,存储用户数据

2.web服务器

2.1 技术

ASP:

  • 国内最早流行的,来自微软
  • 在html中嵌入了VB脚本
  • 在ASP开发中,一个页面往往会有几千行的业务代码,极难维护

PHP:

  • 开发速度快、功能强大、跨平台、代码简单
  • 无法承载大量访问的情况,具有局限性,仅适用于中小型的网站

JSP:

  • 基于java语言
  • 可以承载高并发、高可用、高性能带来的影响
  • 语法和ASP相似,加强市场竞争力

2.2 web服务器

  • 服务器是一种被动的操作,用来处理用户的请求,并给用户响应
  • IIS
  • Tomcat

3. Tomcat详解

3.1 安装tomcat

  1. tomcat官网下载最新的安装包
    在这里插入图片描述
  2. 解压

3.2 Tomcat启动

  1. Tomcat文件夹目录介绍
    • bin目录下是启动、关闭的脚本文件,存放tomcat命令
    • conf是配置文件,里面的server.xml文件是核心的配置文件
    • lib是依赖的jar包
    • logs是日志
    • webapps存放网站
  2. mac操作系统启动、关闭Tomcat的方式
    • 将下载好的tomcat压缩包移入/usr/local目录下
      sudo mv /Users/taozehua/Downloads/apache-tomcat-10.0.10.tar.gz /usr/local/
    • 解压缩在/usr/local/目录
      sudo (需要先进入特权模式)
      cd /usr/local/
      tar zxvf apache-tomcat-10.0.10.tar.gz
    • 建立链接,方便维护使用
      sudo
      ln -s /usr/local/apache-tomcat-10.0.10/Library/Tomcat
    • 命令行启动Tomcat:
      /Library/Tomcat/bin/startup.sh
      若出现如下提示则表示安装并运行成功:
      Using CATALINA_BASE: /Library/Tomcat
      Using CATALINA_HOME: /Library/Tomcat
      Using CATALINA_TMPDIR: /Library/Tomcat/temp
      Using JRE_HOME: /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home
      
    • 打开浏览器,输入 http://localhost:8080/
      回车之后如果看到Apache Tomcat,表示已经成功运行Tomcat
    • 停止tomcat:
      /Library/Tomcat/bin/shutdown.sh
      

3.3 Tomcat配置

  • Tomcat配置,主要的配置都可以在conf目录下的server.xml中修改
  • 可以配置启动的端口号,tomcat的默认端口号为8080
    <Connector port="8080" protocol="HTTP/1.1"
                   connectionTimeout="20000"
                   redirectPort="8443" />
    
  • 可以配置主机的名称(如把localhost换成www.baidu.com)
    • 默认主机名为localhost,等价于127.0.0.1
    • 默认网站应用存放的位置为webapps目录
    <Host name="localhost"  appBase="webapps"
                unpackWARs="true" autoDeploy="true">
    
  • 请你谈谈网站是如何进行访问的?(重要面试题)
    1. 输入一个域名、回车
    2. 检查本机的host配置文件下有没有这个域名的映射。
      • 有就直接返回对应的ip地址(如本机上localhost对应于ip地址127.0.0.1),这个地址中有我们需要访问的web程序,可以直接访问
      • 没有就去DNS服务器(管理域名和ip地址的映射)上找,找的话就返回,找不到就报错。
  • 配置环境变量(方便启动、可以不配置)

3.4 发布一个web网站的流程

  1. 将自己写的网站放到服务器(tomcat)中指定的web应用的文件夹下,这里是webapps目录下。如这里的tao文件夹下面就是自己写的网页。
    在这里插入图片描述
    文件夹结构如下 在这里插入图片描述
    这时启动tomcat服务器,并且使用浏览器访问http://localhost:8080/tao/就会显示出自己写的网站
  2. 网站应有的结构:
    --webapps: Tomcat服务器的web目录
    		--ROOT
    		--tao:自己写的网站的目录名
      		-WEB-INF
      				-classes:java程序
      				-lib:web应用所依赖的jar包
      				-web.xml:网站的配置文件
      		-index.html:默认的首页
      		- static
      				-css
      				-js
      				-img
      				-……
    

4.Http详解

4.1 什么是Http

  1. Http(超文本传输协议)是一个简单的请求响应协议,通常运行在TCP之上。
    • 超文本:图片、音乐、视频、地图……
    • http默认端口:80
  2. Https:(安全的)
    • 默认端口:443

4.2 两个时代

  • http1.0
    • HTTP/1.0:客户端与web服务器连接后,只能获得一个web资源,断开连接(再要使用的时候需要重新连接请求)
  • http2.0
    • HTTP/1.1:客户端与web服务器连接后,只能获得多个web资源

4.3 Http请求(Request)

  • 客户端向服务器发送请求
  • 以百度为例:
    • Request URL:请求地址
    • Request Method:请求方法
    • Status Code:状态码
    • Remote Address:远程地址+端口
    Request URL: https://www.baidu.com/sugrec?prod=pc_his&from=pc_web&json=1&sid=&hisdata=&_t=1631334447290&req=2&csor=0
    Request Method: GET
    Status Code: 200 OK
    Remote Address: 127.0.0.1:7890
    
    Accept: application/json, text/javascript
    Accept-Encoding: gzip, deflate, br
    Accept-Language: zh-CN,zh;q=0.9
    Connection: keep-alive
    Cache-Control: max-age=0
    
  • 请求行:
    在这里插入图片描述
    • 请求行中的请求方式:GET、POST、HEAD、DELETE、PUT……
      • get:一次请求能够携带的参数比较少,大小有限制,会在浏览器的url地址栏显示数据内容,不安全但高效。
      • post:一次请求能够携带的参数没有限制,大小没有限制,不会在浏览器的url地址栏显示数据内容,安全但不高效。
  • 消息头:
    • Accept:告诉浏览器,它所支持的数据类型
    • Accept-Encoding:支持哪种编码格式
    • Accept-Language:告诉浏览器,它的语言环境
    • Cache-Control:缓存控制
    • Connection: 告诉浏览器请求完成是断开还是保持连接
    • HOST:主机

4.4 Http响应(Response)

  • 服务器响应给客户端
  • 以百度为例:
    • Cache-Control:缓存控制
    • Connection:keep-alive 保持连接
    • Content-Encoding:编码
    • Content-Type:类型
    Cache-Control: max-age=315360000
    Connection: keep-alive
    Content-Encoding: gzip
    Content-Type: application/javascript
    
  • 响应体:
    • Accept:告诉浏览器,它所支持的数据类型
    • Accept-Encoding:支持哪种编码格式
    • Accept-Language:告诉浏览器,它的语言环境
    • Cache-Control:缓存控制
    • Connection: 告诉浏览器请求完成是断开还是保持连接
    • HOST:主机
    • Refresh:告诉客户端,多久刷新一次
    • Location:让网页重新定位
  • 响应状态码:
    • 200:请求响应成功
    • 3xx:请求重定向(重新定位到我给你的新位置去)
    • 4xx:找不到资源,资源不存在(404)
    • 5xx:服务器代码错误(502:网关错误、500……)
  • **常见面试题:**当浏览器中地址栏输入地址并回车的一瞬间到页面能够展示,经历了什么?

5. Maven

在javaweb开发中,需要使用大量的jar包,手动导入太麻烦,需要Maven来自动导入和配置jar包。

5.1 Maven(项目架构管理工具)

  1. 使用Maven来自动导入和配置jar包
  2. Maven的核心思想:约定大于配置(有约束不要去违反)
  3. Maven会规定好该如何去编写java代码,必须要按照规范来(如代码的目录结构的规定)

5.2 在IDEA中使用Maven

maven项目创建步骤:

  1. 选择webapp模版进行创建maven项目在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  2. 等待一段时间后导入成功,并且自己加入java目录和resources目录(可能会需要自己标记目录类别),最后完整的项目结构如下:
    在这里插入图片描述

5.3 在IDEA中配置Tomcat

  1. 点击右上角Add Configuration……在这里插入图片描述
  2. 点击左上角的加号添加配置,并且找到Tomcat Server,选择本地
    t
  3. 设置Tomcat的服务器启动名称、JDK环境和Tomcat的默认启动端口号。
    注意还需要在Application Server一栏中选择自己电脑上的tomcat所在的路径(如果出现Application server libraries not found可能是因为tomcat版本过高不兼容,降低tomcat版本就好)
    若出现其他问题点击fix即可在这里插入图片描述
  4. 配置完成后右上角就可以启动tomcat了
    在这里插入图片描述
  5. 启动成功
    在这里插入图片描述
  6. 使用浏览器访问http://localhost:8080/javawebmaven_war/就可以得到Hello World!这里访问到的Hello World!就是项目目录webapp下index.jsp里面的内容

6. Servlet

6.1 Servlet简介

  • Servlet是sun公司开发动态web的一门技术
  • sun公司在这些API中提供一个接口,叫做Servlet。开发一个Servlet程序只需要完成:
    1. 编写一个类,实现Servlet接口
    2. 把开发好的java类部署到web服务器中
  • 把实现了Servlet接口的java程序叫做Servlet,Servlet接口Sun公司有两个默认的实现类:HttpServlet、GenericServlet

6.2 HelloServlet

  1. 构建一个普通的maven项目,不需要以webapp为模版。
  2. 在pom.xml中导入Servlet和JSP的依赖
    <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>javax.servlet.jsp-api</artifactId>
        <version>2.3.3</version>
    </dependency>
    
  3. 在项目下新建一个Model:Servlet-01,相当于一个子模块
    父项目中会有
    <modules>
        <module>Servlet-01</module>
    </modules>
    
    父项目中的jar包子项目可以直接使用,子项目的jar包父项目不可以直接使用
  4. Maven环境优化:
    • 修改web.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">
          <welcome-file-list>
              <welcome-file>index.jsp</welcome-file>
          </welcome-file-list>
      
      </web-app>
      
    • 将maven的结构搭建完整,补上java目录和resources目录
  5. 编写一个Servlet程序
    1. 编写一个普通类
    2. 实现Servlet接口,直接继承HttpServlet
      public class HelloServlet extends HttpServlet {
      
          // 由于get和post只是请求实现的不同方式,可以相互调用,业务逻辑都一样
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              //ServletInputStream inputStream = req.getInputStream();
              //BufferedReader reader = req.getReader();
              //ServletOutputStream outputStream = resp.getOutputStream();
              PrintWriter writer = resp.getWriter(); // 响应流
              writer.println("Hello Servlet!");
          }
      
          @Override
          protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              doGet(req, resp);
          }
      }
      
  6. 编写Servlet的映射
    • 为什么需要映射?我们写的是java程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以需要在web服务中注册我们写的Servlet,还需要给他一个浏览器能够访问的路径
    • 在web.xml中进行Servlet的注册和映射
      <web-app>
        <!--注册Servlet-->
        <servlet>
          <servlet-name>hello</servlet-name>
          <servlet-class>com.example.servlet.HelloServlet</servlet-class>
        </servlet>
        <!--Servlet的请求路径-->
        <servlet-mapping>
          <servlet-name>hello</servlet-name>
          <url-pattern>/hello</url-pattern>
        </servlet-mapping>
      </web-app>
      
  7. 配置Tomcat:见5.3节
  8. 启动测试,使用浏览器访问http://localhost:8080/Servlet01_war/hello就会显示出打印出来的Hello Servlet!

6.3 Servlet原理

Servlet是由web服务器调用,web服务器在收到浏览器请求之后
在这里插入图片描述

6.4 Mapping

  1. 一个Servlet可以指定一个映射路径
    <servlet-mapping>
      <servlet-name>hello</servlet-name>
      <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    
  2. 一个Servlet可以指定多个映射路径,这时候访问/hello、/hello1……都可以得到对应的页面
    <servlet-mapping>
      <servlet-name>hello</servlet-name>
      <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
      <servlet-name>hello</servlet-name>
      <url-pattern>/hello3</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
      <servlet-name>hello</servlet-name>
      <url-pattern>/hello2</url-pattern>
    </servlet-mapping>
    
  3. 一个Servlet可以指定通用映射路径,映射为/hello/*后访问/hello+任意内容(或者不加)都可以访问到该页面
    <!--Servlet的请求路径-->
    <servlet-mapping>
      <servlet-name>hello</servlet-name>
      <url-pattern>/hello/*</url-pattern>
    </servlet-mapping>
    
  4. 如果直接写/*(默认请求路径),那么默认页面就不再是index.jsp对应的那个页面,而是hello对应的页面
    <servlet-mapping>
      <servlet-name>hello</servlet-name>
      <url-pattern>/*</url-pattern>
    </servlet-mapping>
    
  5. 可以自己指定一些后缀,这时候*前面不能加任何映射的路径,即不能出现“/”。(这时候访问/hello/sadhha.truth也能访问到hello)
    <servlet-mapping>
      <servlet-name>hello</servlet-name>
      <url-pattern>*.truth</url-pattern>
    </servlet-mapping>
    
  6. 优先级问题
    指定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求

6.5 ServletContext对象的应用

web容器在启动的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用,可以对当前的web应用进行管理

6.5.1 共享数据:在一个Servlet中保存的数据可以在另一个Servlet中拿到

  • 先实现一个放置数据的servlet类。该类中先使用getServletContext方法得到ServletContext对象,再由setAttribute方法将数据保存在ServletContext中
    public class HelloServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            ServletContext context = this.getServletContext();// servlet上下文
            String username = "tao"; // 数据
    
            context.setAttribute("username",username);  // 将一个数据保存在ServletContext中,名字为username,值为username
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
    
  • 再去实现一个servlet类获取数据。同样可以使用getServletContext方法得到ServletContext对象,并且通过getAttribute方法可以拿到HelloServlet中保存的数据。(注意:HelloServlet和GetServlet共享一个ServletContext对象,因此它们之间可以进行数据交换
    public class GetServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 与HelloServlet共有一个ServletContext对象
            ServletContext servletContext = this.getServletContext();
    
            String username =(String) servletContext.getAttribute("username");
    
            resp.setContentType("text/html");
            resp.setCharacterEncoding("utf-8");
            resp.getWriter().println("name:"+username);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
  • 同样需要在web.xml中进行注册和映射
    <servlet>
      <servlet-name>hello</servlet-name>
      <servlet-class>com.example.servlet.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
      <servlet-name>hello</servlet-name>
      <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    <servlet>
      <servlet-name>get</servlet-name>
      <servlet-class>com.example.servlet.GetServlet</servlet-class>
    </servlet>
    <servlet-mapping>
      <servlet-name>get</servlet-name>
      <url-pattern>/get</url-pattern>
    </servlet-mapping>
    
  • 最后运行项目,先访问http://localhost:8080/Servlet02_war/hello,再去访问http://localhost:8080/Servlet02_war/get就可以得到在HelloServlet中设置的用户名。注意访问顺序不能颠倒,因为需要先设置再读取。

6.5.2 获取初始化参数

  • 在web.xml中配置web应用的初始化参数
    <context-param>
      <param-name>url</param-name>
      <param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
    </context-param>
    
    相当于一个键值对,key是url,value是jdbc:mysql://localhost:3306/mybatis
  • 实现一个DemoServlet类来获取初始化参数。通过servletContext.getInitParameter(“url”)方法就可以获得url对应的参数
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = this.getServletContext();
    
        System.out.println(servletContext.getInitParameter("url"));
    }
    
  • 当然仍然需要在web.xml中进行注册和映射
    <servlet>
      <servlet-name>gp</servlet-name>
      <servlet-class>com.example.servlet.DemoServlet</servlet-class>
    </servlet>
    <servlet-mapping>
      <servlet-name>gp</servlet-name>
      <url-pattern>/gp</url-pattern>
    </servlet-mapping>
    
  • 运行项目后访问http://localhost:8080/Servlet02_war/gp就会在控制台输出jdbc:mysql://localhost:3306/mybatis
  • 注意如果web.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">
        <welcome-file-list>
            <welcome-file>index.jsp</welcome-file>
        </welcome-file-list>
    
    </web-app>
    

6.5.3 请求转发

  • 实现一个DemoServlet2类进行请求转发。这里使用getRequestDispatcher和forward方法将请求转发到6.5.2节实现的DemoServlet类对应的页面
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = this.getServletContext();
    
        RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/gp");  // 设置转发的请求路径
    
        requestDispatcher.forward(req,resp);  // 调用forward方法实现请求转发
    }
    
  • 在web.xml中进行注册
    <servlet>
      <servlet-name>dp</servlet-name>
      <servlet-class>com.example.servlet.DemoServlet2</servlet-class>
    </servlet>
    <servlet-mapping>
      <servlet-name>dp</servlet-name>
      <url-pattern>/dp</url-pattern>
    </servlet-mapping>
    
  • 此时运行项目并且使用浏览器访问http://localhost:8080/Servlet02_war/dp就会显示出/gp页面的内容。可以理解为自动跳转到了该页面,但url路径没变,仍然是/dp。
  • 通常应用于以下场景:
    • a需要向c请求资源,但a只能访问b,这时候就需要b进行请求转发(a始终只与b直接交流)。
    • 不同于重定向,重定向通常是a向b请求资源,然后b告诉a资源在c上,a再去向c请求资源。这时a和b、c都有交流

6.5.4 读取资源文件

要使用Properties类

  • 在java目录下新建properties
  • 在resources目录下新建properties

项目运行后这两个properties都被打包到了一个路径下:classes,我们称这个路径为classpath
在这里插入图片描述

  • 在resources目录下新建一个properties文件,填入如下内容
    username=root
    password=123456
    
  • 实现一个PropertiesServlet类来读取资源。使用ServletContext对象的getResourceAsStream方法(方法参数需要填入资源所在位置的相对路径)获得一个文件流,然后通过Properties类进行加载就可以得到properties文件中存储的内容。
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        InputStream resourceAsStream = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
        Properties properties = new Properties();
        properties.load(resourceAsStream);
    
        resp.getWriter().println(properties.getProperty("username"));
    
        resp.getWriter().println(properties.getProperty("password"));
    }
    
  • 在web.xml中进行注册和映射
    <servlet>
      <servlet-name>prop</servlet-name>
      <servlet-class>com.example.servlet.PropertiesServlet</servlet-class>
    </servlet>
    <servlet-mapping>
      <servlet-name>prop</servlet-name>
      <url-pattern>/prop</url-pattern>
    </servlet-mapping>
    
  • 运行项目后使用浏览器访问http://localhost:8080/Servlet02_war/prop就会得到
    root
    123456
    

6.6 HttpServletResponse

  • web服务器接收到客户端的http请求,会针对这个请求分别创建一个代表请求的HttpServletRequest对象和代表相应的HttpServletResponse对象。
  • 若要获取客户端请求来的参数,就要使用HttpServletRequest
  • 若要给客户端响应一些信息,就要使用HttpServletResponse

6.6.1 方法分类

负责向浏览器发送数据的方法
getOutputStream方法负责向浏览器写流,getWriter方法负责向浏览器写中文

ServletOutputStream getOutputStream() throws IOException;

PrintWriter getWriter() throws IOException;

负责向浏览器发送响应头的方法

void setCharacterEncoding(String var1);

void setContentLength(int var1);

void setContentLengthLong(long var1);

void setContentType(String var1);

void setDateHeader(String var1, long var2);

void addDateHeader(String var1, long var2);

void setHeader(String var1, String var2);

void addHeader(String var1, String var2);

void setIntHeader(String var1, int var2);

void addIntHeader(String var1, int var2);

响应的状态码

public static final int SC_CONTINUE = 100;

public static final int SC_SWITCHING_PROTOCOLS = 101;

public static final int SC_OK = 200;

public static final int SC_CREATED = 201;

public static final int SC_ACCEPTED = 202;

public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203;

public static final int SC_NO_CONTENT = 204;

public static final int SC_RESET_CONTENT = 205;

public static final int SC_PARTIAL_CONTENT = 206;

public static final int SC_MULTIPLE_CHOICES = 300;

public static final int SC_MOVED_PERMANENTLY = 301;

public static final int SC_MOVED_TEMPORARILY = 302;

public static final int SC_FOUND = 302;

public static final int SC_SEE_OTHER = 303;

public static final int SC_NOT_MODIFIED = 304;

public static final int SC_USE_PROXY = 305;

public static final int SC_TEMPORARY_REDIRECT = 307;

public static final int SC_BAD_REQUEST = 400;

public static final int SC_UNAUTHORIZED = 401;

public static final int SC_PAYMENT_REQUIRED = 402;

public static final int SC_FORBIDDEN = 403;

public static final int SC_NOT_FOUND = 404;

public static final int SC_METHOD_NOT_ALLOWED = 405;

public static final int SC_NOT_ACCEPTABLE = 406;

public static final int SC_PROXY_AUTHENTICATION_REQUIRED = 407;

public static final int SC_REQUEST_TIMEOUT = 408;

public static final int SC_CONFLICT = 409;

public static final int SC_GONE = 410;

public static final int SC_LENGTH_REQUIRED = 411;

public static final int SC_PRECONDITION_FAILED = 412;

public static final int SC_REQUEST_ENTITY_TOO_LARGE = 413;

public static final int SC_REQUEST_URI_TOO_LONG = 414;

public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415;

public static final int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;

public static final int SC_EXPECTATION_FAILED = 417;

public static final int SC_INTERNAL_SERVER_ERROR = 500;

public static final int SC_NOT_IMPLEMENTED = 501;

public static final int SC_BAD_GATEWAY = 502;

public static final int SC_SERVICE_UNAVAILABLE = 503;

public static final int SC_GATEWAY_TIMEOUT = 504;

public static final int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
}

6.6.2 常见应用

  1. 向浏览器输出数据、信息
    ServletOutputStream getOutputStream() throws IOException;
    
    PrintWriter getWriter() throws IOException;
    
  2. 下载文件
    • 获取下载文件的路径。之所以使用"/WEB-INF/classes/t.jpg"来获得文件的绝对路径,是因为项目运行后在target目录下的WEB-INF/classes中会生成图片文件。
      String realPath =this.getServletContext().getRealPath("/WEB-INF/classes/t.jpg"); 
      System.out.println(realPath);
      
    • 获取下载的文件名,路径下最后一个"/" 后面的一定是文件名
      String filename = realPath.substring(realPath.lastIndexOf("//") + 1);
      
    • 设置让浏览器能够支持下载我们需要的东西。设置响应头Content-Disposition,表示文件在浏览器中下载。使用URLEncoder.encode可以让中文文件名用UTF-8进行编码,解决在浏览器中的乱码问题。
      resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename,"UTF-8"));
      
    • 获取下载文件的输入流
      FileInputStream fileInputStream = new FileInputStream(realPath);
      
    • 创建缓冲区,通常使用一个1024长度的字节数组来充当缓冲区
      int len=0;
      byte[] buffer = new byte[1024];
      
    • 获得OutputStream对象
      ServletOutputStream outputStream = resp.getOutputStream();
      
    • 将FileOutputStream写入到缓冲区(buffer),并且使用OutputStream将缓冲区中的数据输出到客户端
      while((len=fileInputStream.read(buffer))>0){
          // 使用OutputStream将缓冲区中的数据输出到客户端
          outputStream.write(buffer,0,len);
      }
      
    • 关闭流
      fileInputStream.close();
      outputStream.close();
      
  3. 验证码功能
    • 验证码怎么来的?
      • 前端实现需要通过js来判断
      • 后端实现,需要用到java的图片类,生成一个图片
    • 首先实现一个随机数生成器
      // 生成随机数
      private String makeNum(){
          Random random = new Random();
          // 4个9代表生成的是小于等于四位数
          String num= String.valueOf(random.nextInt(9999));
      
          StringBuffer stringBuffer = new StringBuffer();
      
          // 用0填充
          for(int i=0;i<4-num.length();i++){
              stringBuffer.append("0");
          }
      
          return stringBuffer.toString() + num;
      }
      
    • 在内存中生成一个图片并向图片写入随机数的数据
      // 在内存中创建一个图片
      BufferedImage image = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);
      
      // 得到图片
      Graphics2D graphics = (Graphics2D)image.getGraphics();  // 相当于画笔
      // 设置图片的背景颜色
      graphics.setColor(Color.white);
      graphics.fillRect(0,0,80,20);
      
      // 给图片写数据
      graphics.setColor(Color.blue);
      graphics.setFont(new Font(null,Font.BOLD,20));
      graphics.drawString(makeNum(),0,20);
      
    • 设置响应头,使得浏览器不缓存图片,最后将图片写到浏览器
      // 让浏览器3秒自动刷新一次
      resp.setHeader("refresh","3");  // 3秒刷新一次
      // 告诉浏览器这个请求用图片的方式打开
      resp.setContentType("image/jpeg");
      // 不让浏览器缓存
      resp.setDateHeader("expires",-1);  // expires设置过期时间
      resp.setHeader("Cache-Control","no-cache"); // 不缓存,不会占用浏览器资源
      resp.setHeader("Pragma","no-cache");
      
      // 把图片写给浏览器
      ImageIO.write(image, "jpg",resp.getOutputStream());
      
  4. 实现重定向
    • 重定向:一个web资源受到客户端请求后,他会通知客户端去访问另一个web资源。
    • 常见场景:用户登录
    • 使用sendRedirect来实现重定向
      void sendRedirect(String location) throws IOException;
      
    • 我们以跳转至/image页面为例子,跳转的路径前面要加上项目名称“/HttpServletResponse_war”,否则会跳转失败
      @Override
      protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          resp.sendRedirect("/HttpServletResponse_war/image");
      }
      
    • 注册后再去访问http://localhost:8080/HttpServletResponse_war/redirect就会自动跳转到http://localhost:8080/HttpServletResponse_war/image页面。这时候url路径发生改变,与请求转发不同
    • 上述的sendRedirect方法可以使用如下代码代替,效果一样
      resp.setHeader("Location","/HttpServletResponse_war/image");
      // 状态码设置为重定向
      resp.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
      
    • 面试题:重定向和转发的区别
      • 相同点:页面都会跳转
      • 不同点:请求转发时url不会发生变化;重定向时url地址栏会发生变化

6.7 HttpServletRequest

  • HttpServletRequest代表客户端的请求,用户通过Http协议访问服务器
  • Http请求中的所有信息会被封装到HttpServletRequest,通过HttpServletRequest的方法,可以获得客户端的所有信息

6.7.1 获取前端传递的参数以及请求转发

  1. 首先需要引入jsp的依赖
    <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>javax.servlet.jsp-api</artifactId>
      <version>2.3.3</version>
    </dependency>
    
  2. 用jsp实现登录页面和登录成功页面,模拟前端
    • 登录页面,action="${pageContext.request.contextPath}/login"和method="post"代表以post方式提交表单,提交到web项目下的/login请求
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>Login</title>
      </head>
      <body>
      <h1>登录</h1>
      <div style="text-align: center">
          <%--以post方式提交表单,提交到login请求--%>
          <form action="${pageContext.request.contextPath}/login" method="post">
              用户名:<input type="text" name="username"> <br>
              密码:<input type="password" name="password"> <br>
              爱好:
              <input type="checkbox" name="hobby" value="打篮球">打篮球
              <input type="checkbox" name="hobby"value="唱歌">唱歌
              <input type="checkbox" name="hobby" value="电影">电影
      
              <br>
      
              <input type="submit">
          </form>
      
      </div>
      </body>
      </html>
      
    • 登录成功页面
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>登录成功</title>
      </head>
      <body>
      <h1>登录成功</h1>
      </body>
      </html>
      
  3. 实现一个LoginServlet类使用req.getParameter和req.getParameterValues方法来获得前端传来的参数,并使用req.getRequestDispatcher方法进行请求转发。
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          // 解决乱码问题
            req.setCharacterEncoding("utf-8");
          resp.setCharacterEncoding("utf-8");
          // 获得前端传来的参数
            String username = req.getParameter("username");
            String password = req.getParameter("password");
            String[] hobbies = req.getParameterValues("hobby");
            System.out.println("---------------------------");
            System.out.println(username);
            System.out.println(password);
            System.out.println(Arrays.toString(hobbies));
    
            // 通过请求转发
            // 请求转发的路径中的"/"代表当前web项目,这里跳转到success.jsp对应的页面下面
            req.getRequestDispatcher("/success.jsp").forward(req,resp);
    }
    
  4. 在web.xml中进行注册和映射
    <servlet>
        <servlet-name>login</servlet-name>
        <servlet-class>com.example.servlet.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>login</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mapping>
    
  5. 运行项目后访问http://localhost:8080/HttpServletRequest_war/就会进入登录页面,填入参数后点击提交按钮就会跳转到登录成功页面,且在控制台会输出用户名、密码和爱好。至此已经成功的从前端获得了参数并且进行了请求转发。
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值