【三层架构】三层架构设计(基于Spring Boot + JPA / MyBatis-Plus的三层架构代码示例)
·
文章目录
三层架构
一、三层架构概述
三层架构(Three-Tier Architecture)是一种经典的软件设计模式,将应用程序划分为表现层(Controller)、业务逻辑层(Service)、数据访问层(DAO),通过职责分离实现高内聚、低耦合,提升代码的可维护性、扩展性和可测试性。
二、各层核心职责
1. 表现层(Controller)
- 职责:接收客户端请求(HTTP/API)、参数校验、调用Service层处理业务、将结果转换为响应格式(JSON/HTML)返回。
- 原则:不处理业务逻辑,仅做“请求转发器”和“响应组装器”。
2. 业务逻辑层(Service)
- 职责:核心业务逻辑处理(如计算、规则判断、流程编排)、事务控制、调用DAO层进行数据交互。
- 原则:业务逻辑集中于此,是连接Controller和DAO的桥梁。
3. 数据访问层(DAO/Repository)
- 职责:直接与数据库/存储介质交互,执行CRUD(增删改查)操作,封装数据访问细节。
- 原则:不涉及业务逻辑,仅专注“数据存取”。
三、交互流程
四、优缺点分析
| 优点 | 缺点 |
|---|---|
| 职责单一,易于维护和扩展 | 简单项目会增加代码结构复杂度 |
| 各层可独立测试(如Mock Service测试Controller) | 层级间依赖可能导致性能损耗(需合理设计) |
| 便于团队协作(不同人负责不同层) | 过度分层可能导致代码冗余 |
一、基于 Spring Boot + JPA 的三层架构代码示例
JPA(Java Persistence API) 是Java平台的标准ORM(对象关系映射)规范,用于简化Java对象与关系数据库之间的映射操作,让开发者通过面向对象的方式操作数据库,无需编写复杂的SQL。
1. 项目结构
src/main/java/com/example/demo
├── controller # 表现层
│ └── UserController.java
├── service # 业务逻辑层
│ ├── UserService.java
│ └── impl/UserServiceImpl.java
├── dao # 数据访问层
│ └── UserRepository.java
├── entity # 数据库实体
│ └── User.java
└── dto # 数据传输对象
├── UserRequest.java
└── UserResponse.java
2. 依赖配置(pom.xml)
<dependencies>
<!-- Spring Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- H2数据库(演示用) -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
3. 数据库配置(application.properties)
# H2数据库配置
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
# JPA配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
4. 代码实现
(1)Entity层:User.java(数据库实体)
package com.example.demo.entity;
import jakarta.persistence.*;
import lombok.Data;
@Data
@Entity
@Table(name = "t_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String email;
private Integer age;
}
(2)DTO层:请求/响应对象
// UserRequest.java(接收请求参数)
package com.example.demo.dto;
import lombok.Data;
@Data
public class UserRequest {
private String username;
private String email;
private Integer age;
}
// UserResponse.java(返回响应数据)
package com.example.demo.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class UserResponse {
private Long id;
private String username;
private String email;
}
(3)DAO层:UserRepository.java(数据访问)
package com.example.demo.dao;
import com.example.demo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
// 继承JpaRepository,自动拥有CRUD方法
public interface UserRepository extends JpaRepository<User, Long> {
}
(4)Service层:业务逻辑处理
// UserService.java(接口)
package com.example.demo.service;
import com.example.demo.dto.UserRequest;
import com.example.demo.dto.UserResponse;
public interface UserService {
UserResponse createUser(UserRequest request);
UserResponse getUserById(Long id);
}
// UserServiceImpl.java(实现类)
package com.example.demo.service.impl;
import com.example.demo.dao.UserRepository;
import com.example.demo.dto.UserRequest;
import com.example.demo.dto.UserResponse;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
@Override
@Transactional(rollbackFor = Exception.class) // 事务控制
public UserResponse createUser(UserRequest request) {
// 业务逻辑:比如校验用户名是否存在(示例简化)
User user = new User();
user.setUsername(request.getUsername());
user.setEmail(request.getEmail());
user.setAge(request.getAge());
// 调用DAO层保存数据
User savedUser = userRepository.save(user);
// 转换为响应DTO返回
return new UserResponse(savedUser.getId(), savedUser.getUsername(), savedUser.getEmail());
}
@Override
public UserResponse getUserById(Long id) {
// 调用DAO层查询数据
User user = userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("用户不存在"));
return new UserResponse(user.getId(), user.getUsername(), user.getEmail());
}
}
(5)Controller层:请求处理
package com.example.demo.controller;
import com.example.demo.dto.UserRequest;
import com.example.demo.dto.UserResponse;
import com.example.demo.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
// 创建用户:POST /api/users
@PostMapping
public ResponseEntity<UserResponse> createUser(@RequestBody UserRequest request) {
UserResponse response = userService.createUser(request);
return ResponseEntity.ok(response);
}
// 查询用户:GET /api/users/{id}
@GetMapping("/{id}")
public ResponseEntity<UserResponse> getUserById(@PathVariable Long id) {
UserResponse response = userService.getUserById(id);
return ResponseEntity.ok(response);
}
}
5. 最佳实践
- 分层严格性:Controller不直接调用DAO,必须通过Service;Service只处理业务,不涉及HTTP请求/响应。
- DTO与Entity分离:用DTO(Data Transfer Object)传输数据,避免直接暴露数据库实体(Entity)。
- 事务管理:在Service层使用
@Transactional控制事务,确保数据一致性。 - 异常处理:全局异常处理器(
@ControllerAdvice)统一处理异常,返回友好响应。 - 单元测试:针对各层独立测试(如Mock DAO测试Service,Mock Service测试Controller)。
二、基于 Spring Boot + MyBatis-Plus 的三层架构代码示例
一、项目结构
src/main/java/com/example/demo
├── controller # 表现层
│ └── UserController.java
├── service # 业务逻辑层
│ ├── UserService.java
│ └── impl/UserServiceImpl.java
├── mapper # 数据访问层(MyBatis 的 Mapper)
│ └── UserMapper.java
├── entity # 数据库实体
│ └── User.java
├── dto # 数据传输对象
│ ├── UserRequest.java
│ └── UserResponse.java
├── common # 公共模块
│ ├── Result.java # 统一返回结果
│ └── BusinessException.java # 业务异常
└── config # 配置类
└── GlobalExceptionHandler.java # 全局异常处理器
二、核心依赖配置(pom.xml)
<dependencies>
<!-- Spring Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis-Plus(MyBatis 增强工具,简化 CRUD) -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.5</version>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- Lombok(简化实体类代码) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
三、数据库配置(application.yml)
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/demo_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: your_password
# MyBatis-Plus 配置
mybatis-plus:
configuration:
map-underscore-to-camel-case: true # 数据库下划线转驼峰
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印 SQL
global-config:
db-config:
id-type: auto # 主键自增
四、数据库表初始化 SQL
CREATE DATABASE IF NOT EXISTS demo_db;
USE demo_db;
CREATE TABLE IF NOT EXISTS t_user (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
username VARCHAR(50) NOT NULL COMMENT '用户名',
email VARCHAR(100) COMMENT '邮箱',
age INT COMMENT '年龄',
status TINYINT DEFAULT 1 COMMENT '状态:1-正常,0-禁用',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) COMMENT '用户表';
五、代码实现
1. 公共模块(common)
(1)统一返回结果 Result.java
package com.example.demo.common;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> {
private Integer code; // 状态码:200-成功,500-失败
private String msg; // 提示信息
private T data; // 返回数据
// 成功静态方法
public static <T> Result<T> success(T data) {
return new Result<>(200, "操作成功", data);
}
// 失败静态方法
public static <T> Result<T> fail(String msg) {
return new Result<>(500, msg, null);
}
}
(2)业务异常 BusinessException.java
package com.example.demo.common;
import lombok.Getter;
@Getter
public class BusinessException extends RuntimeException {
private final String msg;
public BusinessException(String msg) {
super(msg);
this.msg = msg;
}
}
(3)全局异常处理器 GlobalExceptionHandler.java
package com.example.demo.config;
import com.example.demo.common.BusinessException;
import com.example.demo.common.Result;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
// 处理业务异常
@ExceptionHandler(BusinessException.class)
public Result<Void> handleBusinessException(BusinessException e) {
return Result.fail(e.getMsg());
}
// 处理其他异常
@ExceptionHandler(Exception.class)
public Result<Void> handleException(Exception e) {
e.printStackTrace();
return Result.fail("系统异常,请联系管理员");
}
}
2. 数据库实体(entity)
User.java
package com.example.demo.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("t_user") // 指定数据库表名
public class User {
@TableId(type = IdType.AUTO) // 主键自增
private Long id;
private String username;
private String email;
private Integer age;
private Integer status;
private LocalDateTime createTime;
private LocalDateTime updateTime;
}
3. 数据传输对象(dto)
(1)请求参数 UserRequest.java
package com.example.demo.dto;
import lombok.Data;
@Data
public class UserRequest {
private String username;
private String email;
private Integer age;
}
(2)响应数据 UserResponse.java
package com.example.demo.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@AllArgsConstructor
public class UserResponse {
private Long id;
private String username;
private String email;
private Integer age;
private LocalDateTime createTime;
}
4. 数据访问层(mapper)
UserMapper.java
package com.example.demo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
// 继承 MyBatis-Plus 的 BaseMapper,自动拥有 CRUD 方法
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
5. 业务逻辑层(service)
(1)接口 UserService.java
package com.example.demo.service;
import com.example.demo.dto.UserRequest;
import com.example.demo.dto.UserResponse;
public interface UserService {
UserResponse createUser(UserRequest request);
UserResponse getUserById(Long id);
void updateUser(Long id, UserRequest request);
void deleteUser(Long id);
}
(2)实现类 UserServiceImpl.java
package com.example.demo.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.demo.common.BusinessException;
import com.example.demo.dto.UserRequest;
import com.example.demo.dto.UserResponse;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
private final UserMapper userMapper;
@Override
@Transactional(rollbackFor = Exception.class) // 事务控制
public UserResponse createUser(UserRequest request) {
// 1. 业务校验:用户名是否已存在
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getUsername, request.getUsername());
if (userMapper.selectCount(wrapper) > 0) {
throw new BusinessException("用户名已存在");
}
// 2. 转换请求参数为实体
User user = new User();
BeanUtils.copyProperties(request, user);
user.setStatus(1); // 默认状态正常
// 3. 调用 Mapper 保存数据
userMapper.insert(user);
// 4. 转换为响应 DTO 返回
return new UserResponse(user.getId(), user.getUsername(), user.getEmail(), user.getAge(), user.getCreateTime());
}
@Override
public UserResponse getUserById(Long id) {
// 1. 调用 Mapper 查询数据
User user = userMapper.selectById(id);
if (user == null) {
throw new BusinessException("用户不存在");
}
// 2. 转换为响应 DTO 返回
return new UserResponse(user.getId(), user.getUsername(), user.getEmail(), user.getAge(), user.getCreateTime());
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateUser(Long id, UserRequest request) {
// 1. 校验用户是否存在
User user = userMapper.selectById(id);
if (user == null) {
throw new BusinessException("用户不存在");
}
// 2. 更新字段
BeanUtils.copyProperties(request, user);
user.setId(id);
// 3. 调用 Mapper 更新数据
userMapper.updateById(user);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteUser(Long id) {
// 1. 校验用户是否存在
User user = userMapper.selectById(id);
if (user == null) {
throw new BusinessException("用户不存在");
}
// 2. 调用 Mapper 删除数据
userMapper.deleteById(id);
}
}
6. 表现层(controller)
UserController.java
package com.example.demo.controller;
import com.example.demo.common.Result;
import com.example.demo.dto.UserRequest;
import com.example.demo.dto.UserResponse;
import com.example.demo.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
// 创建用户:POST /api/users
@PostMapping
public Result<UserResponse> createUser(@RequestBody UserRequest request) {
UserResponse response = userService.createUser(request);
return Result.success(response);
}
// 查询用户:GET /api/users/{id}
@GetMapping("/{id}")
public Result<UserResponse> getUserById(@PathVariable Long id) {
UserResponse response = userService.getUserById(id);
return Result.success(response);
}
// 更新用户:PUT /api/users/{id}
@PutMapping("/{id}")
public Result<Void> updateUser(@PathVariable Long id, @RequestBody UserRequest request) {
userService.updateUser(id, request);
return Result.success(null);
}
// 删除用户:DELETE /api/users/{id}
@DeleteMapping("/{id}")
public Result<Void> deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return Result.success(null);
}
}
六、启动类配置
package com.example.demo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.demo.mapper") // 扫描 Mapper 接口
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
七、关键说明(符合企业实战规范)
- 分层严格:Controller 仅处理请求/响应,Service 处理业务逻辑与事务,Mapper 仅做数据访问。
- 实体分离:Entity 对应数据库,DTO 用于前后端交互,避免敏感字段泄露。
- 事务控制:
@Transactional加在 Service 方法上,确保数据一致性。 - 异常统一处理:全局异常处理器捕获业务异常和系统异常,返回统一格式。
- MyBatis-Plus 简化开发:继承
BaseMapper自动拥有 CRUD 方法,无需编写基础 SQL。
更多推荐


所有评论(0)