JavaWeb笔记(待完整)

682 阅读23分钟

JavaWeb

可拆分为 java(语言) web(网页)

1 基本概念

1.1 前言

Java Web,是用Java技术来解决相关web互联网领域的技术栈。web包括:web服务端和web客户端两部分。Java在客户端的应用有Java Applet,不过使用得很少,**Java在服务器端的应用非常的丰富,比如Servlet,JSP、第三方框架等等。**Java技术对Web领域的发展注入了强大的动力。

web开发:

  • web, 网页的意思, www.baidu.com
  • 静态web资源(如html 页面)
    • html, css
    • web页面中供人们浏览的数据始终是不变
  • 动态web资源
    • 淘宝, 几乎所有的网站
    • web页面中供人们浏览的数据是由程序产生的,不同时间点访问web页面看到的内容各不相同
    • 技术栈: JSP/servlet, ASP, PHP, JavaScript

在Java中, 动态web资源开发的开发统称为JavaWeb


1.2 web应用程序

web应用程序: 可以提供浏览器访问的程序

  • a.html, b.html......多个web资源, 这些web资源可以被外界访问, 对外界提供服务
  • 访问到的任何页面和资源, 是存在于世界上某个角落的计算机上
  • 对外提供URL(统一资源定位器)
  • 这个统一的web资源被放到同一个文件夹下, 即web应用程序(依赖于)-->Tomcat : 服务器
  • 一个web应用有多个部分组成 (静态web, 动态web)
    • html, css
    • jsp, servlet
    • Java程序
    • jar包
    • 配置文件(properties)
    • web应用程序编写完后, 若想提供为外界访问: 需要一个服务器来统一管理

1.3 静态web

*.html等这些都是网页的后缀, 如果服务器上一直存在这些东西, 我们就可以直接进行读取

静态web流程图.png

  • 静态web存在的缺点
    • web页面无法动态更新, 所有用户看到都是同一个页面
      • 轮播图, 点击特效(伪动态)
      • JavaScript
    • 它无法和数据库交互(数据无法持久化, 用户无法交互)

1.4 动态web

页面会动态展示: "Web的页面展示的效果因人而异"

动态web流程图.png 缺点:

  • 加入服务器的动态web资源出现了错误, 我们需要重新编写我们的后台程序,重新发布
    • 停机维护

优点:

  • web页面可以动态更新, 用户看到都不是同一个页面
  • 可以与数据库交互 (数据持久化: 注册, 商品信息, 用户信息...)

动态web持久化.png

2 web服务器

2.1 技术讲解

ASP

  • 微软: 国内最早流行的就是ASP
  • 在HTML中嵌入了VB的脚本, ASP+COM;
  • 在ASP开发中, 基本一个页面

PHP:

  • PHP开发速度很快, 功能很强大, 跨平台, 代码很简单
  • 无法承载大访问量的情况(局限性)

JSP/Servlet:

B/S: 浏览器和服务器

C/S: 客户端和服务器

  • sun公司主推的B/S架构
  • 基于Java语言的
  • 可以承载三高(高并发, 高性能, 高可用)问题代理的影响
  • 语法像ASP, ASP-->JSP

2.2 web服务器

web服务器可以处理浏览器等Web客户端的请求并返回相应响应,也可以放置网站文件,让全世界浏览;可以放置数据文件,让全世界下载。

IIS

微软的; ASP, window自带的

Tomcat

Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。由于有了Sun 的参与和支持,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。

Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个初学者来说,最佳选择

Tomcat 实际上运行JSP 页面和Servlet

......

有3年经验, 可以尝试手写Tomcat服务器;


3 Tomcat

3.1 Tomcat安装

下载Tomcat:

  1. 安装或解压
  2. 了解配置文件和结构目录
  3. 产品的作用

JDK目录.png 如上所示: JDK目录, Java的加载机制==>rt.jar 在lib文件夹里


  • 在官网下载对应的安装包或者压缩包

tomcat官网下载.png

  • 分析一下Tomcat的结构目录

Tomcat目录.png


3.2 Tomcat启动和配置

  • 脚本启动, 如图:

Tomcat文本启动.png 打开默认localhost:8080即可, 上图shutdown.bat就可以关闭Tomcat

  • 服务器核心配置文件

服务器配置.png 可以配置启动的端口号

  • tomcat的默认端口号为: 8080

  • mysql: 3306

  • http: 80

  • https: 443

  • <Connector port="8080" protocol="HTTP/1.1"
        		connectionTimeout="20000"
        		redirectPort="8443" />
    

可以配置主机的名称

  • 默认的主机名为: localhost==>127.0.0.1
  • 默认网站应用存放的位置为: webapps

可以修改localhost域名

hosts.png 修改完此文件域名, 在Tomcat配置文件里改掉域名host-name

高难度面试题

请你谈谈网站是如何进行访问的?

  1. 输入一个域名; 回车

  2. 检查本机的C:\Windows\System32\drivers\etc\hosts配置文件下有没有这个域名映射;

    1. 有: 直接返回对应的ip地址, 这个地址中, 有我们需要访问的web程序, 可以直接访问
    127.0.0.1        www.zisu.com
    
    1. 没有: 去DNS(域名服务器)找

访问流程.png 3. 可以配置一下环境变量(可选性)

3.3 发布一个web网站

将自己写的网站, 放到服务器(Tomcat)中指定的web应用的文件夹(web apps)下, 就可以访问了

网站应该有的结构

--webapps : Tomcat服务器的web目录
    -ROOT
    -zisu : 网站的目录名
        -WEB-INF
        	-classes : java程序
            -lib : web应用所依赖的jar包
            -web.xml : 网站配置文件
        -index.html : 默认的首页
        -static
            -css
            	-style.css
            -js
            -img
        -......

4 HTTP

4.1 什么是HTTP

超文本传输协议(Hypertext Transfer Protocol,HTTP)是一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。

  • 文本: html, 字符串 ......
  • 超文本: 图片, 音乐, 视频, 地图......
  • 默认端口: 80

HTTPS: 安全的

  • 默认端口: 443

4.2 两个时代

  • http1.0
    • HTTP/1.0: 客户端可以与web服务器连接后, 只能获得一个web资源, 断开连接
  • http2.0
    • HTTP/1.1: 客户端可以与web服务器连接后, 能获得多个web资源

4.3 Http请求

  • 客户端 ===发请求(request)===> 服务器

百度:

Request URL: https://www.baidu.com/     请求地址
Request Method: GET                     get方法/post方法
Status Code: 200 OK                     状态码: 200
Remote(远程) Address: 36.152.44.96:443
Referrer Policy: strict-origin-when-cross-origin
Accept: text/html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cache-Control: max-age=0
Connection: keep-alive
Host: www.baidu.com
  1. 请求行
    1. 请求行中的请求方式: GET
    2. 请求方式: GET, POST, HEAD, DELETE, TRACT......
      1. get: 请求能够携带的参数比较少, 大小有限制, 会在浏览器的URL地址栏显示数据内容, 不安全, 但高效
      2. post: 请求能够携带的参数没有限制, 大小没有限制, 不会在浏览器的URL地址栏显示数据内容, 安全, 不高效
  2. 消息头
Accept            支持的数据类型
Accept-Encoding   支持的编码格式  GBK UTF-8  ISO8859-1
Accept-Language   语言环境
Cache-Control     缓存控制
Connection        请求完成是断开连接还是保持
Host              主机

4.4 Http响应

  • 服务器 ===响应===>客户端

百度:

Cache-Control: private
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html;charset=utf-8
Date: Wed, 19 May 2021 09:05:37 GMT
Expires: Wed, 19 May 2021 09:05:37 GMT
  1. 响应体
Accept            支持的数据类型
Accept-Encoding   支持的编码格式  GBK UTF-8  ISO8859-1
Accept-Language   语言环境
Cache-Control     缓存控制
Connection        请求完成是断开连接还是保持
Host              主机
Refresh           多久刷新一次
Location          让网页重新定位
  1. 状态码
    1. 200 : 请求响应成功
    2. 3xx : 请求重定向
    3. 404 : 资源未找到
    4. 5xx : 服务器代码错误

常见面试题:

当你的浏览器中地址栏输入地址并回车的一瞬间到页面能够展示回来, 经历了什么?


5 Maven

为什么要学习此技术

  1. 在Javaweb开发中, 需要使用大量的jar包, 我们收到去导入
  2. 而Maven能够自动导入和配置jar包

5.1 Maven项目架构管理工具

Maven的核心思想: 约定大于配置

  • 有约束, 不要去违反

Maven会规定好你如何去编写Java代码, 必须按照这个规范

5.2 下载安装Maven

官网: maven.apache.org

Maven官网下载.png 下载完成后, 解压即可

5.3 配置环境变量

在我们的系统环境变量中

配置如下配置:

  • M2_HOME maven目录下的bin目录
  • MAVEN_HOME maven的目录
  • 在系统的path中配置 %MAVEN_HOME%\bin

Maven版本.png 测试Maven是否安装成功, 保证必须配置完毕~

5.4 阿里云镜像

  • 镜像: mirrors
    • 作用: 加速下载需要的jar包
  • 国内推荐阿里云的镜像
       <mirror>
           <id>nexus-aliyun</id>
           <mirrorOf>*,!jeecg,!jeecg-snapshots</mirrorOf>
           <name>Nexus aliyun</name>
           <url>http://maven.aliyun.com/nexus/content/groups/public</url> 
       </mirror>

5.5 本地仓库

在本地的仓库, 还有个远程仓库

建立一个本地仓库, 在配置文件夹里有个setting文件: localRepository

<localRepository>/path/to/local/repo</localRepository>

5.6 在IDEA中使用Maven


5.6.1 在IDEA中全局配置maven

#紧急补丁#

在IDEA中全局配置maven

IDEA中maven全局配置01.png IDEA中maven全局配置02.png

5.6.2 正文

#正文#

  1. 启动IDEA
  2. 创建一个Maven项目 IDEA新建Maven01.png IDEA新建Maven02.png IDEA创建Maven03.png
  3. 第一次创建Maven项目, 会下载很多的jar 第一次创建Maven项目.png
  4. 项目搭建成功 项目搭建成功.png
  5. 观察maven仓库中多了什么东西
  6. IDEA中的maven配置, 项目创建成功后看一眼maven配置

Maven在Idea配置.png 7. ok

5.7 创建不用模板的项目

手建目录 web目录.png

标记建好的文件夹为可用的目录 标记文件夹为.png

5.8 项目结构配置(Project Structure...)

也可以用项目结构配置 项目结构配置.png

点进去可以配置 结构配置ModulesP.png

5.9 在IDEA中配置Tomcat

IDEA配置Tomcat01.png

IDEA配置Tomcat02P.png 遇到没有artifacts, 可以点击fix进行添加, 或者从项目构建配置也可以

  • 这是有模板的maven项目

添加artifacts01P.png

  • 这是无模板的maven项目
  • 注意: 无模板的是没有首页index.jsp的, 自己手动添加, 看好目录结构和WEB-INF一层下的

添加首页.png 添加artifacts00.png 添加artifacts01.png 添加artifacts02.png

5.10 pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!-- Maven版本和头文件 -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <!-- 配置的GAV -->
  <groupId>com.zisu</groupId>
  <artifactId>javaweb-01-maven</artifactId>
  <version>1.0-SNAPSHOT</version>

  <!-- Package: 项目打包的方式 -->
  <!-- jar: Java应用 -->
  <!-- war: Java Web应用 -->
  <packaging>war</packaging>

  <!-- 配置 -->
  <properties>
    <!--  项目的默认构建编码  -->
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <!--  编码版本  -->
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>
  <!-- 项目依赖 -->
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <!-- 项目构建用的, 可删 -->
  <build>
  </build>
</project>

5.101 在build配置resources


    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <includes>
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
      </resource>
      <resource>
        <directory>src/main/java</directory>
        <includes>
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
      </resource>
    </resources>

5.11 结构树

maven中jar包的关联关系.png


6 Servlet

6.1 Servlet简介

Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。

狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类

  • Servlet就是sun公司开发动态web的一门技术
  • sun在这些API提供一个接口叫做: Servlet, 如果你想开发一个Servlet程序, 只要完成两步
    • 编写一个类, 实现Servlet接口
    • 把开发好的Java类部署到web服务器中

把实现了Servlet接口的Java程序叫做Servlet

6.2 HellowServlet

写一个Servlet小程序

  1. 创建一个maven父工程, 不用选模板, 并且把不需要的src删掉, 核心是pom.xml

  2. 在父工程的pom文件中导入servlet依赖和JSP依赖

  3. <!--   Servlet依赖     -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
    </dependency>
    <!--   JSP依赖     -->
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>javax.servlet.jsp-api</artifactId>
        <version>2.3.3</version>
    </dependency>
    
  4. 子工程可以继承父工程的依赖, 接下来创建一个web模板的module(子工程)

  5. newModule01.png

  6. newModule02.png

  7. 子module创建完成后, 会在其pom文件中出现标记

  8.     <modules>
            <module>servlet-01</module>
        </modules>
    
  9. 对应的父工程的pom文件也会出现相应的标记(三要素一定都要有), 记住如果没有, 可以手动添加

  10.   <parent>
        <!--  父工程的定位  -->
        <groupId>com.sama</groupId>
        <artifactId>javaweb-02-servlet</artifactId>
        <version>1.0-SNAPSHOT</version>
      </parent>
    
  11. 创建完成的maven目录resources, java下的com.sama.xxxx

  12. 完整目录d520.png

  13. 接下来配置tomcat服务器, 记住有两步

    • 创建新的服务器配置
    • tomcat新配置D520.png
    • 解决没有artifacts问题
    • artifactsD520.png
    • 一定要注意的是, 在添加完artifacts后, 默认的访问路径要改成需要的默认
  14. 所有的东西配置完成后, 接下来写我们的servlet了

  15. 首先分析:

    1. servlet是一个接口, 但是源码中也有两个它的实现类, 已知的有HttpServlet

    2. 这里出现了一个问题, 子工程想继承父工程的依赖可以去添加依赖, 但不用添加版本

    3. 这里其实是起到管理依赖jar版本号的作用,一般只会在项目的最顶层的pom.xml中使用到,所有子module如果想要使用到这里面声明的jar,只需要在子module中添加相应的groupId和artifactId即可,并不需要声明版本号,需要注意的是这里面只是声明一个依赖,并不是真实的下载jar,只有在子module中使用到,才会去下载依赖。

    4. <!--   父工程加入     -->
      <dependencyManagement></dependencyManagement>
      <!--   子工程引用Servlet依赖     -->
      <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
      </dependency>
      
      
    5. 创建一个类先去继承HttpServlet, 然后再去看源码, 还是继承不了( ╯□╰ ), 查了很久才知道

      1. Jakarta EE 9 版本标志着从 javax.* 命名空间到 Eclipse 的 jakarta.* 的最终过渡,此版本将所有 API 更新为在包名称中使用 jakarta.*。
      2. 所以我引用的依赖已经是不能用的了, Tomcat10.0版本,里面的servlet-api.jar中的包名已经改为jakarta.servlet
    6. 我们导入能用的Servlet依赖

    7. <!-- tomcat-servlet-api: 这是最新的servlet包 -->
      <dependency>
          <groupId>org.apache.tomcat</groupId>
          <artifactId>tomcat-servlet-api</artifactId>
          <version>10.0.6</version>
      </dependency>
      
    8. 好了可以继承HttpServlet了, 看看它的源码

      1. //它是一个抽象类, 并且继承了GenericServlet
        public abstract class HttpServlet extends GenericServlet {
            
        }
        
      2. HttpServlet内容结构D520.png

      3. 再由HttpServlet进入GenericServlet

      4. //它是一个抽象类, 并且实现了Servlet, ServletConfig, Serializable
        public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {}
        
      5. 再由GenericServlet进入Servlet

      6. //它是一个接口, 并有四个方法, 也是它的生命周期
        public interface Servlet {
            //初始化
            void init(ServletConfig var1) throws ServletException;
        
            ServletConfig getServletConfig();
        
            //服务(最核心)
            void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
        
            //获取信息
            String getServletInfo();
        
            //销毁
            void destroy();
        }
        
      7. 返回GenericServlet可以看看service方法是怎么去实现的, 发现并没有实现

      8. 那么再返回HttpServlet看看service方法

      9. HttpServlet的service方法.png

      10. 注意是判断方法是什么类型的, 然后再调用各自对应的方法

      11. 它有几种默认实现的方法, doGet(), doPost()...... 我们去重写这些我们需要的方法即可

    9. 我们理清楚servlet大概的结构

      • servlet结构D520.png
  16. 现在分析完成, 可以写我们的servlet, 重写doGet(), doPost()

  17. public class HelloServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //定义内容格式
            resp.setContentType("text/html");
            //定义一下编码格式
            resp.setCharacterEncoding("utf-8");
            //获取输出流, 两种实现方式
            //ServletOutputStream outputStream = resp.getOutputStream();
            PrintWriter out = resp.getWriter();
            out.write("<html>");
            out.write("<head>");
            out.write("<title>");
            out.write("zisusama");
            out.write("</title>");
            out.write("</head>");
            out.write("<body>");
            out.write("<h1>");
            out.write("子苏大人驾到!");
            out.write("</h1>");
            out.write("</body>");
            out.write("</html>");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
  18. 写完servlet记得要去web.xml注册, 编写Servlet的映射

    • 为什么需要映射: 我们写的是Java程序, 但是要通过浏览器访问, 而浏览器需要连接web服务器, 所以我们需要web服务中注册我们写的Servlet, 还需要给他一个浏览器能够访问的路径
  19. 
      <servlet>
        <servlet-name>hello-servlet</servlet-name>
        <servlet-class>com.sama.servlet.HelloServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>hello-servlet</servlet-name>
        <url-pattern>/hw</url-pattern>
      </servlet-mapping>
    
  20. 注册好了, 启动服务器, 看看子苏大人驾到了没 ? (●'◡'●)

  21. 子苏大人驾到D520.png

  22. 撒花完结❀

6.3 Servlet 原理

servlet原理图D520.png

6.4 Mapping问题

1. 精确路径匹配。例子:比如servletA 的url-pattern为 /test,servletB的url-pattern为 /* ,这个时候,如果我访问的url为http://localhost/test ,这个时候容器就会先进行精确路径匹配,发现/test正好被servletA精确匹配,那么就去调用servletA,也不会去理会其他的servlet了。

2. 最长路径匹配。例子:servletA的url-pattern为/test/,而servletB的url-pattern为/test/a/,此时访问http://localhost/test/a时,容器会选择路径最长的servlet来匹配,也就是这里的servletB。

3. 扩展匹配,如果url最后一段包含扩展,容器将会根据扩展选择合适的servlet。例子:servletA的url-pattern:*.action

4. 如果前面三条规则都没有找到一个servlet,容器会根据url选择对应的请求资源。如果应用定义了一个default servlet,则容器会将请求丢给default servlet(什么是default servlet?后面会讲)。

什么是default servlet

  • 首先所有的请求进入tomcat,都会流经servlet,如果没有匹配到任何应用指定的servlet,那么就会流到默认的servlet。
  • 默认的servlet是配置在$catalina/conf/web.xml里面的。
  • 应用的一些静态资源就可以交给该servlet去处理,以减轻服务器压力,节省资源!

6.5 Servlet生命周期

每个Servlet的运行都遵循如下生命周期:

  1. 创建Servlet实例。
  2. Web容器调用Servletinit()方法,对Servlet进行初始化。
  3. Servlet初始化后,将一直存在于容器中,用于响应客户端请求,如果客户端发送GET请求,容器调用ServletdoGet()方法处理并响应请求;如果客户端发送POST请求,容器调用Servlet的*doPost()方法处理并响应请求。或者统一使用service()*方法处理来响应用户请求。
  4. Web容器决定销毁Servlet时,先调用Servletdestory()方法,通常在关闭Web应用时销毁Servlet实例

6.6 ServletContext

1 共享数据

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

  • 共享数据我在这个Servlet中保存到ServletContext的数据, 可以在另外一个servlet中拿到
  • ServletContext与servletD520.png 写一个实例:
  1. 创建一个新的子工程, 并修改tomcat, 只添加新module的artifacts

  2. 完善项目的目录结构, 开始写一个向ServletContext存东西的servlet: HelloServlet

  3. public class HelloServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //获取到ServletContext对象
            ServletContext context = this.getServletContext();
            String info = "子苏大人显身!";
            //再把info放入ServletContext
            context.setAttribute("info",info);
        }
    }
    
  4. 再去写一个在ServletContext取东西的servlet: GetServlet

  5. public class GetServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //获取ServletContext对象
            ServletContext context = this.getServletContext();
            String info = (String) context.getAttribute("info");
    
            //输出拿到的东西
            resp.setContentType("text/html");
            resp.setCharacterEncoding("utf-8");
            PrintWriter out = resp.getWriter();
            out.write("喵喵喵:"+info);
        }
    }
    
  6. 两个servlet写完, 要去web.xml注册和添加映射

  7.  <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/h</url-pattern>
      </servlet-mapping>
       
      <servlet>
        <servlet-name>getInfo</servlet-name>
        <servlet-class>com.sama.servlet.GetServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>getInfo</servlet-name>
        <url-pattern>/getInfo</url-pattern>
      </servlet-mapping>
    
  8. getFromServletContextD520.png

2 获取初始化参数

在ServletContext有一个 getInitParameter() 方法, 它可以获取到web.xml的初始化值

  1. 首先新建一个servlet用来获取初始化参数: getInitParamServlet

  2. public class getInitParamServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //获取ServletContext对象
            ServletContext context = this.getServletContext();
            String param = context.getInitParameter("mysql");
    
            //输出
            resp.getWriter().write("初始化参数: "+param);
        }
    }
    
  3. 在web.xml随便写个context参数, 键值对的方式读取

  4.   <context-param>
        <param-name>mysql</param-name>
        <param-value>jdbc:mysql://localhost:sama</param-value>
      </context-param>
    
  5. 在web.xml把servlet的注册和映射写好

  6.   <servlet>
        <servlet-name>getParam</servlet-name>
        <servlet-class>com.sama.servlet.GetInitParamServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>getParam</servlet-name>
        <url-pattern>/getParam</url-pattern>
      </servlet-mapping>
    
  7. 测试一下即可

3 请求转发

在ServletContext有一个 getRequestDispatcher("url") 方法, 它可以转发到指定路径的页面

  1. 首先新建一个servlet用来转发到指定路径的页面: DispatcherToInitServlet

  2. public class DispatcherToInitServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //ServletContext对象 (上下文对象)
            ServletContext context = this.getServletContext();
            //请求转发对象
            RequestDispatcher requestDispatcher = context.getRequestDispatcher("/getParam");//调度的路径, 去到这个页面
            requestDispatcher.forward(req, resp);//进行转发, 把请求和响应放入
        }
    }
    
  3. 在web.xml把servlet的注册和映射写好

  4.  <servlet>
        <servlet-name>goParam</servlet-name>
        <servlet-class>com.sama.servlet.DispatcherToInitServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>goParam</servlet-name>
        <url-pattern>/goParam</url-pattern>
      </servlet-mapping>
    
  5. 启动测试, 成功分析一下这个流程

dispatcherD520.png

4 读取资源文件

在ServletContext有一个**getResourceAsStream("资源的相对路径")**方法, 它可以把资源文件转为我们需要的流

  1. 新建properties

    1. 在Java目录下新建properties

    2. fileName=javaProp
      author=susama
      
    3. 在resources目录下新建properties

    4. fileName=resProp
      author=susama
      
  2. 可是我们怎么找到这两个文件发布后的路径呢?

    1. target是我们maven在发布后产生的war包, 可以在这里找到我们想要的路径

    2. 先使用maven的命令行清空一下

    3. mavenClean.png

    4. 清空之后, 我们发现target包消失了, 这时我们重新启动项目, 看看新的target里有没有我们写的properties

    5. targetProp01.png

    6. 发现只找到了一个, 说明有一个加载失败, 表示我们的pom.xml文件中build里没有添加相关的读取配置

    7. 我们加如相关配置

    8. <resources>
          <resource>
              <directory>src/main/resources</directory>
              <includes>
                  <include>**/*.properties</include>
                  <include>**/*.xml</include>
              </includes>
              <filtering>false</filtering>
          </resource>
          <resource>
              <directory>src/main/java</directory>
              <includes>
                  <include>**/*.properties</include>
                  <include>**/*.xml</include>
              </includes>
              <filtering>false</filtering>
          </resource>
      </resources>
      
      
    9. 再重新clean和启动, 然后看properties文件的路径

    10. targetProp02.png

    11. 在写相对应的读取这些文件的servlet: getPropServlet

    12. public class getPropServlet extends HttpServlet {
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              ServletContext context = this.getServletContext();
              //Java目录下的properties文件
              InputStream javaStream = context.getResourceAsStream("/WEB-INF/classes/com/sam/servlet/javaProp.properties");
              //resources目录下的properties文件
              InputStream resStream = context.getResourceAsStream("/WEB-INF/classes/resProp.properties");
      
              //用Properties类来接收
              Properties javaProp = new Properties();
              javaProp.load(javaStream);
              String fileName1 = javaProp.getProperty("fileName");
              String author1 = javaProp.getProperty("author");
      
              Properties resProp = new Properties();
              javaProp.load(resStream);
              resProp.getProperty("");
              String fileName2 = javaProp.getProperty("fileName");
              String author2 = javaProp.getProperty("author");
      
              //输出
              PrintWriter out = resp.getWriter();
              out.write(fileName1+" : "+author1+", "+fileName2+" : "+author2+"res#");
          }
      }
      
    13. 这里出现了个问题, 就是路径一定是从项目下开始的, 即/WEB-INF开始的, 还有路径请核对别打错啦

    14. 在web.xml把servlet的注册和映射写好

    15.   <servlet>
          <servlet-name>goProp</servlet-name>
          <servlet-class>com.sama.servlet.GetPropServlet</servlet-class>
        </servlet>
        <servlet-mapping>
          <servlet-name>goProp</servlet-name>
          <url-pattern>/goProp</url-pattern>
        </servlet-mapping>
      
    16. 发现: 在项目发布都被打包到了target里面的同一路径下: classes, 我们俗称这个路径为classpath

    17. 测试完成即可❀

5 HttpServletResponse

web服务器接收到客户端的http请求, 针对这个请求, 分别创建一个代表请求的HttpServletRequest对象

一个代表响应的HttpServletResponse对象

  • 如果要获取客户端请求过来的参数: 找HttpServletRequest, 它实现了ServletRequest接口
  • 如果要给客户端响应一些信息: 找HttpServletResponse, 它实现了ServletResponse接口
1 简单分类

负责向浏览器发送数据的方法

ServletOutputStream getOutputStream() throws IOException;
PrintWriter getWriter() throws IOException;

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

void setHeader(String var1, String var2);
void addHeader(String var1, String var2);
void setIntHeader(String var1, int var2);
void addIntHeader(String var1, int var2);
2 下载文件
  1. 向浏览器输出消息

  2. 下载文件

    1. 获取到文件的路径

    2. 下载的文件名

    3. 设置浏览器能够支持下载

    4. 获取下载文件的输入流

    5. 创建缓冲区(buffer)

    6. 获取OutputStream对象

    7. 将FileOutputStream流写入到buffer缓冲区, 使用OutputStream将缓冲区中的数据输出到客户端

    8. public class FileServlet extends HttpServlet {
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              //1. 获取到文件的路径
              String realPath = this.getServletContext().getRealPath("/WEB-INF/classes/喵.png");
              System.out.println("文件路径: "+realPath);
              //2. 获取下载的文件名
              String fileName = realPath.substring(realPath.lastIndexOf("\\")+1);
              //3. 设置浏览器响应头("Content-Disposition","attachment;filename")能够支持下载
              resp.setHeader("Content-Disposition", "attachment;filename="+ 
                      //这个的作用中文名文件也能正常显示
                      URLEncoder.encode(fileName,"UTF-8"));
              //4. 获取下载文件的输入流
              FileInputStream inputStream = new FileInputStream(realPath);
              //5. 创建缓冲区(buffer)
              int len = 0;
              byte[] buffer = new byte[1024*8];
              //6. 获取OutputStream对象
              ServletOutputStream outputStream = resp.getOutputStream();
              //7. 将FileInputStream流读入到buffer缓冲区, 使用OutputStream将缓冲区中的数据输出到客户端
              while ((len=inputStream.read(buffer))!=-1){
                  outputStream.write(buffer,0,len);
              }
              
              //关闭流
              inputStream.close();
              outputStream.close();
          }
      }
      
    9. 注册servlet, 启动测试

    10. 出现了个问题, 在写路径时, 文件名写错了, 找了很久, maio ==> miao

    11. 输入流读要放到缓冲区去

6 HttpServletRequest

1 获取前端传递的参数
public class LoginServlet extends HttpServlet {

    @Override
    protected void doPost(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("hobbies");

        HttpSession session = req.getSession();
        session.setAttribute("username", username);

        //跳转
        req.getRequestDispatcher("/success.jsp").forward(req,resp);
    }
}
  • 这里要注意有两个获取参数的方法
2 请求转发
request.getRequestDispatcher("/success.jsp").forward(req,resp);
  • **"/"**这个符号在转发中代表项目根路径, 不用再加其他
3 面试题: 转发和重定向的区别

转发D521.png

重定向D521.png

7 Session, Cookie,

7.1 Session(会话)

会话

  • Session:称为“会话控制”。Session对象存储特定用户会话所需的属性及配置信息

  • 当用户在应用程序的Web页之间跳转时,存储在Session对象中的变量将不会丢失。当用户请求来自应用程序的 Web页时,如果该用户还没有会话,则Web服务器将自动创建一个 Session对象。当会话过期或被放弃后,服务器将终止该会话。

  • 注意会话状态仅在支持cookie的浏览器中保留。

有状态会话

​ 客户端 服务端

  1. 服务端给客户端一个信件, 客户端下次访问服务端带上信件就可以了; cookie
  2. 服务器登记你来过了, 下次来的时候匹配你; session

7.2 保存会话的两种技术

cookie

  • 客户端技术 (响应, 请求)

session

  • 服务器技术, 利用这个技术, 可以保存用户的会话信息? 可以把信息或者数据放在session中

常见场景: 登录网站之后, 你下次在短期内不用重新登录

7.3 Cookie

public class CookieDemoServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		//第一次访问标记符
        boolean flag = false;
        //编码格式化
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");
        //日期格式化工具对象
        DateFormat dateFormat = new SimpleDateFormat();

        //输出流
        PrintWriter out = resp.getWriter();
        //从请求得到cookies
        Cookie[] cookies = req.getCookies();
        //遍历获得到我们存的登录时间
        for (Cookie cookie : cookies) {
            if("lastLoginTime".equals(cookie.getName())){
                //改变第一次访问标记, 并优化
                if(!flag){flag = true;}
                long time = Long.parseLong(cookie.getValue());
                Date date = new Date(time);
                out.write("你上次访问时间: "+ dateFormat.format(date));
            }
        }

        //遍历完后, 如果我们的标记flag没有改变, 那么就是第一次访问, 欢迎一下
        if(!flag){
            out.write("这是你第一次访问, 欢迎加入我们暗夜组织~");
        }

        //创建个cookie中存入当前时间
        Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis()+"");
        //设置cookie有效期7天
        cookie.setMaxAge(7*24*60*60);
        //把cookie放入响应response
        resp.addCookie(cookie);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
  • 在传输中文的时候可以用

    • URLEncoder.encode("info","UTF-8");传输加密

    • URLDecoder.decode("info","UTF-8");获取解密

7.4 Session(重点)

  • Session:称为“会话控制”。Session对象存储特定用户会话所需的属性及配置信息

  • 当用户在应用程序的Web页之间跳转时,存储在Session对象中的变量将不会丢失。当用户请求来自应用程序的 Web页时,如果该用户还没有会话,则Web服务器将自动创建一个 Session对象。当会话过期或被放弃后,服务器将终止该会话。

  • 注意会话状态仅在支持cookie的浏览器中保留。

  • session方法D521.png

Session和Cookie的区别:

  • Cookie是把用户的数据写给用户的浏览器, 浏览器保存(可以保存多个)
  • Session把用户的数据写到用户Session中, 服务器端保存 (保存重要信息, 减少服务器资源的浪费)
  • Session对象由服务器创建

使用场景:

  • 保存一个登录用户的信息
  • 购物车信息
  • 在整个网站中经常会使用的数据, 我们将它保存在Session中

会话自动过期: web.xml配置

<!--设置Session默认的失效时间-->
<session-config>
    <!--15分钟后Session自动失效, 以分钟为单位-->
    <session-timeout>15</session-timeout>
</session-config>

session原理D521.png

8 JSP

8.1 简介

Java Server Pages: Java服务器端页面, 和Servlet一样, 用于开发动态web

  • //原始写页面
    public class HelloServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //定义内容格式
            resp.setContentType("text/html");
            //定义一下编码格式
            resp.setCharacterEncoding("utf-8");
            //获取输出流, 两种实现方式
            //ServletOutputStream outputStream = resp.getOutputStream();
            PrintWriter out = resp.getWriter();
            out.write("<html>");
            out.write("<head>");
            out.write("<title>");
            out.write("zisusama");
            out.write("</title>");
            out.write("</head>");
            out.write("<body>");
            out.write("<h1>");
            out.write("子苏大人驾到!");
            out.write("</h1>");
            out.write("</body>");
            out.write("</html>");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
  • 而写JSP就像在写HTML, 方便简单

  • JSP和HTML的区别

    • HTML只提供静态数据
    • JSP页面中可以嵌入Java代码,可以实现提供动态数据

8.2 JSP原理