Spring3+Hibernate4+SpringMVC整合Ext:开发Ext界面及Accordin Tree

本文主要是介绍Spring3+Hibernate4+SpringMVC整合Ext:开发Ext界面及Accordin Tree,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

Spring3+Hibernate4+SpringMVC整合Ext:项目架构搭建中已经介绍了Spring3、Hibernate4和SpringMVC的整合,下面介绍的是开发一个典型的Ext后台管理界面:



        开发这个界面使用了Ext MVC,好多人都叫我用MVC方法去实现,其实MVC不是每个场景都适合。就我现在这个界面的场景而言并不适合用MVC开发,本来一个js文件就可以处理硬生生的分成了好几个文件,效果不是很好。代码是通过MVC实现的,MVC具体怎么样用大家可以去参考下官方的例子,在这里就不在赘述。下面的代码通过mvc的方式进行分层展示:

前台界面


页面

[java]  view plain copy
  1. <%@ page language="java" pageEncoding="UTF-8"%>  
  2. <%  
  3.     String extLibPath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+"/ext4";  
  4.     String ctx = request.getContextPath();  
  5.     pageContext.setAttribute("extLibPath", extLibPath);  
  6.     pageContext.setAttribute("ctx", ctx);  
  7. %>  
  8. <html>  
  9.     <head>  
  10.         <title>业务基础平台</title>  
  11.           
  12.     </head>  
  13.     <body>  
  14.         <div id="loading-tip" style="border-radius:3px;position: absolute;z-index: 1;border: solid 1px #ccc;background-color: #fff;padding: 10px;">  
  15.             <div class="loading-indicator" style="color: #444;font: bold 13px tahoma, arial, helvetica;padding: 10px;height: auto;">  
  16.                 <img src="${ctx}/images/loading32.gif" width="31" height="31"  
  17.                     style="margin-right: 8px; float: left; vertical-align: top;" />  
  18.                 业务基础平台V1.0  
  19.                 <br />  
  20.                 <span id="loading-msg" style="font: normal 10px arial, tahoma, sans-serif;">加载样式和图片...</span>  
  21.             </div>  
  22.         </div>  
  23.         <script type="text/javascript">  
  24.             var extLibPath = "${extLibPath}";  
  25.             var ctx = "${ctx}";  
  26.             var tip = document.getElementById("loading-tip");  
  27.             tip.style.top = (document.body.scrollHeight - tip.style.top - 100) / 2;  
  28.             tip.style.left = (document.body.scrollWidth - 200) / 2;  
  29.         </script>  
  30.         <link rel="stylesheet" type="text/css" href="${extLibPath}/resources/css/ext-all.css" />  
  31.         <link rel="stylesheet" type="text/css" href="icon.css" />  
  32.         <script type="text/javascript">  
  33.             document.getElementById("loading-msg").innerHTML = "加载核心组件...";  
  34.         </script>  
  35.         <script type="text/javascript" src="${extLibPath}/ext-all-debug.js"></script>  
  36.         <script type="text/javascript" src="${extLibPath}/locale/ext-lang-zh_CN.js"></script>  
  37.         <script type="text/javascript" src="app.js"></script>  
  38.     </body>  
  39. </html>  
这个是index.jsp页面,整个界面的代码就在app.js里面:
[javascript]  view plain copy
  1. Ext.Loader.setConfig({  
  2.             enabled : true  
  3.         });  
  4.   
  5. Ext.Loader.setPath({  
  6.             'Ext.ux' : extLibPath + '/examples/ux',  
  7.             'Ext.app' : extLibPath + '/examples/app',  
  8.             'Fes' : 'module'  
  9.         });  
  10.   
  11. Ext.require(['Fes.MsgBox']);  
  12.   
  13. Ext.Ajax.on('requestexception'function(conn, response, options) {  
  14.             var msg = '访问系统资源时发生异常<br/>' + '异常状态:' + response.status + '('  
  15.                     + response.statusText + ')<br/>' + '异常信息:'  
  16.                     + response.responseText  
  17.             Ext.Msg.show({  
  18.                         title : '系统异常',  
  19.                         msg : msg,  
  20.                         width : 400,  
  21.                         icon : Ext.MessageBox.ERROR,  
  22.                         buttonText : {  
  23.                             ok : '  提交错误报告  '  
  24.                         },  
  25.                         buttons : Ext.MessageBox.OKCANCEL  
  26.                     });  
  27.         });  
  28. Ext.get('loading-msg').update('加载系统组件...');  
  29. Ext.create('Fes.desktop.Desktop');  
在app.js的文件中主要是做了一些全局的配置,配置了ext的动态加载和ajax访问时异常的处理,最后创建“Fes.desktop.Desktop”组件开始初始化界面

控制层


控制层的作用是对界面的行为进行控制、逻辑判断和事件响应
module/desktop/Desktop.js
[javascript]  view plain copy
  1. Ext.define('Fes.desktop.Desktop', {  
  2.             extend : 'Ext.app.Application',  
  3.             appFolder : 'module/desktop',  
  4.   
  5.             name : 'Desktop',  
  6.   
  7.             controllers : ['Desktop'],  
  8.               
  9.             enableQuickTips : true,  
  10.               
  11.             autoCreateViewport: true  
  12.   
  13.         });  
Fes.desktop.Desktop继承Ext.app.Application,这个是Ext MVC中规定要继承的父类。配置了autoCreateViewport为true时Ext会自动创建一个Desktop.view.Viewport的组件,这个规则是appname+view .Viewport。

module/desktop/controller/Desktop.js
[javascript]  view plain copy
  1. Ext.define('Desktop.controller.Desktop', {  
  2.     extend : 'Ext.app.Controller',  
  3.   
  4.     models : ['Node'],  
  5.   
  6.     refs : [{  
  7.                 ref : 'navigation',  
  8.                 selector : 'navigation'  
  9.             }, {  
  10.                 ref : 'container',  
  11.                 selector : 'fescontainer'  
  12.             }],  
  13.   
  14.     init : function() {  
  15.         var me = this;  
  16.         this.control({  
  17.                     'viewport' : {  
  18.                         render : me.onRender  
  19.                     },  
  20.                     scope : me  
  21.                 });  
  22.     },  
  23.   
  24.     onRender : function() {  
  25.         var me = this;  
  26.         Ext.get('loading-msg').update('正在加载菜单...');  
  27.         Ext.Ajax.request({  
  28.                     url : 'resource/root',// 获取面板的地址  
  29.                     method : 'GET',  
  30.                     callback : function(options, success, response) {  
  31.                         me.createTree(Ext.JSON.decode(response.responseText));  
  32.                     }  
  33.                 });  
  34.     },  
  35.   
  36.     createTree : function(datas) {  
  37.         var me = this;  
  38.         Ext.each(datas, function(data) {  
  39.                     var tree = Ext.create("Ext.tree.Panel", {  
  40.                                 title : data.text,  
  41.                                 iconCls : data.iconCls,  
  42.                                 useArrows : true,  
  43.                                 autoScroll : true,  
  44.                                 rootVisible : false,  
  45.                                 viewConfig : {  
  46.                                     loadingText : "正在加载..."  
  47.                                 },  
  48.                                 store : me.createTreeStore(data.id)  
  49.                             });  
  50.                     tree.on('itemclick', me.onTreeItemClick, me);  
  51.                     me.getNavigation().add(tree);  
  52.                 });  
  53.         Ext.get('loading-msg').update('加载完成.');  
  54.         Ext.Function.defer(function() {  
  55.                     Ext.get('loading-tip').remove();  
  56.                 }, 1000);  
  57.     },  
  58.   
  59.     onTreeItemClick : function(view, node) {  
  60.         console.log(node.data.component);  
  61.         var tab = this.getContainer();  
  62.         if (node.isLeaf()) { // 判断是否是根节点  
  63.             if (node.data.type === 'URL') { // 判断资源类型  
  64.                 var panel = Ext.create('Ext.panel.Panel', {  
  65.                     title : node.data.text,  
  66.                     closable : true,  
  67.                     iconCls : 'icon-activity',  
  68.                     html : '<iframe width="100%" height="100%" frameborder="0" src="http://www.baidu.com"></iframe>'  
  69.                 });  
  70.                 tab.add(panel);  
  71.                 tab.setActiveTab(panel);  
  72.             } else if (node.data.type === 'COMPONENT') {  
  73.                 var panel = Ext.create(node.data.component, {  
  74.                             title : node.data.text,  
  75.                             closable : true,  
  76.                             iconCls : 'icon-activity'  
  77.                         });  
  78.                 tab.add(panel);  
  79.                 tab.setActiveTab(panel);  
  80.             }  
  81.         }  
  82.     },  
  83.   
  84.     createTreeStore : function(id) {  
  85.         var me = this;  
  86.         return Ext.create("Ext.data.TreeStore", {  
  87.                     defaultRootId : id, // 默认的根节点id  
  88.                     model : this.getNodeModel().$className,  
  89.                     proxy : {  
  90.                         type : 'ajax'// 获取方式  
  91.                         url : 'resource/child' // 获取树节点的地址  
  92.                     },  
  93.                     clearOnLoad : true,  
  94.                     nodeParam : 'id'// 设置传递给后台的参数名,值是树节点的id属性  
  95.                 });  
  96.     }  
  97. });  
这个是整个界面的控制层,在init的方法中为viewport添加了一个render事件,在整个界面渲染完成后开始加载菜单。在菜单加载完成之后添加菜单的点击事件。

视图层


视图层只页面的展示,不做任务的逻辑操作和事件处理
module/desktop/view/Viewport.js
[javascript]  view plain copy
  1. Ext.define('Desktop.view.Viewport', {  
  2.             extend : 'Ext.container.Viewport',  
  3.             requires : ['Desktop.view.Container''Desktop.view.Header',  
  4.                     'Desktop.view.Navigation'],  
  5.   
  6.             layout : 'border',  
  7.             initComponent : function() {  
  8.                 var me = this;  
  9.                 Ext.apply(me, {  
  10.                             items : [Ext.create('Desktop.view.Container'),  
  11.                                     Ext.create('Desktop.view.Header'),  
  12.                                     Ext.create('Desktop.view.Navigation')]  
  13.                         });  
  14.                 this.callParent(arguments);  
  15.             }  
  16.         });  
定义Desktop.view.Viewport组件,这个组件会在控制器中被创建。viewport中定义了整个界面的布局,包含了Desktop.view.Container,Desktop.view.HeaderDesktop.view.
Navigation3个组件。

module/desktop/view/Container.js
[javascript]  view plain copy
  1. Ext.define('Desktop.view.Container', {  
  2.             alias: 'widget.fescontainer',  
  3.             extend : 'Ext.tab.Panel',  
  4.             requires : ['Ext.app.Portlet''Ext.app.PortalColumn''Ext.app.PortalPanel',  
  5.                        'Ext.app.PortalDropZone''Ext.ux.TabReorderer','Ext.ux.TabCloseMenu'],  
  6.             activeTab : 0,  
  7.             enableTabScroll : true,  
  8.             animScroll : true,  
  9.             border : true,  
  10.             autoScroll : true,  
  11.             region : 'center',  
  12.             split : true,  
  13.             plugins : [  
  14.                 Ext.create('Ext.ux.TabReorderer'),  
  15.                 Ext.create('Ext.ux.TabCloseMenu',{  
  16.                             closeTabText: '关闭面板',  
  17.                             closeOthersTabsText: '关闭其他',  
  18.                             closeAllTabsText: '关闭所有'  
  19.                           })  
  20.             ],  
  21.             items : [{  
  22.                         iconCls : 'icon-activity',  
  23.                         title : '平台首页',  
  24.                         xtype : 'portalpanel',  
  25.                         layout : 'column',  
  26.                         items : [{  
  27.                                     xtype : 'portalcolumn',  
  28.                                     columnWidth : 0.7,  
  29.                                     items : [{  
  30.                                                 title : '新闻动态',  
  31.                                                 height : 150,  
  32.                                                 iconCls : 'icon-news'  
  33.                                             }, {  
  34.                                                 title : '最新通知',  
  35.                                                 height : 150,  
  36.                                                 iconCls : 'icon-notice'  
  37.                                             }, {  
  38.                                                 title : '业绩报表',  
  39.                                                 height : 150,  
  40.                                                 iconCls : 'icon-chart'  
  41.                                             }, {  
  42.                                                 title : '邮件列表',  
  43.                                                 height : 150,  
  44.                                                 iconCls : 'icon-email-list'  
  45.                                             }]  
  46.                                 }, {  
  47.                                     xtype : 'portalcolumn',  
  48.                                     columnWidth : 0.3,  
  49.                                     items : [{  
  50.                                                 title : '功能链接',  
  51.                                                 height : 150,  
  52.                                                 iconCls : 'icon-link'  
  53.                                             }, {  
  54.                                                 title : '待办事项',  
  55.                                                 height : 150,  
  56.                                                 iconCls : 'icon-note'  
  57.                                             }, {  
  58.                                                 title : '邮件列表',  
  59.                                                 height : 150,  
  60.                                                 iconCls : 'icon-email-list'  
  61.                                             }, {  
  62.                                                 title : '邮件列表',  
  63.                                                 height : 150,  
  64.                                                 iconCls : 'icon-email-list'  
  65.                                             }]  
  66.                                 }]  
  67.                     }]  
  68.         });  
Desktop.view.Container是一个标签页集合的面板,是整个界面的操作区域。

module/desktop/view/Header.js
[javascript]  view plain copy
  1. Ext.define('Desktop.view.Header', {  
  2.     extend : 'Ext.panel.Panel',  
  3.     height : 80,  
  4.     html : '业务基础平台',  
  5.     region : 'north',  
  6.     split : true,  
  7.     bbar : [{  
  8.                 iconCls : 'icon-user',  
  9.                 text : '管理员'  
  10.             }, '-', {  
  11.                 text : Ext.Date.format(new Date(), 'Y年m月d日')  
  12.             }, '->', {  
  13.                 text : '退出',  
  14.                 iconCls : 'icon-logout'  
  15.             }],  
  16.     bodyStyle : 'backgroud-color:#99bbe8;line-height : 50px;padding-left:20px;' +  
  17.             'font-size:22px;color:#000000;font-family:黑体;font-weight:bolder;'+   
  18.             'background: -webkit-gradient(linear, left top, left bottom, ' +  
  19.             'color-stop(0%, rgba(153,187, 232, 0.4) ),' +  
  20.             'color-stop(50%, rgba(153, 187, 232, 0.8) ),' +  
  21.             'color-stop(0%, rgba(153, 187, 232, 0.4) ) );' ,  
  22.     initComponent : function(){  
  23.         this.callParent();  
  24.     }  
  25. });  
Desktop.view.Header是界面的头部

module/desktop/view/Navigation.js
[javascript]  view plain copy
  1. Ext.define('Desktop.view.Navigation', {  
  2.             alias: 'widget.navigation',  
  3.             extend : 'Ext.panel.Panel',  
  4.             region : 'west',  
  5.             title : '系统菜单',  
  6.             width : 250,  
  7.             iconCls : "icon-tree",  
  8.             autoScroll : false,  
  9.             layout : 'accordion',  
  10.             collapsible : true,  
  11.             layoutConfig : {  
  12.                 animate : true  
  13.             },  
  14.             id : 'navigation',  
  15.             split : true,  
  16.             initComponent : function(){  
  17.                 this.callParent();  
  18.             }  
  19.         });  
Desktop.view.Navigation是界面的导航部分,树形菜单的展示区域

模型层


模型层主要是定义了前后台数据交互的模型
module/desktop/model/Node.js
[javascript]  view plain copy
  1. Ext.define('Desktop.model.Node', {   
  2.     extend: 'Ext.data.Model',  
  3.     fields : [{name : "id",type : "string"},  
  4.             {name : "text",type : "string"},  
  5.             {name : "iconCls",type : "string"},  
  6.             {name : "leaf",type : "boolean"},  
  7.             {name : 'type'},  
  8.             {name : 'component'}]  
  9. });  
Desktop.model.Node定义了菜单数据模型

后台处理


整个界面的数据交互个入口在module/desktop/controller/Desktop.js文件中的对定义了viewport进行的事件响应:
[javascript]  view plain copy
  1. init : function() {  
  2.         var me = this;  
  3.         this.control({  
  4.                     'viewport' : {  
  5.                         render : me.onRender  
  6.                     },  
  7.                     scope : me  
  8.                 });  
  9.     },  
  10.   
  11.     onRender : function() {  
  12.         var me = this;  
  13.         Ext.get('loading-msg').update('正在加载菜单...');  
  14.         Ext.Ajax.request({  
  15.                     url : 'resource/root',// 获取面板的地址  
  16.                     method : 'GET',  
  17.                     callback : function(options, success, response) {  
  18.                         me.createTree(Ext.JSON.decode(response.responseText));  
  19.                     }  
  20.                 });  
  21.     },  
  22.   
  23.     createTree : function(datas) {  
  24.         var me = this;  
  25.         Ext.each(datas, function(data) {  
  26.                     var tree = Ext.create("Ext.tree.Panel", {  
  27.                                 title : data.text,  
  28.                                 iconCls : data.iconCls,  
  29.                                 useArrows : true,  
  30.                                 autoScroll : true,  
  31.                                 rootVisible : false,  
  32.                                 viewConfig : {  
  33.                                     loadingText : "正在加载..."  
  34.                                 },  
  35.                                 store : me.createTreeStore(data.id)  
  36.                             });  
  37.                     tree.on('itemclick', me.onTreeItemClick, me);  
  38.                     me.getNavigation().add(tree);  
  39.                 });  
  40.         Ext.get('loading-msg').update('加载完成.');  
  41.         Ext.Function.defer(function() {  
  42.                     Ext.get('loading-tip').remove();  
  43.                 }, 1000);  
  44.     },  
在viewport渲染完成后发送到resource/root请求获取菜单的根目录,后台java代码:
ResourceController.java
[java]  view plain copy
  1. package com.avicit.fes.system.resource.controller;  
  2.   
  3. import java.util.List;  
  4.   
  5. import org.springframework.beans.factory.annotation.Autowired;  
  6. import org.springframework.stereotype.Controller;  
  7. import org.springframework.web.bind.annotation.RequestMapping;  
  8. import org.springframework.web.bind.annotation.RequestMethod;  
  9. import org.springframework.web.bind.annotation.RequestParam;  
  10. import org.springframework.web.bind.annotation.ResponseBody;  
  11.   
  12. import com.avicit.fes.system.resource.service.ResourceService;  
  13. import com.avicit.fes.system.resource.vo.ResourceNode;  
  14.   
  15. @Controller  
  16. @RequestMapping("/resource")  
  17. public class ResourceController {  
  18.   
  19.     @Autowired  
  20.     private ResourceService resourceService;  
  21.       
  22.     @RequestMapping(value="root",method=RequestMethod.GET)  
  23.     public @ResponseBody List<ResourceNode> root() throws Exception{  
  24.         return this.resourceService.getRoot();  
  25.     }  
  26.       
  27.     @RequestMapping(value="child",method=RequestMethod.GET)  
  28.     public @ResponseBody List<ResourceNode> child(@RequestParam("id") Integer id) throws Exception{  
  29.         return this.resourceService.getChildren(id);  
  30.     }  
  31. }  
在ResourceController类中定义了root方法拦截resource/root请求,在resourceService中获取菜单的根目录发送到页面中,下面看ResourceServiceImpl中的代码:
[java]  view plain copy
  1. package com.avicit.fes.system.resource.service.impl;  
  2.   
  3. import java.util.List;  
  4.   
  5. import org.apache.commons.logging.Log;  
  6. import org.apache.commons.logging.LogFactory;  
  7. import org.springframework.beans.factory.annotation.Autowired;  
  8. import org.springframework.stereotype.Service;  
  9.   
  10. import com.avicit.fes.system.resource.dao.ResourceDAO;  
  11. import com.avicit.fes.system.resource.entity.Resource;  
  12. import com.avicit.fes.system.resource.service.ResourceService;  
  13. import com.avicit.fes.system.resource.vo.ResourceNode;  
  14. import com.avicit.framework.util.ListUtils;  
  15.   
  16. @Service("resourceService")  
  17. public class ResourceServiceImpl implements ResourceService {  
  18.   
  19.     protected Log logger = LogFactory.getLog(this.getClass());  
  20.   
  21.     @Autowired  
  22.     protected ResourceDAO<Resource, Integer> resourceDAO;  
  23.   
  24.     @Override  
  25.     public List<ResourceNode> getRoot() throws Exception {  
  26.         return ListUtils.transform(this.resourceDAO.getRootResource(),ResourceNode.class);  
  27.     }  
  28.       
  29.     public List<ResourceNode> getChildren(Integer id) throws Exception{  
  30.         return ListUtils.transform(this.resourceDAO.getChildrenByParent(id),ResourceNode.class);  
  31.     }  
  32.   
  33. }  
在ResourceServiceImpl类中getRoot方法中从后台数据库中获取到跟目录的数据返回给ResourceController,这样就完成了数据的交互。
在获取根目录之后创建树组件,并通过父节点获取子节点,从而完成了界面菜单的交互。

这篇关于Spring3+Hibernate4+SpringMVC整合Ext:开发Ext界面及Accordin Tree的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/334455

相关文章

Java编译生成多个.class文件的原理和作用

《Java编译生成多个.class文件的原理和作用》作为一名经验丰富的开发者,在Java项目中执行编译后,可能会发现一个.java源文件有时会产生多个.class文件,从技术实现层面详细剖析这一现象... 目录一、内部类机制与.class文件生成成员内部类(常规内部类)局部内部类(方法内部类)匿名内部类二、

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Springboot @Autowired和@Resource的区别解析

《Springboot@Autowired和@Resource的区别解析》@Resource是JDK提供的注解,只是Spring在实现上提供了这个注解的功能支持,本文给大家介绍Springboot@... 目录【一】定义【1】@Autowired【2】@Resource【二】区别【1】包含的属性不同【2】@

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

Java枚举类实现Key-Value映射的多种实现方式

《Java枚举类实现Key-Value映射的多种实现方式》在Java开发中,枚举(Enum)是一种特殊的类,本文将详细介绍Java枚举类实现key-value映射的多种方式,有需要的小伙伴可以根据需要... 目录前言一、基础实现方式1.1 为枚举添加属性和构造方法二、http://www.cppcns.co

Elasticsearch 在 Java 中的使用教程

《Elasticsearch在Java中的使用教程》Elasticsearch是一个分布式搜索和分析引擎,基于ApacheLucene构建,能够实现实时数据的存储、搜索、和分析,它广泛应用于全文... 目录1. Elasticsearch 简介2. 环境准备2.1 安装 Elasticsearch2.2 J

Java中的String.valueOf()和toString()方法区别小结

《Java中的String.valueOf()和toString()方法区别小结》字符串操作是开发者日常编程任务中不可或缺的一部分,转换为字符串是一种常见需求,其中最常见的就是String.value... 目录String.valueOf()方法方法定义方法实现使用示例使用场景toString()方法方法

Java中List的contains()方法的使用小结

《Java中List的contains()方法的使用小结》List的contains()方法用于检查列表中是否包含指定的元素,借助equals()方法进行判断,下面就来介绍Java中List的c... 目录详细展开1. 方法签名2. 工作原理3. 使用示例4. 注意事项总结结论:List 的 contain

Java实现文件图片的预览和下载功能

《Java实现文件图片的预览和下载功能》这篇文章主要为大家详细介绍了如何使用Java实现文件图片的预览和下载功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... Java实现文件(图片)的预览和下载 @ApiOperation("访问文件") @GetMapping("

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis