ExtJS 6与Java代码通讯(Spring MVC)的过程(Model/Store的用法)

  1. 云栖社区>
  2. 博客>
  3. 正文

ExtJS 6与Java代码通讯(Spring MVC)的过程(Model/Store的用法)

pandamonica 2018-01-13 16:01:28 浏览4212
展开阅读全文

ExtJS通常负责网站的前端,我们知道"做网站"这个概念的年代就有了MVC的说法,Java开源框架的范畴也在提及MVC,后来前端火了以后,在前端的范畴MVC又土了,流行的关键词是MVVM或者数据绑定。
没摸到门道的,会比较困惑(比如我)。
下面的博文,我们来探讨一下:

MVC或者MVVM并不是javascript或者java这些语言带来的特性,也不是Spring这类框架创造的概念,它们事实上是 浏览器、html、http范畴的概念。换句话说,假如你不用java语言(使用微软的.net),不使用javascript(采用纯html),不使用任何现成代码(code in box),你也必须在写代码的时候,考虑将自己的代码分成MVC三个部分,以方便后续维护。

简而言之,只要你的程序最后的入口是浏览器,那你就必须考虑MVC。核心就是让你的代码分层,可以复用,容易维护,鲁棒棒的。

我过去的概念中View就是JSP+html,其实说细节那是不对的,因为JSP最终被tomcat解释为Servlet,事实上是服务器端运行的代码,而且做得工作很可能包括Model和Controller。只能说,代码的分层在JSP、PHP、ASP那个年代,是否分层了,取决于你的编码水平。我相信如果纯手写,大多数人写的代码,是无法分层的。

前面说的是上古时代的话题,下面我们说说今天的主题:ExtJS6 与SpringMVC的通讯。

ExtJS 是一个被很多前端工作者嘲讽的js包儿,姑且称为包儿吧。原因就不说了,但是我觉得还行,而且我目前的项目必须用ExtJS,而且必须使用Spring+Hibernate+SpringMVC+MySQL。
我们就一起来好好看看前端的ExtJS。

ExtJS 最近版本是4、5、6三个版本。
上述三个版本的代码,在Model和View部分的代码基本没什么变化,M和V写的好写的不好,拼的是代码量,拼的是脑子好使不好使。
但是
从4跨越到5,概念上虽然还是MVC,已经用ViewController取代了Controller;
从5跨越到6,则新增加了ViewModel的概念,过渡到MVVM。

MVVM在ExtJS的世界里,并不意味着取代MVC。实际一点的表述方式是:ExtJS 6的时代,MVC的基础上顺应时代的提供了“数据绑定”的概念,也就是ViewModel。
MVVM = Model(Store) + View + ViewController + ViewModel ;
_

用官网的原话来说就是:
We have added support for ViewModels and MVVM as well as ViewControllers to enhance MVC applications. Best of all, these choices are not mutually exclusive, so you can introduce these features incrementally or even blend them.
从4到6的两次变革,不是覆盖、取代,而是两次并存的改善。ExtJS的作者们希望到了ExtJS 6的时代,码农们同时采用上述两个改善。

今天是2018年1月13日,官网http://docs.sencha.com/extjs/6.5.2/index.html
Ext 的 doc版本是6.5.2,如下图
_

ExtJS 4的阶段完全采用MVC结构,比如下面黄灯桥4.2版本的书的代码目录结构,可以看到
_
具体到代码的话,你很可能定义一个下面的Controller

Ext.define('MyApp.controller.Users', {
     extend: 'Ext.app.Controller',

     init: function() {
         console.log('Initialized Users! This happens before ' +
                     'the Application launch() function is called');
     }
 });

上述Ext.app.Controller有两个缺陷:controller与view之间的关系不是1对1,因而可能1个controller处理多个view页面的动作的响应。假如多个coder编辑同一个网站,很有可能牵一发而动全身。我把controller代码改了以后,影响到你的view页面的显示或者响应,你就郁闷了。另一个缺陷是,controller可以无限长时间生存下去,没有生命周期控制,这样很不好。

于是ExtJS 5出现以后,提供了Controller的替代者ViewController。只要你写代码的时候写成下面这样:

Ext.define('MyViewController', {
    extend : 'Ext.app.ViewController',
    alias: 'controller.myview',

    // This method is called as a "handler" for the Add button in our view
    onAddClick: function() {
        Ext.Msg.alert('Add', 'The Add button was clicked');
    }
});

恭喜你,之前提到的两个缺陷就全都解决了,而且看上去你的代码也没有发生巨变。

但是网站开发的世界里,前端框架都在自我完善,就逃不开数据绑定和MVVM的概念,于是ExtJS6来了。

ExtJS 6 在5 的基础上 提供了ViewModel。ViewModel就等同于数据绑定。

ExtJS 6的时代,View作为直接和码农打交道的UI,拥有一个ViewController,还拥有一个ViewModel。
Store会通过proxy与后台java打交道,获取数据,然后存储在Store中,并且暴露给ViewModel。
View和ViewModel之间通过数据绑定(双向),就可以使用后台的数据了。

说了这么多,相信你和我的感受是一样的:能感觉到ExtJS的世界中很多概念发生了变化。但是仔细想想,压根就没有View和Model什么事儿,因为就没有变。

具体说来

ExtJS中负责与Coder打交道的View部分,也就是UI部分,也就是那些Component和Container,button啦textfield啦,似乎在版本的升级中没什么变化。

ExtJS中负责获取数据的Model部分,也没有提及变化。

你说对了。MD没变就是没变嘛!

我们博文的重点就是ExtJS中从4到6始终如一的Model部分,如何与SpringMVC+Spring+Hibernate进行数据交换的。

ExtJS中Model部分的概念比较晦涩,有两个原因:难以理解、难以调试。

Model 中包括:
Ext.data.Model
Ext.data.Store
Ext.data.proxy.Proxy

上述三个类什么关系呢?

Store使用proxy对Model所代表的对象的数据进行load或者save。

详细的说:
Store是一个容器,数据的容器。它不是一个格式或者规范,它是ExtJS中存放数据的容器。

Proxy是ExtJS与外界进行数据交换的管道。ExtJS是前端,是生存在浏览器上的代码,Client的PC的浏览器上。然而你的数据往往存储在Server的数据库服务器上。假如你的Java代码(Server上的)已经把Server硬盘上的数据取出来了,那么ExtJS怎样和SpingMVC配合,获取到这些数据呢?答案就是Proxy,它是前端与后台进行交互的管道。

Model是ExtJS中对客观事物的描述,它是一个格式。比如User也就是用户,用户的姓名,年龄,密码。Model只描述、抽象这些概念。

概念上就是这样。

下面说说Model部分为什么晦涩,第二个原因就是难以调试。

Java代码的调试十分成熟,用Eclipse,看Console看返回值,或者使用测试技术比如TestNG,都可以系统的,有层次的对每个java类,每个java方法进行测试。

但是ExtJS的测试,Eclipse插件好像是要花钱的。

好吧,ExtJS代码的调试,当然是使用Chrome浏览器了啊~

下面我们来讲一下,从ExtJS的UI部分点击一下按钮,ExtJS+SpringMVC+Spring+Hibernate+MySQL是怎样联动工作的。有了这个例子,整个数据是如何交互的,以及整个调试过程就都有了。看官们上眼:
我们要做的效果是这样的,打开浏览器,输入一个url
_
输入用户名密码登录,假如用户名密码匹配那么进入如下界面
_
点击左侧第三个tab页,也就是 用户(user)
_
看到右侧出现一个测试按钮,然后我们点击这个按钮,触发ExtJS向Spring发出请求,获取数据库的数据。

上述就是我们要达到的效果。

下面我们看看与ExtJS中Model部分代码与SpringMVC进行交互的代码
ExtJS的View代码


Ext.define('RUKU.view.hr.HRUserList', {
    extend: 'Ext.panel.Panel',
    xtype: 'hruserlist',
    title: '用户列表 ',
    
    requires:[
        'RUKU.model.hr.HRUserListViewModel',
        'RUKU.controller.hr.HRUserListController',
        'RUKU.store.hr.HRUserListStore',
        'RUKU.model.hr.HRUserListModel'
    ],
    
    controller : 'hulc',
    
    items:[
        {
            fieldLabel:'姓名',
            xtype:'textfield'
        },{
            fieldLabel:'胸卡号',
            xtype:'textfield'
        },{
            text:'测试按钮',
            xtype:'button',
            listeners:{
                click : 'onTalk'
            }
        }
    ]

});

我们看到这个view文件已经拥有了一个controller,名字叫做'RUKU.controller.hr.HRUserListController'
上述这个名字,实际上既是名字,也就是目录结构
_
至于RUKU这个字符串为什么对应着app这个文件夹,这是app.js和Application.js这些文件定义的。

接着说,实际上仅仅为这个View指定了一个ViewController,代码如下:

Ext.define('RUKU.controller.hr.HRUserListController',{
    extend : 'Ext.app.ViewController',
    alias: 'controller.hulc',
        
    onTalk:function(){
        var user = Ext.create('RUKU.model.hr.HRUserListModel',{
            
            pernr : '2018001',
            ename : '英格拉姆',
            age : '20'
            
        });
        
        user.load({
            success:function(){
                Ext.Msg.alert("tip","success");
            },
            failure: function() {
                Ext.Msg.alert("tip","fail");
            } 
        
        });
        
    }

});

ViewController属于且仅属于一个View,它的作用就是负责处理这个View的各种事件,各种方法。

上面代码中,创建了一个js变量,变量的内容是一个'RUKU.model.hr.HRUserListModel'类型的变量

我们来看看它的代码

Ext.define('RUKU.model.hr.HRUserListModel', {
    extend: 'Ext.data.Model',
    fields: [
        { name: "pernr" },
        { name: "ename" },
        { name: "pstate"}
    ],
    proxy : {
        type:'ajax',
        url:'/RC0113/hr/userlist.html'
    }
});

它是一个Model

里面直接用了proxy

这个例子十分简陋,但它包括了View,ViewController,Model
哇MVC啊

让我们在浏览器上调试一下,看看上述代码能做什么:
当然前提是我们把上述代码放置到了tomcat对应的目录中
_
这个目录结构的生成过程和部署过程其实是有点复杂的。
1---做一个Maven的Web项目(eclipse上创建)
2---安装一个Sencha的环境,生成一个案例目录结构(Ext的代码结构)(Sencha命令行创建)
3---把Ext代码结构复制到Maven项目目录结构中(复制粘贴)
4---在Eclipse上将整个项目打包成(Export)一个war包
5---把这个war包复制到tomcat的webapp目录下,启动tomcat,这样tomcat可以自动部署这个war文件,生成我们上图看到的目录结构。

然后我们就可以使用浏览器,输入一个url来进行测试了。
这种测试(而不是eclipse中进行测试)的好处就可,可以用强悍的chrome浏览器的开发者工具,去看看ExtJS代码都做了什么

我们在Chrome浏览器上运行,看看效果
_
_
看到请求应该是很成功的
那么返回来什么呢?
_
毕竟只是测试一下数据是否通畅,所以写的方法比较简单
也就是整个数据是通畅的。

下面让我们看看这个触发过程是怎样的:

首先Model代码中proxy中的url部分

 proxy : {
        type:'ajax',
        url:'/RC0113/hr/userlist.html'
    }

它触发了这个http请求
Request URL:http://localhost:6054/RC0113/hr/userlist.html?_dc=1515834448672&id=RUKU.model.hr.HRUserListModel-1

上述http请求的核心是RC0113/hr/userlist.html

我们的tomcat就是http://localhost:6054/ 这个地址
那么对于后缀名为html的请求,tomcat的RC0113这个项目的
web.xml配置文件实际上已经全都拦截了
_
DispatcherServlet是Spring MVC默认的Servlet
也就是说只要是后缀为html的url请求,都会被SpringMVC拦截下来。
拦截干什么呢?
用url的内容去匹配SpringMVC中注册的所有controller或者handler
如果匹配上了,那么就把这个请求交给那个handler处理。

毕竟测试方法,匹配哪个,我们自己心知肚明
直接上图

_
其实这里呢,copy了蒋锋的类,也就是自定义返回值,这个还是挺屌的。
上图中的java方法,也就是web目录下的controller方法(区别ExtJS中的controll和SpringMVC中的controller),被配置用来响应/hr/userlist.html这个url的http request

于是我们的Ext代码就通过SpringMVC获取了后台数据库的数据了。

这里应该有一条分割线

上面的描述虽然尽可能做到全面,但是不够直观,下面从头开始举一个纯ExtJS的例子,也就是我们默认web项目的后台,也就是Spring部分的代码都已经写好了,我们举的例子,纯粹就是基于这个前提,的纯粹前端的代码:

网友评论

登录后评论
0/500
评论
pandamonica
+ 关注