【笔记】javaweb万字学习笔记

JavaWeb

Java Web学习相关笔记。
在博客查看本文

1、基本概念

1.1 前言

web开发:

  • web,网页的意思 , www.baidu.com

  • 静态web:

    • html,css 构成
    • 提供给所有人看的数据始终不会发生变化!
  • 动态web:

  • 淘宝,几乎是所有的网站;

  • 提供给所有人看的数据始终会发生变化,每个人在不同的时间,不同的地点看到的信息各不相 同!

  • 技术栈:Servlet/JSP,ASP,PHP

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

1.2 web应用程序

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

  • a.html、b.html…多个web资源,这些web资源可以被外界访问,对外界提供服务;

  • 你们能访问到的任何一个页面或者资源,都存在于这个世界的某一个角落的计算机上。

  • URL

  • 这个统一的 web 资源会被放在同一个文件夹下,web 应用程序–>Tomcat:服务器

  • 一个 web 应用由多部分组成 (静态web,动态web)

    • html,css,js

    • jsp,servlet

    • Java 程序

    • jar 包 配置文件 (Properties)

web应用程序编写完毕后,若想提供给外界访问:需要一个服务器来统一管理;

1.3 静态web

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

    image-20220612201200600

  • 静态 web 存在的缺点

  • Web页面无法动态更新,所有用户看到都是同一个页面

    • 轮播图,点击特效:伪动态
    • JavaScript [实际开发中,它用的最多]
    • VBScript (微软家)
  • 它无法和数据库交互(数据无法持久化,用户无法交互)

1.4 动态web

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

image-20220612201345922

缺点:

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

优点:

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

image-20220612201540300

2、web服务器

2.1 技术讲解

ASP
  • 微软,国内最早流行的就是ASP;
  • 在 HTML 中嵌入了 VB 的脚本, ASP + COM;
  • 在 ASP 开发中,基本一个页面都有几千行的业务代码,页面极其混乱
  • 维护成本高
  • C#
  • IIS
PHP
  • PHP 开发速度很快,功能很强大,跨平台,代码很简单 (70% , WP)
  • 无法承载大访问量的情况(局限性)
JSP/Servlet

B/S:浏览和服务器

C/S: 客户端和服务器

  • sun公司主推的B/S架构
  • 基于Java语言的 (所有的大公司,或者一些开源的组件,都是用Java写的)
  • 可以承载三高问题带来的影响;
  • 语法像 ASP , ASP–>JSP , 加强市场强度;

2.2 web服务器

服务器是一种被动的操作,用来处理用户的一些请求和给用户一些响应信息;

IIS

微软的; ASP…,Windows中自带的

Tomcat

Apache Tomcat Logo

Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现,因为 Tomcat 技术先进、性能稳定,而且免费,因 而深受 Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的 Web 应用服务器。 Tomcat 服务器是一个免费的开放源代码的 Web 应用服务器,属于轻量级应用服务器,在中小型系统和 并发访问用户不是很多的场合下被普遍使用,是开发和调试 JSP 程序的首选。对于一个 Java 初学 web 的人来说,它是最佳的选择 Tomcat 实际上运行 JSP 页面和 Servlet 。Tomcat最新版本为10.0。

下载tomcat:

  1. 安装 or 解压
  2. 了解配置文件及目录结构
  3. 了解作用

3、Tomcat

3.1 安装 tomcat

官网:http://tomcat.apache.org/

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qJlCbwWF-1656075055794)(https://s2.loli.net/2022/06/24/Sx3YzqyGREWaTph.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sxqoj1Rz-1656075055794)(%E7%8B%82%E7%A5%9E%E8%AF%B4javaweb.assets/image-20220612202858854.png)]

3.2 Tomcat启动和配置

文件夹作用:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yjOPqowY-1656075055795)(%E7%8B%82%E7%A5%9E%E8%AF%B4javaweb.assets/image-20220612202942508.png)]

启动/关闭Tomcat

image-20220612203032082

访问测试:http://localhost:8080/

可能遇到的问题:

  1. Java环境变量没有配置
  2. 闪退问题:需要配置兼容性
  3. 乱码问题:配置文件中设置

3.3 配置

image-20220612203639374

可以配置启动的端口号

<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />
  • tomcat的默认端口号为:8080

  • mysql:3306

  • http:80

  • https:443

可以配置主机的名称

默认的主机名为:localhost->127.0.0.1

默认网站应用存放的位置为:webapps

<Host name="www.qinjiang.com" appBase="webapps"
      unpackWARs="true" autoDeploy="true">

高难度面试题

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

  1. 输入一个域名;回车

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

    • 有:直接返回对应的ip地址,这个地址中,有我们需要访问的web程序,可以直接访问。
    • 没有:去 DNS 服务器找,找到的话就返回,找不到就返回找不到

    image-20220612204722223

  3. 可以配置一下环境变量(可选性)

    尽量不要动系统配置文件

3.4 发布一个 web 网站

不会就先模仿

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

网站应该有的结构:

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

4、Http

4.1 什么是HTTP

HTTP(超文本传输协议)是一个简单的请求-响应协议,它通常运行在 TCP 之上。

文本:html,字符串,~ ….

超文本:图片,音乐,视频,定位,地图…….

http 端口号: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: 127.0.0.1:7890 
    

Accept: text/html
Accept-Encoding: gzip, deflate, br
Accept-Language: en,zh-CN;q=0.9,zh-TW;q=0.8,zh;q=0.7 语言
Cache-Control: max-age=0
Connection: keep-alive


#### 1、请求行 

- 请求行中的请求方式:GET 

- 请求方式:Get,Post,HEAD,DELETE,PUT,TRACT… 

  - get:请求能够携带的参数比较少,大小有限制,会在浏览器的URL地址栏显示数据内容,不安全,但高效

  - post:请求能够携带的参数没有限制,大小没有限制,不会在浏览器的URL地址栏显示数据内容,安全,但不高效。

    > 是否高效 都是相对而言 现在网速很快 其实不太能感受的到 post 和 get 的明显差别。

#### 2、请求头

```java
Accept:告诉浏览器,它所支持的数据类型
Accept-Encoding:支持哪种编码格式 GBK UTF-8 GB2312 ISO8859-1
Accept-Language:告诉浏览器,它的语言环境
Cache-Control:缓存控制
Connection:告诉浏览器,请求完成是断开还是保持连接
HOST:主机..../.

4.4 Http响应

  • 服务器—响应-----客户端

    以百度为例:

    Cache-Control:private 缓存控制
    Connection:Keep-Alive 连接
    Content-Encoding:gzip 编码
    Content-Type:text/html 类型
    
    1、响应体
    Accept:告诉浏览器,它所支持的数据类型
    Accept-Encoding:支持哪种编码格式 GBK UTF-8 GB2312 ISO8859-1
    Accept-Language:告诉浏览器,它的语言环境
    Cache-Control:缓存控制
    Connection:告诉浏览器,请求完成是断开还是保持连接
    HOST:主机..../.
    Refresh:告诉客户端,多久刷新一次;
    Location:让网页重新定位;
    
    2、 响应状态码

200:请求响应成功 200

3xx:请求重定向

  • 重定向:你重新到我给你新位置去;

4xx:找不到资源 404

  • 资源不存在;

5xx:服务器代码错误 500 502:网关错误

常见面试题

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

5、Maven

我为什么要学习这个技术?

  1. 在Javaweb开发中,需要使用大量的jar包,我们手动去导入;
  2. 如何能够让一个东西自动帮我导入和配置这个jar包。
    由此,Maven诞生了。

5.1 Maven项目架构管理工具

我们目前用来就是方便导入jar包的!

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

  • 有约束,不要去违反。

Maven 会规定好你该如何去编写我们的 Java 代码,必须要按照这个规范来;

5.2 下载安装Maven

官网; https://maven.apache.org/

image-20220613110221933

下载完成后,解压即可;

电脑上的所有环境都放在一个文件夹下,方便管理;

5.3 配置环境变量

在我们的系统环境变量中

配置如下配置:

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

image-20220613110451510

测试 Maven 是否安装成功,保证必须配置完毕!

5.4 阿里云镜像

image-20220613110853794

  • 镜像:mirrors
    • 作用:加速我们的下载
  • 国内建议使用阿里云的镜像
    <mirror>
      <id>aliyunmaven</id>
      <mirrorOf>*</mirrorOf>
      <name>阿里云公共仓库</name>
      <url>https://maven.aliyun.com/repository/public</url>
   </mirror>

5.5 本地仓库

在本地的仓库,远程仓库;

建立一个新的本地仓库:localRepository

<Repository>D:\Environment\apache-maven-3.6.2\maven-repo</localRepository>

5.6 在IDEA中使用Maven

  1. 启动IDEA

  2. 创建一个 MavenWeb 项目

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vQ9uqibN-1656075055802)(https://s2.loli.net/2022/06/24/lDoRLnNwchU9OPE.png)]

image-20220613121752882

image-20220613121814858

image-20220613121828783

  1. 等待项目初始化完毕

    image-20220613121949915

  2. 观察 maven 仓库中多了什么东西?

  3. IDEA中的Maven设置

    IDEA项目创建成功后,看一眼 Maven 的配置

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mMtDkjCf-1656075055805)(https://s2.loli.net/2022/06/24/46fwUPaqQhCpmxV.png)]

image-20220613122727953

  1. 到这里,Maven在IDEA中的配置和使用就完成了。

5.7 创建一个普通的 Maven 项目

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ojXXFMGL-1656075055807)(%E7%8B%82%E7%A5%9E%E8%AF%B4javaweb.assets/image-20220613123035628.png)]

image-20220613123807749

这个只有在Web应用下才会有!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-piTuADCG-1656075055809)(%E7%8B%82%E7%A5%9E%E8%AF%B4javaweb.assets/image-20220613124255604.png)]

5.8 标记文件夹功能

image-20220613124508265

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R2Xn5Yub-1656075055824)(https://s2.loli.net/2022/06/24/FvfzWb96jGJ1Bpy.png)]

image-20220613124615209

image-20220613124629885

5.9 在IDEA中配置Tomcat

image-20220613163031396

image-20220613163125215

image-20220613163321964

解决警告问题

必须要的配置:为什么会有这个问题:我们访问一个网站,需要指定一个文件夹名字;

image-20220613163416112

image-20220613163438176

image-20220613163514988

5.10 pom文件

pom.xml 是 Maven 的核心配置文件。

image-20220613164423539

<?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.naru</groupId>
  <artifactId>maven01</artifactId>
  <version>1.0-SNAPSHOT</version>
  <!--打包方式
  jar: java应用
  war: javaweb应用
  -->
  <packaging>war</packaging>

  <name>maven01 Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <!--配置-->
  <properties>
    <!--项目的默认构建编码-->
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <!--编码版本-->
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <!--项目依赖-->
  <dependencies>
    <!--具体依赖的jar包配置文件-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <!--项目构建所需的东西-->
  <build>
    <finalName>maven01</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

image-20220613165851322

maven 由于他的约定大于配置,我们之后可以能遇到我们写的配置文件,无法被导出或者生效的问题, 解决方案:

<!--在build中配置resources,来防止我们资源导出失败的问题-->
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

5.12 IDEA 操作

image-20220613170215647

image-20220613170232740

5.13 解决遇到的问题

  1. Maven 3.6.2

    解决方法:降级为3.6.1

  2. Tomcat闪退

  3. IDEA中每次都要重复配置Maven 在IDEA中的全局默认配置中去配置。

6、Servlet

6.1 Servlet 简介
  • Servlet 就是 sun 公司开发动态 web 的一门技术

  • Sun 在这些API中提供一个接口叫做:Servlet,如果你想开发一个Servlet程序,只需要完成两个小 步骤:

    • 编写一个类,实现Servlet接口

    • 把开发好的 Java 类部署到 web 服务器中。

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

6.2 HelloServlet

Serlvet 接口 Sun 公司有两个默认的实现类:HttpServlet,GenericServlet

  1. 构建一个普通的 Maven 项目,删掉里面的 src 目录,以后我们的学习就在这个项目里面建立 Moudel ;这个空的工程就是 Maven 主工程;
  2. 关于Maven父子工程的理解:

父项目中会有:

<modules>
    <module>servlet-01</module>
</modules>

子项目会有:

<parent>
    <artifactId>javaweb-02-servlet</artifactId>
    <groupId>com.kuang</groupId>
    <version>1.0-SNAPSHOT</version>
</parent>

父项目中的 java 子项目可以直接使用

  1. Maven环境优化

    1. 修改web.xml为最新的
    2. 将maven的结构搭建完整
  2. 编写一个Servlet程序

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cl1fKnl5-1656075055833)(https://s2.loli.net/2022/06/24/R6vi9MygIquF1Tr.png)]

     1. 编写一个普通类
     2. 实现 Servlet 接口,这里我们直接继承 HttpServlet 
    
  3. 编写 Servlet 的映射

为什么需要映射:我们写的是JAVA程序,但是要通过浏览器访问,而浏览器需要连接web服务器, 所以我们需要再web服务中注册我们写的Servlet,还需给他一个浏览器能够访问的路径;

<!--注册Servlet-->
<servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>com.naru.servlet.HelloServlet</servlet-class>
</servlet>
<!--Servlet的请求路径-->
<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello</url-pattern>
</servlet-mapping>

  1. 配置 Tomcat 注意:

    配置项目发布的路径就可以了(这里注意 如果之前 maven 中导入的 jsp 以及 servlet jar 包 为 javax前缀,

    则需要9.0版本以下的tomcat服务器)

  2. 启动测试,OK!

image-20220613200826967

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iIjUKtQ4-1656075055834)(%E7%8B%82%E7%A5%9E%E8%AF%B4javaweb.assets/image-20220613200840455.png)]

6.3 Servlet 原理

Servlet 是由 Web 服务器调用, web 服务器在收到浏览器请求之后,会:

image-20220614162307468

6.4 Mapping问题
  1. 一个 Servlet 可以指定一个映射路径

    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    
  2. 一个 Servlet 可以指定多个映射路径

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

<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello1</url-pattern>
</servlet-mapping>

<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello2</url-pattern>
</servlet-mapping>

<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello3</url-pattern>
</servlet-mapping>

image-20220614163227295

  1. 一个 Servlet 可以指定通用映射路径

    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello/*</url-pattern>
    </servlet-mapping>
    

image-20220614163512027

  1. 默认请求路径
<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

这样重启服务器后会直接跳转至hello 而覆盖掉原有的 index ,因此不建议使用.

  1. 指定一些后缀或者前缀等等…
<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>*.naru</url-pattern>
</servlet-mapping>

image-20220614164311275

  1. 优先级问题

    指定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求;

        <servlet>
            <servlet-name>error</servlet-name>
            <servlet-class>com.naru.servlet.ErrorServlet</servlet-class>
        </servlet>    
        
        <servlet-mapping>
            <servlet-name>error</servlet-name>
            <url-pattern>/*</url-pattern>
        </servlet-mapping>
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7wFWheSY-1656075055837)(%E7%8B%82%E7%A5%9E%E8%AF%B4javaweb.assets/image-20220614165218236.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-30s4HRlN-1656075055838)(%E7%8B%82%E7%A5%9E%E8%AF%B4javaweb.assets/image-20220614165151441.png)]

6.5 ServletContext

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

共享数据

我在这个 Servlet 中保存的数据,可以在另外一个 servlet 中拿到;

这里 HelloServlet 做了一个数据存储的功能,而没有显示任何东西, 因此浏览器访问 /hello 时是空白页面.

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        System.out.println("Do get方法执行");
//        PrintWriter writer = resp.getWriter();
//        writer.print("Hello,Servlet");
        ServletContext context = this.getServletContext();
        String username = "naru";
        context.setAttribute("username:",username);
        //将一个数据保存在ServletContext中
    }

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

GetServlet 做了一个读取数据并显示出来的流程.

public class GetServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        String username = (String) context.getAttribute("username:");

        resp.setContentType("text/html");
        resp.setCharacterEncoding("utf-8");
        resp.getWriter().print("名字:"+username);

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
<servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>com.naru.servlet.HelloServlet</servlet-class>
</servlet>
<!--Servlet的请求路径-->
<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello</url-pattern>
</servlet-mapping>

<servlet>
    <servlet-name>getc</servlet-name>
    <servlet-class>com.naru.servlet.GetServlet</servlet-class>
</servlet>

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

直接访问 getc 可发现 名字对应的数据值为null,因为此时我们没有访问 /hello, 进行数据的存储,直接访问 /getc 数据为空.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3K2ETA01-1656075055838)(https://s2.loli.net/2022/06/24/HDiVvfp5khgN7Eq.png)]

因此我们需要先进行 /hello 的访问.

白色是正常的 因为我们后台并没有做打印数据的相关操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SoYPz5vj-1656075055853)(%E7%8B%82%E7%A5%9E%E8%AF%B4javaweb.assets/image-20220614183208794.png)]

再次访问 /getc 可以看到 名字不再为null 而是变成了我们先前在 HelloServlet 代码中存储的username

image-20220614183450749

要注意 setAttribute 方法中的参数一定要和 getAttribute 中的对应起来,否则将获取不到数据,一直呈现 名字:null 的显示.

获取初始化参数
<context-param>
    <param-name>url</param-name>
    <param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        String url = context.getInitParameter("url");
        resp.getWriter().print(url);
    }
请求转发

新建一个新的 Serlvet

image-20220614191230465

读取资源文件

Properties

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

发现: 都被打包到了同一个路径下: classes, 我们成这个路径为 classespath;

思路: 需要一个文件流 然后对文件流进行读取即可.

username=root
password=123456
public class ServletDemo5 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/aa.properties");
        Properties prop = new Properties();
        prop.load(is);
        String user = prop.getProperty("username");
        String pwd = prop.getProperty("password");

        resp.getWriter().print(user+":"+pwd);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
<servlet>
    <servlet-name>demo5</servlet-name>
    <servlet-class>com.naru.servlet.ServletDemo5</servlet-class>
</servlet>

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4LQQZGWX-1656075055855)(%E7%8B%82%E7%A5%9E%E8%AF%B4javaweb.assets/image-20220614205452173.png)]

6.6 HttpServletResponse

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

  • 如果要获取客户端请求过来的参数:找HttpServletRequest
  • 如果要给客户端响应一些信息:找HttpServletResponse
简单分类

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

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);

响应的状态码

int SC_CONTINUE = 100;
int SC_SWITCHING_PROTOCOLS = 101;
int SC_OK = 200;
int SC_CREATED = 201;
int SC_ACCEPTED = 202;
int SC_NON_AUTHORITATIVE_INFORMATION = 203;
int SC_NO_CONTENT = 204;
int SC_RESET_CONTENT = 205;
int SC_PARTIAL_CONTENT = 206;
int SC_MULTIPLE_CHOICES = 300;
int SC_MOVED_PERMANENTLY = 301;
int SC_MOVED_TEMPORARILY = 302;
int SC_FOUND = 302;
int SC_SEE_OTHER = 303;
int SC_NOT_MODIFIED = 304;
int SC_USE_PROXY = 305;
int SC_TEMPORARY_REDIRECT = 307;
int SC_BAD_REQUEST = 400;
int SC_UNAUTHORIZED = 401;
int SC_PAYMENT_REQUIRED = 402;
int SC_FORBIDDEN = 403;
int SC_NOT_FOUND = 404;
int SC_METHOD_NOT_ALLOWED = 405;
int SC_NOT_ACCEPTABLE = 406;
int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
int SC_REQUEST_TIMEOUT = 408;
int SC_CONFLICT = 409;
int SC_GONE = 410;
int SC_LENGTH_REQUIRED = 411;
int SC_PRECONDITION_FAILED = 412;
int SC_REQUEST_ENTITY_TOO_LARGE = 413;
int SC_REQUEST_URI_TOO_LONG = 414;
int SC_UNSUPPORTED_MEDIA_TYPE = 415;
int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
int SC_EXPECTATION_FAILED = 417;
int SC_INTERNAL_SERVER_ERROR = 500;
int SC_NOT_IMPLEMENTED = 501;
int SC_BAD_GATEWAY = 502;
int SC_SERVICE_UNAVAILABLE = 503;
int SC_GATEWAY_TIMEOUT = 504;
int SC_HTTP_VERSION_NOT_SUPPORTED = 505;

下载文件

新建 servlet 子模块.

然后新建downServlet

  1. 向浏览器输出消息
  2. 下载文件
    1. 要获取下载文件的路径
    2. 下载的文件名是什么
    3. 设置想办法让浏览器能够支持下载我们需要的东西
    4. 获取下载文件的输入流
    5. 创建缓冲区
    6. 获取OutputStream对象
    7. 将FileOutputStream流写入到buffer缓冲区
    8. 使用OutputStream将缓冲区中的数据输出到客户端!
public class downServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1. 获取下载文件的路径
        String realPath = "D:\\javalearn\\kuangjava\\javaweb\\Servlet01\\response\\target\\classes\\1.jpg";
        System.out.println("下载文件的路径:"+realPath);
        //2. 获取下载的文件名
        String fileName = realPath.substring(realPath.lastIndexOf("\\")+1);
       //3.这里做了一个下载头,文件名也做了编码处理,防止中文乱码
        resp.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName,"UTF-8"));
        //4.获取下载文件的输入流
        FileInputStream in = new FileInputStream(realPath);
        
        //5.创建缓冲区
        int len = 0;
        byte[] buffer = new byte[1024];
        //6.获取outputstream对象
        ServletOutputStream out = resp.getOutputStream();
        //7.将fileoutputstream流写入到buffer缓冲区,使用outputstream将缓冲区中的数据输出到客户端
        while ((len = in.read(buffer))>0){
            out.write(buffer, 0, len);
        }
        in.close();
        out.close();
    }

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

image-20220615095055161

验证码功能

验证怎么来的?

  • 前端实现
  • 后端实现,需要用到 Java 的图片类,生产一个图片
package com.naru.servlet;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
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;

public class imageServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       //让浏览器3秒自动刷新一次
        resp.setHeader("refresh","3");
        //在内存中创建一个图片
        BufferedImage image = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);

        //得到图片
        Graphics2D g = (Graphics2D) image.getGraphics();

        //设置图片的背景颜色
        g.setColor(Color.white);
        g.fillRect(0,0,80,20);

        //给图片写数据
        g.setColor(Color.BLUE);
        g.setFont(new Font(null, Font.BOLD, 20));
        g.drawString(makeNum(),0, 20);

        //告诉浏览器,这个请求用图片的方式打开
        resp.setContentType("image/jpg");

        //禁止浏览器缓存
        resp.setDateHeader("expires",-1);
        resp.setHeader("cache-Control","no-cache");
        resp.setHeader("Pragma","no-cache");

        //把图片写给浏览器
        ImageIO.write(image, "jpg", resp.getOutputStream());

    }

    //生成随机数
    private String makeNum(){
        Random random = new Random();
        String num = random.nextInt(9999999)+"";
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 7 - num.length(); i++){
            sb.append("0");
        }
        num = sb.toString()+num;
        return num;
    }

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

实现重定向

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SqLx1aXM-1656075055856)(https://s2.loli.net/2022/06/24/zWLXxsHjvDJ9YtQ.png)]

B 一个 web 资源收到客户端 A 请求后,B 他会通知 A 客户端去访问另外一个 web 资源 C ,这个过程叫重定向

常见应用场景:

用户登录

测试:

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.sendRedirect("/image");
    }
请你聊聊重定向和转发的区别?

相同点:

页面都会实现跳转

不同点:

请求转发的时候,url 不会产生变化,重定向时候,url 地址栏会发生变化。

简单实现登陆重定向
<html>
<body>
<h2>Hello World!</h2>
<%--这里提交的路径,需要寻找到项目的路径--%>
<%--${pageContext.request.contextPath}代表当前的项目--%>
<form action="${pageContext.request.contextPath}/login" method="get">
    用户名:<input type="text" name="username"> <br>
    密码:<input type="password" name="password"> <br>
    <input type="submit">
</form>
</body>
</html>
<servlet>
    <servlet-name>loginServlet</servlet-name>
    <servlet-class>com.naru.servlet.loginServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>loginServlet</servlet-name>
    <url-pattern>/login</url-pattern>
</servlet-mapping>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>success!</h1>
</body>
</html>
6.7 HttpServletRequest

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

image-20220615134404339

image-20220615134445025

获取参数,请求转发

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BxPkaCmt-1656075055858)(https://s2.loli.net/2022/06/24/7ObgneDvYV1GMTy.png)]

登录跳转的实现

package com.naru.servlet;

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

public class LoginServlet extends HttpServlet {
    @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("hobbies");
       System.out.println("============================");
       System.out.println(username);
       System.out.println(password);
       System.out.println(Arrays.toString(hobbies));
       System.out.println("============================");

       System.out.println(req.getContextPath());
       //通过请求转发
        // 这里的 / 代表当前的web应用
       req.getRequestDispatcher("/success.jsp").forward(req, resp);
    }

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

面试题:请你聊聊重定向和转发的区别?
  • 相同点

    页面都会实现跳转

  • 不同点

    请求转发的时候,url 不会产生变化 307

    重定向时候,url 地址栏会发生变化 302

7、Cookie 、Session

7.1 会话

会话

用户打开一个浏览器,点击了很多超链接,访问多个web资源,关闭浏览器,这个过程可以称之 为会话;

有状态会话

一个同学来过教室,下次再来教室,我们会知道这个同学,曾经来过,称之为有状态会 话;

你能怎么证明你是学校的学生?

  1. 学校给你发了学生证
  2. 学校登记 学校标记你来过了

一个网站,怎么证明你来过?

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

7.2 保存会话的两种技术

cookies
  • 客户端技术(响应,请求)
session
  • 服务器技术,利用这个技术可以保存用户的会话信息

    我们可以把信息或者数据放在 Session 中。

    常见场景

网站登录之后,你下次不用再登录了,第二次访问直接就上去了!

7.3 Cookie

image-20220615152639301

  1. 从请求中拿到 cookie 信息
  2. 服务器响应给客户端 cookie
Cookie[] cookies = req.getCookies(); //获得Cookie
cookie.getName(); //获得cookie中的key
cookie.getValue(); //获得cookie中的vlaue
new Cookie("lastLoginTime", System.currentTimeMillis()+""); //新建一个cookie
cookie.setMaxAge(24*60*60); //设置cookie的有效期
resp.addCookie(cookie); //响应给客户端一个cookie
package com.naru.servlet;

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

public class CookiesDemo1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");

        PrintWriter out = resp.getWriter();

        Cookie[] cookies = req.getCookies();

        if (cookies != null){
            out.write("你上一次访问的时间是:");
            for (int i = 0; i < cookies.length; i++) {
                Cookie cookie = cookies[i];
                if (cookie.getName().equals("lastLoginTime")){
                    long lastLoginTime = Long.parseLong(cookie.getValue());
                    Date date = new Date(lastLoginTime);
                    out.write(date.toLocaleString());
                }
            }
        }
        else {
            out.write("这是您第一次访问本站");
        };

        Cookie cookie = new Cookie("lastLoginTime",System.currentTimeMillis()+"");
        resp.addCookie(cookie);

    }

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

刷新即可实现。

image-20220615183138668

image-20220615183225559

cookie:一般会保存在本地的 用户目录下 appdata;

一个网站 cookie 是否存在上限!聊聊细节问题

  • 一个 Cookie 只能保存一个信息;
  • 一个 web 站点可以给浏览器发送多个 cookie ,最多存放20个cookie;
  • Cookie 大小有限制4kb;
  • 300个 cookie 浏览器上限

删除Cookie

  • 不设置有效期,关闭浏览器,自动失效;
  • 设置有效期时间为0;
package com.naru.servlet;

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

public class CookiesDemo2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Cookie cookie = new Cookie("lastLoginTime",System.currentTimeMillis()+"");
        cookie.setMaxAge(0);
        resp.addCookie(cookie);
    }

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

访问/ck2 进行cookies的删除

image-20220615183324030

再进入/ck1 发现 cookies 被清除。

image-20220615183411760

编码解码

URLEncoder.encode("测试","utf-8")
URLDecoder.decode(cookie.getValue(),"UTF-8")

7.4 Session

image-20220615183532207

什么是Session:

  • 服务器会给每一个用户(浏览器)创建一个Seesion对象;
  • 一个Seesion独占一个浏览器,只要浏览器没有关闭,这个Session就存在;
  • 用户登录之后,整个网站它都可以访问!–> 保存用户的信息;保存购物车的信息……

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n4WjZMMO-1656075055863)(https://s2.loli.net/2022/06/24/dNBT8wiD3OmzL6H.png)]

Session 和 cookie 的区别:

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

使用场景:

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

使用Session:

package com.naru.servlet;

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

public class SessionDemo1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=utf-8");

        //得到session
        HttpSession session = req.getSession();

        //给Session中存东西
        //可以存字符串
        session.setAttribute("name","naru");
        //也可以存对象
        //session.setAttribute("name",new Person("naru",1));
        
        
        //获取Session的ID
        String sessionId = session.getId();

        //判断Session是不是新创建的
        if(session.isNew()){
            resp.getWriter().write("session创建成功,ID:"+sessionId);
        }
        else{
            resp.getWriter().write("session以及在服务器中存在了,ID:"+sessionId);
        }
    }

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

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

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

image-20220615202533617

8、JSP

8.1 什么是 JSP

Java Server Pages :

Java服务器端页面,也和Servlet一样,用于动态Web技术!

最大的特点:

  • 写JSP就像在写HTML
  • 区别:
    • HTML只给用户提供静态的数据
    • JSP页面中可以嵌入JAVA代码,为用户提供动态数据;

8.2 JSP原理

JSP到底怎么执行的
  • 代码层面没有任何问题 非常简洁

  • 服务器内部工作

    tomcat 中有一个 work 目录;

    IDEA 中使用 Tomcat 的会在 IDEA 的 tomcat 中生产一个 work 目录

    关于该要怎么查找该目录:

    在idea中运行tomcat 然后复制日志开头的 CATALINA_BASE 即可。

    image-20220616130520446

进去 work 文件夹可以查看到 jsp 文件最终被转换成了 java 文件!

image-20220616130859992

浏览器向服务器发送请求,不管访问什么资源,其实都是在访问Servlet!

JSP最终也会被转换成为一个Java类!

JSP 本质上就是一个Servlet

原因:

继续查看刚才我们打开的源码,可以发现,它继承自 HttpJspBase

image-20220616131205717

继续查看 HttpJspBase

这里先提一下怎么在 idea 中引入 HttpJspBase

笔者使用的是 tomcat8.5 在 maven 中引入 jsp.api 后依旧无法找到 HttpJspBase,是因为它属于 jasper-runtime 包,我们需要导入 jasper-runtime 才可以查看到 HttpJspBase的源码。

导入 jasper-runtime :

    <!-- https://mvnrepository.com/artifact/tomcat/jasper-runtime -->
    <dependency>
      <groupId>tomcat</groupId>
      <artifactId>jasper-runtime</artifactId>
      <version>5.5.23</version>
    </dependency>

导入后可成功查看HttpJspBase类:

image-20220616133840503

包含的一些方法:

//初始化
public void _jspInit() {
}
//销毁
public void _jspDestroy() {
}
//JSPService
public void _jspService(.HttpServletRequest request,HttpServletResponse
response)

回到我们刚刚查看的 jsp 文件的 java 源码,其中包含有:

  1. 判断请求
  2. 内置一些对象
final javax.servlet.jsp.PageContext pageContext; //页面上下文
javax.servlet.http.HttpSession session = null; //session
final javax.servlet.ServletContext application; //applicationContext
final javax.servlet.ServletConfig config; //config
javax.servlet.jsp.JspWriter out = null;//out
final java.lang.Object page = this;//page 当前
HttpServletRequset request; //请求
HttpServletResponse response;  //响应
  1. 输出页面前增加的代码

    response.setContentType("text/html;charset=UTF-8"); //设置响应页面类型
    pageContext = _jspxFactory.getPageContext(this, request, response,
                                              null, true, 8192, true);
    _jspx_page_context = pageContext;
    application = pageContext.getServletContext();
    config = pageContext.getServletConfig();
    session = pageContext.getSession();
    out = pageContext.getOut();
    _jspx_out = out;
    

    image-20220616134643240

在JSP页面中;

只要是 JAVA代码就会原封不动的输出;

如果是HTML代码,就会被转换为:

 out.write("<html>\r\n");

这样的格式,输出到前端!

8.3 JSP基础语法

任何语言都有自己的语法,JAVA中有。

JSP 作为 java 技术的一种应用,它拥有一些自己扩充的语法(了解,知道即可!),Java 所有语法都支持!

JSP表达式
<%--JSP表达式
    作用:用来将程序的输出,输出到客户端
    <%= 变量或者表达式%>
--%>
<%= new java.util.Date()%>
jsp脚本片段
<%--jsp脚本片段--%>
<%
int sum = 0;
for (int i = 1; i <=100 ; i++) {
    sum+=i;
}
out.println("<h1>Sum="+sum+"</h1>");
%>

脚本片段的再实现

<%
int x = 10;
out.println(x);
%>
<p>这是一个JSP文档</p>
<%
int y = 2;
out.println(y);
%>
<hr>
<%--在代码嵌入HTML元素--%>
<%
for (int i = 0; i < 5; i++) {
    %>
<h1>Hello,World <%=i%> </h1>
<%
}
%>
JSP声明
<%!
    static {
    System.out.println("Loading Servlet!");
}
private int globalVar = 0;
public void kuang(){
    System.out.println("进入了方法Kuang!");
}
%>

JSP声明:会被编译到 JSP 生成 Java 的类中!其他的,就会被生成到 _jspService 方法中!

在 JSP 中,嵌入 Java 代码即可!

<%%>
<%=%>
<%!%>
<%--注释--%>

JSP 的注释,不会在客户端显示,HTML 就会!

8.4 JSP指令

<%@page args.... %>
<%@include file=""%>
<%--@include会将两个页面合二为一--%>
<%@include file="common/header.jsp"%>
<h1>网页主体</h1>
<%@include file="common/footer.jsp"%>
<hr>

<%--jSP标签
    jsp:include:拼接页面,本质还是三个
        --%>

<jsp:include page="/common/header.jsp"/>
<h1>网页主体</h1>
<jsp:include page="/common/footer.jsp"/>

8.5 9大内置对象

  • PageContext 存东西
  • Request 存东西
  • Response Session 存东西
  • Application 【SerlvetContext】 存东西
  • config 【SerlvetConfig】
  • out 输出
  • page ,不用了解
  • exception 类似 java 的exception
pageContext.setAttribute("name1","秦疆1号"); //保存的数据只在一个页面中有效
request.setAttribute("name2","秦疆2号"); //保存的数据只在一次请求中有效,请求转发会携
带这个数据
session.setAttribute("name3","秦疆3号"); //保存的数据只在一次会话中有效,从打开浏览器
到关闭浏览器
application.setAttribute("name4","秦疆4号"); //保存的数据只在服务器中有效,从打开服
务器到关闭服务器

新建文件 PageContextDemo1.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <%
        pageContext.setAttribute("name1","naru1号");
        request.setAttribute("name2","naru2号");
        session.setAttribute("name3","naru3号");
        application.setAttribute("name4","naru4号");
        %>

        <%
        String name1 = (String) pageContext.findAttribute("name1");
        String name2 = (String) pageContext.findAttribute("name2");
        String name3 = (String) pageContext.findAttribute("name3");
        String name4 = (String) pageContext.findAttribute("name4");

        %>
        <h3>取出的值</h3>
        <h3>${name1}</h3>
        <h3>${name2}</h3>
        <h3>${name3}</h3>
        <h3>${name4}</h3>
    </body>
</html>
request

客户端向服务器发送请求,产生的数据,用户看完就没用了,比如:新闻,用户看完没用的!

例子验证:

新建一个 jspdemo01.jsp 文件 依旧执行相同的 findAttribute 方法,看跨越页面能取到几个 names ;

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>

        <%
        String name1 = (String) pageContext.findAttribute("name1");
        String name2 = (String) pageContext.findAttribute("name2");
        String name3 = (String) pageContext.findAttribute("name3");
        String name4 = (String) pageContext.findAttribute("name4");


        %>
        <h3>取出的值</h3>
        <h3>${name1}</h3>
        <h3>${name2}</h3>
        <h3>${name3}</h3>
        <h3>${name4}</h3>


    </body>
</html>

运行发现:

image-20220616202107672

1 号和 2 号没有取到!

因为 1 号只在一个页面中有效,而2号需要请求才可以出现,我们没有进行请求而是直接访问页面,因此2号也无法取到。

如何让请求建立?

这里给出一个例子:

在 最开始创建的 PageContextDemo1.jsp 文件中 设置转发。将其转发至 jspdemo01.jsp 文件.

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <%
        pageContext.setAttribute("name1","naru1号");
        request.setAttribute("name2","naru2号");
        session.setAttribute("name3","naru3号");
        application.setAttribute("name4","naru4号");
        %>

        <%

        String name1 = (String) pageContext.findAttribute("name1");
        String name2 = (String) pageContext.findAttribute("name2");
        String name3 = (String) pageContext.findAttribute("name3");
        String name4 = (String) pageContext.findAttribute("name4");

        pageContext.forward("/jspdemo01.jsp");
        %>
        <h3>取出的值</h3>
        <h3>${name1}</h3>
        <h3>${name2}</h3>
        <h3>${name3}</h3>
        <h3>${name4}</h3>
    </body>
</html>

image-20220616202754934

可见网页转发至 jspdemo01 页面 但是url没变,而2号被取到,即请求成功建立。

session

客户端向服务器发送请求,产生的数据,用户用完一会还有用,比如:购物车;

application

客户端向服务器发送请求,产生的数据,一个用户用完了,其他用户还可能使用,比如: 聊天数据;

8.6 JSP标签、JSTL标签、EL表达式

<!-- 添加jstl依赖,使其支持<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>jstl语法 -->
<!-- jstl标签库相关 -->
<dependency>
    <groupId>jstl</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.taglibs/taglibs-standard-impl -->
<dependency>
    <groupId>org.apache.taglibs</groupId>
    <artifactId>taglibs-standard-jstlel</artifactId>
    <version>1.2.5</version>
</dependency>
</dependencies>
EL表达式 ${}
  • 获取数据
  • 执行运算
  • 获取web开发的常用对象
JSP标签

JSTL 标签库的使用就是为了弥补 HTML 标签的不足;它自定义许多标签,可以供我们使用,标签的功能和 Java 代码一样!

格式化标签

SQL标签

XML 标签

核心标签

image-20220617192757901

jstl标签库使用步骤
  • 引入对应的 taglib
  • 使用其中的方法
  • 在Tomcat 也需要引入 jstl的包,否则会报错:JSTL解析错误
c:if
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--一定要记得加标签!--%>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <form action="cif.jsp" method="get">
            <%--
    EL表达式获取表单中的数据
    ${param.参数名}
            --%>
            <input type="text" name="username" value="${param.username}">
            <input type="submit" value="登录">
        </form>
        <%-- 判断如果提交的用户名为管理员,则登录成功--%>
        <c:if test="${param.username=='admin'}" var="isAdmin">
            <c:out value="管理员欢迎您!"/>
        </c:if>

        <%--自闭合标签--%>
        <c:out value = "${isAdmin}"/>
    </body>
</html>

c:choose c:when
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <c:set var="score" value="80"/>
        <c:choose>
            <c:when test="${score>=90}">
                你的成绩为优秀
            </c:when>
            <c:when test="${score>=80}">
                你的成绩为良好
            </c:when>
            <c:when test="${score>=70}">
                你的成绩为一般
            </c:when>
            <c:when test="${score>=60}">
                你的成绩为及格
            </c:when>
            <c:when test="${score<=60}">
                你的成绩为不及格
            </c:when>
        </c:choose>
    </body>
</html>

c:forEach
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <%
        ArrayList<String> people = new ArrayList<>();
        people.add(0,"naru1");
        people.add(1,"naru2");
        people.add(2,"naru3");
        people.add(3,"naru4");
        people.add(4,"naru5");
        request.setAttribute("list",people);
        %>

        <%--
    var , 每一次遍历出来的变量
    items, 要遍历的对象
    begin, 哪里开始
    end, 到哪里
    step, 步长
    --%>
        <c:forEach var="people" items="${list}">
            <c:out value="${people}"/> <br>
        </c:forEach>
        <hr>
        <c:forEach var="people" items="${list}" begin="1" end="3" step="1" >
            <c:out value="${people}"/> <br>
        </c:forEach>


    </body>
</html>

9、 JavaBean

实体类

JavaBean 有特定的写法:

  • 必须要有一个无参构造

  • 属性必须私有化

  • 必须有对应的 get/set 方法;

一般用来和数据库的字段做映射 ORM ;

ORM :对象关系映射

  • 表—>类
  • 字段–>属性
  • 行记录---->对象

people表

idnameageaddress
1naru1号1东北
2naru2号15河南
3naru3号20福建
class People{
    private int id;
    private String name;
    private int age;
    private String address;
}
class A{
    new People(1,"naru1号",1"东北");
    new People(2,"naru2号",15"河南");
    new People(3,"naru3号",2"福建");
}

10、MVC三层架构

什么是 MVC :

Model模型 View视图 Controller控制器

10.1 早些年

image-20220619140743721

用户直接访问控制层,控制层就可以直接操作数据库;

servlet ---- CURD ---> 数据库

弊端:程序十分臃肿 不利于维护

servlet 的代码中:处理请求、响应、视图跳转、处理 JDBC 、处理业务代码、处理逻辑代码

架构:没有什么是加一层解决不了的问题

程序员调用

|

JDBC

|

mysql oracle sqlserver

10.2 MVC三层架构

image-20220619142809887

Model
  • 业务处理 :业务逻辑(Service)

  • 数据持久层:CRUD (Dao)

View
  • 展示数据

  • 提供链接发起Servlet请求 (a,form,img…)

Controller (Servlet)
  • 接收用户的请求 :(req:请求参数、Session信息….)

  • 交给业务层处理对应的代码

  • 控制视图的跳转

登录--->接收用户的登录请求--->处理用户的请求(获取用户登录的参数,username,password)---->
交给业务层处理登录业务(判断用户名密码是否正确:事务)--->Dao层查询用户名和密码是否正确-->数据库

11、Filter(重点)

Filter:过滤器 ,用来过滤网站的数据;

  • 处理中文乱码
  • 登录验证….

image-20220619152049496

Filter开发步骤

导包

切记不要导错包!!

image-20220619162809052

编写过滤器
package com.naru.filter;

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

public class CharacterEncodingFilter  implements Filter {

    @Override //初始化:web服务器启动,就进行了初始化,之后随时等待过滤对象出现
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("过滤器启动");
    }

    //chain: 链
    /*
    1. 过滤器中的所有代码,在过滤特定请求的时候都会执行
    2. 必须要让过滤器继续通行
    chain.doFilter(request, response);
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html; charset=UTF-8");

        System.out.println("Filter 执行前");
        chain.doFilter(request, response);//让请求继续通行,
        // 如果不写,程序到这里就被拦截停止。
        System.out.println("Filter执行后");
    }

    //服务器停止之前 对过滤器进行销毁
    @Override
    public void destroy() {
        System.out.println("销毁过滤器");
    }
}

在 web.xml 中配置 FIlter
<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>com.kuang.filter.CharacterEncodingFilter</filterclass>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <!--只要是 /servlet的任何请求,会经过这个过滤器-->
    <url-pattern>/servlet/*</url-pattern>
    <!--<url-pattern>/*</url-pattern>-->
</filter-mapping>
Servlet 开放两个 url 进行访问对比过滤器效果
<servlet-mapping>
    <servlet-name>fIlterServlet</servlet-name>
    <url-pattern>/servlet/show</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>fIlterServlet</servlet-name>
    <url-pattern>/show</url-pattern>
</servlet-mapping>

直接访问 /show 未经过滤器 所以中文依旧是乱码:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FTyzqvEK-1656075055874)(https://s2.loli.net/2022/06/24/mGc9MeQwu21F8jn.png)]

访问/serlvet/show 经过过滤器 中文成功显示:

image-20220619164407895

12、监听器

实现一个监听器的接口;(有N种)

编写一个监听器

实现监听器的接口…

//统计网站在线人数 : 统计session
public class OnlineCountListener implements HttpSessionListener {

    //创建session监听: 看你的一举一动
    //一旦创建Session就会触发一次这个事件!
    public void sessionCreated(HttpSessionEvent se) {
        ServletContext ctx = se.getSession().getServletContext();
        System.out.println(se.getSession().getId());
        Integer onlineCount = (Integer) ctx.getAttribute("OnlineCount");
        if (onlineCount==null){
            onlineCount = new Integer(1);
        }else {
            int count = onlineCount.intValue();
            onlineCount = new Integer(count+1);
        }
        ctx.setAttribute("OnlineCount",onlineCount);
    }

    //销毁session监听
    //一旦销毁Session就会触发一次这个事件!
    public void sessionDestroyed(HttpSessionEvent se) {
        ServletContext ctx = se.getSession().getServletContext();
        Integer onlineCount = (Integer) ctx.getAttribute("OnlineCount");
        if (onlineCount==null){
            onlineCount = new Integer(0);
        }else {
            int count = onlineCount.intValue();
            onlineCount = new Integer(count-1);
        }
        ctx.setAttribute("OnlineCount",onlineCount);
    }

}

web.xml中注册监听器

<!--注册监听器-->
<listener>
    <listener-class>com.kuang.listener.OnlineCountListener</listenerclass>
</listener>

13、过滤器、监听器常见应用

监听器:GUI编程中经常使用;

public class TestPanel {
    public static void main(String[] args) {
        Frame frame = new Frame("中秋节快乐"); //新建一个窗体
        Panel panel = new Panel(null); //面板
        frame.setLayout(null); //设置窗体的布局
        frame.setBounds(300,300,500,500);
        frame.setBackground(new Color(0,0,255)); //设置背景颜色
        panel.setBounds(50,50,300,300);
        panel.setBackground(new Color(0,255,0)); //设置背景颜色
        frame.add(panel);
        frame.setVisible(true);
        //监听事件,监听关闭事件
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                super.windowClosing(e);
            }
        });
    }
}

用户登录之后才能进入主页!用户注销后就不能进入主页了!

  1. 用户登录之后,向 Sesison 中放入用户的数据
  2. 进入主页的时候要判断用户是否已经登录;要求:在过滤器中实现!
public class SysFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        if (request.getSession().getAttribute(USER_SESSION)==null){
            response.sendRedirect("/error.jsp");
        }
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}

14、JDBC

什么是 JDBC : Java 连接数据库!

image-20220624105613632

需要jar包的支持:

  • java.sql
  • javax.sql
  • mysql-conneter-java… 连接驱动(必须要导入)

实验环境搭建

CREATE TABLE users(
    id INT PRIMARY KEY,
    `name` VARCHAR(40),
    `password` VARCHAR(40),
    email VARCHAR(60),
    birthday DATE
);
INSERT INTO users(id,`name`,`password`,email,birthday)
VALUES(1,'张三','123456','zs@qq.com','2000-01-01');
INSERT INTO users(id,`name`,`password`,email,birthday)
VALUES(2,'李四','123456','ls@qq.com','2000-01-01');
INSERT INTO users(id,`name`,`password`,email,birthday)
VALUES(3,'王五','123456','ww@qq.com','2000-01-01');
SELECT * FROM users;

导入数据库依赖

<!--mysql的驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5hsTVgqf-1656075055877)(https://s2.loli.net/2022/06/24/y4a13Fk9xZ52lfV.png)]

JDBC 固定步骤

  1. 加载驱动
  2. 连接数据库,代表数据库
  3. 向数据库发送SQL的对象Statement : CRUD
  4. 编写SQL (根据业务,不同的SQL)
  5. 执行SQL
  6. 关闭连接

public class jdbc {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        String url = "jdbc:mysql://localhost:3306/jdbc?\n" +
            "useUnicode=true&characterEncoding=utf-8";
        String usename = "root";
        String password = "admin";
        //1.加载驱动
        Class.forName("com.mysql.jdbc.Driver");
        //2.连接数据库,代表数据库
        Connection connection = DriverManager.getConnection(url, usename, password);

        //3.向数据空发送sql的对象statement,PreparedStatement; curd
        Statement statement = connection.createStatement();

        //4.编写sql
        String sql = "select * from  users";
        ResultSet rs = statement.executeQuery(sql);
        while (rs.next()){
            System.out.println("id="+rs.getObject("id"));
            System.out.println("name="+rs.getObject("name"));
            System.out.println("password="+rs.getObject("password"));
            System.out.println("email="+rs.getObject("email"));
            System.out.println("birthday="+rs.getObject("birthday"))

        }
        //关闭连接,释放资源(必须做)先开后关
        rs.close();
        statement.close();
        connection.close();

    }
}

预编译 SQL

package com.naru.jdbctest;

import java.sql.*;

public class jdbc2 {
    public static void main(String[] args) throws SQLException,ClassNotFoundException {
        String url = "jdbc:mysql://localhost:3306/javaweb?\n" +
            "useUnicode=true&characterEncoding=utf-8&useSSL=false";
        String usename = "root";
        String password = "admin";
        //1.加载驱动
        Class.forName("com.mysql.jdbc.Driver");
        //2.连接数据库,代表数据库
        Connection connection = DriverManager.getConnection(url, usename, password);

        //3.编写SQL
        String sql = "insert into users(id, name, password, email, birthday) values (?,?,?,?,?);";

        //4.预编译
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        preparedStatement.setInt(1, 7);//给第一个占位符?赋值 注意这里为 id 不可添加重复的id 
        preparedStatement.setString(2, "naru");//给第二个占位符?赋值为naru
        preparedStatement.setString(3, "123456");
        preparedStatement.setString(4, "3517962@qq.com");
        preparedStatement.setDate(5, new Date(new java.util.Date().getTime()));

        int i = preparedStatement.executeUpdate();

        if (i > 0){
            System.out.println("插入成功!");
        }

        preparedStatement.close();
        connection.close();


    }
}

事务

要么都成功,要么都失败!

ACID 原则:保证数据的安全。

开启事务 

事务提交 commit() 

事务回滚 rollback() 

关闭事务 

转账: 

A:1000 

B:1000 

A(900) --100--> B(1100)

Junit单元测试

<!--单元测试-->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

简单使用

@Test注解只有在方法上有效,只要加了这个注解的方法,就可以直接运行!

@Test
public void test(){
    System.out.println("Hello");
}

image-20220624150411083

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值