Web基础知识
静态资源:像HTML、CSS、JS 以及图片、音频、视频等这些资源
动态资源:在服务器端上存储的,会根据用户请求和其他数据动态生成的,内容可能会在每次请求时都发生变化。比如:Servlet、JSP等(负责逻辑处理)。java程序开发的动态资源来说,我们通常会将这些动态资源部署在Tomcat,这样的Web服务器中运行。 而浏览器与服务器在通信的时候,基本都是基于HTTP协议的。
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。
- 优点:维护方便
- 缺点:体验一般
CS架构:Client/Server,客户端/服务器架构模式。需要单独开发维护客户端。
- 优点:体验不错
- 缺点:开发维护麻烦
Tomcat/Servlet
SpringBootWeb入门
Spring家族旗下这么多的技术,最基础、最核心的是 SpringFramework。其他的spring家族的技术,都是基于SpringFramework的,SpringFramework中提供很多实用功能
SpringFramework:配置繁琐、入门难度大
SpringBoot:简化配置、快速开发(官方推荐)
SpringBoot创建脚手架
Http协议
HTTP:Hyper Text Transfer Protocol(超文本传输协议),规定了浏览器与服务器之间数据传输的规则。
HTML:超文本标记语言
Http协议特点
- 基于TCP协议:面向连接/安全
- TCP是一种面向连接的(建立连接之前是需要经过三次握手)、可靠的、基于字节流的传输层通信协议,在数据传输方面更安全
- 基于请求-响应模型: 一次请求对应一次响应(先请求后响应)
- 请求和响应是一一对应关系,没有请求,就没有响应
- HTTP协议是无状态协议: 对于数据没有记忆能力。每次请求-响应都是独立的
- 无状态指的是客户端发送HTTP请求给服务端之后,服务端根据请求响应数据,响应完后,不会记录任何信息
- 缺点: 多次请求间不能共享数据
- 优点: 速度快
- 无状态指的是客户端发送HTTP请求给服务端之后,服务端根据请求响应数据,响应完后,不会记录任何信息
长连接/短连接
HTTP/1.1 是一种网络协议,用于客户端(如浏览器)和服务器之间的通信。它是超文本传输协议(HTTP)的一个版本,广泛用于互联网上的数据传输
请求头:Connection: keep-alive/close
HTTP/1.1 (默认) 支持两种连接方式:持久连接(长连接) 和 非持久连接(短连接)
长连接:减少开销(减少了频繁建立和关闭连接的开销);适合高频率交互
短连接:连接短暂;适合低频率交互;资源占用少
Http请求协议
Get方式请求协议
请求行(以上图中红色部分) :HTTP请求中的第一行数据。由:请求方式、资源路径、协议/版本组成(之间使用空格分隔)
请求头(以上图中黄色部分) :第二行开始,上图黄色部分内容就是请求头。格式为 key: value 形式
| 请求头 | 含义 |
|---|---|
| Host | 表示请求的主机名 |
| User-Agent | 浏览器版本。 例如:Chrome浏览器的标识类似Mozilla/5.0 ...Chrome/79 ,IE浏览器的标识类似Mozilla/5.0 (Windows NT ...)like Gecko |
| Accept | 表示浏览器能接收的资源类型,如text/*,image/或者/*表示所有; |
| Accept-Language | 表示浏览器偏好的语言,服务器可以据此返回不同语言的网页; |
| Accept-Encoding | 表示浏览器可以支持的压缩类型,例如gzip, deflate等。 |
| Content-Type | 请求主体的数据类型 |
| Content-Length | 数据主体的大小(单位:字节) |
请求体 :存储请求参数,GET请求的请求参数在请求行中,故不需要设置请求体
Post方式请求协议
请求行(以上图中红色部分):包含请求方式、资源路径、协议/版本
请求头(以上图中黄色部分)
请求体(以上图中绿色部分) :存储请求参数
- 请求体和请求头之间是有一个空行隔开(作用:用于标记请求头结束)
Get与Post区别
- get方式的参数在请求行中的资源路径;
- 请求参数长度有限制;
- 安全性低,参数与值直接暴露在浏览器的地址栏中
获取请求数据
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
public String requestTest(HttpServletRequest request) throws IOException {
// 获取 Get 请求中的请求体数据
// get请求要想获取请求体必须通过读取流,这个流相当于是存储了请求体的数据,
// 而且要在方法的第一行就读取流才可以,
// 因为一旦执行了类似request.getParameter的操作相当于底层会执行读取流的操作,
// 因为同一个流是不允许多次写或多次读的,所以要想再读取流就不可以了
String string = IOUtils.toString(request.getInputStream(), "UTF-8");
System.out.println(string);
// 请求方式 GET
System.out.println(request.getMethod());
// 请求url地址 http://localhost:8080/request
System.out.println(request.getRequestURL());
// 请求uri地址 /request
System.out.println(request.getRequestURI());
// 请求参数
System.out.println(request.getParameter("name"));
// 请求头
System.out.println(request.getHeader("accept"));
// 请求协议 http
System.out.println(request.getProtocol());
return "Hello " + request.getParameter("name");
}
Http响应协议
响应行(以上图中红色部分):响应数据的第一行。响应行由协议及版本、响应状态码、状态码描述组成
响应头(以上图中黄色部分):响应数据的第二行开始。格式为key:value形式
Content-Type:表示该响应内容的类型,例如text/html,image/jpeg ;
Content-Length:表示该响应内容的长度(字节数);
Content-Encoding:表示该响应压缩算法,例如gzip ;
Cache-Control:指示客户端应如何缓存,例如max-age=300表示可以最多缓存300秒 ;
Set-Cookie:告诉浏览器为当前页面所在的域设置cookie ;
响应体(以上图中绿色部分): 响应数据的最后一部分。存储响应的数据,响应体和响应头之间有空行隔开
设置响应数据
@RequestMapping("/response")
public void responseTest(HttpServletResponse response) throws IOException {
// 设置响应码
response.setStatus(401);
// 设置响应头
response.setHeader("age", "25");
// 设置响应体
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
response.getWriter().write("<h1>Hello</h1>");
}
@RequestMapping("/response2")
public ResponseEntity<?> responseTest(){
return ResponseEntity.status(401)
.header("age", "25")
.body("<h1>Hello</h1>");
}
HTTP状态码
| 状态码分类 | 说明 |
|---|---|
| 1xx | 响应中 --- 临时状态码。表示请求已经接受,告诉客户端应该继续请求或者如果已经完成则忽略 |
| 2xx | 成功 --- 表示请求已经被成功接收,处理已完成 |
| 3xx | 重定向 --- 重定向到其它地方,让客户端再发起一个请求以完成整个处理 |
| 4xx | 客户端错误 --- 处理发生错误,责任在客户端,如:客户端的请求一个不存在的资源,客户端未被授权,禁止访问等 |
| 5xx | 服务器端错误 --- 处理发生错误,责任在服务端,如:服务端抛出异常,路由出错,HTTP版本不支持等 |
HTTP 状态码分类
1xx-信息性状态码:这些状态码表示临时的响应,通常用于表示服务器已经接收到了请求的一部分,但还需要进一步的信息才能完成请求
- 100 Continue:服务器已接收到请求头,客户端应继续发送请求体
- 101 Switching Protocols:服务器根据客户端的请求切换协议。通常用于升级到 WebSocket 协议
2xx-成功状态码:这些状态码表示请求已成功处理
- 200 OK:请求成功,响应体包含请求的资源
- 201 Created:请求成功,并且服务器创建了新的资源
- 202 Accepted:请求已接受,但处理尚未完成
- 204 No Content:请求成功,但响应体为空
- 206 Partial Content:请求成功,但只返回了部分资源(通常用于范围请求)
3xx-重定向状态码:这些状态码表示客户端需要采取进一步的行动来完成请求,通常涉及跳转到另一个 URI
- 301 Moved Permanently:请求的资源已永久移动到新的 URI(永久重定向)
- 302 Found:请求的资源临时移动到新的 URI(临时重定向)
- 304 Not Modified:请求的资源未修改,客户端可以使用缓存的版本
- 307 Temporary Redirect:请求的资源临时移动到新的 URI,但方法和请求体不变
- 308 Permanent Redirect:请求的资源已永久移动到新的 URI,但方法和请求体不变
4xx-客户端错误状态码:这些状态码表示客户端请求有误,导致服务器无法处理
- 400 Bad Request:请求语法错误或请求参数无效(缺少参数;参数格式不合法)
- 401 Unauthorized:请求未授权,需要身份验证(未登录)
- 403 Forbidden:服务器理解请求,但拒绝执行(登录,但没有权限)
- 404 Not Found:请求的资源未找到(请求路径有误)
- 405 Method Not Allowed:请求方法不被允许(请求方法不匹配)
- 406 Not Acceptable:请求的内容无法满足客户端(返回内容客户端不可接受)
- 408 Request Timeout:服务器等待请求超时
- 412 :请求类型 content-type 有误
- 429 Too Many Requests:客户端发送的请求过多,触发了限流机制
- 431 Request Header Fields Too Large:请求头太大
5xx-服务器错误状态码:这些状态码表示服务器在处理请求时发生了错误
- 500 Internal Server Error:服务器内部错误,无法完成请求(服务端有bug)
- 501 Not Implemented:服务器不支持请求的方法
- 502 Bad Gateway:服务器作为网关或代理时,从上游服务器接收到无效响应(代理服务器正常,网络也正常,但是后端服务器没有启动)
- 503 Service Unavailable:服务器暂时无法处理请求(通常由于过载或维护)(代理服务器负载高或者资源紧张)
- 504 Gateway Timeout:服务器作为网关或代理时,上游服务器响应超时(代理服务器一定时间内没有接收到返回报文)
- 505 HTTP Version Not Supported:服务器不支持请求的 HTTP 版本
HTTP方法
八种方法:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、TRACE(后面三种很少使用)
| HTTP方法 | 说明 | 作用 |
|---|---|---|
| GET | 从服务器端获取数据,请求body在地址栏上 | 获取资源 |
| POST | 向服务器端提交数据,请求数据在报文body里;发送一个修改数据的请求,需求数据要重新新创建。 | 用于创建子资源。创建、更新、删除、查询资源均可使用 |
| PUT | 向服务器端提交数据,请求数据在报文body里;发送一个修改数据的请求,需求数据更新**(全部更新)** | 用于创建、更新资源 |
| DELETE | 向服务器端提交数据,请求数据在报文body里;发送一个删除数据的请求 | 删除资源 |
| PATCH | 向服务器端提交数据,请求数据在报文body里;与PUT类似,发送一个修改数据的请求,区别在于PATCH代表部分更新;后来提出的接口方法,使用时可能去要验证客户端和服务端是否支持 | 用于创建、更新资源(局部更新) |
SpringbootWeb案例/分层解耦
分层:职责分离(每个层次只负责特定的职责)、降低耦合度(层次之间依赖关系更加清晰)
面向接口编程:便于扩展程序功能(新增一个新的接口实现类,扩展功能)
三层架构
- Controller:控制层。接收前端发送的请求,对请求进行处理,并响应数据。
- Service:业务逻辑层。处理具体的业务逻辑。
- Dao:数据访问层(Data Access Object),也称为持久层。负责数据访问操作,包括数据的增、删、改、查。
案例注解
@ResponseBody:书写在Controller方法上或类上,方法的返回值会转换为Json数据直接响应给浏览器
@RestController:@ResponseBody + @Controller
| 注解 | 说明 | 位置 |
|---|---|---|
| @Component | 声明bean的基础注解 | 不属于以下三类时,用此注解 |
| @Controller | @Component的衍生注解 | 标注在控制层类上 |
| @Service | @Component的衍生注解 | 标注在业务层类上 |
| @Mapper/@Repository | @Component的衍生注解 | 标注在数据访问层类上(由于与mybatis整合,用的少) |
组件扫描
- 前面声明bean的四大注解,要想生效,还需要被组件扫描注解
@ComponentScan扫描。 - 该注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解
@SpringBootApplication中,默认扫描的范围是启动类所在包及其子包。
Bean注入注解
@Autowired注解,默认是按照类型进行自动装配的(去IOC容器中找某个类型的对象,然后完成注入操作)
当spring容器中有两个相同类型的bean时
- 使用@Primary注解:当存在多个相同类型的Bean注入时,加上@Primary注解,来确定默认的实现
- 使用@Qualifier注解:指定当前要注入的bean对象。 在@Qualifier的value属性中,指定注入的bean的名称。 @Qualifier注解不能单独使用,必须配合@Autowired使用
- 使用@Resource注解:按照bean的名称进行注入
@Autowird 与 @Resource的区别(面试题)
- @Autowired 是spring框架提供的注解,而@Resource是JDK提供的注解
- @Autowired 默认是按照类型注入,而@Resource是按照名称注入
依赖注入注解详解
@Service("beanName") // 指定bean注入名称为beanName
UserServiceImpl // 默认bean注入名称为userServiceImpl
@Autowird // 通过类型注入bean(多态形式)
private UserService userService;
- @Primary注解:多个相同类型的bean,在相同类型对象上添加注解即为增加优先级
- @Qualifier("userServiceImpl")注解:配合Autowird注解,指定名称注入
@Resource
private UserService userService;
- 先通过名称,再通过类型
- @Resource("beanName"):添加value属性则只会根据name找,找不到也会报错
案例代码
// 实体类:User、Result
// 分层解耦之前
@RequestMapping("/users")
public Result users() throws Exception {
Reader r = new FileReader("springboot-web-demo\\src\\main\\resources\\user.txt");
BufferedReader br = new BufferedReader(r);
List<User> list = new ArrayList<>();
String str;
while((str = br.readLine()) != null){
String[] split = str.split(",");
User user = new User();
user.setId(Integer.parseInt(split[0]));
user.setName(split[1]);
user.setTele(split[2]);
user.setUsername(split[3]);
user.setAge(Integer.parseInt(split[4]));
user.setCreateTime(LocalDateTime.parse(split[5],DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
list.add(user);
}
System.out.println("users()");
br.close();
r.close();
return Result.success(list);
}
// 分层解耦之后
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/list")
public Result list() throws Exception {
return Result.success(this.userService.getUserList());
}
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public List<User> getUserList() throws FileNotFoundException {
List<String> userLines = this.userDao.getUserLines();
List<User> list = userLines.stream().map(line -> {
User user = new User();
String[] str = line.split(",");
user.setId(Integer.parseInt(str[0]));
user.setName(str[1]);
user.setTele(str[2]);
user.setUsername(str[3]);
user.setAge(Integer.parseInt(str[4]));
user.setCreateTime(LocalDateTime.parse(str[5], DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
return user;
}).toList();
return list;
}
}
// txt中多行User数据(1,daqiao,1234567890,大乔,22,2024-07-15 15:05:45)
@Component
public class UserDaoImpl implements UserDao {
@Override
public List<String> getUserLines() throws FileNotFoundException {
InputStream is = new FileInputStream("springboot-web-demo\\src\\main\\resources\\user.txt");
List<String> lines = IoUtil.readLines(is, "UTF-8", new ArrayList<>());
// IoUtil.readLines来自于cn.hutool工具类依赖
return lines;
}
}
Spring中的两个核心概念
控制反转: Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转。
- 对象的创建权由程序员主动创建转移到容器(由容器创建、管理对象)。这个容器称为:IOC容器或Spring容器。
依赖注入: Dependency Injection,简称DI。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。
- 程序运行时需要某个资源,此时容器就为其提供这个资源。
- 例:EmpController程序运行时需要EmpService对象,Spring容器就为其提供并注入EmpService对象。
bean对象:IOC容器中创建、管理的对象,称之为:bean对象。