Java Web学习笔记是在狂神的b站视频学习所整理的笔记!
1 基本概念
1.1 前言
web开发:
-
web,即网页,例如 www.baidu.com
-
静态web
-
html,css
-
提供展示的数据不会发生改变
-
-
动态web
-
提供展示的数据会发生改变,不同的用户在不同的时间地点所看到的数据不同
-
技术栈:Servlet/JSP,ASP,PHP
-
在Java中,动态web资源开发的技术统称为JavaWeb
1.2 web应用程序
web应用程序:可以提供浏览器访问的程序
-
xxx.html、xxxx.html等多个web资源,可以被外界访问,对外提供服务
-
所有能访问到的任何一个页面或者资源,都存在某个计算机中
-
URL
-
统一的web资源会被放在同一个文件夹下,即web应用程序
-
通过 Tomcat服务器 --> web应用程序
-
一个web应用由多部分组成(静态web,动态web)
-
html,css,js
-
jsp,servlet
-
java程序
-
jar包
-
配置文件(properties)
-
web应用程序编写后,需要通过一个服务器来管理
在IDEA中,其实自带了Tomcat服务器 !
1.3 静态web
服务器中若存在 *.html 等静态网页,用户可以直接读取
缺点:
-
Web页面无法动态更新,所有用户看到的都是同一个页面
-
无法和数据库交互(数据无法持久化,用户无法交互)
1.4 动态web
页面可以动态展示,Web页面展示的效果会发生变化
优点:
-
Web页面可以动态更新,所有用户看到的都不是同一个页面
-
可以和数据库交互(数据持久化)
缺点:
-
若服务器的动态web资源出现错误,需要重新编写后台程序,重新上线
2 Web服务器
2.1 技术
ASP
JSP/Servlet
-
B/S架构
-
基于Java语言
-
可以解决三高(高并发,高可用,高性能)问题
PHP
-
开发速度很快,功能很强大,跨平台,代码简单
-
无法承载大访问量(局限性)
2.2 Web服务器
服务器用来处理用户的请求已经给用户反馈响应信息
Tomcat
3 Tomcat
Tomcat 文件夹中的相关文件夹:
-
bin:存放脚本文件
-
lib:存放jar包
-
conf:存放配置文件
-
webapps:存放web应用程序
启动、关闭Tomcat服务器:
1、通过手动打开存放在bin包下的可执行文件
2、通过命令行打开关闭
-
startup.bat
-
shutdown.bat
启动、关闭Tomcat可能发生的问题:
-
Java环境变量没有配置导致闪退
-
兼容性没有配置好导致闪退
-
乱码(配置文件中配置 startup.bat文件用文本编辑器打开)
conf 文件夹下的 server.xml 配置文件
-
可以配置启动的端口号
-
Tomcat的默认端口:8080
-
MySQL的默认端口:3306
-
http的默认端口:80
-
https的默认端口:443
-
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
-
可以配置主机的名称
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
-
默认的主机名称为:localhost ==> 127.0.0.1
-
默认网站应用存放的位置:webapps
-
-
配置环境变量
发布一个Web网站:
-
将自己编写的网站,放到服务器(Tomcat)中指定的Web应用的文件夹(webapps)下
-
网站的基本结构
--webapps:Tomcat服务器的web应用目录 -ROOT -lin:网站的目录名 -WEB-INF -classes:java程序 -lib:web应用所依赖的jar包 -web.xml:网站配置文件 -index.html 默认的首页 -static:静态资源
-
4 HTTP
4.1 什么是HTTP
HTTP(超文本传输协议) 是一个简单的请求-响应协议,它通常运行在 TCP 上。
-
文本:html,字符串等
-
超文本:图片,音乐,视频,定位,地图等
-
默认端口:80
Https:安全的协议
-
默认端口:443
4.2 两个时代
http1.0
-
HTTP/1.0:客户端在与web服务器连接后,只能获得一个web资源,即获得该web资源后断开连接
http2.0
-
HTTP/1.1:客户端在与web服务器连接后,能够获得多个web资源
4.3 HTTP 请求
客户端 ----> 服务器(发送请求)
Request URL: https://www.baidu.com/ 请求地址 Request Method: GET 请求方式 Status Code: 200 OK 状态码 Remote Address: 163.177.151.109: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
-
请求行
-
请求行中的请求方式:GET/POST,HEAD,DELETE,PUT等等
-
GET:一次请求能够携带的参数较少,大小有限制,在浏览器的URL地址栏显示数据内容,不安全,但高效率
-
POST:一次请求能够携带的参数无限制,大小无限制,在浏览器的URL地址栏显示数据内容,安全,但低效率
-
-
消息头
Accept: 告诉浏览器,它所支持的数据类型 Accept-Encoding: 支持的编码格式 GBK UTF-8 Accept-Language: 告诉浏览器,它的语言环境 Cache-Control: 缓存控制 Connection: 告诉浏览器,请求完成后是断开还是保存连接 HOST: 主机
4.4 HTTP 响应
服务器 ----> 客户端(响应)
Cache-Control: private 缓存控制 Connection: keep-alive 连接 Content-Encoding: gzip 编码 Content-Type: text/html;charset=utf-8 类型
-
响应体
Accept: 告诉浏览器,它所支持的数据类型 Accept-Encoding: 支持的编码格式 GBK UTF-8 Accept-Language: 告诉浏览器,它的语言环境 Cache-Control: 缓存控制 Connection: 告诉浏览器,请求完成后是断开还是保存连接 HOST: 主机 Refresh: 指定浏览器刷新间隔时间 Location: 让网页重新定位
-
响应状态码
200:请求响应成功
-
200
3xx:请求重定向
-
重定向:给定新位置
4xx:找不到资源
-
资源不存在
-
404
5xx:服务器代码错误
-
500
-
502:网关错误
-
5 Maven
为什么要学习Maven?
-
在 JavaWeb 开发中,需要大量使用jar包,手动导入太麻烦
-
Maven 是一个工具,帮我们自动导入和配置jar包
5.1 Maven项目架构管理工具
Maven 的核心思想:约定大于配置!
-
不要违反约束
Maven会规定我们如何编写代码,必须按照该规范来编写!
5.2 配置环境
在系统环境中,配置如下环境:
-
M2_HOME:maven目录下的bin目录
-
MAVEN_HOME:maven的目录
-
在系统中的path中配置 %MAVEN_HOME%\bin
5.3 mirrors镜像
镜像:mirrors
-
作用:加快下载
国内可选择的镜像有阿里和清华镜像源!
5.4 本地仓库
创建一个本地仓库,存放依赖
5.4 在IDEA中使用Maven
1.创建一个MavenWeb项目
2.观察Maven仓库增加的jar包
3.IDEA中的Maven设置
解决警告问题
为什么会有这个问题:
访问一个网站,必须指定一个文件夹名称
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.levin</groupId>
<artifactId>javaweb-01-maven</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.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<!--项目依赖-->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<!--项目构建用的东西-->
<build>
<finalName>javaweb-01-maven</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的高级之处在于,会帮你导入jar包所依赖的其他jar包
由于 Maven 约定大于配置的原则,可能会出现我们所编写的配置文件无法导出或者生效的问题,解决方法:
<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>
6 Servelet
6.1 简介
Servlet 是 sun 公司开发动态 web 的一门技术
sun 公司在 API 中提供了一个接口:Servlet
开发 Servlet 程序,只需要两个步骤:
-
编写一个类,实现 Servlet 接口
-
部署编写好的 Java 类到 web 服务器中
实现了 Servlet 的 Java 程序叫做 Servlet
Servlet 接口在 sun 公司有两个默认的实现类:HttpServlet,GenericServlet
6.2 Servlet 入门案例demo
-
构建一个普通的 Maven 项目,删除里面的 src 文件夹,这个空的工程就是 Maven 主工程
-
关于 Maven 父子工程的理解
父项目中会有:
<modules> <module>servlet-01</module> </modules>
父项目中会有:
<parent> <artifactId>javaweb-02-servlet</artifactId> <groupId>com.levin</groupId> <version>1.0-SNAPSHOT</version> </parent>
父项目中的 jar 包,子项目可以直接使用
-
Maven 环境优化
1)将 web.xml 改为最新版本
2)将 Maven 的结构搭建完整
-
编写一个 Servlet 程序
1)编写一个普通类
2)实现 Servlet 接口,此处直接继承 HttpServlet
package com.levin.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; /** * @author Levin * @date 2021/12/22 1:49 */ 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 { } }
-
编写 Servlet 的映射
为什么需要映射:
-
我们编写的是 Java 程序,但是需要通过浏览器访问,而浏览器需要连接 web 服务器,故需要在 web 服务中注册我们的 Servlet,还需要给浏览器能够访问的路径
<!-- 注册Servlet --> <servlet> <servlet-name>hello</servlet-name> <servlet-class>com.levin.servlet.HelloServlet</servlet-class> </servlet> <!-- Servlet的请求路径 --> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
-
-
配置 Tomcat
注意:配置项目发布的路径
-
启动测试
注意:Tomcat10 在日常使用中,经常出错,建议降级为Tomcat9!!!
6.3 Servlet 原理
Servlet 是由 web 服务器调用,web 服务器在收到浏览器请求之后,会发生如下活动:
6.4 mapping
-
一个 Servlet 可以指定一个映射路径
<!-- Servlet的请求路径 --> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
-
一个 Servlet 可以指定多个映射路径
<!-- Servlet的请求路径 --> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> <!-- Servlet的请求路径 --> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello1</url-pattern> </servlet-mapping> <!-- Servlet的请求路径 --> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello2</url-pattern> </servlet-mapping>
-
一个 Servlet 可以指定通用映射路径
<!-- Servlet的请求路径 --> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello/*</url-pattern> </servlet-mapping>
-
默认请求路径
<!-- Servlet的请求路径 --> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
-
指定前缀或者后缀
<!-- Servlet的请求路径 --> <!-- 自定义后缀实现请求映射时,前面不能加 web 路径 --> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>
优先级问题:
-
制定了固有的映射路径优先级最高,找不到的映射路径就会走默认的处理请求
6.5 ServletContext
web 容器(Tomcat)在启动时,它会为每个 web 程序都创建一个对应的 ServletContext 对象,代表当前的 web 应用
6.5.1 共享数据
此 Servlet 中的数据可以在另一个 Servlet 中获取
-
创建一个上传数据的类
package com.levin.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; /** * @author Levin * @date 2021/12/23 1:51 */ public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // this.getInitParameter(); 初始化参数 // this.getServletConfig(); Servlet配置 // this.getServletContext(); 上下文 ServletContext servletContext = this.getServletContext(); String username = "小林"; //数据 servletContext.setAttribute("username", username); // 将数据保存在 ServletContext System.out.println("Hello"); } }
-
创建一个读取数据的类
package com.levin.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; /** * @author Levin * @date 2021/12/23 2:02 */ public class GetServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = this.getServletContext(); String username = (String) servletContext.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 { } }
-
web.xml 中注册 Servlet 和 配置 映射
<servlet> <servlet-name>hello</servlet-name> <servlet-class>com.levin.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.levin.servlet.GetServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>getc</servlet-name> <url-pattern>/getc</url-pattern> </servlet-mapping>
注意:在调用 getc 时,如果未先访问 hello,没有上传数据,访问 getc 获取的数据为 null
6.5.2 获取初始化参数
<!-- 配置一些web应用初始化参数 -->
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>
6.5.3 请求转发
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
System.out.println("进入Demo04");
// RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/GP"); //转发的请求路径
// requestDispatcher.forward(req, resp); //调用forward请求转发
servletContext.getRequestDispatcher("/GP").forward(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
请求转发和重定向不一样!!
6.5.3 读取资源文件
properties
-
在 java 目录下新建 properties
-
在 resource 目录下新建 properties
都被打包到同一路径下:classes,我们俗称这个路径为类路径
思路:需要一个文件流
username=Levin password=123456 #classpath:java+resources #类路径
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
InputStream resourceAsStream = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
Properties properties = new Properties();
properties.load(resourceAsStream);
String username = properties.getProperty("username");
String password = properties.getProperty("password");
resp.getWriter().print(username + ":" + password);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
6.6 HttpServletResponse
web 服务器接收到客户端的 http 请求,针对这个请求,分别创建一个代表请求的 HttpServletRequest 对象和一个代表响应的 HttpServletResponse对象。
-
获取客户端请求的参数:HttpServletRequest
-
响应客户端的信息:HttpServletResponse
6.6.1 分类
负责向浏览器发送数据的方法
负责向浏览器发送请求头的方法
响应的状态码
6.6.2 常见应用
-
向浏览器输出消息
-
getWriter()
-
-
下载文件
-
获取下载文件的路径
-
获取下载的文件名
-
设置浏览器支持的下载格式
-
获取下载文件的输入流
-
输出(IO流)
-
创建缓冲区
-
获取 OutputStream 对象
-
将 FileOutputStream 流写入到缓冲区 buffer
-
使用 OutputStream 将缓冲区的数据输出到客户端
-
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String realPath = "E:\\Projects\\JavaWeb\\javaweb-02-servlet\\response03\\src\\main\\resources\\测试.png"; System.out.println("下载文件的路径为:" + realPath); String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1); // URLEncoder.encode(fileName, "UTF-8"); 解决中文乱码问题 resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); FileInputStream in = new FileInputStream(realPath); int len = 0; byte[] buffer = new byte[1024]; OutputStream out = resp.getOutputStream(); while ((len=in.read(buffer)) != -1){ out.write(buffer, 0, len); } in.close(); out.close(); }
-
-
验证码功能
前端实现
后端实现,需要用到 Java 图片类,产生一个图片
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //如何让浏览器5s自动刷新一次 resp.setHeader("refresh", "5"); //在内存中创建一个图片 BufferedImage image = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB); //得到图片 Graphics2D pen = (Graphics2D)image.getGraphics(); //笔 //设置图片的背景颜色 pen.setColor(Color.white); pen.fillRect(0, 0, 80, 20); //给图片写数据 pen.setColor(Color.blue); pen.setFont(new Font(null, Font.BOLD, 20)); pen.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 stringBuffer = new StringBuffer(); for(int i = 0; i < 7-num.length(); i++){ stringBuffer.append("0"); } num = stringBuffer.toString() + num; return num; }
-
实现重定向
一个 web 资源收到客户端请求后,通知客户端去访问另一个 web 资源,这个过程叫做重定向
常见场景:
-
用户登录
void sendRedirect(String var1) throws IOException;
测试:
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setHeader("Location", "r/image"); resp.setStatus(HttpServletResponse.SC_FOUND); resp.sendRedirect("/r/image"); }
-
6.7 HttpServletRequest
HttpServletRequest 代表客户端的请求,用户通过 Http 协议访问服务器,HTTP 请求中的所有信息会被封装到 HttpServletRequest 中,通过 HttpServletRequest 中的方法获取
6.7.1 获取前端传递的参数
请求转发
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//后台接收中文乱码问题
req.setCharacterEncoding("UTF-8");
//页面中文乱码问题
resp.setCharacterEncoding("UTF-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobbies = req.getParameterValues("hobbies");
System.out.println("=================");
//后台接收中文乱码问题
System.out.println(username);
System.out.println(password);
System.out.println(Arrays.toString(hobbies));
System.out.println("=================");
System.out.println(req.getContextPath());
//通过请求转发
// resp.setCharacterEncoding("UTF-8");
//此处的 / 代表当前的 web 应用
req.getRequestDispatcher("/success.jsp").forward(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}