JavaWeb_SpringBootWeb
- BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。
- 优点:维护方便
- 缺点:体验一般
- CS架构:Client/Server,客户端/服务器架构模式。需要单独开发维护客户端。
- 优点:体验不错
- 缺点:开发维护麻烦
SprintBootWeb
入门程序
需求:基于SpringBoot的方式开发一个web应用,浏览器发起请求/hello后,给浏览器返回字符串 “Hello xxx ~”。
开发步骤
第1步:创建SpringBoot工程,并勾选Web开发相关依赖
第2步:定义HelloController类,添加方法hello,并添加注解
创建Spring Boot 工程
由于我的IDEA版本是社区版,没有办法直接从插件处下载Sprintboot插件,所以要采取一些其他方法。
方法2和方法3都比较方便。
方法2:
使用Spring initializr插件来创建。
- 发现这个插件也变成专业版了!!为什么!
方法3:通过maven来创建
需要修改pom.xml来添加依赖:
- 需要新增父项目配置
1 | <parent> |
用于继承Springboot的默认配置,统一依赖管理版本
- 加入Spring bott核心依赖
1 | <dependency> |
在这里引入依赖坐标,提供了web开发所需的全部依赖(Spring mvc,内嵌tomcat等)
- 引入Spring boot maven插件
1 | <plugin> |
用于打包可执行jar,允许spring boot应用,热部署支持
- 引入测试依赖更新
1 | <dependency> |
方便我们使用JUnit5进行Spring boot测试
在主类App.java中import:
1 | package org.example; |
运行成功:
完整的SpringBoot项目还需要添加资源文件
定义HelloController类,添加方法hello
运行测试:
打开浏览器,输入 localhost:8080/hello?name=土豆
可以看到
回顾一下
在入门程序中,我们发现只需要一个main方法就可以将web应用启动起来,然后可以打开浏览器访问了。
why?
因为我们在创建springboot项目的时候,选择了web开发的起步依赖 spring-boot-starter-web。而spring-boot-starter-web依赖,又依赖了spring-boot-starter-tomcat,由于maven的依赖传递特性,那么在我们创建的springboot项目中也就已经有了tomcat的依赖,这个其实就是springboot中内嵌的tomcat。
- spring-boot-starter-web:包含了web应用开发所需要的常见依赖。
- spring-boot-starter-test:包含了单元测试所需要的常见依赖。
HTTP协议
概述
HTTP:Hyper Text Transfer Protocol(超文本传输协议),规定了浏览器与服务器之间数据传输的规则。(应用层协议)
- http协议又分为请求协议和相应协议
- 规定数据传输的格式:请求数据+响应数据
特点
- 基于TCP协议:面向连接,安全
- TCP是面向连接的协议,需要三次握手
- 基于请求-响应模型:一次请求对应一次响应
- http协议是无状态协议:对于数据没有记忆能力,每次请求-响应都是独立的
- 我们为了有“记忆”引入了cookie等技术
HTTP请求协议
请求协议就是浏览器将数据以请求格式发送到服务器。包括:请求行、请求头、请求体。
请求方式:GET/POST
GET方式的请求协议:

- 请求行:
- 请求方式:GET
- 资源路径:/brand/findAll?name=OPPO&status=1
- 请求路径:/brand/findAll
- 请求参数:name=OPPO&status=1
- 请求参数是以key=value形式出现
- 多个请求参数之间使用
&连接
- 请求路径和请求参数之间使用
?连接
- 协议/版本:HTTP/1.1
- 请求头:key:value
- http是个无状态的协议,所以在请求头设置浏览器的一些自身信息和想要响应的形式。
| 请求头 | 含义 |
| 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方式

请求行:包含请求方式、资源路径、协议版本
请求头:格式key:value
请求体:存储请求参数,请求体于请求头之间是有一行空格隔开(便于标记)
| 区别方式 | GET请求 | POST请求 |
|---|---|---|
| 请求参数 | 请求参数在请求行中。 例:/brand/findAll?name=OPPO&status=1 |
请求参数在请求体中 |
| 请求参数长度 | 请求参数长度有限制(浏览器不同限制也不同) | 请求参数长度没有限制 |
| 安全性 | 安全性低。原因:请求参数暴露在浏览器地址栏中。 | 安全性相对高 |
获取请求数据

HTTP响应协议
响应协议:服务器将数据以响应格式返回给浏览器。包括:相应行、响应头、响应体

200 ok客户端请求成功404 Not Found请求资源不存在500 Internal Server Error服务端发生不可预期的错误
响应数据
Web服务器对http协议的响应数据进行了封装(HttpServletResponse),并在调用Controller方法时传递了该方法。类似的,在请求协议里也进行了封装(HttpServletRequest)
例子
希望实现:
当在浏览器中访问前端静态页面 localhost:8080/user.html后,在前端页面上回发送ajax请求,请求服务端 localhost:8080/list ,服务器端程序加载user.txt文件中的数据,读取出来后最终给前端页面响应json格式的数据,前端页面再将数据渲染展示在表格中

总结
本案例要展示的核心功能:
- 前端展示:希望通过静态html页面,展示用户数据表格
- 后端服务:
- 读取user.txt中的数据
- 将数据解析为User对象集合
- 通过RESTful接口返回json格式数据

涉及到的知识点:
SpringBoot
@RestController注解:组合了@Controller和@ResponseBody,直接返回JSON数据- 在使用
@RestController注解标记的类中,每个方法的返回值都会以 JSON 或 XML 的形式直接写入 HTTP 响应体中,相当于在每个方法上都添加了@ResponseBody注解。
文件操作:
- 资源文件加载:ClassLoader.getResourceAsStream()
- Hutool工具库的IoUtil.readLines()高效读取文件
- 文件路径:src/main/resources下的文件会被打包到classpath
三层架构思想
- Controller:接收请求和响应数据
- Service:业务逻辑处理(虽然本示例未显式分层,但隐含该思想)
- DAO:数据访问(本示例中直接操作文件)
我们定义了一个实体类User:
1 | // Lombok自动生成getter/setter |
这里使用了Lombok自动生成getter和setter
Lombok简介、使用、工作原理、优缺点-CSDN博客
1 | @Setter 注解在类或字段,注解在类时为所有字段生成setter方法,注解在字段上时只为该字段生成setter方法。 |
控制器:(这里给页面响应的代码全部堆积了,实际开发时我们会采用分层解耦的方法)
1 | // = @Controller + @ResponseBody |
这里用到了RESTful接口设计
前端交互部分:
1 | fetch("/list") |
前端通过AJAX消费后端API
分层解耦
三层架构
- 在进行程序设计及开发时,尽可能让每天接口、类、方法的职责更单一(单一职责)
前面入门程序:
但现在,我们应该把它拆开
- 数据访问:负责业务数据的维护操作(增删改查)
- 逻辑处理:负责业务的逻辑代码
- 请求处理、响应数据:负责,接收页面的请求,给页面响应数据。

- Controller:控制层。接收前端发送的请求,对请求进行处理,并响应数据。
- Service:业务逻辑层。处理具体的业务逻辑。
- Dao:数据访问层(Data Access Object),也称为持久层。负责数据访问操作,包括数据的增、删、改、查。
高内聚低耦合
- 内聚: 软件中各个功能模块内部的功能联系。
- 耦合: 衡量软件中各个层/模块之间的依赖、关联的程度。
解耦思路
不要在层里new 对象,很容易导致层与层之间代码耦合。
=>将要用的对象交给一个容器管理
=>应用程序中要到这个对象就从容器中获取
设计到两个概念:控制反转和依赖注入
- 控制反转: Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转。
- 对象的创建权由程序员主动创建转移到容器(由容器创建、管理对象)。这个容器称为:IOC容器或Spring容器。
- 依赖注入: Dependency Injection,简称DI。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。
- 程序运行时需要某个资源,此时容器就为其提供这个资源。
- 例:EmpController程序运行时需要EmpService对象,Spring容器就为其提供并注入EmpService对象。
- bean对象: IOC容器中创建、管理的对象,称之为:bean对象。
IOC和DI
1). 将Service及Dao层的实现类,交给IOC容器管理
在实现类加上 @Component 注解,就代表把当前类产生的对象交给IOC容器管理。
2). 为Controller 及 Service注入运行时所依赖的对象@Autowired // 应用程序运行时,会自动查询该类型的bean对象,并赋值给该成员变量
| 说明 | 位置 | 注解 |
|---|---|---|
| 声明bean的基础注解 | 不属于以下三类时,用此注解 | @Component |
| @Component的衍生注解 | 标注在控制层类上 | @Controller |
| @Component的衍生注解 | 标注在业务层类上 | @Service |
| @Component的衍生注解 | 标注在数据访问层类上(由于与mybatis整合,用的少) | @Repository |
[!NOTE]
注意1:声明bean的时候,可以通过注解的value属性指定bean的名字,如果没有指定,默认为类名首字母小写。
注意2:使用以上四个注解都可以声明bean,但是在springboot集成web开发中,声明控制器bean只能用@Controller。
Bean对象:由Spring IOC容器创建、组装和管理的Java对象(也就是被Spring托管的对象)
- 生命周期:

创建Bean的例子:
1 | // 1. Service层Bean |
Bean的依赖注入:
1 |
|
从bean的生命周期图中看到,为了让bean生效,还需要让它被组件扫描@ComponentScan
- 该注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解
@SpringBootApplication中,默认扫描的范围是启动类所在包及其子包。
DI
依赖注入,是指IOC容器要为应用程序去提供运行时所依赖的资源,而资源指的就是对象。@Autowired注解,默认是按照类型进行自动装配的(去IOC容器中找某个类型的对象,然后完成注入操作)
@Autowired用法
属性注入
1 |
|
一个类依赖了哪些外部组件,通过属性注入是无法一眼看出来的。你必须阅读整个类的所有字段才能知道。(缺点:隐藏了类之间的依赖关系、可能会破坏类的封装性。)
构造函数注入
1 |
|
- 优点:能清晰地看到类的依赖关系、提高了代码的安全性。
- 缺点:代码繁琐、如果构造参数过多,可能会导致构造函数臃肿。
setter注入
1 | /** |
- 优点:保持了类的封装性,依赖关系更清晰。
- 缺点:需要额外编写setter方法,增加了代码量。
如果我们定义了多个相同的类,容器里会存在多个相同类型的bean,而框架不知道具体要注入哪个bean使用,会报错。
- @Primary(存在相同的bean注入时,有这个注解的是默认的实现)
- @Qualifier(指定当前要注入的bean对象–指定注入的bean名称)
- @Qualifier注解不能单独使用,必须配合@Autowired使用。
- @Resource(是按照bean的名称进行注入。通过name属性指定要注入的bean的名称。)
@Autowired和@Resource区别:
- 前者是spring框架提供的注解,而后者是JDK提供的注解
- @Autowired默认是按类型注入,而后者是按照名称注入