基于Vue的前后端分离项⽬实践
⼀、为什么需要前后端分离
1.1什么是前后端分离
前后端分离这个词刚在毕业(15年)那会就听说过,但是直到17年前都没有接触过前后端分离的项⽬。怎么理解前后端分离?直观的感觉就是前后端分开去做,即功能和职责上的⼀种划分,前端负责页⾯的渲染,部分页⾯交互的逻辑,然后通过⽹络请求与后端进⾏数据的交互;后端则着重关注业务逻辑的处理,直接操控数据库。
1.2前后端未分离前
(1)jsp + servlet 开发模式:
JSP页⾯:负责视图层的渲染及交互,内部可以嵌⼊java 代码,在某些场景下开发起来⽐较⽅便,但是这种页⾯和java代码混合开发的⽅式造成逻辑不够直观,项⽬代码维护起来困难。
Servlet类: 负责接收from表单提交的参数,进⾏业务层逻辑和页⾯导航的处理。但是这种⽅式需要区分请求的⽅式,⼿动把请求的参数拿出来进⾏封装。基本上⼀个请求对应⼀个servlet,需要在l⽂件中配置urL映射或者注解的⽅式。
⼤体流程:
编写JSP页⾯,引⼊java常⽤类库和JSTL标签库,编写HTML表单,CSS,javascript。
编写Servlet ⽅法,重写service()⽅法,需要⼿动获取请求参数,然后业务逻辑处理。
配置l。在l⽂件中注册servlet,配置请求映射(简单⽅法:增加注册)。
(2)jsp + spring mvc开发模式:spring 框架流⾏起来后,着重关注的是分层设计,即MVC的概念,个⼈认为jsp+spring 带来的最⼤好处是简化了之前servlet时代编写web流程的复杂度,各种注解、各种参数⾃动注⼊极⼤提⾼了java web的开发效率,此时对Jsp页⾯有⼀个共同的约束,即JSP页⾯不要在嵌⼊除标签外的java代码,这样初步把视图层抽出来。但是这种⽅式的约束性依然很⼤,即应⽤强依赖于java⽣态。
⼤体流程:
搭建spring 框架,在l中配置spring mvc的分发器。
编写jsp页⾯,利⽤各种Jquery插件和前端css框架,也能做出漂亮的交互界⾯。
编写spring controller,只需要⼏个注解即可和表单的请求匹配,web请求的参数能够⾃动注⼊到controller请求的⽅法,⼀个controller可以匹配n多个请求。其中controller可以分为两种,⼀种是返回页⾯路径的controller,这个controller可以携带Java对象到页⾯;另外⼀种是返回特定格式的json,常⽤的是json.
(3)模板+spring boot:
spring boot是spirng的⼀个脚⼿架,能够快速搭建spring项⽬,使⽤默认配置减少开发者⼿动的配置,与第三发包的各种整。模板相对于jsp 页⾯来说,进⼀步进⾏视图层的模块化,即可以按照页⾯的结构进⾏划分,常⽤的例如Header,footer,Silder Menu, Center Conter这样的版块接⼝进⾏划分,把页⾯进⾏分⽚处理,提⾼代码的复⽤度。
模块划分如下:
1.3前后端分离后
从上⾯可以看到java web⽣态系统不断的完善和加强,对于绝⼤多少web系统的开发来说⾜够了,那为什么要搞前后端分离?个⼈认为有以下⼏个原因:⼀个是职责划分需要,页⾯开发和业务逻辑开发并⾏进⾏来缩短开发周期。⼆是术业有专攻,随着页⾯的交互、UI要求不断提升,前端同学在页⾯⽅⾯的开
发更具有专业性。三是前端具有强⼤的⽣态系统,有许多现成的组件和框架可以进⾏⼤项⽬的模块化开发,正则意义上实现交互和逻辑的逻辑和物理上的完全分离。
前端项⽬+后台接⼝
1.4前后端分离的优点与缺点
优点:
对于中⼤型项⽬,能够提升开发效率,提⾼交互和UI效果,缩短开发周期。
前端能够处理⼀⼤部分验证和交互逻辑,从⽽减少与服务器间的交互次数,减⼩服务器处理压⼒,并且页⾯是由浏览器渲染⽣成。
前端具有强⼤的组件库和处理⼯具,项⽬更容易跨平台。
降低维护成本。
接⼝和前端组件能够复⽤。
缺点:
需要更多的沟通成本。未进⾏前后端分离时,由后端同学完成整个项⽬的开发,前后端分离时需要和前端同学进⾏接⼝的沟通和联调。
对于⼩、交互性要求不⾼的项⽬,进⾏前后端分离反⽽效率较低,当然全栈开发除外。
部署流程更复杂。前后端分离⼀般是两个项⽬环境,需要投⼊更多硬件和运维。
⼆、前后端分离步骤
2.1 分离前的业务功能划分
职责划分:当从⾮前后端分离的项⽬转到前后端分离的项⽬,如何确认分离的切⼊点?⾸选需要理解前后端的职责,即前端负责页⾯构建和交互处理,后端负责接⼝定义和业务处理。所有页⾯上能看到的功能基本都是前端的,所有涉及数据的查询、保存都是后端的,前端不需要关⼼数据的输⼊和输出,⽽关注数据在这个过程中的交互逻辑;后端需要关⼼页⾯如何渲染和交互,⽽关注输出数据和接收数据。从上⾯可以看出职责即是功能的划分。
模块划分:前后端模块划分关注点不同。后端模块划分时⼀般有两种⽅式,第⼀种是先分层,再按照模块划分。即先按照全局、⼯具、控制层、服务层、数据操作层等这种基于MVC的结构进⾏划分,然后再将控制层、服务层、数据操作层按照业务模块进⾏划分。第⼆种⽅式按先模块后结构进⾏划分,即先按
照业务模块划分不同的结构,然后每个模块根据需要决定是否进⾏MVC结构的划分。第⼀种更适⽤于中⼩型项⽬的构建,第⼆种更适⽤于⼤型项⽬,能够对按照业务垂直划分结构,⽅便部署和扩展。
前端模块划分基本基于功能的层次结构。第⼀层⼀般是全局配置、静态资源、⼯具类、视图、组件并列的结构,第⼆层是组件的复合结构和视图的复合结构,第三层是组件的独⽴结构。
2.2 前端需要了解的知识点
在进⾏前后端分离之前需要普及⼀下前端相关的知识。如下:
javascript:
基本概念:JavaScript⼀种直译式脚本语⾔,是⼀种动态类型、弱类型、基于原型的语⾔,内置⽀持类型。它的解释器被称为JavaScript引擎,为浏览器的⼀部分,⼴泛⽤于客户端的脚本语⾔,最早是在HTML(标准通⽤标记语⾔下的⼀个应⽤)⽹页上使⽤,⽤来给HTML⽹页增加动态功能。它由ECMAScript(描述该语⾔的语法和基本对象)、⽂档对象模型(DOM,描述处理⽹页内容的⽅法和接⼝)、浏览器对象模型(BOM,描述与浏览器进⾏交互的⽅法和接⼝)三部分构成。
⽣态:这⾥说的⽣态即简单介绍⼀下JS能够做些什么。数据可视化,例如D3.js、百度的Echars;移动端应⽤,例如Cordova、DeviceOne,能够⼀次开发多平台发布。服务端:Node.js,常⽤的框架有Expr
ess;桌⾯应⽤:NW.js和Electron,他们可以使⽤HTML和javascript开发桌⾯⼀个应⽤,⽽且⼀次开发,多平台运⾏。其它的还有游戏(WebGL)、AR、VR的应⽤⽀持。
mvc实例MVVM:MVVM是Model-View-ViewModel的缩写。这个可以和MVC进⾏对⽐⼀下。MVC如下:
MVVM如下:
这⾥可以看到相对于MVC,MVVM多了⼀个ViewModel的概念。在前端页⾯中,把Model⽤纯Javascript对象表⽰,View 负责显⽰,两者做到了最⼤限度的分离。把Model和View关联起来就是ViewModel。ViewModel负责吧Model的数据同步到View显⽰出来,还负责把View的修改同步到Model。想象⼀下传统的MVC开发web应⽤的流程?
Vue: vue 是⼀个MVVM的渐进式框架,被设计可以⾃定向上逐层应⽤。Vue核⼼库只关注视图层,不仅易于上⼿,还便于与第三⽅库或已有项⽬整合。
Node: Node.js 是⼀个基于 Chrome V8 引擎的 JavaScript 运⾏环境。Node.js 使⽤了⼀个事件驱动、⾮阻塞式 I/O 的模型,使其轻量⼜⾼效。Node.js 的包管理器 npm,是全球最⼤的开源库⽣态系统。
ES6: es6的全名是ECMAscript 2015。ECMAScript 6.0(以下简称 ES6)是 JavaScript 语⾔的下⼀代标准,已经在2015年6⽉正式发布了。它的⽬标,是使得 JavaScript 语⾔可以⽤来编写复杂的⼤型应⽤程
序,成为企业级开发语⾔。
Node Express 框架: Express 是⼀个简洁⽽灵活的 node.js Web应⽤框架, 提供了⼀系列强⼤特性帮助你创建各种 Web 应⽤,和丰富的HTTP ⼯具。使⽤ Express 可以快速地搭建⼀个完整功能的⽹站。Express 框架核⼼特性:(1)可以设置中间件来响应 HTTP 请求。(2)定义了路由表⽤于执⾏不同的 HTTP 请求动作。(3)可以通过向模板传递参数来动态渲染 HTML 页⾯。
IView: IView 是⼀个基于Vue 的第三⽅组件库,包含了后台开发过程中最基本的组件,组件代码⽐较简洁,⽂档和⽰例⽐较全。
IView Admin: ⼀个GitHub开源项⽬,是基于IView 基础组件构建的⼀个后台管理系统,包含了最基本的路由、状态管理、权限等后台系统共有的功能,可基于此系统进⾏后台的订制开发。
2.3 前后端分离项⽬开发流程
前后端分离的项⽬开发过程中最重要的就是接⼝⽂档的编写,它是前后端交互的门户。
2.4 前端开发⽅法
了解脚⼿架(CLI):脚⼿架的意思是帮你快速开始⼀个vue的项⽬,也就是给你⼀套vue的结构,包含基础
的依赖库,只需要 npm install就可以安装,让我们不需要为了编辑或者⼀些其他事情浪费时间总⽽⾔之,就是快速搭建项⽬的,让我们可以早点去写代码。Vue 官⽹提供了相应的CLI⼯具,帮助我们快速搭建项⽬。
了解构建⼯具:这⾥介绍⼀下webpack。前端项⽬开发是使⽤Vue基于组件⽅式进⾏的,但是运⾏时需要⽣成浏览器可以理解的js、css、html⽂件,那这两中⽂件形式的转换就是webpack的作⽤,它打包所有资源、打包所有脚本、打包所有图⽚、打包所有样式。
基本插件:Babel: 他是⼀种⽤途很多的javascript编译器,他把最新版的javascript编译成当下可以执⾏的版本,简⾔之,利⽤babel就可以让我们在当前的项⽬中随意的使⽤这些新最新的es6,甚⾄es7的语法。ESLint: ESLint 是⼀个语法规则和代码风格的检查⼯具,可以⽤来保证写出语法正确、风格统⼀的代码。
组件设计:
什么是组件?从代码层⾯来说⼀个.vue⽂件就是⼀个组件,从功能层⾯来说组件应该是⼀个可以复⽤的功能。组件的特点是当⼀个组件设计完毕后,后续需要类似的功能,只需要简单的引⽤组件,然后做些定制化的配置即可。个⼈理解组件可以划分两⼤类,第⼀类是基础组件/原⼦组件,这类组件是页⾯的基础构成不封,本⾝不可或者不宜再划分为⼦组件,例如Button,Table,这类都算是基础组件,IView基本
上是⼀个基础组件库。第⼆类是复合组件/框架性组件,这类组件是由基本组件经过合理的布局聚合在⼀起构成的,它拥有许多默认的配置,从⽽在类似的页⾯视图页⾯能够极⼤的减⼩重复代码。
设计原则:(1)基本思想是组件应该是于业务⽆关的。设计组件时不应该有任何具体业务逻辑因素的影响。(2)组件时复⽤代码和视图的抽象,多关注不同的页⾯,出共同的接⼝和不同的特效,抽象出公⽤的部分。(3)组件应该⾜够灵活,后续功能特效的新增,不应该对原有引⽤组件的地⽅构成影响。
实例分析(复合组件):
2.5 前后端交互
保证前后端开发功能的正确性除了详细的需求⽂档和原型设计外,重要的就是接⼝⽂档。接⼝⽂档描述了前后端数据交互的⽅法、格式。前后端项⽬分离后,许多之前后端需要处理的⼯作,都将由前端处理,主要涉及以下:页⾯的导航功能,即Vue Router、组件之间公共信息的保存,即Vuex,服务器数据资源的请求,即axios,其它的⽐较主要的就是权限、安全。
路由:Vue Router 是 Vue.js 官⽅的路由管理器。它和 Vue.js 的核⼼深度集成,让构建单页⾯应⽤变得易如反掌。包含的功能有:(1)嵌套的路由/视图表;
(2)模块化的、基于组件的路由配置;(3)路由参数、查询、通配符;(4)基于 Vue.js 过渡系统的视图过渡效果;(5)细粒度的导航控制;(6)带有⾃动激活的 CSS class 的链接
状态:Vuex是⼀个专为Vue.js应⽤程序开发的状态管理模式。它采⽤集中式存储管理应⽤的所有组件的状态,并以相应的规则保证状态以
⼀种可预测的⽅式发⽣变化.多个视图依赖于同⼀状态。为什么需要它?在开发应⽤中组件之间需要进⾏信息交流,⽗组件通过Props属性注⼊数据,⼦组件通过感受数据的变化进⾏相应的逻辑相应。⼦组件通过⾃定义事件的⽅式告知⽗组件数据发⽣变化。但是这两种⽅式只合适对于嵌套层次不深的组件,并且对于兄弟组件间的状态传递⽆能为⼒。因此,我们为什么不把组件的共享状态抽取出来,以⼀个全局单例模式管理呢?在这种模式下,我们的组件树构成了⼀个巨⼤的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发⾏为!
资源:这⾥所说的资源主要是指数据资源,即决定前端是否有权限去访问数据资源,⼀般采⽤携带token的⽅式保证资源的安全性。后端采⽤⾃定义token策略或者标准的OAuth 认证策略。
权限:前后端分离后,后端主要控制资源的权限,前端控制页⾯的权限。权限控制可以分为两⼤类,第⼀类是视图权限,即不同的⽤户只能看到⾃⼰改看到的东西,这个细分为菜单权限和按钮权限,菜单权限限制了⽤户看到的页⾯;按钮权限限制了⽤户在页⾯能够进⾏的操作。第⼆类是资源权限:即⽤户是
否⽤访问数据资源的权限,这类权限在后台项⽬中不常见。
菜单权限的实现⽅法:第⼀种由前端维护菜单权限,即前端拥有所有的菜单映射,当⽤户登录后,根据⽤户的⾓⾊对菜单权限进⾏刷选,类似数据库表和视图的关系,这种⽅式开发成本较低,能够满⾜绝⼤多数对权限变动频率低的系统,缺点是有⼀定的维护成本,功能不够灵活。第⼆种是由后端决定菜单权限,即⽤户登录成功后,菜单树由后端⽣成直接返回,这样做是⾜够灵活,但是开发、沟通需要付出更多的时间。第三种是混合开发:即静态权限和动态权限相结合。很多后台系统有⼀部分菜单是⾓⾊公共的后者基本固定⾓⾊的,这部分菜单应该由前端预选定义好,对于变动较多的菜单,由后端返回必要信息,进⾏简单拼接即可。这种⽅式的⼯作量介于第⼀种和第⼆种之间。
按钮权限:按钮权限⼀般通过⾃定义指令实现,即⾃定义Vue权限指令,根据传⼊的⾓⾊决定按钮是否显⽰。但是这种只适⽤于页⾯有表单组件的页⾯,对于需要动态⽣成的组件页⾯,需要提供⼀个全局权限查询⽅法。
2.5 前端项⽬部署
部署⽅式:前后端分离的项⽬⼀般有两种部署⽅式。第⼀种是通过build命令将项⽬打包成静态资源,然后copy静态资源到后端项⽬的静态⽬前下,然后通过tomcat服务器进⾏启动即可,这种⽅式不推荐。第⼆种⽅式是前后端分别部署,前端项⽬可以使⽤node 启动⼀个服务,运⾏在Node环境中,后端部署在t
omcat中,这种⽅式⽅便前后端各⾃⽔平扩展。