原来做项目的时候,会使用Ajax来做一些页面动态功能,最典型的如auto complete。 还有一些小范围的数据保存之类的,基本上从来没有做过全页面的表单都用Ajax来保存的开发。要实现把页面上的所有数据都用Ajax保存不麻烦,麻烦在保存后怎么办。通常保存完数据后,我们都会刷新整个页面,到一个完全不同的页面去:比如,保存完一个订单后跳回订单查询页面。通常用javascript的时候,我们只用它来做一些页面的小范围的动态效果,比如点某些按钮后多出一些输入框之类。我们不想用javascript来写出这个页面,那会太复杂,太难维护。所以总的来说,我们会实用JSP来渲染整个页面,不管直接些HTML还是用些标签库;然后用javascript,结合Ajax来做一些局部动态效果。
有没有办法难够用JSP直接写HTML或者标签来布局整个页面,同时又能在利用上Ajax的好处,在各种操作中不要刷新整个页面呢? 下面是我的两个想法。先声明,这两种方式在Grails上都是可行的,我猜想在Spring MVC上也是可行的。但是不保证在所有框架,比如JSF,上可行。
一,Ajax返回HTML并将其插入页面中
- 浏览器第一次打开页面的时候,只把页面的头部,底部等所有页面都会共用的外框渲染出来
- Javascript和CSS等要共用的资源也在同时加载。图片等具体到不同页面不同的资源不需要加载
- 和特定页面相关的内容,使用一个空的DIV之类的先占位
- 整体页面加载完后,根据具体页面的不同,前端用Ajax去后台二次加载局部页面。这个时候后台可以使用一个JSP模板,根据具体的模型渲染出一段HTML字符串,并返回。前端拿到这段HTML后将其插入预留的DIV中
- 局部页面特定的Javascript可以选择在第一次打开页面的时候加载,也可以选择在这个时候加载
- 如果页面需要变动,比如用户提交数据后我们要刷新都另外一个页面,那我们可以用javascript清除DIV的内容,再用Ajax去请求要显示的页面HTML,插入到DIV中
这种方式在第一次打开页面的时候显示的整体外框可以用JSP生成,后面用Ajax拿到的局部特定页面内容也可以用JSP生成;同时,除了第一次加载页面,后面的都是Ajax操作,保证不会刷新整个页面。
这种方式的不好在于,每次Ajax返回的都是HTML,这个Ajax操作的API通常不便于被其他功能使用。
二,让View和Controller,Model隔离
- Controller, Model不知道View的存在。 它不管调用Controller的是个JSP页面,还是一个Flash程序,或者甚至是iOS程序。Controller只负责处理数据并返回结果。这时候的Controller提供的就是一个单纯的API, 甚至可以做成Rest API。 参考:六步实现Rest风格的API
- 页面(View)还是由JSP来生成,这时候生成HTML的时候因为不存在特定的Model,所以会是一个包含大体结构的HTML,但是可能不是最终要呈现的。Grails里我们可以直接写一个GSP,然后URL直接写成GSP的路径即可让Grails帮忙生成不带Model输入的页面
- Javascript和CSS等资源要在这个时候加载
- 因为这个时候的HTML并没有包含特定的Model数据,所以需要预留对应的位置以备后面填充数据
- 页面加载完后用Ajax调用后台的action, 将返回的数据填入到页面中
- 如果页面需要变动,可以在第2步生成HTML的时候同时将这个时候要显示的HTML生成。改变页面的时候用javascript将一部分HTML隐藏,另外一部分显示即可。不需要将整个应用的所有页面的HTML都在一个View里生成,可以把一个模块的一系列页面,比如订单创建,查找,查看,修改等页面放在一个View里,当用户在同一个模块里操作时不需要刷新页面。如果跳到其他模块,则可让浏览器打开另外一个URL,用刷新页面的方式显示另外一个模块的内容