JavaWeb

Java   Web

1、基本概念

1.1、前言

web开发

  • web,网页的意思

  • 静态web

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

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

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

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

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

1.2、web应用程序

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

  • a.html、b.html……多个web资源,这些web资源可以被外界访问,对外界提供服务;
  • 你们能访问到的任何一个页面或者资源,都存在于这个世界的某-个角落的计算机上
  • URL
  • 这个统一的web资源会被放在同一个文件夹下——>Tomcat:服务器
  • 一个web应用由多部分组成(静态web,动态web)
    • html,css,js
    • jsp,servlet
    • Java程序
    • jar包
    • 配置文件(Properties)

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

1.3、静态web

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

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

1.4、动态web

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

缺点:

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

优点:

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

2、web服务器

2.1、技术讲解

  • ASP

    • 微软:国内最早流行的就是ASP;
    • 在HTML中嵌入了VB的脚本,ASP + COM;
    • 在ASP开发中,基本一个页面都有几千行的业务代码,页面极其混乱
    • 维护成本高!
    • C#
    • IIS服务器
  • JSP/Servlet

    B/S:浏览器和服务器

    C/S:客户端和服务器

    • Sun公司主推的B/S架构
    • 基于Java语言(所有的大公司,或者一些开源的组件,都是用Java写的)
    • 可以承载三高问题带来的影响(高并发、高可用、高性能)
    • 语法像ASP,可以让学ASP的人转为用JSP,加强市场强度;
  • PHP

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

2.2、web服务器

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

  • IIS

    • 微软的;ASP,Windows中自带的服务器
  • Tomcat

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

工作3-5年之后,可以尝试手写Tomcat服务器;

下载Tomcat:

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

3、Tomcat

3.1、安装Tomcat

具体安装步骤参考我的另外一篇名叫“Tomcat安装以及404问题”的博客。

3.2配置

image-20220416163423120

可以配置启动的端口号

  • tomcat的默认端口号为: 8080
  • mysql: 3306
  • http: 80
  • https: 443
<Connector port="8080" protoco1="HTTP/1.1"
		   connectionTimeout="20000"
		   redirectPort="8443"/>

可以配置主机的名称

  • 默认的主机名为: localhost—->127.0.0.1
  • 默认网站应用存放的位置为: webapps
<Host name="localhost"  appBase="webapps"
	  unpackWARs="true" autoDeploy="true">

面试题:

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

1、输入一个域名;回车

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

    1.有:直接返回对应的ip地址,这个地址中,有我们需要访问的web程序,可以直接访问

    2.没有:去DNS服务器上找,找到的话就返回,找不到就返回找不到;

image-20220416164956723

3.3、配置环境变量(可选项)

具体安装步骤参考我的另外一篇名叫“Tomcat安装以及404问题”的博客。

3.4、发布一个web网站

image-20220501191411806

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

网站应该有的结构

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

HTTP协议:面试

Maven:构建工具

  • Maven安装包

Servlet入门

  • HelloWorld!
  • Servlet配置
  • 原理

4、HTTP

4.1、什么是http

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

  • 文本: html,字符串,~……
  • 超文本:图片,音乐,视频,定位,地图……
  • http默认端口:80

Https(s代表安全的security)

  • 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: 183.232.231.174:443
Accept: text/html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9		语言
Cache-Control: max-age=0
Connection: keep-alive

1、请求行

  • 请求行中的请求方式: GET
  • 请求方式: GetPost,,HEAD,DELETE,PUT,TRACT…
    • get:请求能够携带的参数比较少,大小有限制,会在浏览器的URL地址栏显示数据内容,不安全,但高
    • post:请求能够携带的参数没有限制,大小没有限制,不会在浏览器的URL地址栏显示数据内容,安全,但不高效

2、消息头

Accept: text/html		告诉浏览器,它所支持的数据类型
Accept-Encoding: gzip, deflate, br		支持哪种编码格式GBK UTF-8 GB2312 IS08859-1
Accept-Language: zh-CN,zh;q=0.9		告诉浏览器,它的语言环境
Cache-Control: max-age=0		缓存控制
Connection: keep-alive		告诉浏览器,请求完成是断开还是保持连接
HOST:主机...

4.4、Http响应

  • 服务器—响应(Response)—客服端

百度为例

Cache-Control: private		缓存控制
Connection: keep-alive		连接:保持连接状态
Content-Encoding: gzip		内容编码
Content-Type: text/html;	内容类型
charset=utf-8				字符集

1、响应体

Accept:	告诉浏览器,它所支持的数据类型
Accept-Encoding:	支持哪种编码格式GBK UTF-8 GB2312 IS08859-1
Accept-Language:	告诉浏览器,它的语言环境
Cache-Control:	缓存控制
Connection:	告诉浏览器,请求完成是断开还是保持连接
HOST:主机...
Refresh:告诉客户端,多久刷新一次
LOcation:让网页重新定位;

2、响应状态码

200			请求响应成功
3**			请求重定向
404			找不到资源
500			服务器代码错误
502			网关错误

常见面试题

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

5、Maven

为什么要学习这个技术?

  • 在Javaweb开发中,需要使用大量的jar包,我们手动去导入;
  • 如何能够让一个东西自动帮我导入和配置这个jar包。

由此,Maven诞生了!

5.1、Maven项目架构管理工具

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

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

  • 有约束,不要去违反。

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

5.2、下载安装Maven

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

历史各个版本Maven下载地址:https://archive.apache.org/dist/maven/maven-3/

IDEA安装Maven以及配置国内镜像参考这位博主:https://blog.csdn.net/jiyuzzz/article/details/119643665?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_utm_term~default-4.pc_relevant_antiscanv2&spm=1001.2101.3001.4242.3&utm_relevant_index=7

5.3、配置环境变量

1、新建系统变量MAVEN_HOME
变量名:MAVEN_HOME
变量值:D:\apache-maven-3.8.1
(就是maven安装目录)

2、新建系统变量M2_HOME
变量名:M2_HOME
变量值:D:\apache-maven-3.8.1\bin
(就是maven安装目录下的bin目录)

3、编辑系统变量path

打开后在path中点击新建,添加maven根目录,固定写法:
%MAVEN_HOME%\bin

不要忘记最后全部点确定。。

4、检查maven版本

在cmd中输入 mvn -version

5.4、阿里云镜像

配置国内的阿里云镜像可以提高jar包下载速度

在conf文件夹找到settings.xml,打开

image-20220417151543836

复制这段代码,插入mirrors标签对中

<mirror>
      <id>alimaven</id>
      <name>aliyun maven</name>
      <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
      <mirrorOf>central</mirrorOf>        
</mirror>

以下是插入完成后

001

5.5、maven本地仓库

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

建立一个本地仓库:

方便统一管理jar包

还是setting.xml文件
加入localRepository标签对,内部写仓库地址
我是在maven根目录创建了新文件夹maven-repo

001

5.6、在IDEA中使用Maven

首先在D盘新建一个文件夹(名字自己随便取),这个文件夹是专门用来存放你的项目的

1、启动IDEA

2、创建一个Java-web,Maven项目

image-20220417155349450

点击Next

image-20220417161224070

点击Next

image-20220417155901816

最后点击finish即可

3、等待项目初始化完毕。

4、观察maven仓库中多了什么东西?

5、IDEA中的Maven设置

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

image-20220417162030608

6、到这里,Maven在IDEA中的配置和使用就OK了!

5.7、创建一个普通的Maven项目

image-20220417163130299
image-20220417163212403
image-20220417194748230

对比勾选了org.apache.maven.archetype :maven- archetype -webapp模板的项目结构

可以看到这是一个具有Javaweb结构的项目,上面的项目没有webapp这个文件夹。注意观察辨别。

image-20220417195243386

5.8、标记文件夹功能

image-20220417200522678

Javaweb项目具有的Java,resource,webapp

image-20220417200553635
image-20220417200833199

这里也可以对文件夹做标记(就是文件夹没有高亮的情况下)

image-20220417201058372

target的作用就是把Java文件编译成class文件

image-20220417201240971

5.9、在IDEA中配置Tomcat

image-20220417202653828
image-20220417203532215

创建一个artifacts

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

image-20220417203712068
image-20220417204010387

这里我们把路径改成 /javaweb就可以了,不需要那么长

image-20220417204842592

启动Tomcat

image-20220417205234792

看下maven初始化下载了哪些东西

image-20220417205812338

5.10、pom文件

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

<?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.mike</groupId>
  <artifactId>javaweb-exercise</artifactId>
  <version>1.0-SNAPSHOT</version>
  <!--Package:项目的打包方式
  jar: java应用
  war: JavaWeb应用
  -->
  <packaging>war</packaging>

  <!--配置-->
  <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>
    </dependency>
  </dependencies>

  <!--项目构建用的东西-->
  <build>
    <finalName>javaweb-exercise</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>

我们换回普通的maven项目,因为这个maven项目的pom.xml是比较干净的。

image-20220417211843956

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

<!--在build中配置resources,来防止我们资源导出失败的问题-->
<build>
        <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>
    </build>

5.11、IDEA操作

image-20220417212800386

5.12、解决遇到的问题

1、Maven 3.6.2

image-20220417213001668

  • 解决方法:降级为3.6.1

2、Tomcat闪退

3、IDEA中每次都要重复配置Maven

  • 在IDEA中的全局默认配置中去配置

    image-20220417214157983

4、Maven项目中Tomcat无法配置

5.13、Maven仓库的使用

Maven远程仓库:https://mvnrepository.com/

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.mike</groupId>
  <artifactId>javaweb-exercise</artifactId>
  <version>1.0-SNAPSHOT</version>
  <!--Package:项目的打包方式
  jar: java应用
  war: JavaWeb应用
  -->
  <packaging>war</packaging>
  <!--配置-->
  <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>
    <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</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>
  </dependencies>
    
</project>

index.jsp

<html>
<body>
<h2>Hello World!</h2>
</body>
</html>

右键webapp新建一个HTML,名字叫header.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>
    我是导航栏
</h1>
</body>
</html>

HelloServlet类

package com.mike.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.io.PrintWriter;

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException {
        //响应的类型: html
        response.setContentType ("text/html");
        //设置编码格式为utf-8
        response.setCharacterEncoding("utf-8");
        //获取响应的输出流
        PrintWriter out = response.getWriter() ;
        out.println("<html>");
        out.println("<head>");
        out.println("<title>He1lo World!</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<h1>Hello World!</h1>");
        out.println("</body>");
        out.println("</html>");
    }

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

web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <!--web.xmL中是配置我们web的核心应用-->
  <!--注册Servlet-->
  <servlet>
    <servlet-name>HelloServlet</servlet-name>
    <servlet-class>com.mike.servlet.HelloServlet</servlet-class>
  </servlet>
  <!--一个ServLet对应一个Mapping: 映射-->
  <servlet-mapping>
    <servlet-name>HelloServlet</servlet-name>
    <!--请求路径-->
    <url-pattern>/mike</url-pattern>
  </servlet-mapping>

</web-app>

启动Tomcat(上面的项目默认打开的地址是:localhost:8080/javaweb)

首先打开的是默认的index.jsp文件,屏幕前出现Hello World!

地址栏输入localhost:8080/javaweb/mike

屏幕出现Hello World!(注意:这里的Hello World!是HelloServlet类里的h1标签的内容)

地址栏输入localhost:8080/javaweb/header.html

屏幕出现:我是导航栏

以上是简单的servlet使用。

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主工程;

image-20220417224709155

2、关于Maven父子工程的理解:

  父项目中会有

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

  子项目

<parent>
	<artifactId>javaweb-lesson</artifactId>
	<groupId>com.mike</groupId>
	<version>1.0-SNAPSHOT</version>
</parent>

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

son	extends father

3、Maven环境优化

  1. 修改web.xml为最新的
  2. 将maven的结构搭建完整

4、编写一个servlet程序

  1. 编写一个普通类

  2. 实现Servlet接口,这里我们直接继承HttpServlet

    HelloServlet类

    package com.mike.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.ServletOutputStream;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    public class HelloServlet extends HttpServlet {
        //由与get或者post只是请求实现的不同的方式,可以相互调用,业务逻辑都一样;
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //ServletOutputStream outputStream = resp.getOutputStream();
            PrintWriter writer = resp.getWriter();//响应流
            writer.print("Hello,Servlet");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            super.doPost(req, resp);
        }
    }
    

5、编写Servlet的映射

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

web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

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

6、配置Tomcat

注意配置项目发布的路径

7、启动测试

6.3、Servlet原理

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

image-20220418134134277

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>
    
  3. 一个Servlet可以指定通用映射路径

      <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello/*</url-pattern>
      </servlet-mapping>
    
  4. 默认请求路径(不建议使用)

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

    <!--可以自定义后缀实现请求映射
    注意点,*前面不能加项目映射的路径
    -->
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>*.mike</url-pattern>
    </servlet-mapping>
    
  6. 优先级问题

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

例子:404问题

ErrorServlet类

package com.mike.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.io.PrintWriter;

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

        PrintWriter writer = resp.getWriter();
        writer.print("<h1>404</h1>");
    }

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

web.xml映射文件

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <!--注册Servlet-->
  <servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>com.mike.servlet.HelloServlet</servlet-class>
  </servlet>

  <servlet>
    <servlet-name>error</servlet-name>
    <servlet-class>com.mike.servlet.ErrorServlet</servlet-class>
  </servlet>
  <!--Servlet的请求路径-->
  <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>error</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
  
</web-app>

启动Tomcat,地址栏输入一个不存在页面,会自动跳转到自定义的error页面

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

6.5、ServletContext

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

1、共享数据

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

往Servlet存放数据的类

package com.mike.servlet;

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

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //this.getInitParameter()   初始化参数
        //this.getServletConfig()   Servlet配置
        //this.getServletContext()  Servlet上下文
        ServletContext context = this.getServletContext();
        String username = "张三丰";
        context.setAttribute("username",username);//将一个数据保存在了ServletContext中,名字为: username 值: username
    }

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

从Servlet获得数据的类

package com.mike.servlet;

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

public class 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);
    }
}

配置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_3_1.xsd"
         version="3.1"
         metadata-complete="true">

<servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>com.mike.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello</url-pattern>
</servlet-mapping>    
    
<servlet>
    <servlet-name>getc</servlet-name>
    <servlet-class>com.mike.servlet.GetServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>getc</servlet-name>
    <url-pattern>/getc</url-pattern>
</servlet-mapping>
    
</web-app>

启动Tomcat,首先访问localhost:8080/hello存放数据

然后访问localhost:8080/getc获得Servlet里存放的数据

2、获取初始化参数

ServletDemo03类

package com.mike.servlet;

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

public class ServletDemo03 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        //获取web.xml的默认配置文件
        String url = context.getInitParameter("url");
        resp.getWriter().print(url);

    }

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

}

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_3_1.xsd"
         version="3.1"
         metadata-complete="true">

    <!--配置一些web应用初始化参数-->
    <context-param>
        <param-name>url</param-name>
        <param-value>jdbc:mysql://localhost:3306/myblatis</param-value>
    </context-param>

    <servlet>
        <servlet-name>gp</servlet-name>
        <servlet-class>com.mike.servlet.ServletDemo03</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>gp</servlet-name>
        <url-pattern>/gp</url-pattern>
    </servlet-mapping>
</web-app>

3、请求转发

ServletDemo04类

package com.mike.servlet;

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

public class ServletDemo04 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
//        RequestDispatcher requestDispatcher = context.getRequestDispatcher("/gp");//转发的请求路径
//        requestDispatcher.forward(req,resp);//调用forward实现请求转发;
        context.getRequestDispatcher("/gp").forward(req,resp);
    }

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

}

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_3_1.xsd"
         version="3.1"
         metadata-complete="true">

    <!--配置一些web应用初始化参数-->
    <context-param>
        <param-name>url</param-name>
        <param-value>jdbc:mysql://localhost:3306/myblatis</param-value>
    </context-param>

    <servlet>
        <servlet-name>gp</servlet-name>
        <servlet-class>com.mike.servlet.ServletDemo03</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>gp</servlet-name>
        <url-pattern>/gp</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>sd4</servlet-name>
        <servlet-class>com.mike.servlet.ServletDemo04</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>sd4</servlet-name>
        <url-pattern>/sd4</url-pattern>
    </servlet-mapping>
</web-app>

区别请求转发和重定向

  • 请求转发路径地址不会改变
  • 重定向地址会发生变化

image-20220418152503955

4、读取资源文件

Properties

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

发现:都被打包到了同一个路径下: classes,我们俗称这个路径为classpath:

思路:需要一个文件流;

ServletDemo05类

package com.mike.servlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class ServletDemo05 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        InputStream is = context.getResourceAsStream("/WEB-INF/classes/db.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);
    }
}

db.properties

username = root
password = 123456

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_3_1.xsd"
         version="3.1"
         metadata-complete="true">
    <servlet>
        <servlet-name>sd5</servlet-name>
        <servlet-class>com.mike.servlet.ServletDemo05</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>sd5</servlet-name>
        <url-pattern>/sd5</url-pattern>
    </servlet-mapping>
</web-app>

6.6、 HttpServletResponse

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

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

1、简单分类

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

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

2、常见应用

1、向浏览器输出消息

2、下载文件

  1. 要获取下载文件的路径
  2. 下载的文件名是啥?
  3. 设置想办法让浏览器能够支持下载我们需要的东西
  4. 获取下载文件的输入流
  5. 创建缓冲区
  6. 获取OutputStream对象
  7. 将FileOutputStream流写入到buffer缓冲区
  8. 使用OutputStream将缓冲区中的数据输出到客户端!
下载文件案例
package com.mike.servlet;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLEncoder;

public class FileServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1. 要获取下载文件的路径
        String realPath = this.getServletContext().getRealPath("src/main/resources/01.jpg");
        System.out.println("下载文件的路径: "+realPath);
        //2. 下载的文件名是啥?
        String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);
        //3. 设置想办法让浏览器能够支持(Content -Disposition)下载我们需要的东西,中文文件名URLEncoder. encode编码,否则有可能乱码
        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))!=-1){
            out.write(buffer,0,len);
        }
        in.close();
        out.close();
    }

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

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_3_1.xsd"
         version="3.1"
         metadata-complete="true">
<servlet>
  <servlet-name>filedown</servlet-name>
  <servlet-class>com.mike.servlet.FileServlet</servlet-class>
</servlet>
  <servlet-mapping>
    <servlet-name>filedown</servlet-name>
    <url-pattern>/down</url-pattern>
  </servlet-mapping>

</web-app>

3、验证码功能

验证怎么来的?

  • 前端实现
  • 后端实现,需要用到 Java 的图片类,生成一个图片

ImageServlet类

package com.mike.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 graphics2D = (Graphics2D) image.getGraphics();//笔
        //设置图片的背景颜色
        graphics2D.setColor(Color.WHITE);
        graphics2D.fillRect(0,0,80,20);
        //给图片写数据
        //先给画笔换成蓝色,上面是用白色画一个背景
        graphics2D.setColor(Color.BLUE);
        graphics2D.setFont(new Font("宋体",Font.BOLD,20));
        graphics2D.drawString(makeNum(),0,20);

        //告诉浏览器,这个请求用图片的方式打开
        resp.setContentType("image/jpeg");
        //网站存在缓存,不让浏览器缓存
        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();
        //这段代码的含义就是保证得到的一定是7位数的,不够就用0补充
        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);
    }
}

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_3_1.xsd"
         version="3.1"
         metadata-complete="true">

  <servlet>
    <servlet-name>ImageServlet</servlet-name>
    <servlet-class>com.mike.servlet.ImageServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>ImageServlet</servlet-name>
    <url-pattern>/img</url-pattern>
  </servlet-mapping>
</web-app>

4、实现重定向

image-20220418194218402

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

常见场景:

  • 用户登录

    void sendRedirect(String var1) throws IOException;
    

    测试:

    package com.mike.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    public class RedirectServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            /*
            resp.setHeader("Location", "/r/img");
            resp.setStatus(302);
            */
            //这里的/r是localhost:8080/r的r
            resp.sendRedirect("/r/img");//重定向
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
<?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_3_1.xsd"
           version="3.1"
           metadata-complete="true">
    
    <servlet>
      <servlet-name>ImageServlet</servlet-name>
      <servlet-class>com.mike.servlet.ImageServlet</servlet-class>
    </servlet>
    <servlet-mapping>
      <servlet-name>ImageServlet</servlet-name>
      <url-pattern>/img</url-pattern>
    </servlet-mapping>
  
    <servlet>
      <servlet-name>RedirectServlet</servlet-name>
      <servlet-class>com.mike.servlet.RedirectServlet</servlet-class>
    </servlet>
    <servlet-mapping>
      <servlet-name>RedirectServlet</servlet-name>
      <url-pattern>/red</url-pattern>
    </servlet-mapping>
  </web-app>

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

相同点

  • 页面都会实现跳转

不同点

  • 请求转发的时候,URL地址栏不会发生变化
  • 重定向的时候,URL地址栏会发生变化

image-20220418152503955

重定向案例

index.jsp

<html>
<body>
<h2>Hello World!</h2>

<%--这里提交的路径需要寻找到项目的路径--%>
<%--pageContext.request.contextPath代表当前项目--%>
<form action="${pageContext.request.contextPath}/login" method="get">
    <p>用户名:<input type="text" name="username"></p>
    <p>密码:<input type="password" name="password"></p>
    <input type="submit">
</form>
</body>
</html>

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_3_1.xsd"
         version="3.1"
         metadata-complete="true">

  <servlet>
    <servlet-name>RequestTest</servlet-name>
    <servlet-class>com.mike.servlet.RequestTest</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>RequestTest</servlet-name>
    <url-pattern>/login</url-pattern>
  </servlet-mapping>
    
</web-app>

RequestTest类

package com.mike.servlet;

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

public class RequestTest extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("进入doGet方法");
        //处理请求
        String username = req.getParameter("username");
        String password = req.getParameter("password");

        System.out.println(username+":"+password);

        //重定向时候一定要注意,路径问题,否则404;
        resp.sendRedirect("/r/success.jsp");
    }

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

success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>进入了success页面</h1>
</body>
</html>

启动Tomcat首先进入默认界面index.jsp,提交表单后跳转/login地址,/login去RequestTest类中找到doGet方法,doGet方法里面对/login地址进行了重定向,跳转到success.jsp,所以提交表单后,屏幕出现“进入了success页面”。

6.7、HttpServletRequest

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

取前端传递的参数,请求转发

req.getParameter(String S)				String
    
req.getParameterValues(String s)		String[]

案例

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录</title>
</head>
<body>
<h1>登录</h1>
<div>
    <%--这里表单表示的意思:以post 方式提交表单,提交到我们的login请求--%>
    <form action="${pageContext.request.contextPath}/login" method="post">
        <p>用户名:<input type="text" name="username"></p>
        <p>密码:<input type="password" name="password"></p>
        <p>爱好:
            <input type="checkbox" value="sleep" name="hobby">睡觉
            <input type="checkbox" value="shavingDinner" name="hobby" checked>吃饭
            <input type="checkbox" value="beatBeans" name="hobby">打豆豆
        </p>
        <input type="submit">
    </form>
</div>
</body>
</html>

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_3_1.xsd"
         version="3.1"
         metadata-complete="true">

    <servlet>
        <servlet-name>LoginServlet</servlet-name>
        <servlet-class>com.mike.servlet.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LoginServlet</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mapping>

</web-app>

LoginServlet类

package com.mike.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.ArrayList;
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("hobby");
        System.out.println("==================================");
        System.out.println(username);
        System.out.println(password);
        System.out.println(Arrays.toString(hobbies));
        System.out.println("==================================");

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

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

success.jsp

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

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

相同点

  • 页面都会实现跳转

不同点

  • 请求转发的时候,URL地址栏不会发生变化  307
  • 重定向的时候,URL地址栏会发生变化    302

7、Cookie和Session

7.1、会话

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

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

你能怎么证明你是西开的学生?

你      西开

  1. 发票     西开给你发票
  2. 学校登记   西开标记你来过了

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

客户端     服务端

  1. 服务端给客户端一个信件,客户端下次访问服务端带上信件就可以了;cookie

  相对于一个学生带着校卡进校园,保安不认识这个人,但是保安认识学校的校卡

  1. 服务器登记你来过了,下次你来的时候我来匹配你;session

7.2、保存会话的两种技术

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

session

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

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

7.3、Cookie

image-20220428201839286

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

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

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

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

删除Cookie

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

保存日期时间信息

例子:保存用户是一次访问的时间

package com.mike.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 CookieDemo01 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //服务器,告诉你,你来的时间,把这个时间封装成为一个信件,你下次带来,我就知道你来了

        //解决中文乱码
        req.setCharacterEncoding("utf-8");
//        resp.setContentType("text/html");
//        resp.setCharacterEncoding("utf-8");
        //简写成一行
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter out = resp.getWriter();

        //Cookie,服务器端从客户端获取呀;
        Cookie[] cookies = req.getCookies();//这里返回数组,说明Cookie 可能存在多个

        //判断Cookie是否存在
        if (cookies!= null){
            //如果存在怎么办
            out.write("你上一次访问的时间是:");
            //不建议使用增强型for循环,因为不能准确用下标取值
/*            for (Cookie cookie : cookies) {
                
            }*/
            for (int i = 0; i < cookies.length; i++) {
                Cookie cookie = cookies[i];
                //获取cookie的名字
                if (cookie.getName().equals("lastLoginTime")){
                    //获取cookie的值
                    long lastLoginTime = Long.parseLong(cookie.getValue());
                    Date date = new Date(lastLoginTime);
                    out.write(date.toLocaleString());
                }
            }

        }else {
            out.write("这是您第一次访问本站~");
        }

        //服务器给客户端响应一个cookie;
        Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis()+"");

        //cookie有效期为一天
        cookie.setMaxAge(24*60*60);

        resp.addCookie(cookie);

    }

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

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_3_1.xsd"
         version="3.1"
         metadata-complete="true">

    <servlet>
        <servlet-name>CookieDemo01</servlet-name>
        <servlet-class>com.mike.servlet.CookieDemo01</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>CookieDemo01</servlet-name>
        <url-pattern>/c1</url-pattern>
    </servlet-mapping>

</web-app>

image-20220427203456289

存取中文信息

中文的编码和解码

URLEncoder.encode("张三丰","utf-8")
URLDecoder.decode(cookie.getValue(),"UTF-8")

cookie存取中文信息

package com.mike.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.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Date;

//中文数据传递
public class CookieDemo02 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //解决中文乱码
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html");
        resp.setCharacterEncoding("utf-8");
        PrintWriter out = resp.getWriter();

        //Cookie,服务器端从客户端获取呀;
        Cookie[] cookies = req.getCookies();//这里返回数组,说明Cookie 可能存在多个

        //判断Cookie是否存在
        if (cookies!= null){
            //如果存在怎么办
            out.write("你上一次访问的时间是:");

            for (int i = 0; i < cookies.length; i++) {
                Cookie cookie = cookies[i];
                //获取cookie的名字
                if (cookie.getName().equals("name")){
                    //解码
                    out.write(URLDecoder.decode(cookie.getValue(),"UTF-8"));
                }
            }

        }else {
            out.write("这是您第一次访问本站~");
        }
//        Cookie cookie = new Cookie("name","张三丰");
        //因为后台向前台传输中文可能会出现乱码问题,这里需要对中文“张三丰”进行编码,编码后的信息需要进行解码
        Cookie cookie = new Cookie("name", URLEncoder.encode("张三丰","utf-8"));
        resp.addCookie(cookie);
    }

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

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_3_1.xsd"
         version="3.1"
         metadata-complete="true">


    <servlet>
        <servlet-name>cookieDemo02</servlet-name>
        <servlet-class>com.mike.servlet.CookieDemo02</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>cookieDemo02</servlet-name>
        <url-pattern>/c2</url-pattern>
    </servlet-mapping>

</web-app>

image-20220427203653334

7.4、Session(重点)

image-20220428202031701

什么是Session

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

image-20220428124602551

Session和Cookie的区别

  • Cookie是把用户的数据写给用户的浏览器,浏览器保存(可以保存多个)

  • Session把用户的数据写到用户独占Session中,服务器端保存(保存重要的信息, 减少服务器资源的浪费)

  • Session对象由服务创建;

使用场景:

  • 保存一个登录用户的信息;
  • 购物车信息;
  • 在整个网站中经常会使用的数据,我们将它保存在Session中;
案例一:往session存数据
package com.mike.servlet;

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

public class SessionDemo01 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","张三丰");
        //获取Session的ID
        String sessionId = session.getId();
        //判脚Session是不是新创建
        if (session.isNew()){
            resp.getWriter().write("session创建成功,ID:"+sessionId);
        }else {
            resp.getWriter().write("session已经在服务器中存在了,ID:"+sessionId);
        }
        //Session创建的时候做了什么事情;
//        Cookie jsessionid = new Cookie("JSESSIONID", sessionId);
//        resp.addCookie(jsessionid);


    }

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

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_3_1.xsd"
         version="3.1"
         metadata-complete="true">

    <servlet>
        <servlet-name>SessionDemo01</servlet-name>
        <servlet-class>com.mike.servlet.SessionDemo01</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>SessionDemo01</servlet-name>
        <url-pattern>/s1</url-pattern>
    </servlet-mapping>

</web-app>
案例二:从session取数据
package com.mike.servlet;

import com.mike.pojo.Person;

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

public class SessionDemo02 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();

        String name = (String) session.getAttribute("name");

        System.out.println(name);

    }

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

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_3_1.xsd"
         version="3.1"
         metadata-complete="true">


    <servlet>
        <servlet-name>SessionDemo01</servlet-name>
        <servlet-class>com.mike.servlet.SessionDemo01</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>SessionDemo01</servlet-name>
        <url-pattern>/s1</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>SessionDemo02</servlet-name>
        <servlet-class>com.mike.servlet.SessionDemo02</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>SessionDemo02</servlet-name>
        <url-pattern>/s2</url-pattern>
    </servlet-mapping>

</web-app>
案例三:往session存对象

Person类

package com.mike.pojo;

public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

SessionDemo03

package com.mike.servlet;

import com.mike.pojo.Person;

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 SessionDemo03 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",new Person("上官宝",18));
        //获取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

<?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_3_1.xsd"
         version="3.1"
         metadata-complete="true">



    <servlet>
        <servlet-name>SessionDemo03</servlet-name>
        <servlet-class>com.mike.servlet.SessionDemo03</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>SessionDemo03</servlet-name>
        <url-pattern>/s3</url-pattern>
    </servlet-mapping>
    
</web-app>
案例三:从session取对象
package com.mike.servlet;

import com.mike.pojo.Person;

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

public class SessionDemo02 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();

        Person person = (Person) session.getAttribute("name");

        System.out.println(person.toString());

    }

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

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_3_1.xsd"
         version="3.1"
         metadata-complete="true">


    <servlet>
        <servlet-name>SessionDemo02</servlet-name>
        <servlet-class>com.mike.servlet.SessionDemo02</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>SessionDemo02</servlet-name>
        <url-pattern>/s2</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>SessionDemo03</servlet-name>
        <servlet-class>com.mike.servlet.SessionDemo03</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>SessionDemo03</servlet-name>
        <url-pattern>/s3</url-pattern>
    </servlet-mapping>

</web-app>
案例四:手动移除和注销session
package com.mike.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 SessionDemo04 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session = req.getSession();
        //removeAttribute()     移除节点
        session.removeAttribute("name");
        //invalidate()  注销session
        session.invalidate();
    }

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

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_3_1.xsd"
         version="3.1"
         metadata-complete="true">

   
    <servlet>
        <servlet-name>SessionDemo01</servlet-name>
        <servlet-class>com.mike.servlet.SessionDemo01</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>SessionDemo01</servlet-name>
        <url-pattern>/s1</url-pattern>
    </servlet-mapping>

   
    <servlet>
        <servlet-name>SessionDemo04</servlet-name>
        <servlet-class>com.mike.servlet.SessionDemo04</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>SessionDemo04</servlet-name>
        <url-pattern>/s4</url-pattern>
    </servlet-mapping>

</web-app>
案例五:自动注销session

在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_3_1.xsd"
         version="3.1"
         metadata-complete="true">

    <servlet>
        <servlet-name>SessionDemo01</servlet-name>
        <servlet-class>com.mike.servlet.SessionDemo01</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>SessionDemo01</servlet-name>
        <url-pattern>/s1</url-pattern>
    </servlet-mapping>


    <servlet>
        <servlet-name>SessionDemo04</servlet-name>
        <servlet-class>com.mike.servlet.SessionDemo04</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>SessionDemo04</servlet-name>
        <url-pattern>/s4</url-pattern>
    </servlet-mapping>

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

</web-app>

image-20220428202248079

8、JSP

8.1、什么是JSP

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

最大的特点:

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

8.2、JSP原理

思路:JSP到底怎么执行的!

  • 代码层面没有任何问题

  • 服务器内部工作

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

image-20220428204320414

具体的地址可以在idea启动Tomcat时,在控制台的Server区域的Output可以看到

image-20220428204737302

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

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

JSP本质上就是一个Servlet

剖析源码

右键选择记事本打开index_jsp.java文件

//初始化
public void _jspInit() {
}
//销毁
public void _jspDestroy() {
}
//JSPService
public void _jspService(HttpServletRequest request,HttpServletResponse response)
  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:当前页
    HttpServletRequest request							//请求
    HttpServletResponse response						//响应
    
  3. 输出页面前增加的代码

    response.setContentType("text/html");			//设置响应的页面类型
    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;
    
  4. 以上的这些个对象我们可以在JSP页面中直接使用!

image-20220428212142332

在JSP页面中;

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

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

out.write("<html>\n");
out.write("<body>\n");
out.write("<h2>Hello World!</h2>\n");
out.write("</body>\n");
out.write("</html>\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>");
%>

image-20220501192502242

脚本片段的再实现

  <%
    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,Word!</h1>
  <%
    }
  %>

image-20220501193242976

还可以在Hello,Word!后面追加Java表达式

<%--在代码嵌入HTML元素--%>
<%
for (int i = 0; i < 5; i++) {

    %>
<h1>Hello,Word!<%= i%></h1>
<%
}
%>

jsp声明

<%--jsp声明
    作用域是全局的
--%>
<%!
    static {
    	System.out.println("Loading Servlet!");
    }
    private int globalVar = 0;

    public void run() {
        System.out.println("进入了方法run!");
    }
%>

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

在JSP,嵌入ava代码即可!

EL表达式

<%--在代码嵌入HTML元素--%>
<%--EL表达式
    用${}取java代码的值
--%>
<% for(int i = 0; i < 5; i++) { %>
	<h1>Hello,Wor1d ${i} </h1>
<% } %>

总汇

<% %>					这是jsp脚本片段
<%= %>					这是jsp表达式
<%! %>					这是jsp声明(全局)
<%--注释内容--%>

  <!--我是HTML的注释-->
  <%--我是ISP的注释--%>

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

8.4、JSP指令

page指令

定制错误页面

404和500

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">

    <error-page>
        <error-code>404</error-code>
        <location>/error/404.jsp</location>
    </error-page>
    <error-page>
        <error-code>500</error-code>
        <location>/error/500.jsp</location>
    </error-page>
</web-app>

404.jsp

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

</body>
</html>

500.jsp

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

</body>
</html>

image-20220501204105533

或者这样写

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

<%--定制错误页面--%>
<%--<%@ page errorPage="error/500.jsp" %>--%>
<%--显示的声明这是一个错误页面--%>
<%@ page isErrorPage="true" %>

<%@ page pageEncoding= "UTF-8" %>


<html>
<head>
    <title>Title</title>
</head>
<body>

<%
    int x = 1/0;
%>

</body>
</html>

include指令

提取公共页

<%@include file=""%>
拼接页面

header.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<h1>我是Header</h1>

footer.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<h1>我是Footer</h1>

jsp3.jsp

<html>
<head>
    <title>Title</title>
</head>
<body>
        <%@include file="/common/header.jsp" %>
        <h1>网页主体</h1>
        <%@include file="/common/footer.jsp" %>
</body>
</html>

image-20220501205712042

另一种拼接网页的jsp方法

jsp标签

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%@include file="/common/header.jsp" %>
    <h1>网页主体</h1>
    <%@include file="/common/footer.jsp" %>
    <hr>
    <%--jSP标签--%>
    <jsp:include page="/common/header.jsp"/>
    <h1>网页主体</h1>
    <jsp:include page="/common/footer.jsp"/>
</body>
</html>

image-20220501210229328

8.5、九大内置对象

  • pageContext  存东西

  • Request  存东西

  • Response

  • Session  存东西

  • Application【ServletContext】  存东西

  • conflig【ServletConfig】

  • out

  • page  几乎用不到,了解即可

  • exception

pageContext.setAttribute("name1","上官宝1号");//保存的数据只在一个页面中有效
request.setAttribute("name2","上官宝2号");//保存的数据只在一次请求中有效,请求转发会携带这个数据
session.setAttribute("name3","上官宝3号");//保存的数据只在一次会话中有效,从打开浏览器到关闭浏览器
application.setAttribute("name4","上官宝4号");//保存的数据只在服务器中有效,从打开服务器到关闭服务器(保存的最久,因为在服务器中)
  • request:客户端向服务器发送请求,产生的数据,用户看完就没用了,比如:新闻,用户看完没用的!
  • session:客户端向服务器发送请求,产生的数据,用户用完一会还有用, 比如:购物车;
  • application:客户端向服务器发送请求,产生的数据,一个用户用完了,其他用户还可能使用,比如:聊天数据;

用内置对象存值并取值

pageContextDemo01.jsp

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

<%--内置对象--%>

<%
    pageContext.setAttribute("name1","上官宝1号");
    request.setAttribute("name2","上官宝2号");
    session.setAttribute("name3","上官宝3号");
    application.setAttribute("name4","上官宝4号");
%>

<%--注意,脚本片段中的代码是java代码,会被原封不动的生成到jsp.java中,要注意注释的方式--%>
<%
    /*通过pageContext取出我们保存的值,我们通过寻找的方式来*/
    String name1 = (String) pageContext.findAttribute("name1");
    String name2 = (String) pageContext.findAttribute("name2");
    String name3 = (String) pageContext.findAttribute("name3");
    String name4 = (String) pageContext.findAttribute("name4");
    String name5 = (String) pageContext.findAttribute("name5");//不存在,
%>
<%--使用EL表达式输出   ${} --%>
<h1>取出的值为:</h1>
<h3>${name1}</h3>
<h3>${name2}</h3>
<h3>${name3}</h3>
<h3>${name4}</h3>
<h3>${name5}</h3>
</body>
</html>

运行后

可以看到,EL表达式没有打印不存在的值。这是比较理想的,也是我们想看到的。

image-20220504195331133

如果不用EL表达式取一个不存在的值,用传统的jsp表达式取值,网页会打印出什么

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

<%--内置对象--%>

<%
    pageContext.setAttribute("name1","上官宝1号");
    request.setAttribute("name2","上官宝2号");
    session.setAttribute("name3","上官宝3号");
    application.setAttribute("name4","上官宝4号");
%>

<%--注意,脚本片段中的代码是java代码,会被原封不动的生成到jsp.java中,要注意注释的方式--%>
<%
    /*通过pageContext取出我们保存的值,我们通过寻找的方式来*/
    String name1 = (String) pageContext.findAttribute("name1");
    String name2 = (String) pageContext.findAttribute("name2");
    String name3 = (String) pageContext.findAttribute("name3");
    String name4 = (String) pageContext.findAttribute("name4");
    String name5 = (String) pageContext.findAttribute("name5");//不存在,
%>
<%--使用EL表达式输出   ${} --%>
<h1>取出的值为:</h1>
<h3>${name1}</h3>
<h3>${name2}</h3>
<h3>${name3}</h3>
<h3>${name4}</h3>
<h3><%=name5%></h3>//这里我们用传统的jsp表达式取值
</body>
</html>

运行后

可以看到传统的jsp表达式打印出了一个null,这是我们不想看到的,所以推荐使用EL表达式取值

image-20220504195820770

解释内置对象的作用域

先运行一遍pageContextDemo01.jsp

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

<%--内置对象--%>

<%
    pageContext.setAttribute("name1","上官宝1号");//保存的数据只在一个页面中有效
    request.setAttribute("name2","上官宝2号");//保存的数据只在一次请求中有效,请求转发会携带这个数据
    session.setAttribute("name3","上官宝3号");//保存的数据只在一次会话中有效,从打开浏览器到关闭浏览器
    application.setAttribute("name4","上官宝4号");//保存的数据只在服务器中有效,从打开服务器到关闭服务器(保存的最久,因为在服务器中)
%>

<%--注意,脚本片段中的代码是java代码,会被原封不动的生成到jsp.java中,要注意注释的方式--%>
<%
    /*通过pageContext取出我们保存的值,我们通过寻找的方式来*/
    //从底层到高层(作用域) :
    String name1 = (String) pageContext.findAttribute("name1");
    String name2 = (String) pageContext.findAttribute("name2");
    String name3 = (String) pageContext.findAttribute("name3");
    String name4 = (String) pageContext.findAttribute("name4");
    String name5 = (String) pageContext.findAttribute("name5");//不存在,
%>
<%--使用EL表达式输出   ${} --%>
<h1>取出的值为:</h1>
<h3>${name1}</h3>
<h3>${name2}</h3>
<h3>${name3}</h3>
<h3>${name4}</h3>
<h3><%=name5%></h3>

</body>
</html>

然后运行下面代码,pageDemo03.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%
    /*通过pageContext取出我们保存的值,我们通过寻找的方式来*/
    //从底层到高层(作用域) :
    String name1 = (String) pageContext.findAttribute("name1");
    String name2 = (String) pageContext.findAttribute("name2");
    String name3 = (String) pageContext.findAttribute("name3");
    String name4 = (String) pageContext.findAttribute("name4");
    String name5 = (String) pageContext.findAttribute("name5");//不存在,
%>
<%--使用EL表达式输出   ${} --%>
<h1>取出的值为:</h1>
<h3>${name1}</h3>
<h3>${name2}</h3>
<h3>${name3}</h3>
<h3>${name4}</h3>
<h3>${name5}</h3>
</body>
</html>

运行后看到只取到3号和4号

因为3号存在session中,4号存在application中,这两个的作用域是在pageContext和request之上的

可以在不同的页面取到。

image-20220504201335987

分析源码

进入setAttribute()的源码

//scope: 作用城
public void setAttribute(String name, Object attribute, int scope) {
    switch(scope) {
    case 1:
        this.mPage.put(name, attribute);
        break;
    case 2:
        this.mRequest.put(name, attribute);
        break;
    case 3:
        this.mSession.put(name, attribute);
        break;
    case 4:
        this.mApp.put(name, attribute);
        break;
    default:
        throw new IllegalArgumentException("Bad scope " + scope);
    }
}

JSP页面请求转发

pageContextDemo03.jsp

<html>
<head>
    <title>Title</title>
</head>
<body>
<%
    /*页面请求转发*/
    pageContext.forward("/index.jsp");
    //下面这个是后台对页面请求转发,上面是前端对页面请求转发。
    //request.getRequestDispatcher("/index. jsp").forward(request, response);
%>
</body>
</html>

注意看路径,访问路径没改变,但是请求转发到了index.jsp页面

image-20220504203523543

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

需要用到的包

pom.xml

<!--JSTL表达式的依赖-->
<!--注意:EL表达式是不需要导包的,要用JSTL才要到JSTL的包-->
<!--webapp3.2版本之前默认不打开EL表达式-->
<dependency>
    <groupId>javax.servlet.jsp.jstl</groupId>
    <artifactId>jstl-api</artifactId>
    <version>1.2</version>
</dependency>
<!--standard标签库-->
<dependency>
    <groupId>taglibs</groupId>
    <artifactId>standard</artifactId>
    <version>1.1.2</version>
</dependency>

EL表达式:    ${}

  • 获取数据
  • 执行运算
  • 获取web开发的常用对象

JSP标签

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>1</h1>
<%--
<jsp:include>
上面的jsp:include是用来拼接页面的,前面已经讲过了,这里不再叙述
--%>
<%--请求转发到jsptag2.jsp页面--%>
<%--
    相对于在地址栏携带了2个参数,name和age
    http://localhost:8080/jsptag.jsp?name=mike&age=18
--%>
<jsp:forward page="/jsptag2.jsp">
    <jsp:param name="name" value="mike"/>
    <jsp:param name="age" value="18"/>
</jsp:forward>

</body>
</html>

JSTL表达式

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

  • 核心标签 (掌握部分)

  • 格式化标签(几乎用不到就没有讲解)

  • SQL标签(几乎用不到就没有讲解)

  • XML标签 (几乎用不到就没有讲解)

核心标签
<%--
核心标签
核心标签是最常用的 JSTL标签。引用核心标签库的语法如下:
--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

核心标签常用的几个方法

image-20220505194158829

JSTL标签库使用步骤

  • 引入对应的taglib
  • 使用其中的方法
  • 在Tomcat也需要引入jstl的包,否则会报错: JSTL解析错误
< c:if >

登录验证用户例

< c:if >

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--引入JSTL核心标签库,我们才能使用ISTL标签, prefix="c"代表core--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<h4>if测试</h4>
<hr>

<form action="coreif.jsp" method="get">
    <%--
        EL表达式获取表单中的数据
        ${param.参数名}
    --%>
    <input type="text" name="username" value="${param.username}">
    <input type="submit" value="登录">
</form>
<%-- 判断如果提交的用户名是管理员,则登录成功--%>
<%--
<%
if (request.getParameter("username").equals("admin")){
    out.print("登录成功");
}
%>
--%>
<c:if test="${param.username=='admin'}" var="isAdmin">
    <c:out value="管理员,欢迎你~"/>
</c:if>
<c:out value="${isAdmin}"/>
</body>
</html>

没有输入任何信息之前

image-20220505201653243

输入admin后

image-20220505201711906

< c:set >、< c:choose >

< c:set >

< c:choose >

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<%--定义一个变量score,值为99--%>
<c:set var="score" value="99"/>

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

image-20220505203604827

< c:forEach >

< c:forEach >

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<%
    ArrayList<String> people = new ArrayList<>();
    people.add(0,"上官宝");
    people.add(1,"玲珑");
    people.add(2,"雷霆");
    people.add(3,"易小雯");
    people.add(4,"易中天");
    request.setAttribute("list",people);
%>
<%--
var,每一次遍历出来的变量
items,要遍历的对象
begin,  哪里开始
end,    到哪里结束
step,   步长
--%>
<c:forEach var="person" items="${list}">
    <c:out value="${person}"/><br>
</c:forEach>

<hr>
<%--这里的step可以想象成java里面for循环里的自增条件,i++那个--%>
<c:forEach var="person" items="${list}" begin="1" end="3" step="2">
    <c:out value="${person}"/><br>
</c:forEach>
</body>
</html>

image-20220505210803658

9、JavaBean

实体类

JavaBean有特定的写法:

  • 必须要有一个无参构造;
  • 属性必须私有化;
  • 必须有对应的get/set方法;

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

ORM:对象关系映射

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

数据库的people表

id name age address
1 上官宝1号 18 长春
2 上官宝2号 50 西安
3 上官宝3号 100 秦岭

People实体类

package com.mike.pojo;

//实体类我们一般都是和数据库中的表结构一一对应!
public class People {
    private int id;
    private String name;
    private int age;
    private String address;

    public People() {
    }

    public People(int id, String name, int age, String address) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "People{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }
}

jsp文件

<%@ page import="com.mike.pojo.People" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<%
//    People people1 = new People();
//    people1.setId(2);
//    people1.setName("玲珑");
//    people1.setAge(18);
//    people1.setAddress("秦岭");
%>

<%-- new一个People对象 --%>
<jsp:useBean id="people" class="com.mike.pojo.People" scope="page"/>

<%--给属性赋值--%>
<jsp:setProperty name="people" property="id" value="1"/>
<jsp:setProperty name="people" property="name" value="上官宝"/>
<jsp:setProperty name="people" property="age" value="19"/>
<jsp:setProperty name="people" property="address" value="长春"/>

<%--获取属性值--%>
<%--下面的取值等价于<%= people1.getId()%>--%>
ID:<jsp:getProperty name="people" property="id"/><br>
姓名:<jsp:getProperty name="people" property="name"/><br>
年龄:<jsp:getProperty name="people" property="age"/><br>
住址:<jsp:getProperty name="people" property="address"/>

</body>
</html>

image-20220505214556795

后面要讲的内容有:

  • 过滤器
  • 文件上传
  • 邮件发送
  • JDBC复习:如何使用JDBC,JDBC crud,jdbc 事务

10、MVC三层架构

什么是MVC:Model  View  Controller 模型、视图、控制器

10.1、早些年

这时候只有VC两层架构

早些年controller和view通过直接连接Javabean

image-20220529124932103

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

servlet--CRUD-->数据库
弊端:程序十分臃肿,不利于维护
servlet的代码中:处理请求、响应、视图跳转、处理JDBC、处理业务代码、处理逻辑代码
    
架构:没有什么是加一层解决不了的!
程序猿调用
 |
JDBC
 |
Mysq1 oracle SqlServer

10.2、三层架构

这时候出现了M层,才有了mvc三层架构

image-20220529131259018

Model

  • 业务处理:业务逻辑 (Service)
  • 数据持久层:CRUD (Dao)

View

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

Controller

  • 接收用户的请求:(req:请求参数、Session信息….)
  • 交给业务层处理对应的代码
  • 控制视图的跳转
登录--->接收用户的登录请求--->处理用户的请求(获取用户登录的参数,username, password)---->交给业务层处理登录业务(判断用户名密码是否正确:事务)--->Dao层查询用户名和密码是否正确-->数据库

11、Filter(过滤器)

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

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

image-20220529133143512

Filter开发步骤

1.导包

2.编写过滤器

1、导包

导包不要错

image-20220529140246490

2、编写过滤器

ShowServlet类

package com.mike.servlet;

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

public class ShowServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //解决中文乱码,但是以后基本上不会这么解决乱码问题,我们会用过滤器解决中文乱码问题
        /*resp.setContentType("text/html;charset=utf-8");*/
        resp.getWriter().write("你好!世界");
    }

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

CharacterEncodingFilter类(过滤器,这里的过滤器是用来过滤乱码的)

package com.mike.filter;

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

public class CharacterEncodingFilter implements Filter {

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

    //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("CharacterEncodingFilter执行前......");
        chain.doFilter(request,response);//让我们的请求继续走,如果不写,程序到这里就被拦截停止!
        System.out.println("CharacterEncodingFilter执行后......");
    }

    //销毁,关闭服务器(也就是关闭Tomcat)的时候才会出现销毁过滤器
    @Override
    public void destroy() {
        System.out.println("CharacterEncodingFilter销毁");
    }
}

3、在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">
    
    <servlet>
        <servlet-name>ShowServlet</servlet-name>
        <servlet-class>com.mike.servlet.ShowServlet</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>ShowServlet</servlet-name>
        <url-pattern>/servlet/show</url-pattern><!--注意这里的请求是会经过过滤器的-->
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>ShowServlet</servlet-name>
        <url-pattern>/show</url-pattern><!--注意这里的请求是不会经过过滤器的-->
    </servlet-mapping>
    
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>com.mike.filter.CharacterEncodingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <!--只要是/servlet的任何请求,都会经过这个过滤器,这也就是为什么会在/show前面加/servlet-->
        <url-pattern>/servlet/*</url-pattern>
    </filter-mapping>
</web-app>

启动Tomcat,首先访问localhost:8080/show

这是没有经过过滤器的请求,出现乱码

image-20220529144022253

然后访问localhost:8080/servlet/show

这是经过过滤器的请求,中文正常显示

image-20220529144155266

12、监听器

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

统计网站在线人数

index.jsp

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

  <h1>当前在线人数:<span style="color: blue"><%=this.getServletConfig().getServletContext().getAttribute("OnlineCount")%></span></h1>

  </body>
</html>

OnlineCountListener类

package com.mike.listener;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

//统计网站在线人数:统计session(因为一个session对应一个用户)
public class OnlineCountListener implements HttpSessionListener {
    //创建session监听:看你的一举一动
    //一但创建Session就会触发一次这个事件!
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        ServletContext ctx = se.getSession().getServletContext();

        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就会触发一次这个事件!
    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        ServletContext ctx = se.getSession().getServletContext();

        //输出session的id
        System.out.println(se.getSession().getId());

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

        /*
        Session销毁
        1.手动销毁
            se.getSession().invalidate();
        2.自动销毁(在web.xml中配置)
            <session-config>
                //1分钟后自动销毁session
                <session-timeout>1</session-timeout>
            </session-config>
        */
    }
}

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">
    
    <!--注册监听器-->
    <listener>
        <listener-class>com.mike.listener.OnlineCountListener</listener-class>
    </listener>

</web-app>

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

13.1、GUI的监听关闭窗口事件

TestPanel类

package com.mike.listener;

import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

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(Color.BLUE);//设置窗体的背景颜色

        panel.setBounds(50,50,300,300);
        panel.setBackground(Color.pink);//设置面板的背景颜色

        frame.add(panel);

        frame.setVisible(true);

        //监听事件,关闭窗口事件
/*      //这里我们有个模式叫适配器模式,我们只要重写他的子类即可
    frame.addWindowListener(new WindowListener() {
            @Override
            public void windowOpened(WindowEvent e) {
                System.out.println("打开");
            }

            @Override
            public void windowClosing(WindowEvent e) {
                System.out.println("关闭ing");
                *//*这里可以写0或1,
                0:正常终止
                1:异常终止
                *//*
                System.exit(0);

            }

            @Override
            public void windowClosed(WindowEvent e) {
                System.out.println("关闭ed");
            }

            @Override
            public void windowIconified(WindowEvent e) {

            }

            @Override
            public void windowDeiconified(WindowEvent e) {

            }

            @Override
            public void windowActivated(WindowEvent e) {
                System.out.println("激活");
            }

            @Override
            public void windowDeactivated(WindowEvent e) {
                System.out.println("未激活");
            }
        });*/
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
    }
}

13.2、登录验证权限拦截

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

login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>登录</h1>
<%--<form action="${pageContext.request.contextPath}/servlet/login" method="post">
    <input type="text" name="username">
    <input type="submit">
</form>--%>

<form action="/servlet/login" method="post">
    <input type="text" name="username">
    <input type="submit">
</form>

</body>
</html>

success.jsp(成功页面)

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

<%--<%
    Object userSession = request.getSession().getAttribute("USER_SESSION");
    if (userSession==null){
       response.sendRedirect("/login.jsp");
    }
%>--%>


<h1>主页</h1>

<p><a href="/servlet/logout">注销</a></p>


</body>
</html>

error.jsp(错误页面)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>失败页面</h1>
<h3>没有权限</h3>

<a href="/login.jsp">返回登录页面</a>
</body>
</html>

Constant类

(把一个全局静态属性单独放在一个工具类里面,因为后面有很多地方要用到这个属性,方便以后在修改属性的值的时候,不用全部改一遍,只需要修改工具类的一个值,其他地方用到这个值只需要 类名.属性 即可)

package com.mike.util;

public class Constant {
    //全局唯一的常量
    public final static String USER_SESSION = "USER_SESSION";
}

LoginServlet类(登录)

package com.mike.servlet;

import com.mike.util.Constant;

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

public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取前端请求的参数
        String username = req.getParameter("username");

        if (username.equals("admin")){//登录成功
            req.getSession().setAttribute(Constant.USER_SESSION,req.getSession().getId());
            resp.sendRedirect("/sys/success.jsp");
        }else {//登录失败
            resp.sendRedirect("/error.jsp");
        }
    }

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

LogoutServlet类(注销)

package com.mike.servlet;

import com.mike.util.Constant;

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

public class LogoutServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Object user_session = req.getSession().getAttribute(Constant.USER_SESSION);
        if (user_session!=null){
            req.getSession().removeAttribute(Constant.USER_SESSION);
            resp.sendRedirect("/login.jsp");
        }else {
            resp.sendRedirect("/login.jsp");
        }
    }

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

SysFilter类

(当session中不存在待查找的属性时,直接输入成功页面的地址时,应该进入error.jsp页面(即未登录不允许越过登录页面直接进入成功页面))

package com.mike.filter;

import com.mike.util.Constant;

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

public class SysFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //ServletRequest----->HttpServletRequest
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        Object user_session = request.getSession().getAttribute(Constant.USER_SESSION);

        if (user_session==null){
            response.sendRedirect("/error.jsp");
        }

        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {

    }
}

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">


    <servlet>
        <servlet-name>LoginServlet</servlet-name>
        <servlet-class>com.mike.servlet.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LoginServlet</servlet-name>
        <url-pattern>/servlet/login</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>LogoutServlet</servlet-name>
        <servlet-class>com.mike.servlet.LogoutServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LogoutServlet</servlet-name>
        <url-pattern>/servlet/logout</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>SysFilter</filter-name>
        <filter-class>com.mike.filter.SysFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>SysFilter</filter-name>
        <url-pattern>/sys/*</url-pattern>
    </filter-mapping>

    
    <servlet>
        <servlet-name>ShowServlet</servlet-name>
        <servlet-class>com.mike.servlet.ShowServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>ShowServlet</servlet-name>
        <url-pattern>/servlet/show</url-pattern><!--注意这里的请求是会经过过滤器的-->
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>ShowServlet</servlet-name>
        <url-pattern>/show</url-pattern><!--注意这里的请求是不会经过过滤器的-->
    </servlet-mapping>
	<!--乱码过滤器-->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>com.mike.filter.CharacterEncodingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <!--只要是/servlet的任何请求,都会经过这个过滤器,这也就是为什么会在/show前面加/servlet-->
        <url-pattern>/servlet/*</url-pattern>
    </filter-mapping>
    
</web-app>

首先进入login.jsp页面

image-20220529210122635

输入123后

image-20220529210158262

点击“返回登录页面”,输入admin后,成功进入success.jsp页面

image-20220529210307375

复制地址“http://localhost:8080/sys/success.jsp”然后点击注销,

会回到登录页面,直接在登录页面输入刚刚复制的地址,会被重定向到error.jsp页面。

(因为没有登录的用户不能越过权限直接进入成功页面)

image-20220529210417462

14、复习JDBC

什么是JDBC:Java连接数据库

J———》Java

DB—–》DataBase 数据库

C——-》Connection 连接

image-20220529212948852

需要jar包的支持:

  • java.sql
  • javax.sql
  • mysql-connector-java  连接驱动(必须要导入的jar包)

14.1、数据库环境搭建

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,'上官宝','10086','10086@163.com','1999-09-09');

INSERT INTO users(id,`name`,`password`,email,birthday)
VALUES(2,'玲珑','10011','10011@qq.com','2000-06-01');

INSERT INTO users(id,`name`,`password`,email,birthday)
VALUES(3,'雷霆','10088','10088@163.com','1998-09-08');

SELECT * FROM users

14.2、导入数据库依赖

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

14.3、IDEA连接数据库

image-20220530153402334

14.4、JDBC固定步骤

  1. 加载驱动
  2. 连接数据库
  3. 向数据库发送SQL的对象Statement :CRUD
  4. 编写SQL(根据业务,不同的SQL)
  5. 执行SQL
  6. 关闭连接释放资源(一定要做的事情)(关闭原则:先开后关)

用Java从数据库中查询数据

package com.dh.test;

import java.sql.*;

public class TestJdbc {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //配置信息
        //useUnicode=true&characterEncoding=UTF-8   解决中文乱码问题
        String url = "jdbc:mysql://localhost:3306/jdbc?serverTimezone=UTC&useSSL=true&useUnicode=true&characterEncoding=UTF-8";
        String username = "root";
        String password = "123456";

        //1.加载驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //2.连接数据库,代表数据库
        Connection connection = DriverManager.getConnection(url, username, password);

        //3.向数据库发送SQL的对象Statement,PreparedStatement	:CRUD
        Statement statement = connection.createStatement();

        //4.编写SQL
        String sql = "select * from users";

        //5.执行查询SQL,返回一个ResultSet   :结果集
        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"));
        }

        //6.关闭连接释放资源(一定要做的事情)(关闭原则:先开后关)
        rs.close();
        statement.close();
        connection.close();
    }
}

用Java向数据库插入数据

(这里使用另一种预处理PreparedStatement方式,上面的Statement方式也可以插入数据,只不过是不安全的。)

package com.dh.test;

import java.sql.*;

public class TestJdbc2 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //配置信息
        //useUnicode=true&characterEncoding=UTF-8   解决中文乱码问题
        String url = "jdbc:mysql://localhost:3306/jdbc?serverTimezone=UTC&useSSL=true&useUnicode=true&characterEncoding=UTF-8";
        String username = "root";
        String password = "123456";

        //1.加载驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //2.连接数据库,代表数据库
        Connection connection = DriverManager.getConnection(url, username, password);

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

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

        preparedStatement.setInt(1,5);//给第一个占位符? 的值赋值为1;
        preparedStatement.setString(2,"易中天");//给第二个占位符? 的值赋值为易中天;
        preparedStatement.setString(3,"10089");//给第三个占位符? 的值赋值为10089;
        preparedStatement.setString(4,"10089@163.com");//给第四个占位符? 的值赋值为1;
        preparedStatement.setDate(5,new Date(new java.util.Date().getTime()));//给第五个占位符? 的值赋值为new Date(new java.util.Date().getTime());

        //5.执行SQL
        int i = preparedStatement.executeUpdate();

        if (i > 0){
            System.out.println("插入成功~");
        }
        //6.关闭连接释放资源(一定要做的事情)(关闭原则:先开后关)
        preparedStatement.close();
        connection.close();
    }
}

14.5、JDBC事务

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

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

开启事务
事务提交	commit()
事务回滚	rollback()
关闭事务
    
转账
A:1000	
B:1000

A ---100-->	B
A:900	
B:1100

14.6、Junit(单元测试)

依赖

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
</dependency>

简单使用

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

import org.junit.Test;

public class TestJdbc3 {

    //可以使用Junit单独执行任何一个类的任何一个方法。不需要在main方法里面new一个类再去调用这个方法
    @Test
    public void test(){
        System.out.println("Hello~");
    }
}

image-20220530165258084

搭建环境

创建一张account表

CREATE TABLE `account` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(40) DEFAULT NULL,
  `money` decimal(10,0) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;


insert  into `account`(`id`,`name`,`money`) values (1,'A','700'),(2,'B','1700'),(3,'C','1100');

测试转账问题

package com.dh.test;

import org.junit.Test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class TestJdbc3 {

    @Test
    public void test() {
        //配置信息
        //useUnicode=true&characterEncoding=UTF-8   解决中文乱码问题
        String url = "jdbc:mysql://localhost:3306/jdbc?serverTimezone=UTC&useSSL=true&useUnicode=true&characterEncoding=UTF-8";
        String username = "root";
        String password = "123456";
        //提升connection的作用域
        Connection connection =null;

        //1.加载驱动
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");

            //2.连接数据库,代表数据库
            connection = DriverManager.getConnection(url, username, password);

            //3.通知数据库开启事务,false是开启
            connection.setAutoCommit(false);

            String sql = "update jdbc.account set money = money-100 where name = 'A'";
            connection.prepareStatement(sql).executeUpdate();

            //制造一个错误
            //int i = 1/0;

            String sql2 = "update jdbc.account set money = money+100 where name = 'B'";
            connection.prepareStatement(sql2).executeUpdate();

            connection.commit();    //以上两条SQL都执行成功了,才提交事务!
            System.out.println("提交成功~");

        } catch (Exception e) {
            try {
                //如果出现异常,就通知数据库回滚事务
                connection.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            e.printStackTrace();
        }finally {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
版权声明:本文为海边蓝贝壳原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/ldh-0319/p/16196367.html