【家政平台开发(15)】解锁Spring Boot:家政平台后端开发全攻略
本【家政平台开发】专栏聚焦家政平台从 0 到 1 的全流程打造。从前期需求分析,剖析家政行业现状、挖掘用户需求与梳理功能要点,到系统设计阶段的架构选型、数据库构建,再到开发阶段各模块逐一实现。涵盖移动与 PC 端设计、接口开发及性能优化,测试阶段多维度保障平台质量,部署发布阶段确保平稳上线。还深入探讨运营策略、技术创新应用及未来发展方向,为家政平台开发提供全面且实用的知识体系与实践指南。
目录
- 一、Spring Boot 项目初始化与配置
- 1.1 Spring Boot 项目创建
- 1.2 核心依赖配置与管理
- 1.2.1 依赖配置方案
- 1.2.2 常用核心依赖介绍
- 1.2.3 版本管理与冲突解决
- 二、业务模块设计与实现
- 2.1 用户管理模块设计
- 2.1.1 功能需求分析
- 2.1.2 数据模型设计
- 2.1.3 后端业务逻辑实现
- 2.2 订单管理模块设计
- 2.2.1 业务流程梳理
- 2.2.2 订单数据结构设计
- 2.2.3 订单业务逻辑实现
- 三、接口设计与 RESTful API 规范
- 3.1 接口设计原则与方法
- 3.1.1 接口设计六大原则
- 3.1.2 接口设计方法与流程
- 3.1.3 接口安全设计
- 3.2 RESTful API 的实现与版本控制
- 3.2.1 RESTful 风格介绍
- 3.2.2 使用 Spring Boot 实现 RESTful API
- 3.2.3 API 版本控制策略
一、Spring Boot 项目初始化与配置
1.1 Spring Boot 项目创建
在开发家政平台的后端服务时,使用 Spring Boot 能够极大地简化开发流程。以 IDEA 工具为例,我们可以通过 Spring Initializr 快速创建 Spring Boot 项目。首先,打开 IDEA,点击 “Create New Project”,在弹出的窗口中选择 “Spring Initializr”。在这一步,我们需要配置项目的基本信息,包括 Group(通常是公司或组织的域名倒置,如 com.example)、Artifact(项目的唯一标识符,例如 home - service - platform - backend)、Version(版本号,初始可设为 0.0.1 - SNAPSHOT) ,并选择合适的 Spring Boot 版本,建议使用较新的稳定版本,以获取最新的功能和性能优化。
接着,在 “Dependencies” 选项中,根据家政平台的功能需求添加相关依赖。比如,添加 Spring Web 依赖用于构建 Web 服务,Spring Data JPA 或 MyBatis - Plus 依赖用于数据库访问,Spring Security 依赖用于安全认证等。完成这些配置后,点击 “Finish”,IDEA 会自动生成 Spring Boot 项目的基本结构,包括项目的目录结构、配置文件和初始的启动类。
1.2 核心依赖配置与管理
1.2.1 依赖配置方案
在 Spring Boot 项目中,常用的依赖配置方式有继承 parent 和 import 导入。继承 parent 方式是通过在 pom.xml 文件中指定 spring - boot - starter - parent 作为父项目,如下所示:
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.4</version><relativePath/> <!-- lookup parent from repository -->
</parent>
这种方式的好处是 spring-boot-starter-parent 已经定义了大量依赖的版本,子项目继承后无需再显式指定这些依赖的版本,减少了版本冲突的可能性,并且能保证与 Spring Boot 框架的兼容性。同时,它还提供了一些默认的 Maven 插件配置,简化了项目的构建过程。
而 import 导入方式则是使用 dependencyManagement 标签导入 spring-boot-dependencies,例如:
<dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.7.4</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement>
这种方式允许开发者更灵活地控制依赖版本,对于一些有特殊版本需求的依赖,可以在项目中单独指定版本。它适用于需要对依赖进行更细粒度控制,或者项目中存在与 spring-boot-starter-parent 默认版本不兼容的依赖的场景。
1.2.2 常用核心依赖介绍
- Spring Web:这是构建 Web 应用的核心依赖,它包含了 Spring MVC 框架和嵌入式 Tomcat 服务器。通过 Spring Web,我们可以方便地创建 RESTful API,处理 HTTP 请求和响应。例如,在家政平台中,用户管理模块的登录、注册接口,订单管理模块的订单创建、查询接口等都依赖于 Spring Web 来实现。它提供了强大的路由功能和请求处理机制,能够高效地将客户端的请求路由到对应的控制器方法进行处理 。
- Spring Security:主要用于实现应用的安全认证和授权功能。在家政平台中,它可以确保只有合法的用户(家政服务人员和客户)能够访问平台的功能。比如,客户登录后才能查看自己的订单信息、预约家政服务;家政服务人员登录后才能查看自己的服务订单、更新服务状态等。Spring Security 支持多种认证方式,如基于表单的认证、OAuth2 认证等,可以根据项目的实际需求进行灵活配置。
- MyBatis-Plus:作为持久层框架,它在 MyBatis 的基础上进行了增强,简化了数据库操作。在本家政平台中,使用 MyBatis-Plus 可以方便地进行数据库表的增删改查操作。例如,对于用户表,我们可以通过 MyBatis-Plus 的 BaseMapper 接口,快速实现用户信息的插入、查询、更新和删除,而无需编写大量的 SQL 语句。它还提供了分页插件、代码生成器等实用工具,提高了开发效率。
1.2.3 版本管理与冲突解决
在 Spring Boot 项目中,合理管理依赖版本至关重要。通常,使用 spring-boot-starter-parent 或 spring-boot-dependencies 来管理依赖版本,确保项目中所有依赖的兼容性。当出现依赖版本冲突时,可以采用以下方法解决:
- 使用 exclusions 标签排除冲突依赖:如果某个依赖引入了不需要的传递依赖,且该传递依赖与项目中其他依赖的版本冲突,可以在依赖配置中使用 exclusions 标签将其排除。例如,如果项目中引入的 A 依赖自动带入了 B 依赖的某个版本,但项目中已经明确指定了 B 依赖的另一个版本,为了避免冲突,可以这样配置:
<dependency><groupId>com.example</groupId><artifactId>example - library</artifactId><version>1.0.0</version><exclusions><exclusion><groupId>org.unwanted</groupId><artifactId>unwanted - library</artifactId></exclusion></exclusions>
</dependency>
- 使用 dependencyManagement 强制指定依赖版本:在项目的 pom.xml 文件中,可以使用 dependencyManagement 标签集中管理所有依赖项的版本号。这样,子模块或者其他引用了这些依赖的地方将默认使用在这里定义的版本,除非子模块中显式地覆盖这个版本号。例如:
<dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring - boot - starter - web</artifactId><version>2.7.4</version></dependency><!-- 其他依赖版本配置 --></dependencies>
</dependencyManagement>
- 使用 Maven 命令分析和解决冲突:Maven 提供了一些有用的命令来帮助解决依赖冲突。例如,mvn dependency:tree命令可以可视化项目的依赖关系,通过查看依赖树,我们能够清晰地看到每个依赖的来源和版本,从而更容易识别潜在的冲突。mvn dependency:analyze命令则可以帮助我们分析项目中不同依赖项版本之间的冲突,给出相应的提示和建议,以便我们采取针对性的措施解决冲突。
二、业务模块设计与实现
2.1 用户管理模块设计
2.1.1 功能需求分析
在家政平台中,用户管理模块是非常基础且重要的部分,主要涉及家政服务人员和客户两类用户。
- 对于用户注册功能,需支持手机号、邮箱等多种注册方式,并且在注册过程中进行数据校验,比如手机号格式是否正确,邮箱是否已被注册等,以确保注册信息的准确性和唯一性 。同时,为提高注册的安全性,需要对用户输入的密码进行加密处理,防止密码明文存储带来的安全风险,通常可以使用如 BCrypt 等加密算法。
- 用户登录功能要实现身份验证,不仅要验证用户名和密码的正确性,还需考虑多种登录场景,如记住密码、忘记密码找回等。当用户选择记住密码时,通过生成并存储加密的登录凭证(如 JWT,JSON Web Token),使用户在下次访问时无需重复输入登录信息即可快速登录。对于忘记密码功能,可通过向用户注册的邮箱或手机号发送重置密码链接,引导用户重置密码。
- 用户信息编辑功能允许用户修改个人基本信息,如姓名、性别、联系方式等。在修改过程中,同样要进行数据校验,确保修改后的信息符合格式要求且不与其他用户信息冲突。此外,对于一些敏感信息,如身份证号码、银行卡号等,需提供安全的修改流程,可能需要进行额外的身份验证,如短信验证码、人脸识别等,以保障用户信息的安全。
2.1.2 数据模型设计
在 MySQL 数据库中,设计用户表(user)用于存储用户相关信息,表结构如下:
字段名 | 数据类型 | 字段含义 | 备注 |
---|---|---|---|
id | bigint | 用户唯一标识 | 主键,自增长 |
username | varchar(50) | 用户名 | 唯一,不可为空 |
password | varchar(100) | 密码 | 加密存储,不可为空 |
phone | varchar(20) | 手机号码 | 唯一,可通过正则表达式验证格式 |
varchar(50) | 邮箱地址 | 唯一,可通过正则表达式验证格式 | |
real_name | varchar(50) | 真实姓名 | |
gender | tinyint | 性别 | 0 代表男,1 代表女 |
role | tinyint | 用户角色 | 0 代表客户,1 代表家政服务人员 |
create_time | datetime | 注册时间 | 默认值为当前时间 |
update_time | datetime | 信息更新时间 | 每次信息更新时自动更新 |
通过这样的表结构设计,可以满足用户管理模块对用户信息存储和管理的需求,各字段的设置既保证了数据的完整性,又通过约束条件(如唯一性约束、非空约束)确保了数据的准确性和一致性。同时,role字段用于区分用户类型,方便后续根据不同用户角色进行权限控制和业务逻辑处理。
2.1.3 后端业务逻辑实现
在 Spring Boot 项目中,结合 MyBatis-Plus 实现用户管理业务逻辑。首先,定义用户实体类(User),使用@TableName注解指定对应的数据库表名,代码如下:
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;import java.util.Date;@Data
@TableName("user")
public class User {private Long id;private String username;private String password;private String phone;private String email;private String realName;private Integer gender;private Integer role;private Date createTime;private Date updateTime;
}
然后,通过 MyBatis - Plus 的BaseMapper接口创建用户数据访问层(UserMapper),MyBatis - Plus 会自动为我们实现基本的增删改查方法,无需手动编写 SQL 语句:
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface UserMapper extends BaseMapper<User> {
}
在服务层(UserService)中,实现用户注册、登录、信息编辑等业务逻辑。以用户注册为例,代码如下:
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.util.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import javax.annotation.Resource;
import java.util.Date;@Service
@Transactional
public class UserService {@Resourceprivate UserMapper userMapper;public boolean registerUser(User user) {// 检查用户名或手机号是否已存在QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.eq("username", user.getUsername()).or().eq("phone", user.getPhone());if (userMapper.selectOne(wrapper) != null) {return false;}// 密码加密BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();user.setPassword(encoder.encode(user.getPassword()));user.setCreateTime(new Date());user.setUpdateTime(new Date());return userMapper.insert(user) > 0;}
}
在上述代码中,registerUser方法首先检查用户名或手机号是否已被注册,若未注册则对用户密码进行加密处理,然后将用户信息插入数据库。通过这种方式,利用 Spring Boot 的依赖注入和 MyBatis-Plus 的强大功能,简洁高效地实现了用户管理模块的业务逻辑。
2.2 订单管理模块设计
2.2.1 业务流程梳理
家政服务订单的业务流程从客户下单开始。客户在家政平台上浏览各种家政服务项目,选择所需的服务类型(如日常保洁、月嫂服务、家电维修等)、服务时间、服务地点等信息后提交订单。订单提交后,系统进入订单确认阶段,此时平台会根据客户的需求,筛选出合适的家政服务人员,并将订单信息发送给服务人员。服务人员可以查看订单详情,确认是否接单。如果服务人员接单,订单状态更新为 “已接单”;若服务人员拒绝接单,平台则会重新为客户分配服务人员,或者提示客户重新下单。
在服务过程中,订单状态会更新为 “服务中”,服务人员按照约定的时间和服务内容为客户提供家政服务。服务完成后,客户对服务进行验收,若客户满意,订单状态更新为 “已完成”,客户可以对服务人员进行评价;若客户不满意,可与服务人员或平台沟通,协商解决方案,如重新服务、部分退款等,此时订单状态可能会处于 “争议处理中” 。最后,订单完成后,平台会根据订单金额和与服务人员的分成协议,进行费用结算,将服务人员应得的报酬支付给服务人员。
2.2.2 订单数据结构设计
为了存储订单相关信息,设计以下数据库表:
- 订单表(order):
字段名 | 数据类型 | 字段含义 | 备注 |
---|---|---|---|
id | bigint | 订单唯一标识 | 主键,自增长 |
user_id | bigint | 客户用户 ID | 外键,关联user表的id字段 |
service_id | bigint | 服务项目 ID | 外键,关联service表的id字段,用于确定订单对应的家政服务类型 |
service_staff_id | bigint | 服务人员 ID | 外键,关联user表(家政服务人员用户)的id字段,记录提供服务的人员 |
order_time | datetime | 下单时间 | 默认值为当前时间 |
service_time | datetime | 服务时间 | 客户预约的服务时间 |
service_address | varchar(200) | 服务地点 | 详细的服务地址 |
order_amount | decimal(10, 2) | 订单金额 | 订单的总费用 |
order_status | tinyint | 订单状态 | 0 代表待接单,1 代表已接单,2 代表服务中,3 代表已完成,4 代表争议处理中,5 代表已取消 |
- 订单详情表(order_detail):用于记录订单的详细信息,当一个订单包含多个服务项目或服务项目有多个规格时,可通过此表详细记录每个服务项目或规格的信息,与order表通过order_id建立关联。
字段名 | 数据类型 | 字段含义 | 备注 |
---|---|---|---|
id | bigint | 订单详情唯一标识 | 主键,自增长 |
order_id | bigint | 订单 ID | 外键,关联order表的id字段 |
service_item | varchar(100) | 服务项目名称 | 具体的服务项目,如 “卧室清洁”“空调维修” 等 |
quantity | int | 服务数量 | 如清洁次数、维修次数等 |
unit_price | decimal(10, 2) | 单价 | 每个服务项目或规格的单价 |
通过这样的表结构设计,能够全面、清晰地记录订单的相关信息,方便后续对订单的查询、管理和统计分析,同时确保了数据的完整性和一致性,为订单业务逻辑的实现提供了坚实的数据基础。
2.2.3 订单业务逻辑实现
在 Spring Boot 项目中,实现订单管理的业务逻辑。定义订单实体类(Order)和订单详情实体类(OrderDetail),与数据库表结构对应:
// Order.java
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;import java.math.BigDecimal;
import java.util.Date;@Data
@TableName("order")
public class Order {private Long id;private Long userId;private Long serviceId;private Long serviceStaffId;private Date orderTime;private Date serviceTime;private String serviceAddress;private BigDecimal orderAmount;private Integer orderStatus;
}// OrderDetail.java
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;import java.math.BigDecimal;@Data
@TableName("order_detail")
public class OrderDetail {private Long id;private Long orderId;private String serviceItem;private Integer quantity;private BigDecimal unitPrice;
}
创建订单数据访问层(OrderMapper和OrderDetailMapper),继承 MyBatis - Plus 的BaseMapper接口:
// OrderMapper.java
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.Order;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface OrderMapper extends BaseMapper<Order> {
}// OrderDetailMapper.java
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.OrderDetail;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface OrderDetailMapper extends BaseMapper<OrderDetail> {
}
在服务层(OrderService)中实现订单创建、查询、修改、删除等业务逻辑。以订单创建为例,代码如下:
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.demo.entity.Order;
import com.example.demo.entity.OrderDetail;
import com.example.demo.mapper.OrderDetailMapper;
import com.example.demo.mapper.OrderMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;@Service
@Transactional
public class OrderService {@Resourceprivate OrderMapper orderMapper;@Resourceprivate OrderDetailMapper orderDetailMapper;public boolean createOrder(Order order, List<OrderDetail> orderDetails) {// 设置订单基本信息order.setOrderTime(new Date());order.setOrderStatus(0); // 初始状态为待接单int result = orderMapper.insert(order);if (result <= 0) {return false;}// 插入订单详情for (OrderDetail detail : orderDetails) {detail.setOrderId(order.getId());detail.setUnitPrice(detail.getUnitPrice());detail.setQuantity(detail.getQuantity());orderDetailMapper.insert(detail);}return true;}
}
在上述代码中,createOrder方法首先设置订单的基本信息并插入订单表,若插入成功,则遍历订单详情列表,为每个订单详情设置对应的订单 ID,并插入订单详情表。通过这种方式,利用 Spring Boot 的事务管理和 MyBatis - Plus 的数据操作功能,实现了订单创建的业务逻辑,确保了订单数据的完整性和一致性,同时也为其他订单业务逻辑的实现提供了基础。
三、接口设计与 RESTful API 规范
3.1 接口设计原则与方法
3.1.1 接口设计六大原则
- 单一职责原则:接口应该职责单一,一个接口只负责一项功能。例如,在家政平台中,用户管理接口就只专注于处理用户相关的操作,如注册、登录、信息查询与修改等,而不应该将订单管理等其他功能混入其中。这样做的好处是当用户管理功能发生变化时,不会影响到其他不相关的接口,提高了接口的可维护性和可扩展性。如果一个接口承担了过多职责,在修改其中某一项功能时,可能会意外地影响到其他功能,导致系统出现难以排查的问题。
- 里氏替换原则:所有引用基类的地方必须能透明地使用其子类的对象。在家政平台的接口设计中,如果定义了一个家政服务接口,那么具体的家政服务子类(如保洁服务接口、月嫂服务接口等)必须能够完全替代基类接口的使用,并且不会影响系统的正常运行。例如,在订单分配功能中,无论分配的是保洁订单还是月嫂订单,都可以统一使用家政服务接口进行处理,而不需要针对不同的服务类型编写额外的逻辑,确保了代码的灵活性和可复用性。
- 依赖倒置原则:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。以家政平台的订单处理为例,订单处理模块(高层模块)不应该直接依赖于具体的数据库操作实现(低层模块),而是依赖于订单数据访问接口(抽象)。具体的数据库操作实现(如使用 MyBatis - Plus 进行数据访问)则依赖于这个订单数据访问接口。这样,当需要更换数据库或者数据访问方式时,只需要实现新的订单数据访问接口,而订单处理模块不需要进行大量修改,提高了系统的稳定性和可维护性。
- 接口隔离原则:客户端不应该依赖它不需要的接口,类间的依赖关系应该建立在最小的接口上。在家政平台中,对于家政服务人员和客户,他们所需要的接口是不同的。因此,应该为家政服务人员和客户分别设计独立的接口,避免将所有功能都放在一个大接口中。比如,家政服务人员可能需要接单、更新服务状态等接口,而客户可能需要下单、查询订单状态、评价服务等接口。通过将这些功能分别封装在不同的接口中,减少了接口的冗余,提高了系统的内聚性和可维护性,同时也降低了不同角色之间的耦合度。
- 迪米特法则:一个对象应该对其他对象保持最少的了解,即一个类应该对自己需要耦合或调用的类知道得最少。在家政平台的接口设计中,每个接口应该只暴露必要的方法,而不应该暴露过多的内部实现细节。例如,订单管理接口只需要提供订单创建、查询、修改等与订单业务直接相关的方法,而不需要暴露数据库连接、事务管理等内部实现细节给其他模块。这样,当订单管理接口的内部实现发生变化时,对其他依赖它的模块影响较小,提高了系统的稳定性和可维护性。
- 开闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。在家政平台的接口设计中,当需要增加新的功能时,应该通过扩展接口来实现,而不是直接修改现有接口的代码。例如,当平台需要增加新的家政服务类型时,可以通过扩展服务接口来实现,而不需要修改已有的订单处理、用户管理等接口。这样,既保证了系统的灵活性,又确保了现有功能的稳定性,降低了因修改代码而引入新 bug 的风险。
3.1.2 接口设计方法与流程
- 需求分析:与产品经理、业务团队深入沟通,了解家政平台的业务需求和用户需求。例如,明确用户管理模块需要支持哪些注册登录方式,订单管理模块需要处理哪些业务流程和状态变化等。通过对业务流程的梳理,确定接口需要提供的功能和服务,为后续的接口设计提供依据。可以使用用例图、流程图等工具来辅助需求分析,清晰地展示系统的功能和用户操作流程。
- 接口定义:根据需求分析的结果,定义接口的名称、参数、返回值和请求方法等。接口名称应具有描述性,能够准确反映接口的功能,例如 “userRegister” 表示用户注册接口,“orderCreate” 表示订单创建接口。对于参数和返回值,要明确其数据类型、含义和格式。选择合适的请求方法(如 GET、POST、PUT、DELETE 等)来表示不同的操作,遵循 RESTful API 的设计规范。例如,使用 GET 方法获取资源(如获取用户信息、订单列表),使用 POST 方法创建资源(如创建新用户、新订单),使用 PUT 方法更新资源(如更新用户信息、订单状态),使用 DELETE 方法删除资源(如删除用户、删除订单)。
- 接口评审:组织开发团队、测试团队、产品经理等相关人员对接口定义进行评审。评审过程中,重点检查接口的功能是否满足需求,接口设计是否符合设计原则,参数和返回值的定义是否合理,请求方法的使用是否正确等。通过评审,可以发现接口设计中存在的问题和潜在风险,及时进行修改和完善,确保接口的质量和可实现性。评审可以采用会议讨论、代码审查等方式进行,鼓励团队成员积极提出意见和建议。
- 接口实现:在 Spring Boot 项目中,根据接口定义编写接口实现代码。使用 Spring MVC 的注解(如 @RestController、@RequestMapping 等)来创建 RESTful API 接口,并结合业务逻辑实现接口的功能。例如,对于用户注册接口,在实现时需要调用用户管理服务中的注册方法,进行用户信息的验证、加密和存储等操作。在实现过程中,要遵循良好的编码规范和设计模式,确保代码的可读性、可维护性和可扩展性。
- 接口测试:编写接口测试用例,对接口进行全面的测试。测试内容包括接口的功能正确性、参数校验、异常处理、性能等方面。使用工具如 Postman、JUnit 等进行测试,验证接口是否返回正确的结果,是否能够正确处理各种输入参数和异常情况。通过接口测试,可以及时发现接口实现中存在的问题,进行修复和优化,确保接口的质量和稳定性。
3.1.3 接口安全设计
- 接口认证:采用 Token 认证机制,当用户登录成功后,系统生成一个 Token(如 JWT,JSON Web Token)并返回给客户端。客户端在后续的请求中,将 Token 放在请求头(如 “Authorization: Bearer [token]”)中发送给服务器。服务器接收到请求后,通过验证 Token 的有效性来确认用户身份。例如,在家政平台中,用户登录后获取到 Token,在进行订单查询、服务预约等操作时,携带 Token 进行身份验证,确保只有合法用户才能访问相应接口。
- 授权:基于角色的访问控制(RBAC,Role - Based Access Control),将用户分为家政服务人员和客户等不同角色,为每个角色分配相应的权限。例如,家政服务人员具有接单、更新服务状态等权限,而客户具有下单、查询订单、评价服务等权限。在接口实现中,通过 Spring Security 等框架进行权限控制,只有具有相应权限的用户才能访问特定接口。比如,当家政服务人员尝试访问客户下单接口时,系统会根据其角色判断其没有该权限,从而返回权限不足的错误提示。
- 防止 SQL 注入:使用预编译语句(PreparedStatement)代替普通的 SQL 语句。在 MyBatis - Plus 中,已经对 SQL 语句进行了封装,使用预编译机制来防止 SQL 注入。例如,在进行用户信息查询时,使用 MyBatis - Plus 的查询方法,它会自动将用户输入的参数进行预处理,避免了用户输入恶意 SQL 语句篡改查询结果的风险。同时,对用户输入的数据进行严格的校验和过滤,确保输入数据的合法性,进一步增强系统的安全性。
- 数据加密:对于敏感数据,如用户密码、身份证号码、银行卡号等,在传输和存储过程中进行加密处理。在传输时,使用 HTTPS 协议,在 HTTP 和 TCP 之间添加 SSL/TLS 加密层,确保数据在网络传输过程中的安全性。在存储时,使用加密算法(如 AES、RSA 等)对敏感数据进行加密存储。例如,用户注册时,将用户输入的密码使用 BCrypt 等加密算法进行加密后存储在数据库中,当用户登录时,将用户输入的密码加密后与数据库中存储的加密密码进行比对,确保密码的安全性。
3.2 RESTful API 的实现与版本控制
3.2.1 RESTful 风格介绍
RESTful 是一种网络应用程序的设计风格和开发方式,基于 HTTP 协议。其核心概念是将互联网上的所有事物都抽象为资源,每个资源都有一个唯一的资源定位符(URI) 。例如,在家政平台中,用户是一种资源,对应的 URI 可以是 “/users/{id}”,其中 “{id}” 是用户的唯一标识;订单也是一种资源,URI 可以是 “/orders/{orderId}”。通过 URI 来访问资源,并且使用 HTTP 方法(GET、POST、PUT、DELETE 等)来操作资源。
RESTful 风格具有以下特点:
- 资源:一切皆资源,将应用中的数据和功能都抽象为资源,方便对其进行统一管理和操作。例如,家政服务项目(如日常保洁、月嫂服务、家电维修等)都可以看作是不同的资源,通过各自的 URI 进行访问和操作。
- 统一接口:使用标准的 HTTP 方法来操作资源,GET 用于获取资源,POST 用于创建资源,PUT 用于更新资源,DELETE 用于删除资源。这种统一的接口设计使得接口易于理解和使用,不同的客户端(如 Web 端、移动端)都可以方便地与服务端进行交互。
- 无状态:客户端与服务端之间的交互是无状态的,每个请求都包含了理解该请求所必需的信息,服务端不会在请求之间保存客户端的状态。这样可以提高系统的可扩展性和可靠性,因为每个请求都是独立的,服务端可以更容易地进行负载均衡和故障恢复。
- 可缓存:由于 HTTP 协议的特性,RESTful API 的响应可以被缓存,提高了系统的性能和响应速度。例如,对于一些不经常变化的资源(如家政服务项目的基本介绍),客户端可以缓存其响应,下次请求时直接从缓存中获取,减少了对服务端的请求压力。
RESTful 风格的优势在于其简洁性、灵活性和可扩展性。它使得接口设计更加清晰、易于理解和维护,并且能够很好地适应分布式系统和微服务架构的开发需求,是现代 Web 应用开发中广泛采用的接口设计风格。
3.2.2 使用 Spring Boot 实现 RESTful API
在 Spring Boot 项目中实现 RESTful API 非常便捷。首先,引入 Spring Web 依赖,这是构建 Web 服务的基础。然后,使用 @RestController 注解定义控制器类,该注解相当于 @Controller 和 @ResponseBody 的组合,用于返回 JSON、XML 等格式的数据。使用 @RequestMapping 注解来映射请求路径,同时结合 HTTP 方法注解(如 @GetMapping、@PostMapping、@PutMapping、@DeleteMapping)来处理不同类型的 HTTP 请求。
以家政平台的用户管理模块为例,实现获取用户列表的接口:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;@RestController
@RequestMapping("/users")
public class UserController {// 假设这里有一个获取用户列表的服务方法@GetMapping("/")public List<User> getUserList() {// 调用服务层获取用户列表return userService.getAllUsers();}
}
在上述代码中,@RestController 注解标识该类为 RESTful 风格的控制器,@RequestMapping (“/users”) 指定了该控制器下所有接口的基础路径为 “/users” 。@GetMapping (“/”) 表示处理 HTTP GET 请求,路径为 “/users/”,当客户端发送 GET 请求到 “/users/” 时,会调用 getUserList 方法,返回用户列表数据。
再以订单管理模块的订单创建接口为例:
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/orders")
public class OrderController {@PostMapping("/")public Order createOrder(@RequestBody Order order) {// 调用服务层创建订单return orderService.createOrder(order);}
}
这里 @PostMapping (“/”) 处理 HTTP POST 请求,路径为 “/orders/”,@RequestBody 注解用于接收客户端发送的 JSON 格式的订单数据,将其转换为 Order 对象后传递给 orderService.createOrder 方法进行订单创建操作,并返回创建后的订单对象。
3.2.3 API 版本控制策略
- URL 路径版本控制:在 URL 路径中添加版本号,例如 “/v1/users” 表示版本 1 的用户相关接口,“/v2/orders” 表示版本 2 的订单相关接口。这种方式直观易懂,客户端通过访问不同版本号的 URL 来调用不同版本的接口。例如,当家政平台对用户管理接口进行了重大升级,新增了一些功能时,可以创建 /v2/users 接口,而保留 /v1/users 接口以兼容旧的客户端。在 Spring Boot 中,可以通过定义不同的控制器类或者在同一个控制器类中使用不同的 @RequestMapping 路径来实现版本控制。
- 请求头版本控制:在请求头中添加版本信息,例如 “X - API - Version: 1.0” 表示请求使用版本 1.0 的接口。服务器在接收到请求后,根据请求头中的版本信息来调用相应版本的接口实现。这种方式对 URL 没有影响,保持了 URL 的简洁性,但需要客户端在每次请求时设置正确的请求头信息。在 Spring Boot 中,可以通过自定义过滤器或者拦截器来解析请求头中的版本信息,并根据版本信息进行相应的处理。
- 查询参数版本控制:通过在 URL 的查询参数中传递版本号,例如 “/users?version=1.0”。这种方式也比较简单,客户端通过修改查询参数来请求不同版本的接口。但它可能会使 URL 变得冗长,并且不太符合 RESTful 的设计理念。在 Spring Boot 中,通过在控制器方法中获取查询参数 “version” 的值,来判断请求的接口版本,并调用相应的业务逻辑。
不同的版本控制方式各有优缺点,在实际项目中,需要根据项目的需求、规模和客户端的情况来选择合适的版本控制策略,以确保接口的兼容性和可扩展性。
相关文章:
【家政平台开发(15)】解锁Spring Boot:家政平台后端开发全攻略
本【家政平台开发】专栏聚焦家政平台从 0 到 1 的全流程打造。从前期需求分析,剖析家政行业现状、挖掘用户需求与梳理功能要点,到系统设计阶段的架构选型、数据库构建,再到开发阶段各模块逐一实现。涵盖移动与 PC 端设计、接口开发及性能优化…...
AI Agent设计模式二:Parallelization
概念 :并行任务执行引擎 ✅ 优点:提升吞吐量,充分利用多核资源❌ 缺点:复杂度高,存在竞态条件风险 from langchain_openai import ChatOpenAI from langgraph.graph import StateGraph, START, END from typing impor…...
Upload-labs靶场通关
之前搭好了靶场,Upload-labs 靶场搭建 及一句话木马的原理与运用-CSDN博客 今天开始通关并写详细流程 Pass-1 来到靶场的第一关 先随便上传php 代码 点击上传 发现文件类型被限制了 方法1: 改文件后缀为合法文件(.jpg .png .gif…...
Python数据结构之有序列表
一.基本介绍 在有序列表中,元素的相对位置取决于它们的基本特征。它们通常以升序或者降序排列,并且我们假设元素之间能进行有意义的比较。有序列表和无序列表(链表)的许多操作都是相同的。 二.代码实现 class OrderedList:"""有序列表类…...
LMK04828使用指南-01-简介与引脚功能描述
简介 LMK0482x系列是业界性能最高的时钟调节器,支持JEDEC JESD204B。 PLL2的14个时钟输出可以配置为使用设备和SYSREF时钟驱动七个JESD204B转换器或其他逻辑设备。可以使用直流和交流耦合提供SYSREF。不限于JESD204B应用,14个输出中的每一个都可以单独…...
统计学基本原理
目录 文章目录 目录统计学统计学基本概念描述性统计数据可视化图表工具 汇总统计统计数据的分布情况:中位数、众数、平均值统计数据的离散程度:极差、方差、标准差、离散系数 相关分析Pearson 线性关系相关系数Spearman 单调关系相关系数 回归分析回归模…...
日常真实工作环境,Mysql常用操作命令,笔记!
1、开放增删改查权限,不开放表结构修改权限 有许多生产环境是不需要修改表结构的,也是为了防止SQL注入。 创建用户 mysql> grant all on *.* to ie% identified by test1设置权限 1.首先我们先回收所有权限。 revoke all on *.* from ie% ;2.设…...
洛谷题单3-P1307 [NOIP 2011 普及组] 数字反转-python-流程图重构
题目描述 给定一个整数 N N N,请将该数各个位上数字反转得到一个新数。新数也应满足整数的常见形式,即除非给定的原数为零,否则反转后得到的新数的最高位数字不应为零(参见样例 2)。 输入格式 一个整数 N N N。 …...
洛谷题单3-P1420 最长连号-python-流程图重构
题目描述 输入长度为 n n n 的一个正整数序列,要求输出序列中最长连号的长度。 连号指在序列中,从小到大的连续自然数。 输入格式 第一行,一个整数 n n n。 第二行, n n n 个整数 a i a_i ai,之间用空格隔开…...
PostgreSQL:表分区与继承
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编…...
【NLP 55、投机采样加速推理】
目录 一、投机采样 二、投机采样改进:美杜莎模型 流程 改进 三、Deepseek的投机采样 流程 Ⅰ、输入文本预处理 Ⅱ、引导模型预测 Ⅲ、候选集筛选(可选) Ⅳ、主模型验证 Ⅴ、生成输出与循环 骗你的,其实我在意透了 —— 25.4.4 一、…...
CSS 创建与使用学习笔记
一、CSS 的作用 CSS(层叠样式表)用于控制 HTML 文档的样式和布局。当浏览器读取一个样式表时,它会根据样式表中的规则来格式化 HTML 文档,从而实现页面的美化和布局调整。 二、插入样式表的方法 CSS 可以通过以下三种方式插入到…...
CSS Id 和 Class 选择器学习笔记
一、概述 在 CSS 中,id 和 class 选择器是用于为 HTML 元素指定样式的强大工具。它们可以帮助我们精确地控制页面中元素的样式,让页面设计更加灵活和高效。 二、id 选择器 1. 定义和使用 定义:id 选择器用于为具有特定 id 属性的 HTML 元素…...
从小米汽车事故反思 LabVIEW 开发
近期,小米汽车的一起严重事故引发了社会各界的广泛关注。这起事故不仅让我们对智能汽车的安全性产生了深深的思考,也为 LabVIEW 开发领域带来了诸多值得汲取的知识与领悟。 在智能汽车领域,尤其是涉及到智能驾驶辅助系统时,安全是…...
解锁工业通信:Profibus DP到ModbusTCP网关指南!
解锁工业通信:Profibus DP到ModbusTCP网关指南! 在工业自动化领域,随着技术的不断进步和应用场景的日益复杂,不同设备和系统之间的通讯协议兼容性问题成为了工程师们面临的一大挑战。尤其是在Profibus DP和Modbus/TCP这两种广泛应…...
web漏洞靶场学习分享
靶场:pikachu靶场 pikachu漏洞靶场漏洞类型: Burt Force(暴力破解漏洞)XSS(跨站脚本漏洞)CSRF(跨站请求伪造)SQL-Inject(SQL注入漏洞)RCE(远程命令/代码执行)Files Inclusion(文件包含漏洞)Unsafe file downloads(不安全的文件下载)Unsafe file uploads(不安全的文…...
【C++学习笔记】十三、速通笔记
完整的C编程教程 目录 开发环境配置C知识体系现代C特性设计模式数据结构CMake项目构建调试技巧进阶主题学习资源 1. 开发环境配置 1.1 安装编译器 sudo apt-get install g build-essential1.2 安装构建工具 sudo apt-get install cmake1.3 VS Code配置 安装C扩展配置调试…...
硬件电路(23)-输入隔离高低电平有效切换电路
一、概述 项目中为了防止信号干扰需要加一些隔离电路,而且有时传感器的信号是高有效有时是低有效,所以基于此背景,设计了一款方便实现高低电平有效检测切换电路。 二、应用电路...
基于深度学习的多模态癌症数据集调研
基于深度学习的多模态癌症数据集调研 关键词: 癌症、分割、多模态、radiology、pathology、深度学习 目录: 一、 数据集总结 二、 胶质瘤/脑肿瘤(glioma) 三、 肺癌/非小细胞肺癌(NSCLC) 四、 乳腺癌&am…...
Logo语言的系统监控
Logo语言的系统监控 引言 在信息技术飞速发展的时代,系统监控成为了确保计算机系统和网络平稳运行的重要手段。系统监控不仅可以实时跟踪系统的性能、资源使用情况和安全风险等,还能够在出现问题时及时发出警报,从而避免潜在的故障和损失。…...
Go语言-初学者日记(八):构建、部署与 Docker 化
🧱 一、go build:最基础的构建方式 Go 的构建工具链是出了名的轻量、简洁,直接用 go build 就能把项目编译成二进制文件。 ✅ 构建当前项目 go build -o myapp-o myapp 指定输出文件名默认会构建当前目录下的 main.go 或 package main &a…...
青少年编程与数学 02-015 大学数学知识点 08课题、信息论
青少年编程与数学 02-015 大学数学知识点 08课题、信息论 一、信息论基础二、熵与信息量三、信源编码四、信道编码五、率失真理论六、信息论的应用七、网络信息论八、信息论与统计学习九、量子信息论十、信息论的前沿研究总结 信息论是研究信息传输、存储和处理的数学理论&…...
【已解决】Webstorm 每次使用 git pull/push 都要输入令牌/密码登录
解决办法:勾上【使用凭据帮助程序】(英文:Use credential helper)...
FreeRTOS:嵌入式实时操作系统的轻量化解决方案
一、FreeRTOS 的核心定位 FreeRTOS(Free Real-Time Operating System)是一款专为微控制器及资源受限的嵌入式设备设计的开源实时操作系统内核。自2003年由Richard Barry发布以来,其以轻量化、高实时性、低资源占用的特点,成为物…...
Linux操作系统 4.Linux实用操作
一、各类小技巧(快捷键) 强制停止 退出、登出 历史命令搜索 光标移动 1.CTRL C 强制停止 1.Linux某些程序的运行,如果想要强行停止它,可以使用ctrlc 2.命令输入错误,也可以通过快捷键ctrl c,退出当前输入࿰…...
学透Spring Boot — 010. 单元测试和Spring Test
系列文章目录 这是CSDN postnull 博客《学透Spring Boot》系列的一篇,更多文章请移步:Postnull - 学透Spring Boot系列文章 文章目录 系列文章目录前言1. 基本概念UT 单元测试TDD 测试驱动开发UT测试框架Mock框架 3. Spring Test为什么要用Spring Test引…...
Perl语言的文件系统
Perl语言中的文件系统操作 引言 在软件开发中,文件系统操作是一个不可或缺的部分。无论是简单的文件读取、写入,还是复杂的文件管理,合理的文件系统操作都能极大提升程序的效率和可维护性。Perl语言是一种强大的文本处理语言,凭…...
ffmpeg基础指令学习
文章目录 1. **基本的 FFmpeg 语法**2. **常见的 FFmpeg 基础指令****1. 转换视频格式****2. 视频剪切****3. 转换视频的编码****4. 提取音频****5. 改变视频分辨率****6. 改变音视频的比特率****7. 合并音视频****8. 提取视频中的一帧图片****9. 提取视频的帧速率(…...
英国电商物流变革:ebay私人卖家如何借势简易配送提升履约效率?
近年来,英国电商物流正在经历一场不小的变革。从“等待5-7个工作日”到如今“次日达”成为常态,市场和用户对配送效率的要求越来越高。对于在 eBay 平台上的私人卖家来说,这既是挑战,也是机会。如何用有限的资源跟上平台和消费者对…...
第15周:注意力汇聚:Nadaraya-Watson 核回归
注意力汇聚:Nadaraya-Watson 核回归 Nadaraya-Watson 核回归是一个经典的注意力机制模型,它展示了如何通过注意力权重来对输入数据进行加权平均。以下是该内容的核心总结: 关键概念 注意力机制框架:由查询(自主提示…...
批量图片文本识别重命名,批量ocr识别图片重命名,基于WPF和腾讯OCR云部署实,现批量对图片局部提取文字后重命名的操作详细步骤
1. 项目背景 在日常工作中,我们经常需要处理大量图片文件,这些图片可能包含重要的文字信息。为了提高工作效率,我们需要一种自动化的方式,从图片中提取文字,并根据提取的文字对图片进行重命名。 本项目基于 WPF 框架开发桌面应用程序,结合 腾讯 OCR…...
26考研——排序(8)
408答疑 文章目录 一、排序的基本概念二、插入排序三、交换排序四、选择排序五、归并排序、基数排序和计数排序六、排序的代码实操七、各种内部排序算法的比较及应用八、外部排序九、参考资料鲍鱼科技课件26王道考研书 十、总结基本排序算法希尔排序快速排序、堆排序和归并排序…...
KUKA机器人导入设备说明文件
KUKA机器人在应用中需要进行通讯配置,通讯前需要导入设备说明文件,比如常用的倍福设备说明文件。在Workvisual软件上通过以下步骤即可导入设备说明文件。 一、打开Workvisual软件,在选项卡【File】下找到【Import/Export】输入/输出并点击打…...
ssl.SSLCertVerificationError报错解决方案
这个错误 ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate 指出 Python 在尝试建立安全的 HTTPS 连接时,无法验证远程服务器(在此案例中是 GitHub 或 Hugging Face…...
drawio导出流程图为白色背景png图片
draw.io 操作路径: 1.纯白背景图片(一般导出流程图就这种纯白背景,看自己需求 什么都不勾选 导出效果图 2.田字格白背景 只勾选网格 导出效果图 3.方块背景 只勾选背景 导出效果图 4.大方块背景 都勾选 导出效果图...
【Linux】——手撕线程池、简易线程池
前言 在现代计算机编程领域,随着多核处理器和分布式系统的广泛应用,并发编程变得越来越重要。而线程作为实现并发的基本手段之一,其重要性不言而喻。然而,在实际的应用开发中,如何高效地管理和调度线程,以充…...
使用mcp自定义编写mcp tool,使用 conda 启动,在cline中配置使用
自定义 mcp tool 例子 ## /langchain_learn/mcp学习/base_mcp_tool_study2.py # 导入必要模块 import os from typing import Optional from mcp.server.fastmcp import FastMCP# 初始化 MCP 服务器实例,指定服务器名称和版本 mcp_server FastMCP(name"DemoS…...
OpenEuler/CentOS一键部署OpenGauss数据库教程(脚本+视频)
📌OpenEuler/CentOS一键安装OpenGauss数据库教程 为什么需要OpenGauss一键安装脚本? 手动部署OpenGauss数据库时,环境适配、依赖冲突等问题常让开发者头疼。尤其对新人而言,官方文档的配置步骤可能耗时数小时甚至引发未知报错。 …...
python如何快速删除文件夹中的大量文件
在 Python 中,删除文件夹中的大量小图片文件可以通过使用 os 模块或 shutil 模块来实现。以下是一个示例代码,展示了如何快速删除指定文件夹中的所有文件。如果你只需要删除小图片文件,可以添加额外的逻辑来检查文件大小。 以下是一个示例代…...
【mongodb】MongoDB的应用场景
目录 1.说明2.内容管理系统(CMS)2.1 场景描述2.2 MongoDB优势2.3 示例 3.实时分析与大数据3.1 场景描述3.2 MongoDB优势3.3 示例 4.移动应用后端4.1 场景描述4.2 MongoDB优势4.3 示例 5.游戏开发5.1 场景描述5.2 MongoDB优势5.3 示例 6.电子商务平台6.1 …...
使用 Swift 实现 LRU 缓存淘汰策略
📌 实现思路 一、核心目标 我们要实现一个缓存类: 支持通过 get(key) 获取缓存的值;支持通过 put(key, value) 写入缓存;缓存容量有限,当超过容量时要淘汰最久未使用的元素。 二、为什么用「哈希表 双向链表」 功…...
【面试篇】Dubbo
基础概念 问题:请简要介绍一下 Dubbo 是什么,它的主要用途是什么?答案:Dubbo 是阿里巴巴开源的高性能、轻量级的分布式服务框架,它致力于提供高性能和透明化的 RPC 远程服务调用方案,以及 SOA 服务治理方案…...
01-STM32(介绍、工具准备、新建工程)p1-4
文章目录 工具准备和介绍硬件设备stm32简介和arm简介stm32简介STM32命名规则STM32选型STM32F103C8T6最小系统板引脚定义STM32启动配置STM32最小系统电路ARM简介 软件安装注册器件支持包安装ST-LINK驱动安装USB转串口驱动 新建工程创建stm32工程STM32工程编译和下载型号分类及缩…...
关于termux运行pc交叉编译的aarch64 elf的问题
在Linux系统上交叉编译Nim程序到Android Termux环境需要特殊处理,以下是详细的解决方案: 问题根源分析 ABI不兼容 Android使用bionic libc而非标准glibc,直接编译的Linux ARM二进制无法直接运行 动态链接错误 默认编译会链…...
Ansible Playbook 进阶探秘:Handlers、变量、循环及条件判断全解析
192.168.60.100ansible.com192.168.60.110 client-1.com 192.168.60.120client-2.com192.168.60.130client-1.com 一、Handlers 介绍:在发生改变时执行的操作(类似puppet通知机制) 示例: 当apache的配置文件发生改变时,apache服务才会重启…...
解决GraalVM Native Maven Plugin错误:JAVA_HOME未指向GraalVM Distribution
目录 问题描述解决方案为什么需要这样配置? 问题描述 在你的项目中,如果你遇到了以下错误信息: [ERROR] Failed to execute goal org.graalvm.buildtools:native-maven-plugin:0.10.5:test (native-test) on project DIctSystemInJavaUsing…...
006贪心——算法备赛
跨步问题 跳跃游戏|| 问题描述 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向后跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i j] 处: 0 < j < nums[i]i j &…...
Hyperlane:高性能 Rust HTTP 服务器框架评测
Hyperlane:高性能 Rust HTTP 服务器框架评测 在当今快速发展的互联网时代,选择一个高效、可靠的 HTTP 服务器框架对于开发者来说至关重要。最近,我在评估各种服务器框架性能时,发现了一个名为 Hyperlane 的 Rust HTTP 服务器库&a…...
解锁多元养生密码,开启活力生活
在车水马龙、节奏飞快的现代社会,亚健康像阴霾一样,笼罩着不少人的生活。不少上班族长期久坐,肩颈酸痛;有的人作息混乱,皮肤状态差。想要驱散这些健康阴霾,拥抱活力生活,不妨解锁下面这些多元养…...
如何安全地访问AWS
如何安全地访问AWS 推荐超级课程: 本地离线DeepSeek AI方案部署实战教程【完全版】Docker快速入门到精通Kubernetes入门到大师通关课AWS云服务快速入门实战目录 如何安全地访问AWS当可以使用AWS Organizations & IAM Identity Center时理想的访问方式补充:什么是IAM IIC…...