CoderZQYのBlog

个人不定期更新的学习周报

0%

javaweb进阶学习

JavaWeb进阶学习

配合学习视频:狂神说Java—JavaWeb入门到实战

内容主要包括:

  • web开发基本概念
  • Tomcat服务器的学习和使用
  • Maven项目的搭建
  • Servlet介绍
  • Cookie、Session
  • Jsp
  • MVC架构
  • 过滤器Filter、监听器Listener
  • JDBC

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资源,可以被外界访问,对外界提供服务;
  • 能访问到的任何一个页面或者资源,都存在于世界上的某一个计算机;
  • URL:统一资源定位符
  • 这个统一的web资源会被放在同一个文件夹下,web应用程序—>Tomcat:服务器
  • 一个web应用由多部份组成(静态web、动态web)
    • html、css、js
    • jsp、servlet
    • Java程序
    • jar包
    • 配置文件(Properties)
  • web应用程序编写完毕后,若想提供给外界访问,需要一个服务器来统一管理

1.3、静态web

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

image-20210222143234818

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

1.4、动态web

页面展示的效果会因人而异

image-20210222144143176

缺点:

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

优点:

  • Web页面可以动态更新,所有用户看到的都不是同一个页面
  • 可以与数据库进行交互(可以数据持久化)

image-20210222144553507

2、web服务器

2.1、技术讲解

  1. ASP
  • 微软:国内最早流行的就是ASP
  • 在HTML中嵌入了VB脚本,ASP+COM
  • 在ASP开发中,基本一个页面都有几千行的业务代码,页面及其混乱
  • 维护成本高
  • C#
  • IIS
  1. php
  • PHP开发速度很快,功能很强大,跨平台,代码简单
  • 缺点:无法承载大访问量的情况(局限性)
  1. JSP/Servlet
  • sun公司主推的B/S架构

  • 基于Java语言(所有的大公司,或者一些开源的组件,都是用Java语言写的)

  • 可以承载三高(高并发、高可用、高性能)问题带来的影响

  • 语法像ASP,易于ASP程序员转JSP,加强市场强度

    ……

2.2、web服务器

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

  1. IIS

微软的,ASP…,Windows自带的

  1. Tomcat

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

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

Tomcat 实际上运行JSP 页面和Servlet。目前Tomcat最新版本为9.0.41

……

ps. 工作3-5年后可尝试手写Tomcat服务器(了解底层原理);

下载Tomcat:

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

3、Tomcat

3.1、安装Tomcat

Tomcat官网

image-20210222151743336

3.2、Tomcat启动和关闭

image-20210222152144770

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

可能遇到的问题:

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

image-20210222152442488

3.3、配置

可以配置启动的端口号

  • Tomcat的端口号:8080
  • mysql:3306
  • http:80
  • https:443
1
2
3
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />

可以配置主机名称

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

面试题:请你谈谈网站是如何进行访问的?

  1. 输入一个域名,回车
  2. 检查本机的C:\Windows\System32\drivers\etc\hosts配置文件下有没有对应这个域名的映射
    1. 有,返回对应的ip地址
    2. 没有,去DNS服务器进行域名解析,获取ip地址

3.4、发布一个web网站

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

网站应该有的结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
--webapps : Tomcat服务器的web目录
-ROOT
-webname : 网站的目录名
-WEB-INF
-classes : java程序
-lib : web应用所依赖的jar包
-web.xml : 网站的配置文件
-intdex.html 默认的首页
-static
-css
-style.css
-js
-img
-......

4、Http

4.1、什么是Http

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

  • 文字:html、字符串…
  • 超文本:图片、音乐、视频、地图…
  • 端口号:80

Https:安全的

  • 端口号:443

4.2、两个时代

  • http1.0

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

    • HTTP/1.1:客户端与web服务器连接后,可以获得多个web资源。

4.3、Http请求

  • 客户端—发请求(Request)—服务器

百度:

1
2
3
4
请求 URL: https://www.baidu.com/	 请求地址
请求方法: GET get方法/post方法
状态代码: 200 OK 状态码
远程地址: 110.242.68.4:443
1
2
3
4
5
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cache-Control: max-age=0
Connection: keep-alive
  • 请求行

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

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

4.4、Http响应

  • 服务器—响应—客户端

百度:

1
2
3
4
Cache-Control: private		缓存控制
Connection: keep-alive 连接
Content-Encoding: gzip 编码
Content-Type: text/html 类型
  • 响应体

1
2
3
4
5
6
7
8
Accept				告诉浏览器,它所支持的数据类型
Accept-Encoding 支持哪种编码格式 GBK、UTF-8、GB2312、ISO8859-1
Accept-Language 告诉浏览器,它的语言环境
Cache-Control 缓存控制
Connection 告诉浏览器,请求完成是断开,还是保持连接
Host 主机
Refresh 告诉客户端,多久刷新一次
Location 让网页重新定位
  • 响应请求码

200:请求响应成功

3xx:请求重定向

  • 重定向:转向新的位置

4xx:找不到资源(404)

  • 资源不存在

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

面试题:当浏览器输入地址并回车的一瞬间到页面显示出来,经历了什么?(思考)

5、Maven

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

  1. 在Javaweb开发中,需要使用大量的jar包,手动导入效率低下
  2. Maven——自动导入jar包

5.1、Maven项目架构管理工具

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

5.2、下载安装Maven

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

image-20210222174202816

下载完成后解压即可

友情建议:电脑所有环境都放在一个文件夹下,方便管理

5.3、配置环境变量

在系统环境变量中,配置如下配置

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

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

image-20210222174908648

5.4、阿里云镜像

  • 镜像:mirrors
    • 作用:加速我们的下载
  • 国内建议使用阿里云的镜像
1
2
3
4
5
6
7
8
<mirrors>
<mirror>
<id>aliyunmaven</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>https://maven.aliyun.com/repository/public </url>
</mirror>
</mirrors>

5.5、本地仓库

建立一个本第仓库:localRepository

1
<localRepository>E:\Idea_jars\apache-maven-3.6.3\maven-repo</localRepository>

5.6、在IDEA中使用Maven

  1. 启动IDEA
  2. 创建一个Maven项目

image-20210222180127599

image-20210222180514095

image-20210222181107728

  1. 等待项目初始化完毕

image-20210222181408584

  1. 观察maven仓库中多了什么东西
  2. 检查IDEA中的Maven设置

注意:IDEA中配置Maven经常会出现一个问题:自动创建完成后,它这个MAVEN_HOME会使用IDEA默认,如果发现需要手动改为本地

image-20210222182145013

image-20210222182409985

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

5.7、标记文件夹功能

法一:

image-20210222211754894

法二:

image-20210222212128571

5.8、在IDEA中配置Tomcat

image-20210222212352975

image-20210222212531734

image-20210222213319824

解决警告问题:

image-20210222213455024

image-20210222213543756

image-20210222214237961

image-20210222214624913

5.9、pom文件

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<?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.zqy</groupId>
<artifactId>javaweb_learn</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>
<scope>test</scope>
</dependency>
</dependencies>

<!--项目构建用的东西,不需要可删掉-->
<build>
<finalName>javaweb_learn</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>

6、Servlet

6.1、Servlet简介

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

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

6.2、HelloServlet

Servlet接口Sun公司有两个默认实现类:HttpServlet、GenericServlet

  1. 编写一个Servlet程序
    1. 编写一个普通类
    2. 实现Servlet接口,这里我们直接继承HttpServlet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//响应类型
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
//获取响应的输出流
PrintWriter out = resp.getWriter();
out.println("HttpServlet类");
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
  1. 编写Servlet的映射

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

  2. 配置Tomcat

    注意:配置项目发布的路径就可以了

  3. 启动测试,OK!

6.3、Servlet原理

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

image-20210223001832555

6.4、Mapping问题

  1. 一个Servlet可以指定一个映射路径
1
2
3
4
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mappng>
  1. 一个Servlet可以指定多个映射路径
1
2
3
4
5
6
7
8
9
10
11
12
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/hello1</url-pattern>
</servlet-mappng>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mappng>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/hello3</url-pattern>
</servlet-mappng>
  1. 一个Servlet可以指定通用映射路径
1
2
3
4
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mappng>

默认请求路径:

1
2
3
4
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mappng>
  1. 一个Servlet可以指定一些后缀或者前缀等等…
1
2
3
4
5
6
<!--可以自定义后缀实现请求映射
注意:*前面不能加映射路径-->
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
  1. 优先级问题

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

6.5、ServletContext

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

  1. 共享数据

image-20210223004807634

  1. 获取初始化参数
1
2
3
4
5
<!--配置一些web应用初始化参数-->
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>
1
2
3
4
5
6
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String url = context.getInitParameter("url");
resp.getWriter().print(url);
}
  1. 请求转发
1
2
3
4
5
6
7
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
// RequestDispatcher requestDispatcher = context.getRequestDispatcher("/hello");//转发的请求路径
// requestDispatcher.forward(req,resp);//调用forward实现转发请求
context.getRequestDispatcher("/hello").forward(req,resp);
}
  1. 读取资源文件

Properties

  • 在Java目录下新建properties

    • 如果遇到Maven项src/main/java目录下配置文件无法被导出或者生效的问题和处理方案:

      在pom.xml文件的< build >标签中添加以下内容,把java目录下的文件也打包编译

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
  • 在resources目录下新建properties

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

思路:需要一个文件流

1
2
username=root
password=123456
1
2
3
4
5
6
7
8
9
10
11
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
//下面用的是相对路径,第一个斜杠(/)表示当前web应用路径下
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);
}

6.6、HttpServletResponse

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

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

1、简单分类

  1. 负责向浏览器发送数据的方法
1
2
ServletOutputStream getOutputStream() throws IOException;
PrintWriter getWriter() throws IOException;
  1. 向浏览器发送响应头的方法
1
2
3
4
5
6
7
8
9
10
11
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);
  1. 响应的状态码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
int SC_CONTINUE = 100;
int SC_SWITCHING_PROTOCOLS = 101;
int SC_OK = 200;
int SC_CREATED = 201;
int SC_ACCEPTED = 202;
int SC_NON_AUTHORITATIVE_INFORMATION = 203;
int SC_NO_CONTENT = 204;
int SC_RESET_CONTENT = 205;
int SC_PARTIAL_CONTENT = 206;
int SC_MULTIPLE_CHOICES = 300;
int SC_MOVED_PERMANENTLY = 301;
int SC_MOVED_TEMPORARILY = 302;
int SC_FOUND = 302;
int SC_SEE_OTHER = 303;
int SC_NOT_MODIFIED = 304;
int SC_USE_PROXY = 305;
int SC_TEMPORARY_REDIRECT = 307;
int SC_BAD_REQUEST = 400;
int SC_UNAUTHORIZED = 401;
int SC_PAYMENT_REQUIRED = 402;
int SC_FORBIDDEN = 403;
int SC_NOT_FOUND = 404;
int SC_METHOD_NOT_ALLOWED = 405;
int SC_NOT_ACCEPTABLE = 406;
int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
int SC_REQUEST_TIMEOUT = 408;
int SC_CONFLICT = 409;
int SC_GONE = 410;
int SC_LENGTH_REQUIRED = 411;
int SC_PRECONDITION_FAILED = 412;
int SC_REQUEST_ENTITY_TOO_LARGE = 413;
int SC_REQUEST_URI_TOO_LONG = 414;
int SC_UNSUPPORTED_MEDIA_TYPE = 415;
int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
int SC_EXPECTATION_FAILED = 417;
int SC_INTERNAL_SERVER_ERROR = 500;
int SC_NOT_IMPLEMENTED = 501;
int SC_BAD_GATEWAY = 502;
int SC_SERVICE_UNAVAILABLE = 503;
int SC_GATEWAY_TIMEOUT = 504;
int SC_HTTP_VERSION_NOT_SUPPORTED = 505;

2、常见应用

  1. 向浏览器输出信息
  2. 下载文件
    • 获取下载文件路径
    • 下载的文件名
    • 设置浏览器支持下载
    • 获取下载文件的输入流
    • 创建缓冲区
    • 获取OutputStream对象
    • 将FileOutputStream流写入到缓冲区(buffer)
    • 使用OutputStream将缓冲区中的数据输出到客户端!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、获取下载文件路径
String realPath = "E:\\java课设参考文件\\javaweb_learn\\src\\main\\resources\\头像.jpg";
System.out.println("下载文件的路径为:"+realPath);
//2、下载的文件名
String fileName = realPath.substring(realPath.lastIndexOf("\\")+1);
//3、设置浏览器支持下载,中文文件名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 outputStream = resp.getOutputStream();
//7、将FileOutputStream流写入到缓冲区(buffer)
while ((len = in.read(buffer)) != -1){
//8、使用OutputStream将缓冲区中的数据输出到客户端!
outputStream.write(buffer,0,len);
}
in.close();
outputStream.close();
}

3、验证码功能

验证怎么来的?

  • 前端实现
  • 后端实现,需要java的图片类,生成一个图片
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//如何让浏览器每3s刷新一次
resp.setHeader("refresh","3");
//在内存中创建一个图片
BufferedImage image = new BufferedImage(80,20,BufferedImage.TYPE_INT_RGB);
//得到图片
Graphics2D g = (Graphics2D)image.getGraphics(); //笔
//设置图片的背景颜色
g.setColor(Color.white);
g.fillRect(0,0,80,20);
//给图片写数据
g.setColor(Color.blue);
g.setFont(new Font(null,Font.BOLD,20));
g.drawString(randNum(),0,20);

//告诉浏览器,这个请求用图片的形式打开
resp.setContentType("image/jpg");
//网站存在缓存,不让浏览器缓存
resp.setDateHeader("expires",-1);
resp.setHeader("Cache-Control","no-cache");
resp.setHeader("Pragma","no-cache");
//把图片写给浏览器
ImageIO.write(image,"jpg", resp.getOutputStream());
}
//生成7位随机数
private String randNum(){
StringBuilder str = new StringBuilder();
Random random = new Random();
for (int i = 0; i < 7; i++) {
str.append(random.nextInt(10));
}
return str.toString();
}

4、实现重定向

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

常见场景:

  • 用户登入
1
void sendRedirect(String var1) throws IOException;

测试:

1
2
3
4
5
6
7
8
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*
resp.setHeader("Location","/zqy/header.jsp");
resp.setStatus(302); //HttpServletResponse.SC_MOVED_TEMPORARILY
*/
resp.sendRedirect("/zqy/header.jsp");
}

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

相同点:都会实现页面跳转

不同点:请求转发的时候,url不会发生跳转 307;重定向的时候url地址栏会变化 302

6.7、HttpServletRequest

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

image-20210223213038083

1、获取参数、请求转发

1
2
3
4
String getParameter(String var1);
Enumeration<String> getParameterNames();
String[] getParameterValues(String var1);
Map<String, String[]> getParameterMap();

其中getParameter() 和 getParameterValues() 重点记忆

登录示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
<h2>登录界面</h2>
<%--这里提交的路径,需要寻找到项目的路径--%>
<%--${pageContext.request.contextPath}代表当前的项目--%>
<div>
<%--这里表单表示的意思:以get方式提交表单,提交到我们的login请求--%>
<form action="${pageContext.request.contextPath}/login" method="get">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
爱好:
<input type="checkbox" name="hobbys" value="女孩">女孩
<input type="checkbox" name="hobbys" value="吉他">吉他
<input type="checkbox" name="hobbys" value="网球">网球
<input type="checkbox" name="hobbys" value="金币">金币
<br>
<input type="submit" >
</form>
</div>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@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 pwd = req.getParameter("password");
String[] hobbys = req.getParameterValues("hobbys");

System.out.println(username);
System.out.println(pwd);
System.out.println(Arrays.toString(hobbys));

//请求转发
System.out.println(req.getContextPath());
req.getRequestDispatcher("./header.jsp").forward(req,resp);
}

7、Cookie、Session

7.1、Session会话

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

有状态会话:每个用户有自己特有的一个实例,在用户的生存期内,bean保持了用户的信息,即“有状态”;一旦用户灭亡(调用结束或实例结束),bean的生命期也告结束。即每个用户最初都会得到一个初始的bean。

7.2、保存会话的两种技术

Cookie与Session是Web程序中用来跟踪用户的整个会话常用的两个技术

  • Cookie通过在客户端记录信息确定用户身份
  • Session通过在服务器端记录信息确定用户身份

7.3、Cookie

image-20210224013118157

  1. 从请求中拿到cookie信息
  2. 服务器相应给客户端cookie
1
2
3
4
5
6
Cookie[] cookies = req.getCookies();							//从客户端获取Cookie
cookie.getName() //获取cookie中的key
cookie.getValue() //获取cookie中的value
new Cookie("lastLoginTime", System.currentTimeMillis() + ""); //新建一个cookie
cookie.setMaxAge(24*60*60); //设置cookie有效期为一天
resp.addCookie(cookie); //服务器给客户端响应一个Cookie

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

一个网站的Cookie是否存在上限?

  • 浏览器一般只允许存放300个Cookie

  • 一个web站点最多存放20个cookie

  • Cookie大小有限制,最多4kb

  • 一个Cookie只能保存一个信息

删除Cookie:

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

中文乱码可以考虑的解决方式:编码解码

1
2
URLEncoder.encode("雷克萨","utf-8")
URLDecoder.decode(cookie.getValue(),"utf-8");

7.4、Session(重点)

image-20210224013459890

什么是Session?

  • 服务器会给每一个用户(浏览器)创建一个Session对象
  • 一个Session独占一个浏览器,只要浏览器没关,这个Session就存在
  • 用户登录后,保存用户的信息

image-20210224010010090

Session和Cookie的区别:

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

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

  • Session对象由服务器创建

使用场景:

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

使用Session:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决中文乱码
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html");
//得到Session
HttpSession session = req.getSession();
//存东西
session.setAttribute("name","雷克萨");
//获取session的ID
String id = session.getId();
//判断是不是新创建的
if(session.isNew()){
resp.getWriter().write("session创建成功,ID为:"+id);
}else {
resp.getWriter().write("session已经存在了,ID为:"+id);
}
}

//得到Session
HttpSession session = req.getSession();
Person person = (Person)session.getAttribute("name");
System.out.println(person.toString())
HttpSession session = req.getSession();
session.removeAttribute("name")

//手动注销Session
session.invalidate();

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

1
2
3
4
<session-config>
<!--1分钟后Session自动失效-->
<session-timeout>1</session-timeout>
</session-config>

8、JSP

8.1、什么是JSP

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

  • 最大的特点:写Jsp就像写Html

  • 区别:

    • Html只给用户提供静态的数据
    • Jsp页面可以嵌入Java代码,为用户提供动态数据

8.2、Jsp原理

思路:Jsp到底是如何执行的?

  • 代码层面没有任何问题

  • 服务器内部工作

    Tomcat中有一个work目录,IDEA中使用Tomcat的会在IDEA的Tomcat中生成一个work目录

image-20210224014853250

我电脑的地址:

1
C:\Users\86138\.IntelliJIdea2019.3\system\tomcat\Unnamed_javaweb_learn_4\work\Catalina\localhost\zqy\org\apache\jsp	 

发现页面转成了Java程序

image-20210224015139147

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

Jsp最终会被转为一个Java类,本质上就是一个Servlet

1
2
3
4
5
6
//初始化
public void _jspInit() {}
//销毁
public void _jspDestroy() {}
//JspService
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response) {...}
  1. 判断请求

  2. 内置一些对象

1
2
3
4
5
6
7
8
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; //响应
  1. 输出页面前增加的代码:
1
2
3
4
5
6
7
8
response.setContentType("text/html;charset=UTF-8");	//设置响应的页面类型
pageContext = _jspxFactory.getPageContext(this, request, response,null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
  1. 以上的这些对象我们可以在Jsp中直接使用

image-20210224021905837

在Jsp页面中,只要是Java代码,就会原封不动的输出,如果是Html代码,就会转换为

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

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

8.3、Jsp基础语法

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

Jsp表达式

1
2
<%-- JSP表达式,作用:将程序输出到客户端<%= 变量或者表达式%> --%>
<%= new java.util.Date()%>

Jsp脚本片段

1
2
3
4
5
6
7
8
<%--Jsp脚本片段:--%>
<%
int sum = 0;
for (int i = 0; i <= 100; i++) {
sum += i;
}
out.println("<h1>Sum="+sum+"</h1>");
%>

脚本片段的再实现

1
2
3
4
5
6
7
<%
for (int i = 0; i < 5; i++) {
%>
<h1>Hello World <%=i%></h1>
<%
}
%>

Jsp声明

1
<%!...%>

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

综上,在Jsp中嵌入Java代码即可

1
2
3
4
5
<%%>
<%=%>
<%!%>

<%--注释--%>

Jsp的注释不会在客户端显示,而Html的注释<!—- >当查看源代码时会显示出来

8.4、Jsp指令

1
2
3
4
5
6
7
8
9
10
11
12
<%@ page args ...%>
<%@ include file=""%>

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

<%--jsp标签,jsp:include:拼接页面,本质还是三个--%>
<jsp:include page="common/header.jsp"/>
<h1>网页主体</h1>
<jsp:include page="common/footer.jsp"/>

8.5、九大内置对象

  • PageContext 存东西
  • Request 存东西
  • Response
  • Session 存东西
  • Application【ServletContext】 存东西
  • config【ServletConfig】
  • out
  • page 不用了解
  • exception

demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<%
pageContext.setAttribute("name1","雷克萨1号"); //保存的数据只在一个页面中有效
request.setAttribute("name2","雷克萨2号"); //保存的数据在一次请求中有效,请求转发会携带这个数据
session.setAttribute("name3","雷克萨3号"); //保存的数据在一次会话中有效,从打开浏览器到关闭浏览器
application.setAttribute("name4","雷克萨4号"); //保存的数据在服务器中有效,从打开服务器到关闭服务器
%>
<%
//从pageContext中取出每一个,并输出
//从底层到高层(作用域):page->request->session->application
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> <%--什么也不输出--%>
<h3><%= name5%></h3> <%--会输出null--%>

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

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

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

8.6、Jsp标签,Jstl标签,EL表达式

需要导包:

1
2
3
4
5
6
7
8
9
10
11
12
<!-- jstl表达式依赖 -->
<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开发的常用对象
  • 调用java方法

Jsp标签

1
2
3
4
5
6
<%--<jsp:include>--%>

<jsp:forward page="jsp1.jsp">
<jsp:param name="name" value="雷克萨"/>
<jsp:param name="age" value="12"/>
</jsp:forward>

Jstl表达式

Jstl标签库的使用就是为了弥补Html标签的不足,它自定义了许多标签,标签的功能和java一样

核心标签(掌握部分)

引用核心标签库的语法如下:

1
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

image-20210224192407623

Jstl标签库使用步骤

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

c:if 测试

1
2
3
4
5
6
7
8
9
10
11
12
13
<h4>if测试</h4>

<form action="/index.jsp" method="get">
<%--EL表达式获取表单中的数据:${param.参数名}}--%>
<input type="text" name="username" value="${param.username}">
<input type="submit" value="登入">
</form>

<c:if test="${param.username == 'admin'}" var="isAdmin">
<c:out value="管理员欢迎您"/>
</c:if>

<c:out value="${isAdmin}"/>

c:choose测试

1
2
3
4
5
6
7
8
9
<c:set var="score" value="88"/>
<c:choose>
<c:when test="${score>=90}">
你的成绩为优秀
</c:when>
<c:when test="${score>=80}">
你的成绩为优秀
</c:when>
</c:choose>

c:forEach测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<%
ArrayList<String> people = new ArrayList<>();
people.add("张三");
people.add("李四");
people.add("王五");
people.add("赵六");
people.add("田七");
request.setAttribute("list",people);
%>
<%--
var:每一次遍历出来的变量
items:要遍历的对象
begin:开始下标
end:结束下标
step:步长
--%>
<c:forEach var="people" items="${list}" begin="1" end="3" step="1">
<c:out value="${people}"/><br>
</c:forEach>

格式化标签

JSTL格式化标签用来格式化并输出文本、日期、时间、数字。引用格式化标签库的语法如下:

1
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

SQL标签

JSTL SQL标签库提供了与关系型数据库(Oracle,MySQL,SQL Server等等)进行交互的标签。引用SQL标签库的语法如下:

1
<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>

XML 标签

JSTL XML标签库提供了创建和操作XML文档的标签。引用XML标签库的语法如下:

1
<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>

JSTL函数

JSTL包含一系列标准函数,大部分是通用的字符串处理函数。引用JSTL函数库的语法如下:

1
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

9、JavaBeen

实体类

Javabeen有特定的写法:

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

一般用来和数据库的字段做映射 ORM(对象关系映射)

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

比如people表:

id name age address
1 雷克萨 18 金星
2 巫妖王 100 木星
3 恶魔猎手 3 土星
1
2
3
4
5
6
class People{
private int id;
private String name;
private int age;
private String address;
}

10、MVC架构

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

10.1、早期

image-20210225004208097

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

servlet——>CRUD——>数据库

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

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

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

10.2、MVC三层架构

image-20210225010045881Model

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

View

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

Controller(Servlet)

  • 接收用户的请求(req:请求参数,Session信息……)
  • 交给业务层处理对应的代码
  • 控制视图跳转

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

11、Filter(重点)

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

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

image-20210225112115029

Filter开发步骤:

  1. 导包
  2. 编写过滤器
    1. 导包不要错

image-20210225112552606

​ 2. 实现Filter接口,重写对应方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//web服务器启动就会初始化,随时等待过滤对象出现
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("初始化");
}
/*
1. 过滤中的所有代码,在过滤特定请求时都会执行
2. 必须要让过滤器继续执行:chain.doFilter(request,response);
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setCharacterEncoding("utf-8");
servletResponse.setContentType("text/html;charse=utf-8");

System.out.println("过滤器执行前");
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("过滤器执行后");
}
//服务器关闭的时候,过滤自动销毁
@Override
public void destroy() {
System.out.println("销毁");
}

​ 3. 在web.xml中配置Filter

1
2
3
4
5
6
7
8
9
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<!--只要是/servlet的任何请求,都会经过这个过滤器-->
<url-pattern>/servlet/*</url-pattern>
</filter-mapping>

12、监听器

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

  1. 编写一个监听器的接口

    实现监听器的接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//创建Session监听,一旦创建Session就会触发一次这个事件
@Override
public void sessionCreated(HttpSessionEvent se) {
ServletContext ctx = se.getSession().getServletContext();
Integer num = (Integer) ctx.getAttribute("OnlineCount");
if(num == null){
num = 1;
}else {
num += 1;
}
ctx.setAttribute("OnlineCount",num);
}
//销毁Session监听,一旦销毁Session就会触发一次这个事件
@Override
public void sessionDestroyed(HttpSessionEvent se) {
ServletContext ctx = se.getSession().getServletContext();
Integer num = (Integer) ctx.getAttribute("OnlineCount");
if(num == null){
num = 0;
}else {
num -= 1;
}
ctx.setAttribute("OnlineCount",num);
}


/*Session销毁:
手动销毁 getSession().invalidate();
自动销毁:
<session-config>
<!--1分钟后Session自动失效-->
<session-timeout>1</session-timeout>
</session-config>
*/
  1. web.xml中注册监听器
1
2
3
<listener>
<listener-class>listener.OnlineCountListener</listener-class>
</listener>
  1. 看情况使用

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

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

demo:用户登录后才能进入主页,用户注销后不能。

  1. 用户登入以后,向Session中放入用户的数据
  2. 进入主页的时候,要判断用户是否已经登入,要求在过滤器中实现
1
2
3
4
5
6
HttpServletRequest request = (HttpServletRequest)  req;
HttpServletResponse response = (HttpServletResponse) resp;
if(request.getSession().getAttribute("USER_SESSION") == null){
response.sendRedirect("/error.jsp");
}
chain.doFilter(req,resp);

14、JDBC

什么是JDBC:java连接数据库(java database connectivity)

image-20210225181205142

需要jar包的支持:

  • java.sql
  • Javax.sql
  • mysql-connector-java连接驱动(必须要导入)
1
2
3
4
5
6
<!--mysql驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>

JDBC六大步骤:

  1. 加载驱动
  2. 获取连接
  3. 获得执行命令
  4. 执行
  5. 结果处理
  6. 释放资源(关闭资源)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private static final String CLASSDRIVER="com.mysql.cj.jdbc.Driver";
private static final String URL="jdbc:mysql://127.0.0.1:3306/test?";
private static final String USERNAME="root";
private static final String PASSWORD="qingyang1234";

public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1、加载驱动
Class.forName(CLASSDRIVER);
//2、获取连接
Connection conn = DriverManager.getConnection(URL,USERNAME,PASSWORD);
//3、获得执行命令,预编译使用prepareStatement
Statement stat = conn.createStatement();
//4、执行
String sql = "select * from emp";
//5、结果处理
//增删改使用executeUpdate(),返回影响的行数
ResultSet rs = stat.executeQuery(sql);
while (rs.next()){
System.out.println(rs.getString("ename")+"\t"+rs.getString("sal"));
}
//6、关闭连接
rs.close();
stat.close();
conn.close();
}

事务

一句话:要么都成功,要么都失败

ACID原则,保证数据的安全

  1. 开启事务
  2. 事务提交 commit()
  3. 事务回滚 rollback()
  4. 关闭事务

Junit单元测试

依赖

1
2
3
4
5
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>

简单使用

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

-------------本文结束感谢您的阅读-------------