《苍穹外卖》SpringBoot后端开发项目核心知识点与常见问题整理(DAY1 to DAY3)

ops/2025/3/19 10:59:14/

目录

  • 一、在本地部署并启动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, 重新运行服务
  • 十、SpringBoot配置类详解
    • 1. 生产环境与开发环境配置
      • 1.1 配置文件命名规则
      • 1.2 激活环境配置
      • 1.3 占位符替换
        • 示例
    • 2. Spring 前缀与自定义前缀配置
      • 2.1 Spring 内置配置
      • 2.2 自定义配置
    • 3. 自定义配置类的注册与使用
      • 3.1 创建配置类
        • 3.1.1 JWT 配置类
        • 3.1.2 阿里云 OSS 配置类
      • 3.2 使用配置类
        • 3.2.1 在 Service 中使用配置类
      • 3.3 配置类的注册
  • 十一、SpringBoot注解汇总
    • 1. Spring MVC 相关注解
    • 2. Swagger 相关注解
    • 3. Spring 核心注解
    • 4. AOP 相关注解
    • 5. Lombok 相关注解
    • 6. MyBatis 相关注解
    • 7. 配置相关注解


本文旨在为刚完成《苍穹外卖》项目DAY1至DAY3章节学习的学员提供难点解析与核心知识点梳理。鉴于该项目由黑马程序员于2023年推出,在实际构建过程中可能会遇到诸如网站链接失效、阿里OSS服务不可用等问题。本文将针对这些常见问题提供解决方案,并帮助学员更好地掌握项目关键内容。

视频链接:黑马程序员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。如果直接使用固定值,会导致数据不准确,无法真实反映操作者。

java">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信息。

java">/*** 员工管理*/
@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。

java">/*** 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层。

java">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,并设置为创建人和修改人。

java">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

java">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

java">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 代码。

七、Spring Boot 的请求映射规则

在 Spring Boot 中,请求的映射是通过 类级别的 @RequestMapping方法级别的 @PutMapping@GetMapping 等注解 共同决定的。

  • 类级别的 @RequestMapping
    • 定义了该类中所有方法的公共路径前缀。
    • 例如,@RequestMapping("/admin/dish") 表示该类中的所有方法都映射到 /admin/dish 路径下。
    • 管理端发出的请求,统一使用/admin作为前缀。
    • 用户端发出的请求,统一使用/user作为前缀。
  • 方法级别的 @PutMapping@GetMapping
    • 定义了具体的 HTTP 方法和路径。
    • 如果方法级别的注解没有指定路径,则默认使用类级别的路径。

1. 类级别路径

java">@RestController
@RequestMapping("/admin/dish")
public class DishController {// 方法定义...
}
  • 所有方法的公共路径前缀是 /admin/dish

2. 方法级别路径

2.1 分页查询

java">@GetMapping("/page")
public Result<PageResult> page(DishPageQueryDTO dishPageQueryDTO) {// 方法实现...
}
  • 完整路径是 /admin/dish/page

2.2 根据 ID 查询菜品

java">@GetMapping("/{id}")
public Result<DishVO> getById(@PathVariable Long id) {// 方法实现...
}
  • 完整路径是 /admin/dish/{id}

2.3 修改菜品

java">@PutMapping
public Result update(@RequestBody DishDTO dishDTO) {// 方法实现...
}
  • 由于 @PutMapping 没有指定路径,默认使用类级别的路径 /admin/dish

2.4 新增菜品

java">@PostMapping
public Result save(@RequestBody DishDTO dishDTO) {// 方法实现...
}
  • 由于 @PostMapping 没有指定路径,默认使用类级别的路径 /admin/dish

2.5 批量删除菜品

java">@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),用于封装分页查询的参数。以下是代码的详细分析:

java">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代码分析

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

注册完成后,开通对象存储服务OSS,创建第一个Bucket,并获取以下四个关键信息:

  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配置类详解

在 Spring Boot 项目中,配置文件是管理应用程序行为的关键部分。通过合理使用配置类,我们可以轻松实现多环境配置、自定义配置以及配置的动态注入。

1. 生产环境与开发环境配置

Spring Boot 支持多环境配置,通常我们会为不同环境(如开发、测试、生产)创建不同的配置文件。通过 spring.profiles.active 属性,可以动态切换环境。

1.1 配置文件命名规则

  • 默认配置文件application.yaml(或 application.properties)。
  • 环境特定配置文件application-{profile}.yaml,其中 {profile} 是环境标识,如 devprod

1.2 激活环境配置

application.yaml 中,通过 spring.profiles.active 指定激活的环境:

spring:profiles:active: dev  # 激活开发环境
  • dev 的含义:表示加载 application-dev.yaml 文件。
  • prod 的含义:表示加载 application-prod.yaml 文件。

1.3 占位符替换

在配置文件中,可以使用 ${} 占位符引用其他配置项的值。Spring Boot 会在启动时自动替换这些占位符。

示例
  • application.yaml

    spring:datasource:url: jdbc:mysql://${sky.datasource.host}:${sky.datasource.port}/${sky.datasource.database}
    
  • application-dev.yaml

    sky:datasource:host: localhostport: 3306database: devdb
    
  • 最终替换结果

    spring:datasource:url: jdbc:mysql://localhost:3306/devdb
    

2. Spring 前缀与自定义前缀配置

Spring Boot 的配置文件支持两种类型的配置:Spring 内置配置自定义配置

2.1 Spring 内置配置

Spring Boot 使用 spring 作为内置配置的命名空间,用于配置框架本身的行为,例如:

  • 数据源配置spring.datasource
  • Redis 配置spring.redis
  • Profile 激活spring.profiles.active
spring:datasource:url: jdbc:mysql://localhost:3306/mydbusername: rootpassword: rootredis:host: localhostport: 6379

2.2 自定义配置

自定义配置通常用于业务相关的配置项。我们可以使用自定义前缀(如 sky)来组织这些配置。

sky:jwt:admin-secret-key: itcastadmin-ttl: 7200000alioss:endpoint: oss-cn-shenzhen.aliyuncs.comaccess-key-id: LTAI5tRK6gZ9f6CyHCaWh7e8

3. 自定义配置类的注册与使用

Spring Boot 提供了 @ConfigurationProperties 注解,用于将配置文件中的值绑定到 Java 对象中。

3.1 创建配置类

通过 @ConfigurationProperties 注解,指定配置的前缀,并定义与配置项对应的字段。

3.1.1 JWT 配置类
java">package com.sky.properties;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Component
@ConfigurationProperties(prefix = "sky.jwt")
@Data
public class JwtProperties {private String adminSecretKey;private long adminTtl;private String adminTokenName;
}
3.1.2 阿里云 OSS 配置类
java">package com.sky.properties;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Component
@ConfigurationProperties(prefix = "sky.alioss")
@Data
public class AliOssProperties {private String endpoint;private String accessKeyId;private String accessKeySecret;private String bucketName;
}

3.2 使用配置类

在其他组件(如 Service、Controller)中,可以通过 @Autowired 注入配置类,直接使用配置值。

3.2.1 在 Service 中使用配置类
java">package com.sky.service;import com.sky.properties.AliOssProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class OssService {@Autowiredprivate AliOssProperties aliOssProperties;public void printOssConfig() {System.out.println("Endpoint: " + aliOssProperties.getEndpoint());System.out.println("AccessKeyId: " + aliOssProperties.getAccessKeyId());}
}

3.3 配置类的注册

  • @Component:将配置类注册为 Spring 的 Bean。
  • @ConfigurationProperties:指定配置的前缀,并绑定配置项。

十一、SpringBoot注解汇总

1. Spring MVC 相关注解

  1. @RestController
    标记一个类为 RESTful 控制器,返回值直接作为响应体(通常是 JSON 格式),它结合了 @Controller@ResponseBody 的功能,适用于开发 RESTful API。

  2. @RequestMapping
    映射 HTTP 请求到控制器方法,可以指定请求路径、请求方法(如 GET、POST)等。

  3. @PostMapping
    专门处理 HTTP POST 请求,是 @RequestMapping(method = RequestMethod.POST) 的简写。

  4. @GetMapping
    专门处理 HTTP GET 请求,是 @RequestMapping(method = RequestMethod.GET) 的简写。

  5. @DeleteMapping
    专门处理 HTTP DELETE 请求,是 @RequestMapping(method = RequestMethod.DELETE) 的简写。

  6. @PutMapping
    专门处理 HTTP PUT 请求,是 @RequestMapping(method = RequestMethod.PUT) 的简写。

  7. @RequestBody
    将 HTTP 请求体(通常是 JSON 格式)绑定到方法参数,适用于接收客户端传递的复杂数据。

  8. @ResponseBody
    将方法的返回值直接作为 HTTP 响应体(通常是 JSON 格式),而不是跳转到视图页面。

  9. @PathVariable
    将 URL 路径中的变量绑定到方法参数,适用于 RESTful 风格的 URL。

2. Swagger 相关注解

  1. @Api
    标记一个类为 Swagger 资源,用于生成 API 文档。

  2. @ApiModel
    描述 Swagger 模型类,通常用于实体类,生成文档中的模型信息。

  3. @ApiModelProperty
    描述 Swagger 模型类的属性,用于生成文档中属性的详细信息。

  4. @ApiOperation
    描述 API 接口的操作,用于生成文档中接口的详细信息。

3. Spring 核心注解

  1. @Autowired
    自动注入 Spring Bean,用于依赖注入。

  2. @Bean
    声明一个方法返回的对象为 Spring Bean,通常用于配置类中。

  3. @Configuration
    标记一个类为配置类,用于定义 Bean 或其他配置。

  4. @Service
    标记一个类为服务层组件,通常用于业务逻辑层。

  5. @Component
    标记一个类为 Spring 组件,泛指任何 Spring 管理的 Bean。

  6. @SpringBootApplication
    标记主启动类,包含 @Configuration@EnableAutoConfiguration@ComponentScan,用于启动 Spring Boot 应用。

  7. @EnableTransactionManagement
    启用 Spring 的事务管理,通常用于配置类中。

4. AOP 相关注解

  1. @Aspect
    标记一个类为切面,用于定义横切关注点(如日志、事务)。

  2. @Before
    在目标方法执行前执行切面逻辑。

  3. @Pointcut
    定义切点表达式,用于指定哪些方法需要被切面处理。

5. Lombok 相关注解

  1. @Slf4j
    自动生成日志对象 log,简化日志记录代码。

  2. @Data
    自动生成 gettersettertoStringequalshashCode 等方法。

  3. @Builder
    为类生成 Builder 模式支持,简化对象的创建。

  4. @NoArgsConstructor
    生成无参构造方法。

  5. @AllArgsConstructor
    生成全参构造方法。

6. MyBatis 相关注解

  1. @Mapper
    标记一个接口为 MyBatis 的 Mapper 接口,用于定义数据库操作。

  2. @Delete
    映射 SQL 删除操作。

  3. @Select
    映射 SQL 查询操作。

  4. @Insert
    映射 SQL 插入操作。

  5. @AutoFill
    自定义注解,用于自动填充字段(如创建时间、更新时间)。

7. 配置相关注解

  1. @ConfigurationProperties
    将配置文件中的值绑定到 Java 对象中,通常用于加载自定义配置,其中 prefix:指定配置项的前缀,从配置文件中加载特定部分的配置。

http://www.ppmy.cn/ops/167008.html

相关文章

Hunyuan3D,腾讯推出的3D资产系统

Hunyuan3D 2.0是腾讯推出的大规模3D 资产生成系统&#xff0c;专注于从文本和图像生成高分辦率的3D模型。系统采用两阶段生成流程&#xff1a;首先生成无纹理的几何模型&#xff0c;再合成高分辨率纹理贴图。包含两个核心组件&#xff1a;Hunyuan3D-DiT&#xff08;几何生成模型…

如何通过Python的`requests`库接入DeepSeek智能API

本文将详细介绍如何通过Python的requests库接入DeepSeek智能API&#xff0c;实现数据交互与智能对话功能。文章涵盖环境配置、API调用、参数解析、错误处理等全流程内容&#xff0c;并提供完整代码示例。 一、环境准备与API密钥获取 1. 注册DeepSeek账号 访问DeepSeek官网&am…

Maven | 站在初学者的角度配置

目录 Maven 是什么 概述 常见错误 创建错误代码示例 正确代码示例 Maven 的下载 Maven 依赖源 Maven 环境 环境变量 CMD测试 Maven 文件配置 本地仓库 远程仓库 Maven 工程创建 IDEA配置Maven IDEA Maven插件 Maven 是什么 概述 Maven是一个项目管理和构建自…

LuaJIT 学习(4)—— FFI 语义

文章目录 C Language SupportC Type Conversion RulesConversions from C types to Lua objects例子&#xff1a;访问结构体成员 Conversions from Lua objects to C typesConversions between C types例子&#xff1a;修改结构体成员 Conversions for vararg C function argum…

vlc录制的视频伪时长修复方法

问题描述 遇到个vlc录制的rtsp视频流&#xff0c;duration时长只有12分钟&#xff0c;但src duration有3个多小时&#xff08;实际正确时长&#xff09;&#xff0c;而且用potplayer能播放3个小时的完整视频&#xff0c;但vlc只能播放12分钟。 解决方法 下载ffmpeg&#xf…

vulhub-joker攻略

靶场下载链接 https://download.vulnhub.com/ha/joker.zip 将kali和joker,桥接模式 获取靶场ip arp-scan -l 使用nmap扫描 nmap -sS -sV -p- 访问80端口什么都没有发现 访问8080端口发现 用drib进行目录扫描 dirb "http://192.168.117.157" -X .txt,php,json,html…

企业安全——密码学基础

0x00 前言 密码学的内容一直都是零零散散的&#xff0c;学一遍忘一遍&#xff0c;对于这些很少用到的内容&#xff0c;只能这样子去进行重复&#xff0c;效率低从此没有效率会稍微好一点。 总会比说出base64是一种加密方式贻笑大方的好一点。 0x01 密码学的目的 密码学的主要…

C++11 详解版本1.0

目录 &#x1f31f;1. C11的大优势 &#x1f31f;2、列表初始化 &#x1f31f;3、变量类型推导 一、为什么需要类型推导 二、decltype类型推导&#xff08;了解&#xff09; &#x1f31f;4、final 与 override &#x1f31f;5. 左值和右值 &#x1f31f;6. 左值引…