前后端分离——MVVM 模式

本文介绍了MVVM(Model-View-ViewModel)模式,一种简化用户界面事件驱动编程的方式。MVVM模式促进了前端开发与后端业务逻辑的分离,提高了前端开发效率。文章详细解释了MVVM的组成部分:View、Model及ViewModel层的作用和职责。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

阅读目录

  • 简而言之
  • 组成部分
  • 没有什么是一个栗子不能解决的

简而言之

之前对 MVVM 模式一直只是模模糊糊的认识,正所谓没有实践就没有发言权,通过这两年对 Vue 框架的深入学习和项目实践,终于可以装B了有了拨开云雾见月明的感觉。

Model–View–ViewModel(MVVM) 是一个软件架构设计模式,由微软 WPF 和 Silverlight 的架构师 Ken Cooper 和 Ted Peters 开发,是一种简化用户界面的事件驱动编程方式。由 John Gossman(同样也是 WPF 和 Silverlight 的架构师)于2005年在他的博客上发表。

MVVM 源自于经典的 Model–View–Controller(MVC)模式(期间还演化出了 Model-View-Presenter(MVP)模式,可忽略不计)。MVVM 的出现促进了 GUI 前端开发与后端业务逻辑的分离,极大地提高了前端开发效率。MVVM 的核心是 ViewModel 层,它就像是一个中转站(value converter),负责转换 Model 中的数据对象来让数据变得更容易管理和使用,该层向上与视图层进行双向数据绑定,向下与 Model 层通过接口请求进行数据交互,起呈上启下作用。如下图所示:

MVVM模式

MVVM 已经相当成熟了,主要运用但不仅仅在网络应用程序开发中。KnockoutJS 是最早实现 MVVM 模式的前端框架之一,当下流行的 MVVM 框架有 Vue,Angular 等。

组成部分

简单画了一张图来说明 MVVM 的各个组成部分:

MVVM分层示意图

分层设计一直是软件架构的主流设计思想之一,MVVM 也不例外。

# View 层

View 是视图层,也就是用户界面。前端主要由 HTML 和 CSS 来构建,为了更方便地展现 ViewModel 或者 Model 层的数据,已经产生了各种各样的前后端模板语言,比如 FreeMarker、Marko、Pug、Jinja2等等,各大 MVVM 框架如 KnockoutJS,Vue,Angular 等也都有自己用来构建用户界面的内置模板语言。

# Model 层

Model 是指数据模型,泛指后端进行的各种业务逻辑处理和数据操控,主要围绕数据库系统展开。后端的处理通常会非常复杂:

前后端对比

后端:我们这里的业务逻辑和数据处理会非常复杂!
前端:关我屁事!

后端业务处理再复杂跟我们前端也没有半毛钱关系,只要后端保证对外接口足够简单就行了,我请求api,你把数据返出来,咱俩就这点关系,其他都扯淡。

# ViewModel 层

ViewModel 是由前端开发人员组织生成和维护的视图数据层。在这一层,前端开发者对从后端获取的 Model 数据进行转换处理,做二次封装,以生成符合 View 层使用预期的视图数据模型。需要注意的是 ViewModel 所封装出来的数据模型包括视图的状态和行为两部分,而 Model 层的数据模型是只包含状态的,比如页面的这一块展示什么,那一块展示什么这些都属于视图状态(展示),而页面加载进来时发生什么,点击这一块发生什么,这一块滚动时发生什么这些都属于视图行为(交互),视图状态和行为都封装在了 ViewModel 里。这样的封装使得 ViewModel 可以完整地去描述 View 层。由于实现了双向绑定,ViewModel 的内容会实时展现在 View 层,这是激动人心的,因为前端开发者再也不必低效又麻烦地通过操纵 DOM 去更新视图,MVVM 框架已经把最脏最累的一块做好了,我们开发者只需要处理和维护 ViewModel,更新数据视图就会自动得到相应更新,真正实现数据驱动开发。看到了吧,View 层展现的不是 Model 层的数据,而是 ViewModel 的数据,由 ViewModel 负责与 Model 层交互,这就完全解耦了 View 层和 Model 层,这个解耦是至关重要的,它是前后端分离方案实施的重要一环。

没有什么是一个栗子不能解决的

扯了这么多,并没有什么卵用。千言万语不如一个栗子来的干脆,下面用一个 Vue 实例来说明 MVVM 的具体表现。

Vue 的 View 模板:

<div id="app">
    <p>{{message}}</p>
    <button v-on:click="showMessage()">Click me</button>
</div>
 

Vue 的 ViewModel 层(下面是伪代码):

var app = new Vue({
    el: '#app',
    data: {     // 用于描述视图状态(有基于 Model 层数据定义的,也有纯前端定义)
        message: 'Hello Vue!',  // 纯前端定义
        server: {}, // 存放基于 Model 层数据的二次封装数据
    },
    methods: {  // 用于描述视图行为(完全前端定义)
        showMessage(){
            let vm = this;
            alert(vm.message);
        }
    },
    created(){
        let vm = this;

        // Ajax 获取 Model 层的数据
        ajax({
            url: '/your/server/data/api',
            success(res){
                // TODO 对获取到的 Model 数据进行转换处理,做二次封装
                vm.server = res;
            }
        });
    }
})
 

服务端的 Model 层(省略业务逻辑处理,只描述对外接口):

{
    "url": "/your/server/data/api",
    "res": {
        "success": true,
        "name": "IoveC",
        "domain": "www.cnblogs.com"
    }
}
 

这就是完整的 MVVM 编程模式。

代码执行之后双向绑定的效果如下:

Vue实现的响应的数据绑定

嘿嘿,前后端可以成功分手了,以后再也不用关心后端个锤子开发进度\暴怒脸,复杂实现,blabla...,尽情享用前端如丝般顺滑的开发快

### 如何使用 SpringBoot 和 Vue 实现前后端分离的在线预约功能 #### 后端部分 (SpringBoot) 后端主要负责处理业务逻辑、数据持久化以及提供 API 接口供前端调用。 1. **创建 SpringBoot 项目** 使用 Spring Initializr 创建一个新的 SpringBoot 项目,引入必要的依赖项,如 `spring-boot-starter-web`、`spring-boot-starter-data-jpa`、`mysql-connector-java` 等[^1]。 2. **配置数据库连接** 配置文件 `application.yml` 中设置 MySQL 数据库连接信息,并指定 Druid 作为数据库连接池: ```yaml spring: datasource: url: jdbc:mysql://localhost:3306/appointment?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource ``` 3. **定义实体类** 定义用于表示预约记录的数据模型。例如,假设有一个简单的预约表结构: ```java @Entity public class Appointment { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String phone; private LocalDateTime appointmentDate; // Getters and Setters } ``` 4. **编写 Repository 层** 利用 Spring Data JPA 提供的功能快速完成 CRUD 操作: ```java public interface AppointmentRepository extends JpaRepository<Appointment, Long> {} ``` 5. **实现 Service 层** 将核心业务逻辑封装到服务层中,便于维护和扩展: ```java @Service public class AppointmentService { @Autowired private AppointmentRepository repository; public List<Appointment> getAllAppointments() { return repository.findAll(); } public void saveAppointment(Appointment appointment) { repository.save(appointment); } } ``` 6. **构建 Controller 层** 设计 RESTful API 来暴露给前端访问接口: ```java @RestController @RequestMapping("/api/appointments") public class AppointmentController { @Autowired private AppointmentService service; @GetMapping public ResponseEntity<List<Appointment>> getAppointments() { return ResponseEntity.ok(service.getAllAppointments()); } @PostMapping public ResponseEntity<Void> createAppointment(@RequestBody Appointment appointment) { service.saveAppointment(appointment); return new ResponseEntity<>(HttpStatus.CREATED); } } ``` 7. **集成验证码功能** 可选地增加验证码验证机制来提高系统的安全性。通过 `easy-captcha` 库生成图片验证码并将结果存入缓存以便后续校验[^3]。 --- #### 前端部分 (Vue.js) 前端专注于用户体验界面的设计与交互行为的实现。 1. **初始化 Vue 项目** 使用 Vue CLI 工具搭建基础框架环境,安装所需插件如 Axios(网络请求)、Vuex(状态管理)和 Element UI(UI 组件库)。 2. **布局页面模板** 构建一个简洁明了的预约表单视图,允许用户输入姓名、联系方式及期望的时间点等字段。 3. **发起 HTTP 请求** 调用后端提供的 REST API 获取或提交数据。以下是发送 POST 请求的一个例子: ```javascript methods: { submitForm() { const formData = this.$refs.form.model; // 表单绑定对象 axios.post('/api/appointments', formData).then(response => { console.log('成功:', response.data); alert('预约已提交!'); }).catch(error => { console.error('失败:', error.response); }); } } ``` 4. **状态管理和导航控制** 如果涉及多页切换,则需借助 Vue Router 设置路由规则;对于全局共享的状态变量则推荐 Vuex 处理。 5. **优化体验细节** 添加加载动画提示正在等待服务器反馈期间的操作进度条或者模态框展示最终确认消息等内容提升整体观感质量。 --- #### 整体架构说明 整个系统遵循典型的 MVC 或 MVVM 模式划分职责边界清晰明确。其中 SpringBoot 承担起 Model 和 Controller 的角色而 Vue 主要扮演 View 的职能共同协作达成目标——即支持在线预约的服务能力[^2][^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值