MVC架构概述:模型、视图、控制器及其优势与在Java Web中的实现
JAVA中的MVC三层架构 MVC架构概述

MVC 是一种软件设计模式,它将应用程序划分成主要的几个部分。其中有模型部分,还有视图部分以及控制器部分。这种架构对提高代码的可维护性和可扩展性是有帮助的。
MVC 的优势在于它能够将业务逻辑、数据和界面显示分离,提高代码的可维护性和可扩展性。在 Java Web 应用中,MVC 实现了这种分离,使得开发人员可以专注于各自的领域。Spring 中的 MVC 三层架构进一步简化了开发过程,提供了更好的开发体验和更高的性能。它包括控制器层,用于处理用户请求和调用业务逻辑;视图层,用于展示数据和界面;模型层,用于存储和管理数据。通过这种分层结构,开发人员可以更好地组织和管理代码,提高开发效率。
三层指的是界面层属于 Web 层,业务逻辑层属于 Service 层,数据持久层属于 Dao 层。
Web层,界面层(例如:餐厅中的服务员)
负责与前端交互,对用户的请求进行处理,然后把结果返回给用户。而业务逻辑的处理情况,Web 层并不在意。Servlet/Controller 能够起到充当的作用。
Service层,业务逻辑层 (例如:厨师)
只负责对核心的业务逻辑进行处理,至于请求的发起者是谁,Service 层并不关心。它会与 Web 层以及 Dao 层进行交互,然而不会直接与前端或者数据库进行交互。它是系统架构中最为重要的一层,Service 层的设计如果灵活且通用,那么就会决定整个系统未来的可扩展性以及组件事务的可替换性。
Dao 层,也就是数据访问对象层,它属于数据持久层,比如像采购员这样的角色。
负责与数据库进行交互,能够提供数据的增加、删除、修改和查询操作,对于具体的业务功能不予以关注,而是将精力集中在数据的存储以及检索方面。
采用自顶而下,自低向上的层次关系
Web 层会接收来自前端的请求,然后会调用 Service 层的方法去处理业务逻辑。
Service 层依据业务需求调用 Dao 层的方法以对数据库进行操作。
Dao 层执行完数据库操作后,将其结果返还给 Service 层。
Service 层把处理后的结果交给 Web 层,接着 Web 层把最终结果展示给用户。
Spring框架大量运用了 MVC 架构模式,利用注解能够清晰地分辨出不同的层次,从而让代码变得更加清晰且具备模块化特点。以下是 Spring 中 MVC 三层架构的具体呈现:
控制器层的工作流程;服务层的工作流程;数据访问层的工作流程。
用户请求:用户通过浏览器发送HTTP请求到服务器。
Spring 的前端控制器是 DispatcherServlet,它接收到了请求。
处理器进行映射:DispatcherServlet依据请求的 URL 以及配置好的映射规则,能够找到与之相对应的控制器方法。
控制器处理:控制器方法被调用,处理用户的请求。
调用服务层:控制器调用服务层的方法,进行业务逻辑处理。
调用数据访问层:服务层调用数据访问层的方法,进行数据操作。
数据访问层将数据返回给服务层,服务层在处理完业务之后把数据返回给控制器。
控制器会选择合适的视图来进行渲染,同时把数据传递给该视图。
视图渲染:视图生成最终的HTML页面。
DispatcherServlet 生成了 HTML 页面,然后将其返回给了用户。
优势 总结
Spring 框架利用@Controller 注解、@Service 注解和@Repository 注解,将 MVC 三层架构的各个层次划分得很清晰,这样能让开发人员更高效地去构建以及维护复杂的 Web 应用。
POJO(Plain Old Java Object)类
示例:
public class User {
private Long id;
private String username;
private String email;
// Getter 和 Setter 方法
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
设置用户名这个操作,是将传入的字符串 username 进行设定。
this.username = username;
}
public String getEmail() {
return email;
}
如果传入的 email 不为空且符合邮箱格式,就将其赋值给成员变量 email;否则,不进行赋值操作。
this.email = email;
}
}
DAO(Data Access Object)类
示例:
@Repository
公共类 UserDaoImpl 实现了 UserDao 接口。
@Autowired
创建了一个名为 jdbcTemplate 的私有 JdbcTemplate 对象。
@Override
public List findAll() {
从 users 表中选择所有数据,语句为“SELECT * FROM users”。
jdbcTemplate 执行查询操作,传入的 SQL 语句为指定的 sql,同时使用 UserRowMapper 进行行映射。最终返回查询结果。
}
@Override
查找具有指定 id 的用户,即通过给定的 id 去查找对应的用户。
从 users 表中选择所有数据,条件是 id 等于某个值,这个值由问号(?)表示。即 SELECT * FROM users WHERE id = 某个值,这里的某个值用问号(?)来指代。
使用 jdbcTemplate 执行查询操作,查询的 SQL 语句为 sql,传入的参数为一个包含 id 的数组 {id},并使用 UserRowMapper 进行行映射,最终返回查询到的单个对象。
}
@Override
public void save(User user) {
将数据插入到 users 表中,插入的字段为 username 和 email,对应的值分别为问号占位符所代表的值,即 INSERT INTO users (username, email) VALUES (?,?) 。
jdbcTemplate 执行更新操作,其传入的 SQL 语句为 sql,同时传入了 user 的用户名 user.getUsername() 和邮箱 user.getEmail() 作为参数。
}
@Override
公共的 void 方法 update,它的参数是一个 User 对象 user。
字符串 sql 为“UPDATE users SET username = 某个值, email = 另一个值 WHERE id = 特定值”;这里是将 users 表中的 username 字段更新为某个值,email 字段更新为另一个值,条件是 id 等于特定值。
jdbcTemplate 执行更新操作,其传入的 SQL 语句为 sql,同时传入了 user 的用户名 user.getUsername()、邮箱 user.getEmail()以及用户 ID user.getId()。
}
@Override
public void delete(Long id) {
从 users 表中删除满足 id =?条件的记录,其对应的 SQL 语句为:DELETE FROM users WHERE id =?;即通过该语句可以实现从 users 表中删除特定 id 记录的操作。
jdbcTemplate.update(sql, id);
}
静态内部类 UserRowMapper 实现了 RowMapper 接口。 {
@Override
在获取行数据的过程中可能会抛出 SQLException 异常;
User user = new User();
user.setId(rs.getLong("id"));
user 设置用户名为 rs.getString("username")。
用户设置电子邮件为 rs 字符串中的“email”值。
return user;
}
}
}
两者的关系 示例应用
有一个简单的用户管理系统,此系统包含用户实体即 User 以及用户数据访问对象即 UserDao 。
public class User {
private Long id;
private String username;
private String email;
// Getter 和 Setter 方法
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
@Repository
public class UserDaoImpl implements UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public List findAll() {
String sql = "SELECT * FROM users";
return jdbcTemplate.query(sql, new UserRowMapper());
}
@Override
public User findById(Long id) {
String sql = "SELECT * FROM users WHERE id = ?";
return jdbcTemplate.queryForObject(sql, new Object[]{id}, new UserRowMapper());
}
@Override
public void save(User user) {
String sql = "INSERT INTO users (username, email) VALUES (?, ?)";
jdbcTemplate.update(sql, user.getUsername(), user.getEmail());
}
@Override
public void update(User user) {
String sql = "UPDATE users SET username = ?, email = ? WHERE id = ?";
jdbcTemplate.update(sql, user.getUsername(), user.getEmail(), user.getId());
}
@Override
public void delete(Long id) {
String sql = "DELETE FROM users WHERE id = ?";
jdbcTemplate.update(sql, id);
}
private static class UserRowMapper implements RowMapper {
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setId(rs.getLong("id"));
user.setUsername(rs.getString("username"));
user.setEmail(rs.getString("email"));
return user;
}
}
}
总结