标签:java 数据结构 对象 springmvc mybatis
最近一直在思考,如何设计一个毕业论文呢?后台就回想起自己以前大学做的项目,每次都需要开发一个后台网站,及其繁琐,后来就慢慢有了个想法,开发一个网站固件,可以动态配置,于是就动手设计了起来...
所以通常而言,超级管理员属于开发阶段的开发人员使用。每当一个新的功能加入时,就需要配置一个权限,然后将权限关联到相关菜单下面
使用技术:spring mvc + mybatis + ligerui + javascript + css + jsp + html + mysql
下面看看工程的包组织,这里使用了按照模块划分来组织包。
下面是jsp的组织,同样采用按照模块来组织,并且将所有的jsp界面放在了WEB-INF下面,可以确保文件的相关安全
在开发过程中,最主要的是抽象与设计架构,所以这里主要做了一个树组件的抽象。也就是将数据库的数据,变成js框架中的组件。于是设计了一个liger ui的树组件
下面先看看liger ui树组件的数据
<span style="font-size:18px;">var indexdata =
[
{ text: '基础',isexpand:false, children: [
{url:"demos/base/resizable.htm",text:"改变大小"},
{url:"demos/base/drag.htm",text:"拖动"},
{url:"demos/base/drag2.htm",text:"拖动2"},
{url:"demos/base/dragresizable.htm",text:"拖动并改变大小"},
{url:"demos/base/tip.htm",text:"气泡"},
{url:"demos/base/tip2.htm",text:"气泡2"}
]
}
];
</span><span style="font-size:18px;">package net.itaem.view;
import java.util.List;
/**
* liger ui中Tree模型
*
* 菜单模型使用树的结构进行组织
* 一个ITreeModel有两个形态,一个是Menu,一个Leaf
* 遍历节点的时候,会递归遍历结点
*
* 这个接口主要用来描述菜单的一些相关操作
* 每一个后台框架都应该实现该接口,然后对外体现出一致性
* 目前框架提供了LigerUI Tree的实现
*
* <br>
* 如果用户如果感兴趣,可以提供一个DWZ, EXTJS的实现
* 在判断一个结点是否是同一个结点,这里使用结点ID来判断
* 为了配置菜单的显示顺序,这里需要默认指定一个排序方式
*
* @see LigerUiTree
*
* @date 2014-08-19 10:17 am
* @author 骆宏
* @email 846705189@qq.com
*
* */
public interface ITreeModel {
/**
* 定义一个字符串,用来表示树模型中的菜单节点
* */
String MENU = "menu";
/**
* 定义一个字符串,用来表示数模型中的叶子节点
* */
String LEAF = "leaf";
/**
* 返回当前菜单的结构层次
* @return 返回菜单的结构层次
* 如果是叶子节点,那么返回0
* */
public int level();
/**
* 返回当前节点的所有子节点,子节点包括了子菜单以及叶子节点
* @return 返回当前菜单的全部子节点
* */
public List<ITreeModel> children();
/**
* 返回当前节点的父节点
* @return 返回当前节点的父亲节点,如果没有父亲节点,返回null
* */
public ITreeModel parent();
/**
* 返回当前节点的节点类型,这里的节点类型一共有两种,一种是菜单,另外一种是叶子节点
* @return 节点类型
* @see ITreeModel#MENU
* @see ITreeModel#LEAF
* */
public String nodeType();
/**
* 返回当前节点的url
* @return 当前节点的url
* */
public String url();
/**
* 放回当前节点的id
* @return 当前节点id
* */
public String id();
/**
* 返回节点的名字
* @return 节点名字
* */
public String name();
/**
* 当前节点如果是菜单,那么该菜单默认是否展开呢?如果是返回true,代表展开;否则,代表不展开
* @return 返回菜单节点的展开状态
* */
public boolean isexpand();
/**
* 设置菜单名字
* @param name
* */
public void setName(String name);
/**
* 设置菜单url
* @param url
* */
public void setUrl(String url);
/**
* 设置菜单展开状态
* @param isexpend
* */
public void setIsexpand(boolean isexpand);
/**
* 设置父节点
* @param parent
* */
public void setParent(ITreeModel parent);
/**
* 设置孩子节点
* @param children
* */
public void setChildren(List<ITreeModel> children);
/**
* 设置节点id
* @param id
* */
public void setId(String id);
/**
* 返回该节点的json数据,包含该节点下面的所有子节点
* @return 返回当前节点的json数据
* */
public String toTreeJson();
/**
* 返回从根节点到当前节点的所有节点集合,包含当前节点
* 该集合的第一个元素为最大根节点,第二个元素为第二个根结点,依次类推
* @return 返回根节点到当前节点的集合
* */
public List<ITreeModel> route();
/**
* 返回当前结点下面的第position结点
* @return 返回以当前节点子根节点的子树
* */
public ITreeModel subTree(int position);
/**
* 添加子节点,添加到结点的结尾处
* @param subTree 要添加的子节点
* */
public boolean addSubTree(ITreeModel subTree);
/**
* 在指定position添加结点
* @param position 下标
* @param subTree 要添加的子节点
* */
public void addSubTree(int position, ITreeModel subTree);
/**
* 删除子节点
* @param subTree 要删除的结点
* */
public boolean deleteSubTree(ITreeModel subTree);
/**
* 删除子节点
* @param position 要删除的结点在子节点中的位置
* */
public boolean deleteSubTree(int position);
/**
* 判断类型
* @return
* */
public boolean isMenu();
/**
* 判断类型
* @return
* */
public boolean isLeaf();
/**
* 返回Menu的图片
* @return
* */
public String pic();
/**
* 返回图标的图片
* @param pic 图片url地址
* */
public void setPic(String pic);
} </span><span style="font-size:18px;">package net.itaem.view.ligerui;
import java.util.ArrayList;
import java.util.List;
import net.itaem.view.ITreeModel;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
/**
* 这里是liger ui树的插件实现类
*
* 在每次add、delete之后,都需要计算树的level
*
*
*
* @author 骆宏
* @date 2014-08-19 19:39 am
* @email 846705189@qq.com
* */
public class LigerUiTree implements ITreeModel{
//定义一个level,用来保存树的层次
private int level = 1;
//定义一个url,用来保存当前节点的url
private String url;
//定义一个id,用来保存当前节点id
private String id;
//定义一个isexpend,用来保存节点展开状态
private boolean isexpand;
//定义一个name,用来保存节点的名称
private String name;
//定义一个parent,用来保存节点的父亲节点
private ITreeModel parent;
//定义一个children,用来保存当前节点的所有子节点
private List<ITreeModel> children = new ArrayList<ITreeModel>();
//定义一个nodeType,用来保存结点类型
private String nodeType = LEAF;
//定义一个pic,用来保存图片的url地址
private String pic;
//用来缓存树的json数据
private String jsonCache;
//用来保存用户的操作状态,如果树已经构建好,并且没有删除、添加,那么继续使用jsonCache
private boolean hasChange;
public LigerUiTree(){
}
/**
* 定义一个基本的构造方法,该构造方法的参数都不能为空
* @param id 节点id
* @param name 节点name
* @param url 节点url
* */
public LigerUiTree(String id, String name, String url){
if(id == null || name == null || url == null) throw new RuntimeException("id name url都不能为空");
this.id = id;
this.name = name;
this.url = url;
hasChange = true;
}
public LigerUiTree(String id, String name, String url, ITreeModel parent) {
this(id, name, url);
this.parent = parent;
hasChange = true;
}
public LigerUiTree(String id, String name, String url, List<ITreeModel> children) {
this(id, name, url);
this.children = children;
hasChange = true;
}
@Override
public void setUrl(String url) {
this.url = url;
hasChange = true;
}
@Override
public void setId(String id) {
this.id = id;
hasChange = true;
}
@Override
public void setIsexpand(boolean isexpand) {
this.isexpand = isexpand;
hasChange = true;
}
@Override
public void setName(String name) {
this.name = name;
hasChange = true;
}
@Override
public void setParent(ITreeModel parent) {
this.parent = parent;
hasChange = true;
}
/**
* 这里同时会计算树的层次
* 并且这里会同时维护parant - children之间的关联管理,也就是在设置当前节点的子节点时,同时会指点这些子节点的父亲节点为当前节点
* */
@Override
public void setChildren(List<ITreeModel> children) {
if(children == null || children.size() == 0) return; //如果为null,do nothing
this.children = children; //设置当前结点的子节点为children
int max = 0;
ITreeModel child = null;
for(int i=0; i < children.size(); i++){
child = children.get(i);
child.setParent(this);
if(max < child.level()) max = child.level();
}
level += max;
nodeType = MENU;
hasChange = true;
}
@Override
public int level() {
//每次要计算树的高度,都必须遍历整棵树的,然后确定树的高度,由于树随时可以被改变,所以这里不适合使用缓存模式
return level;
}
@Override
public List<ITreeModel> children() {
return children;
}
@Override
public ITreeModel parent() {
return parent;
}
@Override
public String nodeType() {
return nodeType;
}
@Override
public String url() {
return url;
}
@Override
public String id() {
return id;
}
@Override
public boolean isexpand() {
return isexpand;
}
@Override
public String name(){
return name;
}
@Override
public String toTreeJson() {
if(hasChange && jsonCache == null){
JSONObject json = new JSONObject();
//生成这个节点的基本数据
json.put("text", name);
json.put("isexpand", isexpand);
json.put("id", id);
json.put("icon", pic);
if(url != null && !"".equals(url))
json.put("url", url);
if(parent != null){
json.put("pid", parent.id());
}
//生成这个节点的子菜单数据
JSONArray childrenJson = new JSONArray();
if(children != null && children.size() != 0){
for(ITreeModel child: children){
//让每个子menu递归的去生成json数据
childrenJson.add(toJson(child));
}
json.put("children", childrenJson);
}
jsonCache = json.toString();
return jsonCache;
}else
return jsonCache;
}
/**
* 递归入口
* @see MenuVo#toJson()
* */
private String toJson(ITreeModel tree){
JSONObject json = new JSONObject();
if(tree.children() != null && tree.children().size() != 0){
//生成这个菜单节点的基本数据
json.put("text", tree.name());
json.put("id", tree.id());
json.put("icon", tree.pic());
if(tree.parent() != null){
json.put("pid", tree.parent().id());
}
json.put("isexpand", tree.isexpand());
//生成这个菜单节点的子菜单数据
JSONArray childrenJson = new JSONArray();
if(tree.children() != null){
for(ITreeModel child: tree.children()){
//让每个子menu递归的去生成json数据
childrenJson.add(toJson(child));
}
json.put("children", childrenJson);
}
}else{ //这个节点不是菜单,是菜单下面的一个具体子节点,该节点已经没有子节点了
json.put("id", tree.id());
if(tree.parent() != null){
json.put("pid", tree.parent().id());
}
json.put("text", tree.name());
json.put("url", tree.url());
json.put("icon", tree.pic());
}
return json.toString();
}
@Override
public List<ITreeModel> route() {
List<ITreeModel> route = new ArrayList<ITreeModel>();
ITreeModel current = this;
while(current != null){
route.add(current);
current = current.parent();
}
java.util.Collections.reverse(route);
return route;
}
@Override
public ITreeModel subTree(int position) {
if(position < 0) throw new RuntimeException("position 小于0");
if(children != null && children.size() > 0 && position <= children.size()-1){
return children.get(position);
}
return null;
}
/**
* 生成hashCode
* */
@Override
public int hashCode() {
return id.hashCode() * 37 + 5;
}
/**
* 比较两个菜单是否相等
* */
@Override
public boolean equals(Object obj) {
return id.equals(((ITreeModel)obj).id());
}
/**
* 返回节点的基本信息
* @return
* */
@Override
public String toString() {
return "LigerUiTree [" + "id=" + id + ", name=" + name
+ ", level=" + level + ", url=" + url
+ ", nodeType=" + nodeType() + ", isexpand=" + isexpand + ", pic=" + pic + "]";
}
@Override
public boolean addSubTree(ITreeModel subTree) {
if(subTree == null) return false;
nodeType = MENU;
subTree.setParent(this);
boolean addedFlag = children.add(subTree);
calculateLevel0(subTree);
hasChange = true;
return addedFlag;
}
@Override
public void addSubTree(int position, ITreeModel subTree) {
if(position < 0 || position >= children.size()) return;
children.add(position, subTree);
calculateLevel0(subTree);
if(children.size() > 0)
nodeType = MENU;
hasChange = true;
}
/**
* 增加一个结点,计算level,分为四种情况
* */
private void calculateLevel0(ITreeModel subTree){
if(this.isLeaf() && subTree.isLeaf()){
level = 2;
}else if(this.isMenu() && subTree.isMenu()){
level += subTree.level();
}else if(this.isLeaf() && subTree.isMenu()){
level = subTree.level() + 1;
}else{
//is menu, so add a new leaf, the level not change
}
}
@Override
public boolean deleteSubTree(ITreeModel subTree) {
boolean deletedFlag = false;
for(int i=0; i<children.size(); i++){
if(children.get(i).equals(subTree)){
children.remove(i);
break;
}
}
if(children.size() > 0)
nodeType = MENU;
calculateLevel();
hasChange = true;
return deletedFlag;
}
@Override
public boolean deleteSubTree(int position) {
if(position < 0 || children == null || children.size() == 0 || position >= children.size()) return false;
ITreeModel tree = children.remove(position);
if(children.size() > 0)
nodeType = MENU;
calculateLevel();
hasChange = true;
if(tree == null) return false;
else return true;
}
/**
* 计算输的层次,每次删除一个结点,需要遍历当前所有子节点,看看当前的子节点中,最大的level,然后将这个值+1即可
* */
private void calculateLevel(){
//设置level,遍历所有的children树,然后取最大值
int max = -1;
for(int i=0; i<children.size(); i++){
children.get(i).setParent(this); //维护parent-children的相互关联关系
if(children.get(i).level() > max) max = children.get(i).level();
}
//如果添加的节点都是叶子节点,那么当前层次为2
//否则计算最大的树层次 = 子节点最大的层次 + 1
if(max != -1){
level = max + 1;
}else{
level = 2;
}
}
@Override
public boolean isMenu() {
return nodeType.equals(ITreeModel.MENU);
}
@Override
public boolean isLeaf() {
return nodeType.equals(ITreeModel.LEAF);
}
@Override
public String pic() {
return pic;
}
@Override
public void setPic(String pic) {
this.pic = pic;
}
}</span><span style="font-size:18px;">package net.itaem.view;
import net.itaem.menu.entity.Menu;
import net.itaem.privilege.entity.Privilege;
import net.itaem.role.entity.Role;
/**
* 实现菜单、角色、权限-->Liger Ui Tree转换
*
* @author luohong
* @date 2014-12-24
* @email 846705189@qq.com
* */
public interface IToTree {
/**
* 将Menu变成一个Tree
* @param menu
* @return
* */
public ITreeModel menuToTree(Menu menu);
/**
* 将Role变成一个Tree
* @param role
* @return
* */
public ITreeModel roleToTree(Role role);
/**
* 将一个Privilege变成一个Tree
* @param privilege
* @return
* */
public ITreeModel privilegeToTree(Privilege privilege);
}
</span><span style="font-size:18px;"> </span>
<pre name="code" class="html"><span style="font-size:18px;">package net.itaem.view.ligerui;
import java.util.ArrayList;
import java.util.List;
import net.itaem.view.ITreeModel;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
/**
* 这里是liger ui树的插件实现类
*
* 在每次add、delete之后,都需要计算树的level
*
*
*
* @author 骆宏
* @date 2014-08-19 19:39 am
* @email 846705189@qq.com
* */
public class LigerUiTree implements ITreeModel{
//定义一个level,用来保存树的层次
private int level = 1;
//定义一个url,用来保存当前节点的url
private String url;
//定义一个id,用来保存当前节点id
private String id;
//定义一个isexpend,用来保存节点展开状态
private boolean isexpand;
//定义一个name,用来保存节点的名称
private String name;
//定义一个parent,用来保存节点的父亲节点
private ITreeModel parent;
//定义一个children,用来保存当前节点的所有子节点
private List<ITreeModel> children = new ArrayList<ITreeModel>();
//定义一个nodeType,用来保存结点类型
private String nodeType = LEAF;
//定义一个pic,用来保存图片的url地址
private String pic;
//用来缓存树的json数据
private String jsonCache;
//用来保存用户的操作状态,如果树已经构建好,并且没有删除、添加,那么继续使用jsonCache
private boolean hasChange;
public LigerUiTree(){
}
/**
* 定义一个基本的构造方法,该构造方法的参数都不能为空
* @param id 节点id
* @param name 节点name
* @param url 节点url
* */
public LigerUiTree(String id, String name, String url){
if(id == null || name == null || url == null) throw new RuntimeException("id name url都不能为空");
this.id = id;
this.name = name;
this.url = url;
hasChange = true;
}
public LigerUiTree(String id, String name, String url, ITreeModel parent) {
this(id, name, url);
this.parent = parent;
hasChange = true;
}
public LigerUiTree(String id, String name, String url, List<ITreeModel> children) {
this(id, name, url);
this.children = children;
hasChange = true;
}
@Override
public void setUrl(String url) {
this.url = url;
hasChange = true;
}
@Override
public void setId(String id) {
this.id = id;
hasChange = true;
}
@Override
public void setIsexpand(boolean isexpand) {
this.isexpand = isexpand;
hasChange = true;
}
@Override
public void setName(String name) {
this.name = name;
hasChange = true;
}
@Override
public void setParent(ITreeModel parent) {
this.parent = parent;
hasChange = true;
}
/**
* 这里同时会计算树的层次
* 并且这里会同时维护parant - children之间的关联管理,也就是在设置当前节点的子节点时,同时会指点这些子节点的父亲节点为当前节点
* */
@Override
public void setChildren(List<ITreeModel> children) {
if(children == null || children.size() == 0) return; //如果为null,do nothing
this.children = children; //设置当前结点的子节点为children
int max = 0;
ITreeModel child = null;
for(int i=0; i < children.size(); i++){
child = children.get(i);
child.setParent(this);
if(max < child.level()) max = child.level();
}
level += max;
nodeType = MENU;
hasChange = true;
}
@Override
public int level() {
//每次要计算树的高度,都必须遍历整棵树的,然后确定树的高度,由于树随时可以被改变,所以这里不适合使用缓存模式
return level;
}
@Override
public List<ITreeModel> children() {
return children;
}
@Override
public ITreeModel parent() {
return parent;
}
@Override
public String nodeType() {
return nodeType;
}
@Override
public String url() {
return url;
}
@Override
public String id() {
return id;
}
@Override
public boolean isexpand() {
return isexpand;
}
@Override
public String name(){
return name;
}
@Override
public String toTreeJson() {
if(hasChange && jsonCache == null){
JSONObject json = new JSONObject();
//生成这个节点的基本数据
json.put("text", name);
json.put("isexpand", isexpand);
json.put("id", id);
json.put("icon", pic);
if(url != null && !"".equals(url))
json.put("url", url);
if(parent != null){
json.put("pid", parent.id());
}
//生成这个节点的子菜单数据
JSONArray childrenJson = new JSONArray();
if(children != null && children.size() != 0){
for(ITreeModel child: children){
//让每个子menu递归的去生成json数据
childrenJson.add(toJson(child));
}
json.put("children", childrenJson);
}
jsonCache = json.toString();
return jsonCache;
}else
return jsonCache;
}
/**
* 递归入口
* @see MenuVo#toJson()
* */
private String toJson(ITreeModel tree){
JSONObject json = new JSONObject();
if(tree.children() != null && tree.children().size() != 0){
//生成这个菜单节点的基本数据
json.put("text", tree.name());
json.put("id", tree.id());
json.put("icon", tree.pic());
if(tree.parent() != null){
json.put("pid", tree.parent().id());
}
json.put("isexpand", tree.isexpand());
//生成这个菜单节点的子菜单数据
JSONArray childrenJson = new JSONArray();
if(tree.children() != null){
for(ITreeModel child: tree.children()){
//让每个子menu递归的去生成json数据
childrenJson.add(toJson(child));
}
json.put("children", childrenJson);
}
}else{ //这个节点不是菜单,是菜单下面的一个具体子节点,该节点已经没有子节点了
json.put("id", tree.id());
if(tree.parent() != null){
json.put("pid", tree.parent().id());
}
json.put("text", tree.name());
json.put("url", tree.url());
json.put("icon", tree.pic());
}
return json.toString();
}
@Override
public List<ITreeModel> route() {
List<ITreeModel> route = new ArrayList<ITreeModel>();
ITreeModel current = this;
while(current != null){
route.add(current);
current = current.parent();
}
java.util.Collections.reverse(route);
return route;
}
@Override
public ITreeModel subTree(int position) {
if(position < 0) throw new RuntimeException("position 小于0");
if(children != null && children.size() > 0 && position <= children.size()-1){
return children.get(position);
}
return null;
}
/**
* 生成hashCode
* */
@Override
public int hashCode() {
return id.hashCode() * 37 + 5;
}
/**
* 比较两个菜单是否相等
* */
@Override
public boolean equals(Object obj) {
return id.equals(((ITreeModel)obj).id());
}
/**
* 返回节点的基本信息
* @return
* */
@Override
public String toString() {
return "LigerUiTree [" + "id=" + id + ", name=" + name
+ ", level=" + level + ", url=" + url
+ ", nodeType=" + nodeType() + ", isexpand=" + isexpand + ", pic=" + pic + "]";
}
@Override
public boolean addSubTree(ITreeModel subTree) {
if(subTree == null) return false;
nodeType = MENU;
subTree.setParent(this);
boolean addedFlag = children.add(subTree);
calculateLevel0(subTree);
hasChange = true;
return addedFlag;
}
@Override
public void addSubTree(int position, ITreeModel subTree) {
if(position < 0 || position >= children.size()) return;
children.add(position, subTree);
calculateLevel0(subTree);
if(children.size() > 0)
nodeType = MENU;
hasChange = true;
}
/**
* 增加一个结点,计算level,分为四种情况
* */
private void calculateLevel0(ITreeModel subTree){
if(this.isLeaf() && subTree.isLeaf()){
level = 2;
}else if(this.isMenu() && subTree.isMenu()){
level += subTree.level();
}else if(this.isLeaf() && subTree.isMenu()){
level = subTree.level() + 1;
}else{
//is menu, so add a new leaf, the level not change
}
}
@Override
public boolean deleteSubTree(ITreeModel subTree) {
boolean deletedFlag = false;
for(int i=0; i<children.size(); i++){
if(children.get(i).equals(subTree)){
children.remove(i);
break;
}
}
if(children.size() > 0)
nodeType = MENU;
calculateLevel();
hasChange = true;
return deletedFlag;
}
@Override
public boolean deleteSubTree(int position) {
if(position < 0 || children == null || children.size() == 0 || position >= children.size()) return false;
ITreeModel tree = children.remove(position);
if(children.size() > 0)
nodeType = MENU;
calculateLevel();
hasChange = true;
if(tree == null) return false;
else return true;
}
/**
* 计算输的层次,每次删除一个结点,需要遍历当前所有子节点,看看当前的子节点中,最大的level,然后将这个值+1即可
* */
private void calculateLevel(){
//设置level,遍历所有的children树,然后取最大值
int max = -1;
for(int i=0; i<children.size(); i++){
children.get(i).setParent(this); //维护parent-children的相互关联关系
if(children.get(i).level() > max) max = children.get(i).level();
}
//如果添加的节点都是叶子节点,那么当前层次为2
//否则计算最大的树层次 = 子节点最大的层次 + 1
if(max != -1){
level = max + 1;
}else{
level = 2;
}
}
@Override
public boolean isMenu() {
return nodeType.equals(ITreeModel.MENU);
}
@Override
public boolean isLeaf() {
return nodeType.equals(ITreeModel.LEAF);
}
@Override
public String pic() {
return pic;
}
@Override
public void setPic(String pic) {
this.pic = pic;
}
}</span><span style="font-size:18px;"> </span>恩,代码就补贴那么多了,需要源码的直接发我邮箱即可,有时间我直接把源码发你...哈哈,有兴趣的,可以自己完善代码。
下面我们看看工程跑起来的相关界面,目前处于开发中,所以还有几个模块在开发中,需要源码的,可以联系我
通用权限设计(springmvc + mybatis + ligerui)
标签:java 数据结构 对象 springmvc mybatis
原文地址:http://blog.csdn.net/u010469003/article/details/42392549