最近想实现一个内容管理系统(CMS),首先就是要实现权限管理这一块。查询了一些资料,决定用SpringCloud+Thymeleaf实现该功能。现在跟大家分享下思路。
数据库设计
三军未动,粮草先行。数据库的设计相当于软件开发中的“粮草”,下面说说数据库的设计。
表名 | 描述 |
---|---|
t_cloumn | 权限分栏表 |
t_perm | 权限表 |
t_permmapping | 权限映射表 |
t_role | 权限角色表 |
t_usermapping | 用户映射表 |
t_user | 用户表 |
建表语句:
DROP TABLE IF EXISTS `t_column`;
CREATE TABLE `t_column` (
`columnId` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '分栏Id',
`columnName` varchar(16) NOT NULL COMMENT '分栏名称',
`columnInfo` varchar(128) NOT NULL COMMENT '分栏信息',
PRIMARY KEY (`columnId`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `t_perm`;
CREATE TABLE `t_perm` (
`permId` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '权限id',
`perm` varchar(16) NOT NULL COMMENT '权限',
`permName` varchar(16) NOT NULL COMMENT '权限名称',
`urlMapping` varchar(16) NOT NULL COMMENT 'url映射(请求url)',
`methodName` varchar(16) NOT NULL COMMENT '请求(权限)对应的方法名',
`className` varchar(36) NOT NULL COMMENT '请求(权限)对应的方法名',
`permInfo` varchar(128) NOT NULL COMMENT '权限信息',
`columnId` int(11) DEFAULT NULL COMMENT '权限所属分栏(对应权限分栏表的Id)',
PRIMARY KEY (`permId`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `t_role`;
CREATE TABLE `t_role` (
`roleId` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '角色Id',
`roleName` varchar(16) NOT NULL COMMENT '角色名称',
`roleInfo` varchar(128) NOT NULL COMMENT '角色信息',
`creatorName` varchar(16) NOT NULL COMMENT '创建者',
`createTime` datetime NOT NULL COMMENT '创建名称',
PRIMARY KEY (`roleId`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `t_permmapping`;
CREATE TABLE `t_permmapping` (
`permmappingId` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '权限映射Id',
`roleId` int(11) NOT NULL COMMENT '角色Id(对应角色表的Id)',
`permId` int(11) NOT NULL COMMENT '权限Id(对应权限表的Id)',
`creatorName` varchar(16) NOT NULL COMMENT '创建者',
`createTime` datetime NOT NULL COMMENT '创建日期',
PRIMARY KEY (`permmappingId`)
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`userId` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '用户Id',
`userName` varchar(16) NOT NULL COMMENT '用户名称',
`password` varchar(16) NOT NULL COMMENT '密码',
`sex` tinyint(4) NOT NULL COMMENT '性别',
`mobile` varchar(16) NOT NULL COMMENT '手机号码',
`createTime` datetime NOT NULL COMMENT '创建时间',
PRIMARY KEY (`userId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `t_usermapping`;
CREATE TABLE `t_usermapping` (
`usermappingId` int(11) unsigned NOT NULL AUTO_INCREMENT,
`userId` int(11) NOT NULL COMMENT '用户Id(对应用户表的Id)',
`userName` varchar(16) NOT NULL COMMENT '用户名(对应用户表的userName)',
`roleId` int(11) NOT NULL COMMENT '角色Id(对应角色表的Id)',
`creatorName` varchar(16) NOT NULL COMMENT '创建者',
`createTime` datetime NOT NULL COMMENT '创建时间',
PRIMARY KEY (`usermappingId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
各数据表的关联关系:
思路描述:
一个角色拥有多个权限(1对N),一个用户拥有多个角色(有些一个用户对应一个角色,这个要看看自己的需求。1对N或1对1).它们的关系都是通过第三张表来维护(映射表,方便维护和扩展)。为了方便操作,对权限进行分类(即权限分栏)。
系统架构
采用SpringCloud+Thymeleaft架构构建系统。
服务发现:consul
ORM框架:Mybatis
数据库连接池:Druid
前端模板:Thymeleaf
因为只是为了简单的实现权限功能,所有没有整合SpringCloud的其他模块。
配置文件如下:
#端口
server:
port: 7001
#springboot整合Mybatis
#加载Mybatis配置文件
mybatis:
type-aliases-package: com.xue.test.domain
mapper-locations: classpath:mapper/*Mapper.xml
#加载数据库
spring:
datasource:
url: jdbc:mysql://localhost:3306/cms?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
username: root
password: root
application:
name: cms
cloud:
consul:
host: localhost
port: 8500
discovery:
enabled: true
service-name: ${spring.application.name}
prefer-ip-address: true
#服务提供者需要注册
enabled: true
#thymelea模板配置
thymeleaf:
cache: false
mode: HTML5
encoding: UTF-8
servlet:
content-type: text/html
prefix: classpath:/templates
suffix: .html
resources:
chain:
strategy:
content:
enabled: true
paths: /**
为了系统整体性,封装了一个ResultEntity(返回结果实体类)
public class ResultEntity {
/*结果码*/
private String resultCode;
/*操作信息*/
private String operMessage;
/*异常信息*/
private String exceptionMessage;
/*返回对象*/
private Object resultObject;
/*返回对象数组*/
private Object[] resultArray;
/*返回List*/
private List<?> resultList;
/*返回Map,key为String,value为对象*/
private Map<String,Object> resultObjMap;
/*返回Map,key为String,value为List*/
private Map<String,List<?>> resultListMap;
/*返回Map,key为对象,value为List*/
private Map<Object,List<?>> resultObjectListMap;
public String getResultCode() {
return resultCode;
}
public void setResultCode(String resultCode) {
this.resultCode = resultCode;
}
public String getOperMessage() {
return operMessage;
}
public void setOperMessage(String operMessage) {
this.operMessage = operMessage;
}
public String getExceptionMessage() {
return exceptionMessage;
}
public void setExceptionMessage(String exceptionMessage) {
this.exceptionMessage = exceptionMessage;
}
public Object getResultObject() {
return resultObject;
}
public void setResultObject(Object resultObject) {
this.resultObject = resultObject;
}
public Object[] getResultArray() {
return resultArray;
}
public void setResultArray(Object[] resultArray) {
this.resultArray = resultArray;
}
public List<?> getResultList() {
return resultList;
}
public void setResultList(List<?> resultList) {
this.resultList = resultList;
}
public Map<String, Object> getResultObjMap() {
return resultObjMap;
}
public void setResultObjMap(Map<String, Object> resultObjMap) {
this.resultObjMap = resultObjMap;
}
public Map<String, List<?>> getResultListMap() {
return resultListMap;
}
public void setResultListMap(Map<String, List<?>> resultListMap) {
this.resultListMap = resultListMap;
}
public Map<Object, List<?>> getResultObjectListMap() {
return resultObjectListMap;
}
public void setResultObjectListMap(Map<Object, List<?>> resultObjectListMap) {
this.resultObjectListMap = resultObjectListMap;
}
}
为了方便传值,添加一个将实体类转化为Json实体的属性。
public JSONObject toJSON(){
JSONObject jsonObject = new JSONObject();
return jsonObject.fromObject(this);
}
需要导包net.sf.json.JSONObject,添加如下依赖即可:
<dependency>
<groupId>net.sf.ezmorph</groupId>
<artifactId>ezmorph</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.2.3</version>
<classifier>jdk15</classifier><!-- 指定jdk版本 -->
</dependency>
代码逻辑
前端逻辑:
以添加和编辑角色(role)为例,其他类似。
<div class="role_box" style="display: none">
<form action="#">
<div class="step clearfix">
<div class="items">
<input type="hidden" id="roleId" name="roleId" value="-1">
<div class="item clearfix">
<div class="label"> 角色名:</div>
<div class="value">
<input type="text" class="text" name="roleName" value="" id="roleName" autocomplete="off">
</div>
</div>
<div class="item clearfix">
<div class="label">角色描述:</div>
<div class="value">
<textarea class="textarea" name="roleInfo" id="roleInfo"></textarea>
</div>
</div>
<input type="button" name="submit" value=" 确定 " class="button clearfix" id="submitBtn">
</div>
</div>
</form>
</div>
在表单中设置roleId为隐藏项,其默认值为-1。正常情况下,该表单是隐藏的,当点击"新增"时,表单呈现,但不改变roleId的值。当点击"编辑"时,传入的参数为当前对象(json类型),同时将roleId的值赋值为当前对象的roleId。
function editRole(role){
$(".role_box").show();
$(".role_box").css({"position":"fixed","top":"0","right":"0",
"bottom":"0","left":"0","margin":"auto","z-index":"100"});
console.info("id: "+role.columnId+" ,name: "+role.columnName);
$("#roleId").val(role.roleId);
$("#roleName").val(role.roleName);
$("#roleInfo").val(role.roleInfo);
};
点击表单提交时,在js判断中,当roleId==-1时,执行添加操作(/admin/addRole.asy);否则,执行编辑操作(/admin/editRole.asy)
$("#submitBtn").click(
function(){
var roleId = $("#roleId").val().trim();
var roleName = $("#roleName").val().trim();
var roleInfo = $("#roleInfo").val().trim();
var creatorName = 'admin';
console.info("roleId:"+roleId+" ,roleName:"+roleName+" ,roleInfo:"+roleInfo);
if(roleName == "" || roleInfo == ""){
alert("输入的内容不能为空!!!")
}else{
if(roleId == -1){
$.ajax({
url: [[@{/admin/addRole.asy}]],
type: 'post',
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify({roleName : roleName,roleInfo : roleInfo,creatorName : creatorName}),
async: true,
success: function(data){
if(data != null){
alert(data.hintMsg);
if(data.operFlag == true){
window.location.reload();
}else{
$(".role_box").hide();
}
}
}
});
}else{
$.ajax({
url: [[@{/admin/editRole.asy}]],
type: 'post',
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify({roleId : roleId,roleName : roleName,roleInfo : roleInfo,creatorName : creatorName}),
async: true,
success: function(data){
if(data != null){
alert(data.hintMsg);
if(data.operFlag == true){
window.location.reload();
}else{
$(".column_box").hide();
}
}
}
});
}
}
}
);
具体的数据插入及数据编辑我就不细说了,我这里只说思路。
关于我
可以扫描关注下面的公众号(公众号:猿类进化论)