当前位置: 首页 > news >正文

《苍穹外卖》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 查询员工信息

  • 前端只需要员工的基本信息(如 idusernamenamephonesexidNumber)。
  • 后端返回 EmployeeDTO,过滤掉敏感字段(如 password)和内部字段(如 createTime)。

3.2 更新员工信息

  • 前端传递 EmployeeDTO 作为请求体,后端根据 DTO 更新员工信息。
  • 避免前端传递不必要的字段(如 passwordcreateTime)。

3.3 新增员工

  • 前端传递 EmployeeDTO 作为请求体,后端将 DTO 转换为实体类并保存到数据库。
  • 避免前端传递内部字段(如 createTimeupdateTime)。

4. DTO、VO和实体类的区别

特性DTOVOEntity
目的数据传输数据展示或封装值表示数据库中的数据结构
使用场景跨层数据传输(如Controller-Service)展示层或领域模型数据库操作、业务逻辑
可变性可变(通常有setter)通常不可变(无setter)可变(用于持久化和业务逻辑)
字段与传输需求相关与展示或业务逻辑相关与数据库表字段严格对应
行为通常无行为可能包含简单行为(如格式化)包含业务逻辑和验证规则
示例UserDTOUserVOUserEntity

六、为什么使用 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. 请求参数说明

在这里插入图片描述

从接口文档中可以看到,请求参数包括以下几项:

参数名类型说明必需性示例值
categoryIdstring分类id可选101
namestring菜品名称可选官保鸡丁
pagestring页码必需1
pageSizestring每页记录数必需10
statusstring分类状态可选1
  • 必需参数

    • pagepageSize 是分页查询的必需参数,用于指定查询的页码和每页的记录数。
  • 可选参数

    • categoryIdnamestatus 是可选参数,用于过滤查询结果。

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 可选参数
  • namecategoryIdstatus 是可选参数,通过 <if> 标签动态生成查询条件。
  • 如果某个参数为 null,则对应的条件不会添加到 SQL 查询中。

通过这种设计,分页查询接口既满足了基本的查询需求,又提供了灵活的过滤选项,适用于不同的业务场景。


2. 返回响应说明

在 API 设计中,返回响应的数据结构通常需要遵循一定的规范,以确保客户端能够准确处理和理解服务器的响应。Result<T> 类是一个典型的统一响应格式,根据不同的设计需求,我们发现 code 一定是必需的,而 msgdata 在某些情况下是可选的,而在某些情况可能是必需的。接下来,我们将详细探讨这种设计背后的原因。

在这里插入图片描述
在这里插入图片描述

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,这会增加响应的冗余。
    • 灵活性:某些接口可能只需要返回状态信息(如 codemsg),而不需要额外的数据。

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. 获取关键信息

注册完成后,获取以下四个关键信息:

  1. Endpoint:OSS服务的访问地址。
  2. Access Key ID:用于身份验证的访问密钥ID。
  3. Access Key Secret:用于身份验证的访问密钥。
  4. 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是否启动成功&#xff1a; 二、导入接口文档1. 黑马程序员提供的YApi平台2. YApi Pro平台3. 推荐工具&#xff1a;Apifox 三、Swagger1. 常用注解1.1 Api与ApiModel1.2 ApiModelProperty与Ap…...

管理网络安全

防火墙在 Linux 系统安全中有哪些重要的作用&#xff1f; 防火墙作为网络安全的第一道防线&#xff0c;能够根据预设的规则&#xff0c;对进出系统的网络流量进行严格筛选。它可以阻止未经授权的外部访问&#xff0c;只允许符合规则的流量进入系统&#xff0c;从而保护系统免受…...

明日直播|Go IoT 开发平台,开启万物智联新征程

在物联网技术飞速发展的当下&#xff0c;物联网行业却深受协议碎片化、生态封闭、开发低效等难题的困扰。企业和开发者们渴望找到一个能突破这些困境&#xff0c;实现高效、便捷开发的有力工具。 3 月 11 日&#xff08;星期二&#xff09;19:00&#xff0c;GitCode 特别邀请独…...

系统架构设计师—系统架构设计篇—软件架构风格

文章目录 概述经典体系结构风格数据流风格批处理管道过滤器对比 调用/返回风格主程序/子程序面向对象架构风格层次架构风格 独立构件风格进程通信事件驱动的系统 虚拟机风格解释器基于规则的系统 仓库风格&#xff08;数据共享风格&#xff09;数据库系统黑板系统超文本系统 闭…...

【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&#xff1a;Zinx 的连接属性设置给连接添加连接配置的接口连接属性方法的实现 测试 Zinx-v1.0总结 Day5-Part4&#xff1a;Zinx 的连接属性设置 在 Zinx 当中&#xff0c;我们使用 Server 来开启服务并监听指定的端口&#xff0c;当接收到来自客户端的连接请求…...

【英伟达AI论文】多模态大型语言模型的高效长视频理解

摘要&#xff1a;近年来&#xff0c;基于视频的多模态大型语言模型&#xff08;Video-LLMs&#xff09;通过将视频处理为图像帧序列&#xff0c;显著提升了视频理解能力。然而&#xff0c;许多现有方法在视觉主干网络中独立处理各帧&#xff0c;缺乏显式的时序建模&#xff0c;…...

小程序事件系统 —— 32 事件系统 - 事件分类以及阻止事件冒泡

在微信小程序中&#xff0c;事件分为 冒泡事件 和 非冒泡事件 &#xff1a; 冒泡事件&#xff1a;当一个组件的事件被触发后&#xff0c;该事件会向父节点传递&#xff1b;&#xff08;如果父节点中也绑定了一个事件&#xff0c;父节点事件也会被触发&#xff0c;也就是说子组…...

全球首款 5G-A 人形机器人发布

全球首款 5G-A 人形机器人于世界移动通信大会&#xff08;MWC2025&#xff09;上由中国移动、华为、乐聚联合发布。以下是关于这款机器人的详细介绍&#xff1a; 名称与背景 名称9&#xff1a;这款人形机器人名为 “夸父”&#xff0c;是中国移动、华为与乐聚机器人在 GTI 平台…...

Tomcat 新手入门指南

Tomcat 新手入门指南 Apache Tomcat 是一个开源的 Java Servlet 容器和 Web 服务器&#xff0c;广泛用于部署和运行 Java Web 应用程序。以下是 Tomcat 的入门指南&#xff0c;帮助你快速上手。 1. 安装 Tomcat 步骤 1: 下载 Tomcat 访问 Apache Tomcat 官网。选择适合的版…...

Flink-DataStreamAPI-生成水印

下面我们将学习Flink提供的用于处理事件时间戳和水印的API&#xff0c;也会介绍有关事件时间、流转时长和摄取时间&#xff0c;下面就让我们跟着官网来学习吧 一、水印策略介绍 为了处理事件时间&#xff0c;Flink需要知道事件时间戳&#xff0c;这意味着流中的每个元素都需要…...

【单片机】ARM 处理器简介

ARM 公司简介 ARM&#xff08;Advanced RISC Machine&#xff09; 是英国 ARM 公司&#xff08;原 Acorn RISC Machine&#xff09; 开发的一种精简指令集&#xff08;RISC&#xff09; 处理器架构。ARM 处理器因其低功耗、高性能、广泛适用性&#xff0c;成为嵌入式系统、移动…...

Flutter——最详细原生交互(MethodChannel、EventChannel、BasicMessageChannel)使用教程

MethodChannel&#xff08;方法通道&#xff09; 用途&#xff1a;实现 双向通信&#xff0c;用于调用原生平台提供的 API 并获取返回结果。 场景&#xff1a;适合一次性操作&#xff0c;如调用相机、获取设备信息等。 使用步骤&#xff1a; Flutter 端&#xff1a;通过 Meth…...

Kafka常用指令(详细)

Kafka常用指令&#xff08;详细&#xff09; 启停命令 前台启动 前台启动命令 ./bin/kafka-server-start.sh config/server.properties 后台启动方式1 后台启动命令加上参数-daemon&#xff0c;窗口关闭之后kafka后台程序继续运行 ./bin/kafka-server-start.sh -daemon co…...

供应链工作效率如何提升

提升供应链工作效率可以从以下几个关键方面入手&#xff1a; 1. 优化供应链管理 数据驱动决策&#xff1a;利用AI和大数据分析&#xff0c;提高预测准确性&#xff0c;优化库存管理。供应链可视化&#xff1a;采用ERP&#xff08;企业资源计划&#xff09;和SCM&#xff08;供…...

1-001:MySQL的存储引擎有哪些?它们之间有什么区别?

MySQL 存储引擎 ├── InnoDB&#xff08;默认引擎&#xff09; │ ├── 事务支持&#xff1a;支持 ACID 和事务&#xff08;事务日志、回滚、崩溃恢复&#xff09; │ ├── 锁机制&#xff1a;支持行级锁&#xff0c;提高并发性能 │ ├── 外键支持&#xff1a;支持外键…...

Java/Kotlin逆向基础与Smali语法精解

1. 法律警示与道德边界 1.1 司法判例深度剖析 案例一&#xff1a;2021年某游戏外挂团伙刑事案 犯罪手法&#xff1a;逆向《王者荣耀》通信协议&#xff0c;修改战斗数据包 技术细节&#xff1a;Hook libil2cpp.so的SendPacket函数 量刑依据&#xff1a;非法经营罪&#xff…...

用AI学编程4——swift学习1

一个swift文件&#xff0c; 整理出swift从入门到精通的所有知识点&#xff0c; 给出注释&#xff0c; 给出这样的swift文件 以下是一个整合了 Swift 从入门到精通的主要知识点的 Swift 文件&#xff0c;包含了基础语法、面向对象编程、异常处理、集合框架、多线程、Lambda 表达…...

数据集构建与训练前准备

训练数据集目录结构与格式 作者笨蛋学法&#xff0c;先将其公式化&#xff0c;后面逐步自己进行修改&#xff0c;读者觉得看不懂可以理解成&#xff0c;由结果去推过程&#xff0c;下面的这个yaml文件就是结果&#xff0c;我们去推需要的文件夹(名字可以不固定&#xff0c;但是…...

在大型语言模型的提示词设计中,system、user和assistant三个角色的区别与联系

在大型语言模型的提示词设计中,system、user和assistant三个角色承担不同的功能,其区别与联系如下: 1. 角色定义与功能 system(系统指令) 作用:设定模型的整体行为、角色定位和任务框架。例如,“你是一位专业的科技作家”或“仅回答与医疗相关的问题”。特点:在多轮对话…...

Zabbix监控进程报警(Zabbix Monitoring Process Alarm)

zabbix监控进程占cpu、内存、磁盘RAID情况 1、cpu达到90%时报警 名称: cpu user percent gt 90% 表达式&#xff1a;{Template OS Linux:system.cpu.util[,idle].avg(1m)}<10 2、内存达到80%时报警 配置—主机(选择监控主机)—监控项—创建监控项 1、创建监控项 名称&…...

p5.js:sound(音乐)可视化,动画显示音频高低变化

本文通过4个案例介绍了使用 p5.js 进行音乐可视化的实践&#xff0c;包括将音频振幅转化为图形、生成波形图。 承上一篇&#xff1a;vite&#xff1a;初学 p5.js demo 画圆圈 cd p5-demo copy .\node_modules\p5\lib\p5.min.js . copy .\node_modules\p5\lib\addons\p5.soun…...

HAL库常用函数

一、通用函数 系统初始化&#xff1a; HAL_Init(): 初始化HAL库和系统时钟&#xff08;调用前需配置系统时钟源&#xff09;。 HAL_Delay(uint32_t Delay): 毫秒级阻塞延时&#xff08;基于SysTick定时器&#xff09;。 HAL_GetTick(): 获取系统运行时间&#xff08;毫秒计数…...

【Zinx】Day5-Part3:Zinx 的连接管理

目录 Day5-Part3&#xff1a;Zinx 的连接管理创建连接管理模块将连接管理模块集成到 Zinx 当中将 ConnManager 集成到 Server 当中在 Connection 的工厂函数中将连接添加到 ConnManagerServer 中连接数量的判断连接的删除 补充&#xff1a;连接的带缓冲发包方式补充&#xff1a…...

C语言:6.20字符型数据练习题

编写程序,输人一行数字字符(用回车结束),每个数字字符 的前后都有空格。 把这一行中的数字转换成一个整数。 例如,若输入(<CR>代表 Enter键):2 4 8 3<CR>则输出 整数:2483。 #include <stdio.h>int main() {char ch;int number 0;printf("请输入一行…...

SpringBoot Test详解

目录 spring-boot-starter-test 1、概述2、常用注解 2.1、配置类型的注解2.2、Mock类型的注解2.3、自动配置类型的注解2.4、启动测试类型的注解2.5、相似注解的区别和联系 3、SpringBootTest和Junit的使用 3.1、单元测试3.2、集成测试 4、MockMvc 4.1、简单示例4.2、自动配置4…...

CDefView::_GetPIDL函数分析之ListView_GetItem函数的参数item的item.mask 为LVIF_PARAM

CDefView::_GetPIDL函数分析之ListView_GetItem函数的参数item的item.mask 为LVIF_PARAM 第一部分&#xff1a; 1: kd> t SHELL32!CDefView::_GetPIDL: 001b:77308013 55 push ebp 1: kd> dv this 0x00000015 i 0n21 …...

Android Retrofit 框架注解定义与解析模块深度剖析(一)

一、引言 在现代 Android 和 Java 开发中&#xff0c;网络请求是不可或缺的一部分。Retrofit 作为 Square 公司开源的一款强大的类型安全的 HTTP 客户端&#xff0c;凭借其简洁易用的 API 和高效的性能&#xff0c;在开发者社区中广受欢迎。Retrofit 的核心特性之一便是通过注…...

项目上传到Gitee过程

在gitee上新建一个仓库 点击“克隆/下载”获取仓库地址 电脑上要装好git 在电脑本地文件夹右键“Git Bash Here” 依次执行如下命令 git init git remote add origin https://gitee.com/qlexcel/stm32-simple.git git pull origin master git add . git commit -m ‘init’…...

DeepSeek R1在医学领域的应用与技术分析(Discuss V1版)

DeepSeek R1作为一款高性能、低成本的国产开源大模型,正在深刻重塑医学软件工程的开发逻辑与应用场景。其技术特性,如混合专家架构(MoE)和参数高效微调(PEFT),与医疗行业的实际需求紧密结合,推动医疗AI从“技术驱动”向“场景驱动”转型。以下从具体业务领域需求出发,…...