整体逻辑
- 控制层(Controller)
- 业务逻辑层(Service) → 服务层实现类(ServiceImpl)
- 数据访问层(Repository/DAO) → 数据访问实现类(RepositoryImpl)
各层之间的分离 和 松耦合,每个层次只关注自己的职责,并通过接口与实现层进行解耦。
控制层
控制层(Controller)是应用的入口,负责接收来自客户端的请求,执行一些简单的输入验证,然后将请求转发到业务逻辑层(Service)进行处理,最后将处理结果返回给客户端。
控制层应尽量保持简洁,只负责接受请求、验证输入、调用业务层方法并返回结果。复杂的业务逻辑、事务管理等应该委托给业务逻辑层。
业务逻辑层
Bean是实现逻辑层的载体,其通常采用单例的模式,这些单例Bean通常不会包含会话或请求特有的数据,而是包含无状态的业务逻辑、常量以及通用功能。
而在业务逻辑中的变量通常是随着某次请求变化的值,因此Bean的输入数据通常通过一个专门的数据模型(如DTO,数据传输对象)来封装,然后作为参数传递给业务层的服务方法。这个数据模型包含了业务逻辑所需的动态数据,它是业务逻辑处理的输入
逻辑层的职责包括对外提供服务、协调数据访问、事务管理等,因此通常会由一组或多个服务类(Bean)来实现。
数据访问层
基于 MyBatis 的一种常见数据库访问层架构设计,涉及了 (repo impl
)、数据访问层(repository
)、映射器接口(Mapper
) 和 SQL 映射文件(Mapper.xml
)。 映射器接口是映射器能作为java类被其他模块使用的前提,使用Mapper.xml的方式可以完全自定义 SQL,提高 SQL 和 Java 代码的清晰分离
模块管理
主要借助Maven或者是Gradle,类似于pip的管理机制,都可以用来自动管理和下载第三方库(依赖)。你在配置文件中声明了项目所需的库及其版本,Maven/Gradle 会自动从中央仓库或私有仓库下载并将其集成到项目中,甚至其还有更加 丰富的类似于项目的构建、版本控制、生命周期管理等多个方面。
依赖注入(DI)
依赖注入(Dependency Injection,DI)是一种设计模式,它将对象的依赖交给容器管理,由容器在运行时自动创建和注入依赖,从而降低组件间耦合、提高可测试性和可维护性。
简单说,依赖注入是一种让对象无需自行创建依赖,由容器自动提供所需组件的设计模式。
Spring中的依赖注入
Spring采用注解来简化依赖注入的复杂度,有一个全局可以访问的 IoC 容器,其遵循以下步骤:
扫描注册 Bean → 实例化 Bean → 解析依赖 → 注入依赖 → 初始化完成。
扫描和注册 Bean 的类
Bean类包括:
@Component
(通用组件)@Service
(业务逻辑层)@Repository
(数据访问层)@Controller
(Web 控制器)- 等等
以及一些配置类 (@Configuration) 中的 Bean方法,@Bean
方法返回的对象也会被注册为 Bean。
@Configuration
public class AppConfig {
@Bean
public UserService userService(UserRepository repo) {
return new UserService(repo);
}
}
解析依赖关系
读取注入点:
- 构造器注入:Bean类的构造器 (无需标注)
- 字段注入:字段带有
@Autowired
标注 - 方法注入:在Bean类的方法上标注
@Autowired
并且被注入的点必须属于一个被 Spring 管理的 Bean
实例化单例 Bean
对我们注册的Bean类进行下一步操作:
对默认单例 Bean,容器会在启动时提前创建实例(Eager Initialization),对原型 Bean 或延迟加载 Bean,则在第一次使用时才创建。
注入依赖
按照依赖关系将 Bean 注入到其他 Bean 的构造器、字段或 setter 中,并处理循环依赖(字段/Setter 注入可以,构造器注入可能报错)
过滤器Fliter使用
先编写继承自OncePerRequestFilter
的 Fliter 类
Fliter类编写
可以编写 doFilterInternal
来说明Fliter逻辑,编写 shouldNotFilter
来决定哪些可以跳过而不经过过滤器。
/**
* JwtAuthFilter 用于在每次 HTTP 请求中处理 JWT 认证。
* 它会在请求到达 Controller 前被调用,验证请求中的 JWT 并设置安全上下文。
*/
public class JwtAuthFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
// 功能说明:
// 1. 从请求头获取 JWT(通常从 Authorization 字段)
// 2. 检查 Token 是否有效或是否在黑名单中
// 3. 验证 Token 并解析出用户信息
// 4. 将认证信息设置到 SecurityContext 中,以便后续鉴权
// 5. 调用 filterChain.doFilter 放行请求,无论认证是否成功
}
@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
// 功能说明:
// 用于判断哪些请求无需经过该过滤器
// 例如公开路径(login、register)或静态资源等
// 如果返回 true,doFilterInternal 将不会被执行
return false; // 默认全部请求都执行过滤
}
}
Config编写
再在 config
中设立一个Bean方法:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth.requestMatchers(SecurityConstants.PUBLIC_PATHS).permitAll()
.anyRequest()
.authenticated())
.addFilterBefore(new JwtAuthFilter(jwtCoreUtil, tokenBlacklistService),
UsernamePasswordAuthenticationFilter.class);
return http.build();
authorizeHttpRequests
是专门用于鉴权的机制,用来控制每个 HTTP 请求是否允许访问某个资源,和身份认证(JWT 校验)配合使用。鉴权机制下添加了我们上面的Fliter,并还可以通过 requestMatchers
来直接决定是否经过这个Fliter。
一个是内部的跳过,一个是从更上层根本跳过。
其中例如用到的PUBLIC_PATHS,设置哪些是公开的路径,可以写到constant里作为运行时常量。
DTO(Data Transfer Object)
PO、VO、DTO 对比整理
类型 | 全称 | 主要作用 | 特点 |
---|---|---|---|
PO | Persistent Object(持久化对象) | 与数据库表结构一一对应 | - 通常与 ORM 框架(MyBatis、Hibernate)配合使用- 一个 PO 对应数据库中的一张表- 包含表的所有字段及 getter/setter- 一般不包含业务逻辑 |
VO | Value Object(值对象/视图对象) | 用于展示层,向前端传递数据 | - 根据前端页面需求定制数据结构- 可以组合多个 PO 的信息- 可以包含格式化后的数据- 通常用于接口返回给前端 |
DTO | Data Transfer Object(数据传输对象) | 在不同层或不同系统之间传输数据 | - 封装多个数据对象,减少网络传输次数- 可以聚合多个 PO 的数据- 用于服务间调用或前后端数据传输- 可以包含业务相关的数据转换逻辑 |
通常在数据层与逻辑层之间依旧采用PO,对于数据层和控制层之间,或者是控制层与请求之间的交互则使用DTO。
record
用于定义一种 不可变的数据载体类,也叫 记录类。它主要用于简化只存储数据的类的写法。