之前的项目中使用的是ssm+ftl,使用简单的html来战士相应的数据,这样的操作手工量比较大,而且对于数据的操作以及展示美观度不够,所以在学习easyui的过程中,通过对于easyui的练习,将之前的项目使用easyui进行改进。
ssm环境搭建在之前的项目中关于配置文件的介绍已经足够完善了,所以本次对于ssm的环境搭建不再赘述,本次只是对于easyui前台页面的显示布局进行搭建介绍。
easyui作为一个便捷的前台显示框架,提供了很多的空间。本次布局会通过很多页面的嵌套来实现页面的跳转,以及弹框的显示。首先需要准备的是index.ftl页面,作为项目访问的首页,因为加入了登录操作,所以首先需要验证当前用户是否登录,如果没有则弹出登录弹框(login.ftl),否则跳转到消息展示页面。在展示页面中进行具体内容格局的布置,文件名称为mainContent.ftl。
修改IndexController.java类
@Controller
public class IndexController {
@RequestMapping("/")
String index() {
return "index";
}
@RequestMapping("toLogin")
String toLogin() {
return "login";
}
}
修改拦截器在spring-mvc.xml文件中的配置
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/"/>
<mvc:exclude-mapping path="/toLogin"/>
<mvc:exclude-mapping path="/code/**"/>
<mvc:exclude-mapping path="/logincontroller/**"/>
<mvc:exclude-mapping path="/plugins/**"/>
<bean class="cn.mldn.szq.interceptor.LoginInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
1、建立index.ftl文件
因为index.ftl页面中会包含所有的页面,所以只需要在该文件中将所有需要引入的css,js等文件即可,减少很多页面中的文件引入操作。其中包括,jQuery开发包,easyui中的主体样式easyui.css文件,和字体图标icon.css文件,和其主要的开发包,jquery.easyui.min.js文件,并且引入语言包设置。
easyui中并没有提供有图片上传,文本域等组件,所以还需要引入相关的layui的核心样式文件和js文件。
用户登录与否,只需要查询session中的属性“uid”中是否存在有值即可。所以通过该值判断,应该进入首页,还是需要进如到登录页面。而本次的登录页面使用的是easyui中的模态窗口,通过href属性将login.ftl文件展示到该窗口中,然后设置一个“保存”按钮,来到用login.ftl文件中的user_login()方法进行登录操作。
<#assign base=request.contextPath/>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" type="text/css" href="${base}/plugins/jquery-easyui-1.4.1/themes/ui-sunny/easyui.css">
<link rel="stylesheet" type="text/css" href="${base}/plugins/jquery-easyui-1.4.1/themes/icon.css">
<link rel="stylesheet" href="${base}/plugins/layui/css/layui.css">
<link rel="stylesheet" href="${base}/plugins/layui/css/modules/layer/default/layer.css">
</head>
<body>
<script type="text/javascript" src="${base}/plugins/jquery.min.js"></script>
<script type="text/javascript" src="${base}/plugins/jquery-easyui-1.4.1/jquery.easyui.min.js"></script>
<script type="text/javascript" src="${base}/plugins/jquery-easyui-1.4.1/locale/easyui-lang-zh_CN.js"></script>
<script src="${base}/plugins/layui/layui.all.js"></script>
<#if Session.uid?? >
<#include "mainContent.ftl" />
<#else>
<script type="text/javascript">
//打开登陆对话框
var add_user_dialog = $("<div></div>").dialog({
title:"用户登陆",
width:400,
height:280,
closable:false,
modal:true,
href:"${base}/toLogin",
buttons:[{
text:'登陆',
handler:function(){
user_login();
}
}]
});
</script>
</#if>
</body>
</html>
2、建立mainContent.ftl文件
进入到该文件中首先会使用easyui中的layout进行页面的布局。可以通过data-options直接在设置了”class='easyui-layout'”样式的DIV中的DIV中设置对应的布局方位”region“,他可以有五个值”south,north,east,west,center“,center在布局中是必须要存在的,其他四个是可选的。根据这些规则,在本次页面中只是用了west和center,但是为了练习,将其都加入了。如下
<#assign base=request.contextPath />
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body class="easyui-layout">
<div data-options="region:'north',title:'上',split:true" style="height:100px;">
<center><h1><font color='red'>fuck you</font></h1></center>
</div>
<div data-options="region:'south',title:'下',split:true" style="height:100px;">
<center><h1><font color='red'>holy shit</font></h1></center>
</div>
<div data-options="region:'east',iconCls:'icon-reload',title:'右',split:true" style="width:100px;">
<center><h1><font color='red'>妈卖批 </font></h1></center>
</div>
<div data-options="region:'west',title:'左',split:true" style="width:100px;"> </div>
<div data-options="region:'center',title:'中间'" style="padding:5px;background:#eee;">
<div id="tt" class="easyui-tabs" data-options="fit:true"> </div>
</div>
</body>
</html>
在这些布局当中,可以在里面加入任何内容,所以按照常规的布局,会在west中加入系统的菜单,在north中设置标题,在center中设置对应的Tabs,也就是选项卡。首先介绍,选项卡的建立。两种方式
~直接将选项卡写在center中,然后用class修饰即可。
<div data-options="region:'center',title:'中间'" style="padding:5px;background:#eee;">
<div id="tt" class="easyui-tabs" data-options="fit:true">
<div title="Tab1" data-options="iconCls:'icon-reload',closable:true" style="padding:20px;">
what the mother fucker?
</div>
</div>
</div>
~可以动态建立相应的选项卡,在west的菜单栏中加入两个按钮,然后动态的创建选项卡。
选项卡的建立,可以通过调用tabs的add方法来进行添加,但是考虑到,对于已建立的选项卡不能重复的创建,所以还需要使用其exists方法根据其唯一标识判断是否存在当前选项卡,而唯一标识可以是id或者选项卡的标题。因为创建选项卡的时候,会将当前的菜单标题设置为选项卡的title,所以其一般不会重复。之后,如果该选项卡已经存在,则直接激活选项卡,并且还需要其刷新选项卡中的内容。如果不存在,则为其添加新的选项卡。
<div data-options="region:'west',title:'左',split:true" style="width:100px;">
<a id="btn" href="#" class="easyui-linkbutton" data-options="plain:true" onclick="openTabs('资产列表','/shop/list')" >资产列表</a><br/>
<a id="btn" href="#" class="easyui-linkbutton" data-options="plain:true" onclick="openTabs('用户列表','/shop/list2')">用户列表</a>
</div>
<script type="text/javascript">
function openTabs(tab_title,page_href){
var tabexists = $('#tt').tabs('exists',tab_title) //判断选项卡是否存在
if(tabexists){ 存在
$('#tt').tabs('select',tab_title); //激活已存在选项卡
$('#tt').tabs('getSelected').panel('refresh'); //激活之后刷新选项卡中的内容
}else{ //不存在
$('#tt').tabs('add',{
title:tab_title, //选项卡的标题
href:"${base}"+page_href, //展示内容的路径
//content:'<font color="red">惊不惊喜</font>',
closable:true,
});
}
}
</script>
此为第一种方式,通过按钮的形式,调用js动态创建选项卡, 并且展示对应href的页面内容,但是此种做法,在视觉上并不符合实际的应用,所以可以使用easyui中提供的tree组件,将菜单做成类似于树的结构。
树结构的生成也是两种方式,静态数据生成,动态数据生成。
~静态数据的生成,内容是直接写在页面上的,也就相当于写了几个按钮操作,只不过显示的方式是树的形式。
~动态数据生成,也就是可以通过url属性,读取数据库返回的json格式的数据,来生成相应的树。
静态格式生成树,可以直接参考文档。本次直接记性动态树的生成。不管是静态写,还是访问数据库返回,都需要注意其中的data的数据格式
-
id:节点ID,对加载远程数据很重要。
-
text:显示节点文本。
-
state:节点状态,'open' 或 'closed',默认:'open'。如果为'closed'的时候,将不自动展开该节点。
-
children: 一个节点数组声明了若干节点
①在west中添加“<ul>”标签,也就是设置树的位置,也可以使用“<div>”代替,并且设置相应的脚本
<div data-options="region:'west',title:'左',split:true" style="width:100px;">
<#--生成树,ul可以使用div代替-->
<ul id="main_Tree"></ul>
</div>
<script type="text/javascript">
//异步加载生成树
$('#main_Tree').tree({
url:"${base}/maintree/listRecursion",
onClick:function(node){
if(node.href != null && "" != node.href){
openTabs(node.text,node.href);
}
}
});
function openTabs(tab_title,page_href){
var tabexists = $('#tt').tabs('exists',tab_title)
if(tabexists){
$('#tt').tabs('select',tab_title);
$('#tt').tabs('getSelected').panel('refresh');
}else{
$('#tt').tabs('add',{
title:tab_title,
href:"${base}"+page_href,
//content:'<font color="red">惊不惊喜</font>',
closable:true,
});
}
}
</script>
②建立MainTree.java实体类
@SuppressWarnings("serial")
public class MainTree implements Serializable{
private int id; //树的结点
private String text; //树节点的内容
private String state; //文件状态还是文件夹状态:closed,open
private String href; //该节点要展示的页面路径
private int pid; //父节点ID
private List<MainTree> children; //所有的子节点
}
为了数据的接收与返回,所以本次设置的名字与data中地字段名称完全一致。
其中,pid为父节点的id,而这里的设置与二级联动中的地址设置是类似的,为了逻辑上的理解,所以会根据pid来查询所有的节点
③建立IMainTreeDAO.java接口
public interface IMainTreeDAO {
@Select("select m_id AS id,m_title AS text, m_href AS href,m_pid AS pid from T_STAFF_MENU"
+" where m_pid=#{pid}")
public List<MainTree> findAll(MainTree vo);
}
④建立IMainTreeService.java接口以及其实现类,在业务层中就可以有两种方式来实现数据的读取。
~每次只读一层的结点,当用户点击父级节点时,会自动的访问url的路径查询父路径下的菜单。
public interface IMainTreeService {
public List<MainTree> list(MainTree vo);
}
@Service
public class MainTreeServcieImpl implements IMainTreeService {
@Autowired
private IMainTreeDAO treeDAO;
@Override
public List<MainTree> list(MainTree vo) {
List<MainTree> list = this.treeDAO.findAll(vo);
for(MainTree tree : list){
if(tree.getPid() == 0){
tree.setState("closed");
}
}
return list;
}
}
~第二种方式是通过递归的方式,一次性把所有的数据都读取出来。
public List<MainTree> listByRecursion(MainTree vo);
@Override
public List<MainTree> listByRecursion(MainTree vo) {
List<MainTree> list = this.treeDAO.findAll(vo);
for(MainTree tree : list){
if(tree.getPid() == 0){
tree.setState("closed");
}
tree.setPid(tree.getId());
List<MainTree> children = listByRecursion(tree);
tree.setChildren(children);
}
return list;
}
这两种方式都有一个共同的问题,当点击空的文件夹时,会自动查询有没有子节点,而这个在第一种情况下属于正常情况,而在第二种递归方式查询过程中,就比较不合理,但是没有找到解决方案。
⑤建立对应的MainTreeController.java类,为两种方式都设置相应的访问路径
@Controller
@RequestMapping("maintree")
public class MainTreeController {
@Resource
private IMainTreeService treeService;
@RequestMapping("list")
@ResponseBody
public List<MainTree> list(MainTree vo){
vo.setPid(vo.getId());
return this.treeService.list(vo);
}
@RequestMapping("listRecursion")
@ResponseBody
public List<MainTree> listRecursion(MainTree vo){
vo.setPid(vo.getId());
return this.treeService.listByRecursion(vo);
}
}
这样与上面的url对应起来,即可自动生成相应的树目录,并且设置好菜单中的href。如果以后需要改变树的结构,只需要修改数据库中的内容即可,不需要重新修改程序代码。
而对于登录页面login.ft会在下一节笔记中进行阐述。