MVC架构
分层概念
MVC模型
M:Model模型
V:View视图
C:Controller控制器
MVC是在表述层开发中运用的一种设计理念。主张把封装数据的『模型』、显示用户界面的『视图』、**协调调度的『控制器』**分开。
好处:
- 进一步实现各个组件之间的解耦
- 让各个组件可以单独维护
- 将视图分离出来以后,我们后端工程师和前 端工程师的对接更方便
Service层
从上面能够看出:注册功能不是一个简单的业务功能,而是一个复杂的业务功能它里面包含了4个Dao方法的调用
因此,我们说:
Dao方法是单精度方法(细粒度方法)。单精度方法指的是,这个方法只考虑一件事。
业务方法是粗粒度方法。一个业务方法可能会由多个单精度方法组合而成。
业务方法存在于业务层。业务层一般我们称之为biz,或者 service层
// MVC: Model-Wiew-ControlModel:
模型层;数据访问模型;业务逻模型;数据传输模型(POJO,DTO)
View:视图层
Control:控制层
DTO层
DTO(Data Transfer Object,数据传输对象)
直译就是 数据传输对象,通常用于在 不同层 或 不同系统 之间传递数据。
在一个三层架构(Controller → Service → DAO/Entity)或前后端交互中:
Entity(实体类) 直接对应数据库表,往往带有很多不需要对外暴露的字段(如密码、状态、创建时间等)。
DTO(数据传输对象) 只保留和“数据传输”相关的字段,用于前后端交互,避免暴露过多内部细节。
VO(View Object) 一般用于返回给前端的对象(View 层),可能是 DTO 的扩展,包含展示需要的额外字段。
举个例子
用户注册时,前端提交的数据:用户名、邮箱、密码 → 后端用 UserDTO 接收。
数据库存储的 UserEntity 可能还包含 id、创建时间、加密后的密码、角色 等字段。
如果直接用 Entity 去做数据交互,容易暴露敏感字段。
所以,我们用 DTO 来“裁剪”和“隔离”。
DTO 的优点
解耦:DTO 和数据库实体解耦,修改数据库结构不会直接影响前端。
安全性:避免直接把数据库字段(比如密码)暴露给前端。
灵活性:可以根据业务需求定制,只包含必要的数据。
数据校验:DTO 上可以加注解(如 @NotNull @Email)做参数校验。
DTO 示例
实体类(Entity,对应数据库)
public class UserEntity {
private Long id;
private String username;
private String password; // 存储加密后的密码
private String email;
private Date createTime;
private Date updateTime;
// getter/setter
}
数据传输对象(DTO,用于前后端交互)
public class UserDTO {
private String username;
private String password;
private String email;
// getter/setter
}
控制器使用 DTO
@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping("/register")
public String register(@RequestBody UserDTO userDTO) {
// 接收前端传过来的 DTO
System.out.println("注册用户:" + userDTO.getUsername());
return "注册成功";
}
}
这样,数据库中真正的 UserEntity 不会直接暴露给前端,安全性和灵活性更好。
DTO 不要和数据库实体类混用,否则就失去了隔离的意义。
建议使用 BeanUtils / MapStruct 来做 DTO ↔ Entity 的属性转换,避免手写冗余代码。
DTO 应该只包含 业务需要传输的字段,而不是照搬数据库表。
POJO层
翻译过来就是 简单的 Java 对象,指那些不依赖框架、只包含属性和 getter/setter 的普通类。
它本身是一个 概念,不局限于“实体类”,只要是“没有复杂逻辑的普通 Java 对象”都可以叫 POJO。
在一个分层项目里(比如 Spring Boot 项目),你会看到这些类,统称 POJO:
Entity(实体类):数据库表对应对象(存储数据用)
DTO(数据传输对象):前后端传输用
VO(视图对象):返回给前端展示用
BO(业务对象):业务逻辑层封装的对象
微服务架构
API 层
位置:最外层,直接暴露给前端或外部系统调用。
作 用:
定义服务的输入和输出(通常是 DTO/VO)。
接收请求、做参数校验、调用内部服务。
对应技术:Controller 层 (Spring MVC 的 @RestController、@RequestMapping)。
简单说:API 层就是 对外提供接口的入口。
Gateway 层
位置:API 层的前面(或者外部流量的第一个入口)。
作用:
请求路由(转发到具体服务)。
统一认证、鉴权。
统一限流、日志、监控。
对应技术:Spring Cloud Gateway、Nginx、Kong、Zuul 等。
网关就是 大门口,所有流量先进来这,检查完才能进去。
Process 层
位置:API 层和 Service(领域/业务逻辑层)之间。
作用:
封装跨多个服务或多个业务对象的流程。
做“业务编排”,调用不同的 Service 完成一个完整业务。
对应技术:自己写的 Service/Manager 类,或者工作流引擎(如 Camunda、Activiti)。
Process 层更像是 管弦乐队的指挥,调度不同的业务模块协同完成任务。
CMC 层
你说的 cmc 更像是一个 特定业务域的核心服务层,通常存放和核心业务逻辑相关的类
解耦合
耦合的概念:
控制层需要业务层组件才能工作;
业务层需要数据访问层组件才能工作;
我们把这种需要称之为依赖;
依赖就是”"离不开”,依赖:dependency;
当前层和层之间存在依赖,我们将这种现象称之为层和层之间存在耦合;
解耦合:
因此我们需要降低耦合度或者消除耦合,称之为 解耦合/解耦
假设之前controller中有100个地方出现了new FruitServicelmpl:
那么我们就简单认为耦合度是100:1
如果我们使用简单工厂方法模式,调用工厂的静态方法获取实例那么耦合度降低成 1:1
耦合度大大降低,但不得不承认,问题依然存在:如果FruitServicelmpl修改成FruitServicelmpl2.
工厂中方法代码依然需要修改,那么需要重新编译,重新部署
配置 java.beans
JavaBean
JavaBean 是 Java 语言中一种符合特定规范的类,通常用来 封装数据。 它常用于表示一个实体(例如:用户、商品、订单),把属性和对应的 getter/setter 方法封装在一个类中。在我们的项目中JavaBean主要用于存储内存中的数据。
简单说:JavaBean = 一种标准的可重用组件。
JavaBean 规范
1、必须是一个 public 类。
2、必须有一个 无参构造方法(便于框架反射创建对象)。
3、属性通常用 private 修饰(实现封装)。
4、提供 public 的 getter/setter 方法 来访问属性。
5、通常是 可序列化的(可选,实现
Serializable
接口),方便对象存储和传输。6、建议重写toString()方法,便于打印对象。
7、基本类型简写使用包装类型
8、不要写业务逻辑:JavaBean 应该专注于封装数据,而不是业务逻辑。
使用场景
1、数据封装:存储和传递数据(比如 MVC 模式里 Model 层)。
2、与数据库表对应:一个表对应一个 JavaBean,ORM(如 MyBatis、Hibernate)会自动映射。
3、Web 开发:Servlet/JSP、Spring、Spring Boot 中大量使用 JavaBean 来作为数据模型。
4、配置类:Spring 配置文件中的 Bean,大多数就是 JavaBean。
使用示例
JavaBean
import java.io.Serializable;
// 用户类
public class User implements Serializable {
private int id;
private String name;
private String email;
private boolean active;
// 无参 构造方法
public User() {}
// 全参构造方法(可选)
public User(int id, String name, String email, boolean active) {
this.id = id;
this.name = name;
this.email = email;
this.active = active;
}
// Getter 和 Setter
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
// 布尔类型建议用 isXxx
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
@Override
public String toString() {
return "User {id=" + id + ", name='" + name + "', email='" + email + "', active=" + active + "}";
}
}
使用 JavaBean
public class Main {
public static void main(String[] args) {
// 创建 JavaBean 对象
User user = new User();
// 使用 setter 设置属性
user.setId(1);
user.setName("Alice");
user.setEmail("alice@example.com");
user.setActive(true);
// 使用 getter 获取属性
System.out.println("用户ID: " + user.getId());
System.out.println("