《苍穹外卖》SpringBoot后端开发项目重点知识整理(DAY1 to DAY3)
目录
- 一、在本地部署并启动Nginx服务
- 1. 解压Nginx压缩包
- 2. 启动Nginx服务
- 3. 验证Nginx是否启动成功:
- 二、导入接口文档
- 1. 黑马程序员提供的YApi平台
- 2. YApi Pro平台
- 3. 推荐工具:Apifox
- 三、Swagger
- 1. 常用注解
- 1.1 @Api与@ApiModel
- 1.2 @ApiModelProperty与@ApiOperation
- 四、基于JWT和ThreadLocal动态获取员工ID
- 1. 在pom.xml中引入JWT依赖
- 2. 在application.yaml中配置JWT参数
- 3. 使用JWT获取当前登录员工ID
- 4. 通过拦截器解析JWT
- 5. 使用ThreadLocal传递员工ID
- 6. 在Service中获取员工ID
- 五、DTO的使用原因
- 1. 实体类 Employee
- 2. DTO EmployeeDTO
- 3. 使用 DTO 的场景
- 3.1 查询员工信息
- 3.2 更新员工信息
- 3.3 新增员工
- 4. DTO、VO和实体类的区别
- 六、为什么使用 XML 注解而不是 MyBatis 注解
- 1. 使用 XML 注解的原因
- 1.1 动态 SQL 支持
- 1.2 SQL 与代码分离
- 1.3 复用性
- 1.4 工具支持
- 2. MyBatis 注解的局限性
- 2.1 动态 SQL 支持有限
- 2.2 可读性差
- 2.3 维护困难
- 七、Spring Boot 的请求映射规则
- 1. 类级别路径
- 2. 方法级别路径
- 2.1 分页查询
- 2.2 根据 ID 查询菜品
- 2.3 修改菜品
- 2.4 新增菜品
- 2.5 批量删除菜品
- 3. 如何区分不同的功能
- 4. 示例请求
- 4.1 新增菜品
- 4.2 修改菜品
- 4.3 批量删除菜品
- 4.4 分页查询菜品
- 4.5 根据 ID 查询菜品
- 八、接口设计中的是否必须原则
- 1. 请求参数说明
- 1.1 Java代码分析
- 1.1.1 必需参数
- 1.2 XML映射文件分析
- 1.2.1 可选参数
- 2. 返回响应说明
- 2.1 Java代码分析
- 2.1.1 必需参数
- 2.1.2 可选参数
- 2.2 返回响应示例
- 2.2.1 成功响应(带数据)
- 2.2.2 成功响应(不带数据)
- 2.2.3 失败响应
- 九、阿里云OSS配置指南
- 1. 注册阿里云OSS账号
- 2. 获取关键信息
- 3. 更新配置文件
- 4, 重新运行服务
视频链接:黑马程序员Java项目实战《苍穹外卖》,最适合新手的SpringBoot+SSM的企业级Java项目实战
网盘资料:苍穹外卖讲义&前后端源码
一、在本地部署并启动Nginx服务
在开发过程中,我们经常需要使用Nginx来部署前端项目或作为反向代理服务器。
1. 解压Nginx压缩包
首先,确保你已经从黑马程序员资料中下载了Nginx的压缩包。接下来,按照以下步骤解压:
选择解压路径:
- 将Nginx压缩包解压到一个全英文路径中。例如:
D:\nginx - 注意:路径中不要包含中文或特殊字符,否则可能会导致Nginx无法正常运行。
2. 启动Nginx服务
解压完成后,按照以下步骤启动Nginx:
进入Nginx目录:
- 打开解压后的Nginx文件夹,找到
nginx.exe文件。路径通常为:C:\nginx\nginx.exe
启动Nginx:
- 双击
nginx.exe文件,启动Nginx服务。 - 启动后,Nginx会在后台运行,你可以在任务管理器中看到
nginx.exe进程。
3. 验证Nginx是否启动成功:
- 打开浏览器,访问以下地址(其中80是默认端口可省略不写):
http://localhost:80 - 如果看到此页面,说明Nginx已成功启动。

- 注意:Nginx默认不会随系统自动启动,因此每次重启电脑后,都需要手动启动Nginx
二、导入接口文档
在开发过程中,接口管理平台是团队协作和项目管理的重要工具。以下是几个常用平台的对比:
1. 黑马程序员提供的YApi平台
- 地址:http://yapi.smart-xwork.cn/
- 状态:已弃用
- 功能:适合用于接口管理和文档生成。
2. YApi Pro平台
- 地址:https://yapi.pro/
- 问题:需要挂梯子才能访问,且极易卡顿,使用体验不佳。
3. 推荐工具:Apifox
- 地址:https://apifox.com/
- 优势:
- 无需梯子即可访问。
- 性能流畅,支持接口文档、Mock数据、自动化测试等功能。
- 支持导入YApi数据格式的接口文档,方便无缝迁移现有项目。

三、Swagger
Swagger 是一种用于设计、构建、记录和使用 RESTful Web 服务的开源框架。它提供了一套工具,帮助开发者设计、构建、文档化和测试 API。
启动服务:访问 http://localhost:8080/doc.html

1. 常用注解
通过注解可以控制生成的接口文档,使接口文档拥有更好的可读性,常用注解如下:
| 注解 | 说明 |
|---|---|
| @Api | 用在类上,例如Controller,表示对类的说明 |
| @ApiModel | 用在类上,例如entity、DTO、VO |
| @ApiModelProperty | 用在属性上,描述属性信息 |
| @ApiOperation | 用在方法上,例如Controller的方法,说明方法的用途、作用 |
1.1 @Api与@ApiModel


1.2 @ApiModelProperty与@ApiOperation


四、基于JWT和ThreadLocal动态获取员工ID
在开发员工管理系统时,新增员工时需要记录创建人和修改人的ID。如果直接使用固定值,会导致数据不准确,无法真实反映操作者。
public void save(EmployeeDTO employeeDTO) {Employee employee = new Employee();employee.setCreateUser(10L); // 固定值employee.setUpdateUser(10L); // 固定值employeeMapper.insert(employee);
}
因此我们要通过JWT和ThreadLocal动态获取当前登录员工的ID,并实现数据的准确记录。在使用 JWT(JSON Web Token)进行身份验证时,通常需要在项目中引入相关的依赖库,并在配置文件中设置 JWT 的参数。以下是如何在 Spring Boot 项目中引入 JWT 并进行配置的简单说明:
1. 在pom.xml中引入JWT依赖
为了使用 JWT,我们需要引入一个 JWT 库,比如 java-jwt(由 Auth0 提供)。
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>4.4.0</version> <!-- 使用最新版本 -->
</dependency>
2. 在application.yaml中配置JWT参数
在 application.yaml 文件中定义 JWT 的相关配置,例如密钥、过期时间和令牌名称。
sky:jwt:# 设置 JWT 签名加密时使用的秘钥admin-secret-key: itcast# 设置 JWT 过期时间(单位:毫秒)admin-ttl: 7200000 # 2小时# 设置前端传递过来的令牌名称admin-token-name: token
admin-secret-key:用于签名和验证 JWT 的密钥。必须保密,且长度足够复杂以确保安全性。admin-ttl:JWT 的有效期(以毫秒为单位)。例如,7200000表示 2 小时。admin-token-name:前端传递 JWT 时使用的参数名称。例如,前端可能会在请求头或请求参数中传递token=xxx。
3. 使用JWT获取当前登录员工ID
员工登录成功后,系统会生成JWT令牌并返回给前端。JWT中包含了当前登录员工的ID信息。
/*** 员工管理*/
@RestController
@RequestMapping("/admin/employee")
@Api(tags = "员工相关接口")
@Slf4j
public class EmployeeController {@Autowiredprivate EmployeeService employeeService;@Autowiredprivate JwtProperties jwtProperties;/*** 登录** @param employeeLoginDTO* @return*/@PostMapping("/login")public Result<EmployeeLoginVO> login(@RequestBody EmployeeLoginDTO employeeLoginDTO) {log.info("员工登录:{}", employeeLoginDTO);Employee employee = employeeService.login(employeeLoginDTO);//登录成功后,生成jwt令牌Map<String, Object> claims = new HashMap<>();claims.put(JwtClaimsConstant.EMP_ID, employee.getId());String token = JwtUtil.createJWT(jwtProperties.getAdminSecretKey(),jwtProperties.getAdminTtl(),claims);EmployeeLoginVO employeeLoginVO = EmployeeLoginVO.builder().id(employee.getId()).userName(employee.getUsername()).name(employee.getName()).token(token).build();return Result.success(employeeLoginVO);}...
}
4. 通过拦截器解析JWT
在每次请求时,前端会携带JWT令牌。通过拦截器解析JWT,获取当前登录员工的ID。
/*** jwt令牌校验的拦截器*/
@Component
@Slf4j
public class JwtTokenAdminInterceptor implements HandlerInterceptor {@Autowiredprivate JwtProperties jwtProperties;/*** 校验jwt** @param request* @param response* @param handler* @return* @throws Exception*/public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//判断当前拦截到的是Controller的方法还是其他资源if (!(handler instanceof HandlerMethod)) {//当前拦截到的不是动态方法,直接放行return true;}//1、从请求头中获取令牌String token = request.getHeader(jwtProperties.getAdminTokenName());//2、校验令牌try {log.info("jwt校验:{}", token);Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());log.info("当前员工id:", empId);BaseContext.setCurrentId(empId);//3、通过,放行return true;} catch (Exception ex) {//4、不通过,响应401状态码response.setStatus(401);return false;}}
}
5. 使用ThreadLocal传递员工ID
通过ThreadLocal实现线程隔离,将当前登录员工的ID传递给Service层。
public class BaseContext {public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();public static void setCurrentId(Long id) {threadLocal.set(id);}public static Long getCurrentId() {return threadLocal.get();}public static void removeCurrentId() {threadLocal.remove();}
}
6. 在Service中获取员工ID
在Service层中,从ThreadLocal中获取当前登录员工的ID,并设置为创建人和修改人。
public void save(EmployeeDTO employeeDTO) {Employee employee = new Employee();employee.setCreateUser(BaseContext.getCurrentId()); // 动态获取当前登录员工IDemployee.setUpdateUser(BaseContext.getCurrentId()); // 动态获取当前登录员工IDemployeeMapper.insert(employee);
}
五、DTO的使用原因
在项目中,Employee 是实体类(Entity),用于表示数据库中的员工记录,而 EmployeeDTO 是数据传输对象(DTO),用于在不同层之间传递数据。以下是使用 DTO 的主要原因和优势:
1. 实体类 Employee
package com.sky.entity;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;
import java.time.LocalDateTime;@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Employee implements Serializable {private static final long serialVersionUID = 1L;private Long id; // 员工IDprivate String username; // 用户名private String name; // 姓名private String password; // 密码(敏感字段)private String phone; // 手机号private String sex; // 性别private String idNumber; // 身份证号private Integer status; // 状态private LocalDateTime createTime; // 创建时间(内部字段)private LocalDateTime updateTime; // 更新时间(内部字段)private Long createUser; // 创建人(内部字段)private Long updateUser; // 更新人(内部字段)
}
2. DTO EmployeeDTO
package com.sky.dto;import lombok.Data;
import java.io.Serializable;@Data
public class EmployeeDTO implements Serializable {private Long id; // 员工IDprivate String username; // 用户名private String name; // 姓名private String phone; // 手机号private String sex; // 性别private String idNumber; // 身份证号
}
3. 使用 DTO 的场景
3.1 查询员工信息
- 前端只需要员工的基本信息(如
id、username、name、phone、sex、idNumber)。 - 后端返回
EmployeeDTO,过滤掉敏感字段(如password)和内部字段(如createTime)。
3.2 更新员工信息
- 前端传递
EmployeeDTO作为请求体,后端根据 DTO 更新员工信息。 - 避免前端传递不必要的字段(如
password、createTime)。
3.3 新增员工
- 前端传递
EmployeeDTO作为请求体,后端将 DTO 转换为实体类并保存到数据库。 - 避免前端传递内部字段(如
createTime、updateTime)。
4. DTO、VO和实体类的区别
| 特性 | DTO | VO | Entity |
|---|---|---|---|
| 目的 | 数据传输 | 数据展示或封装值 | 表示数据库中的数据结构 |
| 使用场景 | 跨层数据传输(如Controller-Service) | 展示层或领域模型 | 数据库操作、业务逻辑 |
| 可变性 | 可变(通常有setter) | 通常不可变(无setter) | 可变(用于持久化和业务逻辑) |
| 字段 | 与传输需求相关 | 与展示或业务逻辑相关 | 与数据库表字段严格对应 |
| 行为 | 通常无行为 | 可能包含简单行为(如格式化) | 包含业务逻辑和验证规则 |
| 示例 | UserDTO | UserVO | UserEntity |
六、为什么使用 XML 注解而不是 MyBatis 注解
1. 使用 XML 注解的原因
1.1 动态 SQL 支持
- XML 提供了强大的动态 SQL 支持,例如
<if>、<foreach>、<choose>等标签。 - 在复杂的查询场景中,动态 SQL 可以更灵活地构建 SQL 语句。
1.2 SQL 与代码分离
- 将 SQL 语句写在 XML 文件中,可以使 SQL 与 Java 代码分离,便于维护和管理。
- 对于复杂的 SQL 语句,XML 文件的可读性更高。
1.3 复用性
- XML 文件中的 SQL 语句可以在多个 Mapper 接口中复用。
- 例如,可以在不同的 Mapper 接口中引用同一个 SQL 片段。
1.4 工具支持
- MyBatis 提供了丰富的工具支持 XML 文件的编写和调试。
- 例如,MyBatis Generator 可以自动生成 XML 映射文件。
2. MyBatis 注解的局限性
2.1 动态 SQL 支持有限
- MyBatis 注解对动态 SQL 的支持较弱,复杂的 SQL 语句难以用注解实现。
- 例如,
@Select注解无法直接实现<foreach>这样的动态 SQL。
<select id="getSetmealIdsByDishIds" resultType="java.lang.Long">select setmeal_id from setmeal_dish where dish_id in<foreach collection="dishIds" item="dishId" separator="," open="(" close=")">#{dishId}</foreach>
</select>
2.2 可读性差
- 复杂的 SQL 语句写在注解中会导致代码冗长,可读性差。
- 例如,一个包含多个条件的查询语句会显得非常混乱。
2.3 维护困难
- SQL 语句与 Java 代码混合在一起,维护起来不如 XML 文件方便。
- 修改 SQL 语句时需要重新编译 Java 代码。
你提到的代码中有两个 @PutMapping 注解没有指定路径,这意味着它们默认映射到类级别的路径 /admin/dish。以下是对这个问题的详细解释:
七、Spring Boot 的请求映射规则
在 Spring Boot 中,请求的映射是通过 类级别的 @RequestMapping 和 方法级别的 @PutMapping、@GetMapping 等注解 共同决定的。
- 类级别的
@RequestMapping:- 定义了该类中所有方法的公共路径前缀。
- 例如,
@RequestMapping("/admin/dish")表示该类中的所有方法都映射到/admin/dish路径下。 - 管理端发出的请求,统一使用
/admin作为前缀。 - 用户端发出的请求,统一使用
/user作为前缀。
- 方法级别的
@PutMapping、@GetMapping等:- 定义了具体的 HTTP 方法和路径。
- 如果方法级别的注解没有指定路径,则默认使用类级别的路径。
1. 类级别路径
@RestController
@RequestMapping("/admin/dish")
public class DishController {// 方法定义...
}
- 所有方法的公共路径前缀是
/admin/dish。
2. 方法级别路径
2.1 分页查询
@GetMapping("/page")
public Result<PageResult> page(DishPageQueryDTO dishPageQueryDTO) {// 方法实现...
}
- 完整路径是
/admin/dish/page。
2.2 根据 ID 查询菜品
@GetMapping("/{id}")
public Result<DishVO> getById(@PathVariable Long id) {// 方法实现...
}
- 完整路径是
/admin/dish/{id}。
2.3 修改菜品
@PutMapping
public Result update(@RequestBody DishDTO dishDTO) {// 方法实现...
}
- 由于
@PutMapping没有指定路径,默认使用类级别的路径/admin/dish。
2.4 新增菜品
@PostMapping
public Result save(@RequestBody DishDTO dishDTO) {// 方法实现...
}
- 由于
@PostMapping没有指定路径,默认使用类级别的路径/admin/dish。
2.5 批量删除菜品
@DeleteMapping
public Result delete(@RequestParam List<Long> ids) {// 方法实现...
}
- 由于
@DeleteMapping没有指定路径,默认使用类级别的路径/admin/dish。
3. 如何区分不同的功能
Spring Boot 通过 HTTP 方法 来区分不同的功能。例如:
| HTTP 方法 | 路径 | 功能 |
|---|---|---|
POST | /admin/dish | 新增菜品 |
PUT | /admin/dish | 修改菜品 |
DELETE | /admin/dish | 批量删除菜品 |
GET | /admin/dish/page | 分页查询菜品 |
GET | /admin/dish/{id} | 根据 ID 查询菜品 |
4. 示例请求
4.1 新增菜品
- HTTP 方法:
POST - URL:
/admin/dish - 请求体:
{"name": "宫保鸡丁","price": 38.0,"flavors": [{"name": "微辣","value": "少辣"}] }
4.2 修改菜品
- HTTP 方法:
PUT - URL:
/admin/dish - 请求体:
{"id": 1,"name": "宫保鸡丁","price": 40.0,"flavors": [{"name": "微辣","value": "少辣"}] }
4.3 批量删除菜品
- HTTP 方法:
DELETE - URL:
/admin/dish?ids=1,2,3 - 请求参数:
ids=1,2,3
4.4 分页查询菜品
- HTTP 方法:
GET - URL:
/admin/dish/page?page=1&pageSize=10 - 请求参数:
page=1&pageSize=10
4.5 根据 ID 查询菜品
- HTTP 方法:
GET - URL:
/admin/dish/1 - 路径参数:
id=1
八、接口设计中的是否必须原则
参数的必需与非必需性是通过不同的方式来体现的,以下是具体案例
1. 请求参数说明

从接口文档中可以看到,请求参数包括以下几项:
| 参数名 | 类型 | 说明 | 必需性 | 示例值 |
|---|---|---|---|---|
categoryId | string | 分类id | 可选 | 101 |
name | string | 菜品名称 | 可选 | 官保鸡丁 |
page | string | 页码 | 必需 | 1 |
pageSize | string | 每页记录数 | 必需 | 10 |
status | string | 分类状态 | 可选 | 1 |
-
必需参数:
page和pageSize是分页查询的必需参数,用于指定查询的页码和每页的记录数。
-
可选参数:
categoryId、name和status是可选参数,用于过滤查询结果。
1.1 Java代码分析
在此 Java 代码中,DishPageQueryDTO 是一个数据传输对象(DTO),用于封装分页查询的参数。以下是代码的详细分析:
public PageResult pageQuery(DishPageQueryDTO dishPageQueryDTO) {// 1. 使用 PageHelper 进行分页PageHelper.startPage(dishPageQueryDTO.getPage(), dishPageQueryDTO.getPageSize());// 2. 调用 Mapper 进行查询Page<DishVO> page = dishMapper.pageQuery(dishPageQueryDTO);// 3. 返回分页结果return new PageResult(page.getTotal(), page.getResult());
}
1.1.1 必需参数
dishPageQueryDTO.getPage()和dishPageQueryDTO.getPageSize()是分页查询的必需参数。- 如果这两个参数为空或未提供,分页功能将无法正常工作。
1.2 XML映射文件分析
在 SQL 代码中,动态 SQL 语句根据传入的参数生成查询条件。以下是代码的详细分析:
<select id="pageQuery" resultType="com.sky.vo.DishVO">select d.* , c.name as categoryName from dish d left outer join category c on d.category_id = c.id<where><if test="name != null">and d.name like concat('%',#{name},'%')</if><if test="categoryId != null">and d.category_id = #{categoryId}</if><if test="status != null">and d.status = #{status}</if></where>order by d.create_time desc
</select>
1.2.1 可选参数
name、categoryId和status是可选参数,通过<if>标签动态生成查询条件。- 如果某个参数为
null,则对应的条件不会添加到 SQL 查询中。
通过这种设计,分页查询接口既满足了基本的查询需求,又提供了灵活的过滤选项,适用于不同的业务场景。
2. 返回响应说明
在 API 设计中,返回响应的数据结构通常需要遵循一定的规范,以确保客户端能够准确处理和理解服务器的响应。Result<T> 类是一个典型的统一响应格式,根据不同的设计需求,我们发现 code 一定是必需的,而 msg 和 data 在某些情况下是可选的,而在某些情况可能是必需的。接下来,我们将详细探讨这种设计背后的原因。


2.1 Java代码分析
package com.sky.result;import lombok.Data;import java.io.Serializable;`/*** 后端统一返回结果* @param <T>*/
@Data
public class Result<T> implements Serializable {private Integer code; //编码:1成功,0和其它数字为失败private String msg; //错误信息private T data; //数据public static <T> Result<T> success() {Result<T> result = new Result<T>();result.code = 1;return result;}public static <T> Result<T> success(T object) {Result<T> result = new Result<T>();result.data = object;result.code = 1;return result;}public static <T> Result<T> error(String msg) {Result result = new Result();result.msg = msg;result.code = 0;return result;}}
2.1.1 必需参数
code 是必需的
- 作用:
code用于表示请求的处理结果状态,通常是一个数字。- 例如:
1表示成功,0或其他数字表示失败。
- 例如:
- 为什么必需:
- 明确状态:客户端需要知道请求是否成功。
code提供了一个明确的状态标识,客户端可以根据它决定后续操作。 - 标准化:统一的
code值可以让客户端以一致的方式处理所有 API 的响应。 - 错误处理:当请求失败时,
code可以帮助客户端快速定位问题类型(如权限不足、资源不存在等)。
- 明确状态:客户端需要知道请求是否成功。
2.1.2 可选参数
msg 是可选的
- 作用:
msg用于提供额外的错误信息或成功提示。- 例如:成功时:
msg可以为空或包含提示信息(如“操作成功”),失败时:msg可以包含具体的错误描述(如“用户未找到”)。
- 例如:成功时:
- 为什么可选:
- 成功时可能不需要:在请求成功的情况下,客户端可能只需要
data,而不需要额外的提示信息。 - 减少冗余:如果
msg是必需的,即使没有实际意义的信息(如成功时的默认提示),也需要返回,这会增加响应的冗余。 - 灵活性:在某些场景下,错误信息可能由其他方式提供(如日志或专门的错误处理机制),因此
msg可以省略。
- 成功时可能不需要:在请求成功的情况下,客户端可能只需要
data 是可选的
- 作用:
data用于承载实际的响应数据。- 例如:查询接口返回的列表或对象,创建接口返回的新创建的资源。
- 为什么可选:
- 某些操作不需要返回数据:例如,删除操作或简单的状态更新操作可能不需要返回任何数据。
- 减少冗余:如果
data是必需的,即使没有数据也需要返回一个空对象或null,这会增加响应的冗余。 - 灵活性:某些接口可能只需要返回状态信息(如
code和msg),而不需要额外的数据。
2.2 返回响应示例
2.2.1 成功响应(带数据)
{"code": 1,"msg": "操作成功","data": {"id": 123,"name": "John Doe"}
}
2.2.2 成功响应(不带数据)
{"code": 1
}
2.2.3 失败响应
{"code": 0,"msg": "用户未找到"
}
这种设计符合 API 设计的最佳实践,能够满足大多数场景的需求,同时保持简洁和一致性。
九、阿里云OSS配置指南
在使用对象存储服务时,可能会遇到Bucket失效的情况,从而导致服务无法正常运行。为了解决这个问题,我们需要重新配置一个新的Bucket,并更新相关配置文件。参考教程:Java利用阿里云OSS/本地存储实现文件上传功能
1. 注册阿里云OSS账号
首先,访问阿里云-对象存储OSS官网注册账号。新用户可免费试用20GB存储空间,有效期为3个月。

2. 获取关键信息
注册完成后,获取以下四个关键信息:
Endpoint:OSS服务的访问地址。Access Key ID:用于身份验证的访问密钥ID。Access Key Secret:用于身份验证的访问密钥。Bucket Name:新创建的Bucket名称。

3. 更新配置文件
将上述获取的信息填写到对应的YAML配置文件sky-server/src/main/resources/application-dev.yml目录下
sky:datasource:driver-class-name: com.mysql.cj.jdbc.Driverhost: localhostport: 3306database: sky_take_outusername: your_usernamepassword: your_passwordalioss:endpoint: your_endpointaccess-key-id: your_accessKeyIdaccess-key-secret: your_keySecretbucket-name: your_bucketName# endpoint: oss-cn-hangzhou.aliyuncs.com
# access-key-id: LTAI5tPeFLzsPPT8gG3LPW64
# access-key-secret: U6k1brOZ8gaOIXv3nXbulGTUzy6Pd7
# bucket-name: sky-take-out
4, 重新运行服务
保存配置文件后,重新运行服务并打开前端页面,发现图片能够正常上传了!

并且我们可以在自己的对象存储OSS文件管理中监控到从前端页面上传的图片文件

相关文章:
《苍穹外卖》SpringBoot后端开发项目重点知识整理(DAY1 to DAY3)
目录 一、在本地部署并启动Nginx服务1. 解压Nginx压缩包2. 启动Nginx服务3. 验证Nginx是否启动成功: 二、导入接口文档1. 黑马程序员提供的YApi平台2. YApi Pro平台3. 推荐工具:Apifox 三、Swagger1. 常用注解1.1 Api与ApiModel1.2 ApiModelProperty与Ap…...
管理网络安全
防火墙在 Linux 系统安全中有哪些重要的作用? 防火墙作为网络安全的第一道防线,能够根据预设的规则,对进出系统的网络流量进行严格筛选。它可以阻止未经授权的外部访问,只允许符合规则的流量进入系统,从而保护系统免受…...
明日直播|Go IoT 开发平台,开启万物智联新征程
在物联网技术飞速发展的当下,物联网行业却深受协议碎片化、生态封闭、开发低效等难题的困扰。企业和开发者们渴望找到一个能突破这些困境,实现高效、便捷开发的有力工具。 3 月 11 日(星期二)19:00,GitCode 特别邀请独…...
系统架构设计师—系统架构设计篇—软件架构风格
文章目录 概述经典体系结构风格数据流风格批处理管道过滤器对比 调用/返回风格主程序/子程序面向对象架构风格层次架构风格 独立构件风格进程通信事件驱动的系统 虚拟机风格解释器基于规则的系统 仓库风格(数据共享风格)数据库系统黑板系统超文本系统 闭…...
【MySQL_04】数据库基本操作(用户管理--配置文件--远程连接--数据库信息查看、创建、删除)
文章目录 一、MySQL 用户管理1.1 用户管理1.11 mysql.user表详解1.12 添加用户1.13 修改用户权限1.14 删除用户1.15 密码问题 二、MySQL 配置文件2.1 配置文件位置2.2 配置文件结构2.3 常用配置参数 三、MySQL远程连接四、数据库的查看、创建、删除4.1 查看数据库4.2 创建、删除…...
【Zinx】Day5-Part4:Zinx 的连接属性设置
目录 Day5-Part4:Zinx 的连接属性设置给连接添加连接配置的接口连接属性方法的实现 测试 Zinx-v1.0总结 Day5-Part4:Zinx 的连接属性设置 在 Zinx 当中,我们使用 Server 来开启服务并监听指定的端口,当接收到来自客户端的连接请求…...
【英伟达AI论文】多模态大型语言模型的高效长视频理解
摘要:近年来,基于视频的多模态大型语言模型(Video-LLMs)通过将视频处理为图像帧序列,显著提升了视频理解能力。然而,许多现有方法在视觉主干网络中独立处理各帧,缺乏显式的时序建模,…...
小程序事件系统 —— 32 事件系统 - 事件分类以及阻止事件冒泡
在微信小程序中,事件分为 冒泡事件 和 非冒泡事件 : 冒泡事件:当一个组件的事件被触发后,该事件会向父节点传递;(如果父节点中也绑定了一个事件,父节点事件也会被触发,也就是说子组…...
全球首款 5G-A 人形机器人发布
全球首款 5G-A 人形机器人于世界移动通信大会(MWC2025)上由中国移动、华为、乐聚联合发布。以下是关于这款机器人的详细介绍: 名称与背景 名称9:这款人形机器人名为 “夸父”,是中国移动、华为与乐聚机器人在 GTI 平台…...
Tomcat 新手入门指南
Tomcat 新手入门指南 Apache Tomcat 是一个开源的 Java Servlet 容器和 Web 服务器,广泛用于部署和运行 Java Web 应用程序。以下是 Tomcat 的入门指南,帮助你快速上手。 1. 安装 Tomcat 步骤 1: 下载 Tomcat 访问 Apache Tomcat 官网。选择适合的版…...
Flink-DataStreamAPI-生成水印
下面我们将学习Flink提供的用于处理事件时间戳和水印的API,也会介绍有关事件时间、流转时长和摄取时间,下面就让我们跟着官网来学习吧 一、水印策略介绍 为了处理事件时间,Flink需要知道事件时间戳,这意味着流中的每个元素都需要…...
【单片机】ARM 处理器简介
ARM 公司简介 ARM(Advanced RISC Machine) 是英国 ARM 公司(原 Acorn RISC Machine) 开发的一种精简指令集(RISC) 处理器架构。ARM 处理器因其低功耗、高性能、广泛适用性,成为嵌入式系统、移动…...
Flutter——最详细原生交互(MethodChannel、EventChannel、BasicMessageChannel)使用教程
MethodChannel(方法通道) 用途:实现 双向通信,用于调用原生平台提供的 API 并获取返回结果。 场景:适合一次性操作,如调用相机、获取设备信息等。 使用步骤: Flutter 端:通过 Meth…...
Kafka常用指令(详细)
Kafka常用指令(详细) 启停命令 前台启动 前台启动命令 ./bin/kafka-server-start.sh config/server.properties 后台启动方式1 后台启动命令加上参数-daemon,窗口关闭之后kafka后台程序继续运行 ./bin/kafka-server-start.sh -daemon co…...
供应链工作效率如何提升
提升供应链工作效率可以从以下几个关键方面入手: 1. 优化供应链管理 数据驱动决策:利用AI和大数据分析,提高预测准确性,优化库存管理。供应链可视化:采用ERP(企业资源计划)和SCM(供…...
1-001:MySQL的存储引擎有哪些?它们之间有什么区别?
MySQL 存储引擎 ├── InnoDB(默认引擎) │ ├── 事务支持:支持 ACID 和事务(事务日志、回滚、崩溃恢复) │ ├── 锁机制:支持行级锁,提高并发性能 │ ├── 外键支持:支持外键…...
Java/Kotlin逆向基础与Smali语法精解
1. 法律警示与道德边界 1.1 司法判例深度剖析 案例一:2021年某游戏外挂团伙刑事案 犯罪手法:逆向《王者荣耀》通信协议,修改战斗数据包 技术细节:Hook libil2cpp.so的SendPacket函数 量刑依据:非法经营罪ÿ…...
用AI学编程4——swift学习1
一个swift文件, 整理出swift从入门到精通的所有知识点, 给出注释, 给出这样的swift文件 以下是一个整合了 Swift 从入门到精通的主要知识点的 Swift 文件,包含了基础语法、面向对象编程、异常处理、集合框架、多线程、Lambda 表达…...
数据集构建与训练前准备
训练数据集目录结构与格式 作者笨蛋学法,先将其公式化,后面逐步自己进行修改,读者觉得看不懂可以理解成,由结果去推过程,下面的这个yaml文件就是结果,我们去推需要的文件夹(名字可以不固定,但是…...
在大型语言模型的提示词设计中,system、user和assistant三个角色的区别与联系
在大型语言模型的提示词设计中,system、user和assistant三个角色承担不同的功能,其区别与联系如下: 1. 角色定义与功能 system(系统指令) 作用:设定模型的整体行为、角色定位和任务框架。例如,“你是一位专业的科技作家”或“仅回答与医疗相关的问题”。特点:在多轮对话…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...
PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...
Ubuntu Cursor升级成v1.0
0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
快速排序算法改进:随机快排-荷兰国旗划分详解
随机快速排序-荷兰国旗划分算法详解 一、基础知识回顾1.1 快速排序简介1.2 荷兰国旗问题 二、随机快排 - 荷兰国旗划分原理2.1 随机化枢轴选择2.2 荷兰国旗划分过程2.3 结合随机快排与荷兰国旗划分 三、代码实现3.1 Python实现3.2 Java实现3.3 C实现 四、性能分析4.1 时间复杂度…...
RabbitMQ 各类交换机
为什么要用交换机? 交换机用来路由消息。如果直发队列,这个消息就被处理消失了,那别的队列也需要这个消息怎么办?那就要用到交换机 交换机类型 1,fanout:广播 特点 广播所有消息:将消息…...
