共计 21865 个字符,预计需要花费 55 分钟才能阅读完成。
1 角色治理设计说明
1.1 业务设计说明
本模块次要实现的是企业外部角色 (岗位) 的治理, 能够在增加角色时, 为角色分配资源拜访权限, 最初将角色再调配给用户,图所示:
基于对表的设计,其数据逻辑关系的展现,如图所示:
角色表设计脚本如下:
CREATE TABLE `sys_roles` (`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(100) DEFAULT NULL COMMENT '角色名称',
`note` varchar(500) DEFAULT NULL COMMENT '备注',
`createdTime` datetime DEFAULT NULL COMMENT '创立工夫',
`modifiedTime` datetime DEFAULT NULL COMMENT '批改工夫',
`createdUser` varchar(20) DEFAULT NULL COMMENT '创立用户',
`modifiedUser` varchar(20) DEFAULT NULL COMMENT '批改用户',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=46 DEFAULT CHARSET=utf8 COMMENT='角色';
菜单与角色的关系表脚本设计如下:
CREATE TABLE `sys_role_menus` (`id` int(11) NOT NULL AUTO_INCREMENT,
`role_id` int(11) DEFAULT NULL COMMENT '角色 ID',
`menu_id` int(11) DEFAULT NULL COMMENT 'ID',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='角色与菜单对应关系';
用户与角色关系表设计脚本如下:
CREATE TABLE `sys_user_roles` (`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL COMMENT '用户 ID',
`role_id` int(11) DEFAULT NULL COMMENT '角色 ID',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='用户与角色对应关系';
1.2 原型设计说明
基于用户需要,通过动态页面为用户出现角色模块的根本需要。当在主页点击角色治理时,出现角色列表页面,如图所示。
在列表页面点击增加按钮时,出现角色编辑页面, 如图所示.
在列表页面点击编辑按钮时,出现角色编辑页面,如图所示。
阐明: 如果客户对此原型进行了确认, 后续则能够基于此原型进行研发。
1.3 API 设计说明
角色治理业务后盾 API 分层架构及调用关系如图所示:
阐明:分层目标次要将简单问题简单化,实现各司其职,各尽所能。
2 角色治理列表页面出现
2.1 业务时序剖析
角色列表页面,其加载时序剖析,如图所示:
2.2 服务端实现
2.2.1 Controller 实现
▪ 业务形容与设计实现
基于角色治理的申请业务,在 PageController 中增加返回角色页面相干办法。
▪ 要害代码设计与实现
查看 PageController 中是否有返回 UI 页面的办法,有则无需增加。例如:
@RequestMapping("{module}/{moduleUI}")
public String doModuleUI(@PathVariable String moduleUI) {return "sys/"+moduleUI;}
2.3 客户端实现
2.3.1 首页菜单事件处理
▪ 业务形容与设计实现
首先筹备角色列表页面(/templates/pages/sys/role_list.html),而后在 starter.html 页面中点击菜单治理时异步加载角色列表页面。
▪ 要害代码设计与实现
找到我的项目中的 starter.html 页面,页面加载实现当前,注册菜单治理项的点击事件,当点击角色治理时,执行事件处理函数。要害代码如下:
$(function(){
…
doLoadUI("load-role-id","role/role_list")
})
function doLoadUI(id,url){$("#"+id).click(function(){$("#mainContentId").load(url);
});
}
其中,load 函数为 jquery 中的 ajax 异步申请函数。
2.3.2 角色列表页面
▪ 业务形容与设计实现
本页面出现角色信息时要以分页模式进行出现。
▪ 要害代码设计与实现:
参考 sys_role.html 文件内容。
3 角色治理列表数据出现
3.1 数据架构剖析
角色列表页面加载实现,启动角色数据异步加载操作,本次角色列表页面要以分页模式出现角色信息,其数据查问时,数据的封装及传递过程,如图所示。
阐明:本模块将从数据库查问到的角色数据封装到 SysRole 对象,一行记录一个 SysRole 对象。
角色数据分页查问时, 其时序剖析如图所示:
3.2 服务端要害业务及代码实现
3.2.1 Entity 类实现
▪ 业务形容及设计实现
构建实体对象(POJO)封装从数据库查问到的记录,一行记录映射为内存中一个的这样的对象。对象属性定义时尽量与表中字段有肯定的映射关系,并增加对应的 set/get/toString 等办法,便于对数据进行更好的操作。
▪ 要害代码剖析及实现
package com.cy.pj.sys.entity;
import java.io.Serializable;
import java.util.Date;
public class SysRole implements Serializable{
private static final long serialVersionUID = -356538509994150709L;
private Integer id;
private String name;
private String note;
private Date createdTime;
private Date modifiedTime;
private String createdUser;
private String modifiedUser;
public Integer getId() {return id;}
public void setId(Integer id) {this.id = id;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public String getNote() {return note;}
public void setNote(String note) {this.note = note;}
public Date getCreatedTime() {return createdTime;}
public void setCreatedTime(Date createdTime) {this.createdTime = createdTime;}
public Date getModifiedTime() {return modifiedTime;}
public void setModifiedTime(Date modifiedTime) {this.modifiedTime = modifiedTime;}
public String getCreatedUser() {return createdUser;}
public void setCreatedUser(String createdUser) {this.createdUser = createdUser;}
public String getModifiedUser() {return modifiedUser;}
public void setModifiedUser(String modifiedUser) {this.modifiedUser = modifiedUser;}
}
阐明:通过此对象除了能够封装从数据库查问的数据,还能够封装客户端申请数据,实现层与层之间数据的传递。
3.2.2 Dao 接口实现
▪ 业务形容及设计实现
通过数据层对象,基于业务层参数数据查问角色记录总数以及以后页面要出现的角色信息。
▪ 要害代码剖析及实现:
第一步:定义角色数据层接口对象,通过将此对象保障给业务层以提供角色数据操作。代码如下:
@Mapper
public interface SysRoleDao {}
第二步:在 SysRoleDao 接口中增加 getRowCount 办法用于按条件统计记录总数。代码如下:
int getRowCount(@Param("name") String name);
第三步:在 SysRoleDao 接口中增加 findPageObjects 办法,基于此办法实现当前页记录的数据查问操作。代码如下:
List<SysRole> findPageObjects(@Param("name")String name,
@Param("startIndex")Integer startIndex,
@Param("pageSize")Integer pageSize);
阐明:
1) 当 DAO 中办法参数多余一个时尽量应用 @Param 注解进行润饰并指定名字,而后再 Mapper 文件中便能够通过相似 #{username}形式进行获取,否则只能通过#{arg0},#{arg1}或者#{param1},#{param2}等形式进行获取。
2) 当 DAO 办法中的参数利用在动静 SQL 中时无论多少个参数,尽量应用 @Param 注解进行润饰并定义。
3.2.3 Mapper 文件实现
▪ 业务形容及设计实现
基于 Dao 接口创立映射文件,在此文件中通过相干元素 (例如 select) 形容要执行的数据操作。
▪ 要害代码设计及实现
第一步:在映射文件的设计目录中增加 SysRoleMapper.xml 映射文件,代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cy.pj.sys.dao.SysRoleDao">
</mapper>
第二步:在映射文件中增加 sql 元素实现,SQL 中的共性操作,代码如下:
<sql id="queryWhereId">
<where>
<if test="name!=null and name!=''">
name like concat("%",#{name},"%")
</if>
</where>
</sql>
第三步:在映射文件中增加 id 为 getRowCount 元素,按条件统计记录总数,代码如下:
<select id="getRowCount"
resultType="int">
select count(*)
from sys_roles
<include refid="queryWhereId"/>
</select>
第四步:在映射文件中增加 id 为 findPageObjects 元素,实现分页查问。代码如下:
<select id="findPageObjects"
resultType="com.cy.pj.sys.entity.SysRole">
select *
from sys_roles
<include refid="queryWhereId"/>
order by createdTime desc
limit #{startIndex},#{pageSize}
</select>
思考:
1) 动静 sql: 基于用于需要动静拼接 SQL
2) Sql 标签元素的作用是什么? 对 sql 语句中的共性进行提取, 以遍实现更好的复用.
3) Include 标签的作用是什么? 引入应用 sql 标签定义的元素
3.2.4 Service 接口及实现类
▪ 业务形容与设计实现
在角色分页查问中,业务层对象次要负责对业务数据进行校验,并借助数据层对象实现数据的分页查问操作。
▪ 要害代码设计及实现
第一步:定义角色业务接口及办法,裸露外界对角色业务数据的拜访,其代码参考如下:
package com.cy.pj.sys.service;
public interface SysRoleService {
PageObject<SysRole> findPageObjects(String name,Integer pageCurrent);
}
第二步:定义角色业务接口实现类,并增加角色业务数据分页查问操作的具体实现, 其代码参考如下:
package com.cy.pj.sys.service.impl;
import org.springframework.util.StringUtils;
@Service
public class SysRoleServiceImpl implements SysRoleService {
@Autowired
private SysRoleDao sysRoleDao;
@Override
public PageObject<SysRole> findPageObjects(String name,Integer pageCurrent) {
//1. 对参数进行校验
if(pageCurrent==null||pageCurrent<1)
throw new IllegalArgumentException("以后页码值有效");
//2. 查问总记录数并进行校验
int rowCount=sysRoleDao.getRowCount(name);
if(rowCount==0)
throw new ServiceException("没有找到对应记录");
//3. 查问当前页记录
int pageSize=2;
int startIndex=(pageCurrent-1)*pageSize;
List<SysRole> records=
sysRoleDao.findPageObjects(name,
startIndex, pageSize);
//4. 对查问后果进行封装并返回
return new PageObject<>(pageCurrent, pageSize,
rowCount, records);
}
}
3.2.5 Controller 类实现
▪ 业务形容与设计实现
管制层对象次要负责申请和响应数据的解决,例如,本模块通过业务层对象执行业务逻辑,再通过 VO 对象封装响应后果(次要对业务层数据增加状态信息),最初将响应后果转换为 JSON 格局的字符串响应到客户端。
▪ 要害代码设计与实现
定义 Controller 类,并将此类对象应用 Spring 框架中的 @RestController 注解进行标识,示意此类对象要交给 Spring 治理。而后基于 @RequestMapping 注解为此类定义根门路映射。代码参考如下:
package com.cy.pj.sys.controller;
@RequestMapping("/role/")
@RestController
public class SysRoleController {private SysRoleService sysRoleService;}
在 Controller 类中增加菜单查询处理办法,代码参考如下:
@RequestMapping("doFindPageObjects")
public JsonResult doFindPageObjects(String name,Integer pageCurrent) {
return new JsonResult(
sysRoleService.findPageObjects(name,
pageCurrent));
}
3.3 客户端要害业务及代码实现
3.3.1 菜单列表信息出现
▪ 业务形容与设计实现
角色分页页面加载实现当前,向服务端发动异步申请加载角色信息,当角色信息加载实现须要将角色信息、分页信息出现到列表页面上。
▪ 要害代码设计与实现
异步申请处理函数,要害代码如下:
第一步:分页页面加载实现,向服务端发动异步申请,代码参考如下:
$(function(){
// 为什么要将 doGetObjects 函数写到 load 函数对应的回调外部。$("#pageId").load("doPageUI", doGetObjects)
});
第二步:定义异步申请处理函数,代码参考如下:
function doGetObjects(){
//debugger;// 断点调试
//1. 定义 url 和参数
var url="role/doFindPageObjects"
var params={"pageCurrent":1};//pageCurrent=2
//2. 发动异步申请
$.getJSON(url,params,function(result){doHandleResponseResult(result);
}
);// 非凡的 ajax 函数
}
第三步:定义回调函数,解决服务端的响应后果。代码如下:
function doHandleResponseResult (result){ //JsonResult
if(result.state==1){//ok
// 更新 table 中 tbody 外部的数据
doSetTableBodyRows(result.data.records);// 将数据出现在页面上
// 更新页面 page.html 分页数据
doSetPagination(result.data); // 此办法写到 page.html 中
}else{alert(result.msg);
}
}
第四步:将异步响应后果出现在 table 的 tbody 地位。代码参考如下:
function doSetTableBodyRows(records){
//1. 获取 tbody 对象,并清空对象
var tBody=$("#tbodyId");
tBody.empty();
//2. 迭代 records 记录,并将其内容追加到 tbody
for(var i in records){
//2.1 构建 tr 对象
var tr=$("<tr></tr>");
//2.2 构建 tds 对象
var tds=doCreateTds(records[i]);
//2.3 将 tds 追加到 tr 中
tr.append(tds);
//2.4 将 tr 追加到 tbody 中
tBody.append(tr);
}
}
第五步:创立每行中的 td 元素,并填充具体业务数据。代码参考如下:
function doCreateTds(row,i){
var tds=
"<td>"+(parseInt(i)+1)+"</td>"+
"<td>"+row.name+"</td>"+
"<td>"+row.note+"</td>"+
"<td>"+new Date(row.createdTime).toLocaleString()+"</td>"+
"<td>"+new Date(row.modifiedTime).toLocaleString()+"</td>"+
"<td>"+row.createdUser+"</td>"+
"<td>"+row.modifiedUser+"</td>"+
"<td><a class='btn-delete'>delete</a>"+
" <a class='btn-update'>update</a></td>";
return tds;
}
4 角色治理删除操作实现
4.1 业务时序剖析
基于用户在列表页面上抉择的的用户记录 ID,执行删除操作,本次删除业务实现中,首先要基于 id 删除角色菜单关系数据,而后基于 id 删除用户角色关系数据,最初删除角色本身信息,如图所示:
4.2 服务端要害业务及代码实现
4.2.1 Dao 接口实现
▪ 业务形容及设计实现
数据层基于业务层提交的角色记录 id,先删除角色相干的关系数据,而后删除角色本身记录信息。
▪ 要害代码设计及实现:
第一步:在创立 SysRoleMenuDao 并定义基于角色 id 删除关系数据的办法,要害代码如下:
public interface SysRoleMenuDao {int deleteObjectsByRoleId(Integer roleId);
}
第二步:创立 SysUserRoleDao 并定义基于角色 id 删除关系数据的办法,要害代码如下:
public interface SysUserRoleDao {int deleteObjectsByRoleId(Integer roleId);
}
第三步:在 SysRoleDao 中增加基于菜单 id 删除角色记录的办法。代码参考如下:
int deleteObject(Integer id);
4.2.2 Mapper 文件实现
▪ 业务形容及设计实现
在 SysRoleMenuDao,SysUserRoleDao,SysRoleDao 接口对应的映射文件中增加用于执行删除业务的 delete 元素,而后在元素外部定义具体的 SQL 实现。
▪ 要害代码设计与实现
第一步:创立 SysRoleMenuMapper.xml 文件并增加基于菜单 id 删除关系数据的元素,要害代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cy.pj.sys.dao.SysRoleMenuDao">
<delete id="deleteObjectsByRoleId"
parameterType="int">
delete from sys_role_menus
where role_id=#{roleId}
</delete>
</mapper>
第二步:在 SysUserRoleMapper.xml 文件中增加基于 id 删除用户角色关系数据的元素,要害代码如下:
<delete id="deleteObjectsByRoleId">
delete from sys_user_roles
where role_id=#{roleId}
</delete>
第三步:在 SysRoleMapper.xml 文件增加 delete 元素, 基于角色 id 删除角色本身记录信息,要害代码如下:
<delete id="deleteObject">
delete from sys_roles
where id =#{id}
</delete>
4.2.3 Service 接口及实现类
▪ 业务形容与设计实现
在角色业务层定义用于执行角色删除业务的办法,首先通过办法参数接管管制层传递的角色 id,并对参数 id 进行校验。而后基于角色 id 删除角色菜单关系数据,用户角色关系数据。最初删除本身记录信息后并返回业务执行后果。
▪ 要害代码设计与实现
第一步:在 SysRoleService 接口中,增加基于 id 进行角色删除的办法。要害代码如下:
int deleteObject(Integer id);
第二步:在 SysRoleServiceImpl 实现类中注入 SysRoleMenuDao,SysUserRoleDao 相干对象。要害代码如下:
@Autowired
private SysRoleMenuDao sysRoleMenuDao;
@Autowired
private SysUserRoleDao sysUserRoleDao;
第二步:在 SysRoleServiceImpl 实现类中增加删除业务的具体实现。要害代码如下:
@Override
public int deleteObject(Integer id) {
//1. 验证数据的合法性
if(id==null||id<=0)
throw new IllegalArgumentException("请先抉择");
//3. 基于 id 删除关系数据
sysRoleMenuDao.deleteObjectsByRoleId(id);
sysUserRoleDao.deleteObjectsByRoleId(id);
//4. 删除角色本身
int rows=sysRoleDao.deleteObject(id);
if(rows==0)
throw new ServiceException("此记录可能曾经不存在");
//5. 返回后果
return rows;
}
4.2.4 Controller 类实现
▪ 业务形容与设计实现
在角色管制层对象中,增加用于解决角色删除申请的办法。首先在此办法中通过形参接管客户端提交的数据,而后调用业务层对象执行删除操作,最初封装执行后果,并在运行时将响应对象转换为 JSON 格局的字符串,响应到客户端。
▪ 要害代码设计与实现
第一步:在 SysRoleController 中增加用于执行删除业务的办法。代码如下:
@RequestMapping("doDeleteObject")
public JsonResult doDeleteObject(Integer id){sysRoleService.deleteObject(id);
return new JsonResult("delete ok");
}
第二步:启动 tomcat 进行拜访测试,关上浏览器输出如下网址:
http://localhost/role/doDeleteObject?id=10
4.3 客户端要害业务及代码实现
4.3.1 菜单列表页面事件处理
▪ 业务形容及设计实现
用户在页面上首先抉择要删除的元素,而后点击删除按钮,将用户抉择的记录 id 异步提交到服务端,最初在服务端执行角色的删除动作。
▪ 要害代码设计与实现
第一步:页面加载实现当前,在删除按钮上进行点击事件注册。要害代码如下:
$(".input-group-btn")
.on("click",".btn-delete",doDeleteObject)
第二步:定义删除操作对应的事件处理函数。要害代码如下:
function doDeleteObject(){//1. 获取选中的值(分页显示记录时在 tr 上要绑定 id 的值)
var id=$(this).parents("tr").data("id");
//2. 构建参数对象
var params={id:id};
//3. 异步申请执行删除
var url="role/doDeleteObject";
$.post(url,params,function(result){if(result.state==1){alert(result.message);
doGetObjects();}else{alert(result.message);
}
})
}
5 角色增加页面出现
5.1 业务时序剖析
点击角色列表上的增加按钮,其时序剖析,如图所示:
5.2 筹备角色编辑页面
筹备角色编辑页面(/templates/pages/sys/role_edit.html)
5.3 角色编辑页面出现
▪ 业务形容与设计实现
在角色列表页面中点击增加按钮时,出现角色编辑页面。
▪ 要害代码设计与实现
第一步:角色列表事件注册,要害代码如下:
$(document).ready(function(){
...
$(".input-group-btn")
.on("click",".btn-add",doLoadEditUI);
});
第二步:定义角色列表页面增加按钮的事件处理函数,要害代码如下:
// 异步加载编辑页面
function doLoadEditUI(){
var title;
//hasClass 函数用于断定对象中是否蕴含某个款式
if($(this).hasClass("btn-add")){title="角色增加";}else{title="角色批改";}
loadPageUI(url);
}
5.4 角色编辑页面事件处理
▪ 业务形容与设计实现
角色编辑页面加载实现,异步加载菜单信息并出现在页面上。
▪ 要害代码设计与实现
第一步:页面中引入 zTree 相干 JS
第二步:页面上定义 zTree 初始配置
var zTree;
var setting = {
data : {
simpleData : {
enable : true,
idKey : "id", // 节点数据中保留惟一标识的属性名称
pIdKey : "parentId", // 节点数据中保留其父节点惟一标识的属性名称
rootPId : null // 根节点 id
}
},
check:{
enable:true,
nocheckInherit:true
}
}
第三步:异步加载菜单信息并进行出现。
function doLoadSysMenus(){
var url="menu/doFindZtreeMenuNodes"
$.getJSON(url,function(result){if(result.state==1){
zTree=$.fn.zTree.init($("#menuTree"),setting,result.data);
}else{alert(result.message);
}
});
}
6 角色数据增加实现
6.1 数据根本架构剖析
用户在角色编辑页面输出数据,而后异步提交到服务端,其繁难数据传递根本架构,如图所示:
角色数据保留时,数据时序图剖析,
如图所示:
6.2 服务端要害业务及代码实现
6.2.1 DAO 接口定义
▪ 业务形容与设计实现
负责将用户提交的角色数据,长久化到数据库。
▪ 要害代码设计与实现
在 SysRoleDao 接口中定义数据长久化办法:
int insertObject(SysRole entity);
SysRoleMenuDao 接口中办法定义(不存在则创立)
int insertObjects(@Param("roleId")Integer roleId,
@Param("menuIds")Integer[] menuIds);
6.2.2 Mapper 映射文件定义
▪ 业务形容与设计实现
基于 SysRoleDao 中办法的定义,编写用于实现角色增加的 SQL 元素。
▪ 要害代码设计与实现
第一步: 在 SysRoleMapper.xml 中增加 insertObject 元素,用于写入菜单信息。其中 useGeneratedKeys 示意应用 insert 操作的自增主键值,keyProperty 示意将获取的自增主键值赋值给参数对象的 id 属性,要害代码如下:
<insert id="insertObject"
parameterType="com.cy.pj.sys.entity.SysRole"
useGeneratedKeys="true"
keyProperty="id">
insert into sys_roles
(id,name,note,createdTime,modifiedTime,
createdUser,modifiedUser)
values
(null,#{name},#{note},now(),now(),
#{createdUser},#{modifiedUser})
</insert>
第二步: 在 SysRoleMenuMapper 中元素定义,要害代码如下:
<insert id="insertObjects">
insert into sys_role_menus
(role_id,menu_id)
values
<foreach collection="menuIds"
separator=","
item="item">
(#{roleId},#{item})
</foreach>
</insert>
6.2.3 Service 接口定义及实现
▪ 业务形容与设计实现
基于管制层申请,调用数据层对象将角色以及对应的菜单信息写入到数据库中。
▪ 要害代码设计与实现
第一步:在 SysRoleService 接口中,增加用于保留角色对象的办法。要害代码如下:
int saveObject(SysRole entity,Integer[]menuIds);
第二步:在 SysRoleServiceImpl 类中,实现菜单保留操作。要害代码如下:
@Override
public int saveObject(SysRole entity, Integer[] menuIds) {
//1. 参数有效性校验
if(entity==null)
throw new IllegalArgumentException("保留对象不能为空");
if(StringUtils.isEmpty(entity.getName()))
throw new IllegalArgumentException("角色名不容许为空");
if(menuIds==null||menuIds.length==0)
throw new ServiceException("必须为角色调配权限");
//2. 保留角色本身信息
int rows=sysRoleDao.insertObject(entity);
//3. 保留角色菜单关系数据
sysRoleMenuDao.insertObjects(entity.getId(), menuIds);
//4. 返回业务后果
return rows;
}
6.2.4 Controller 类定义
▪ 业务形容与设计实现
接管客户端提交的菜单数据,并对其进行封装,而后调用业务层对象进行业务解决,最初将业务层处理结果响应到客户端。
▪ 要害代码设计与实现
定义 Controller 办法,借助此办法解决保留角色数据申请和响应逻辑。要害代码如下:
@RequestMapping("doSaveObject")
@ResponseBody
public JsonResult doSaveObject(SysRole entity,Integer[] menuIds){sysRoleService.saveObject(entity,menuIds);
return new JsonResult("save ok");
}
6.3 客户端要害业务及代码实现
6.3.1 页面 cancel 按钮事件处理
▪ 业务形容与设计实现
点击页面 cancel 按钮时,加载菜单那列表页面。
▪ 要害代码设计与实现
第一步:事件注册(页面加载实现当前)
$(".box-footer")
.on("click",".btn-cancel",doCancel)
第二步:事件处理函数定义
function doCancel(){
var url="role/role_list";
$("#mainContentId").load(url);
}
6.3.2 页面 Save 按钮事件处理
▪ 业务形容与设计实现
点击页面 save 按钮时,将页面上输出的菜单信息提交到服务端。
▪ 要害代码设计与实现
第一步:事件注册(页面加载实现当前)。
$(".box-footer")
.on("click",".btn-save",doSaveOrUpdate)
第二步:Save 按钮事件处理函数定义。要害代码如下:
function doSaveOrUpdate(){
//1. 获取表单数据
var params=doGetEditFormData();
//2. 异步提交表单数据
var insertUrl="role/doSaveObject";
$.post(insertUrl,params,function(result){if(result.state==1){alert(result.message);
doCancel();}else{alert(result.message);
}
});
}
第三步:表单数据获取及封装函数定义。要害代码如下:
// 获取表单数据
function doGetEditFormData(){
var params={name:$("#nameId").val(),
note:$("#noteId").val()}
// 获取选中的 node 节点
var menuIds=[];
var checkedNodes=zTree.getCheckedNodes(true);//zTree
for(var i in checkedNodes){console.log(checkedNodes[i]);
menuIds.push(checkedNodes[i].id)
}
params.menuIds=menuIds.toString();//(1,2,3,4,5)
return params;
}
7 角色批改页面数据出现
7.1 业务时序剖析
点击角色列表页面的编辑按钮,其时序剖析,如图所示:
7.2 服务端要害业务及代码实现
外围业务:在角色列表页面点击批改按钮时, 基于 id 进行角色信息的查问, 在查问角色信息时将角色信息与对应的菜单关系数据封装到到一个值对象,而后传递到客户端在批改页面进行出现,如图所示。
7.2.1 VO 定义
▪ 业务形容及设计实现
构建值对象(VO),用于封装从数据库查问到的角色菜单记录,并增加对应的 set/get/toString 等办法,便于对数据进行更好的操作。
▪ 要害代码剖析及实现
package com.cy.pj.sys.vo;
import java.util.List;
import com.cy.pj.sys.entity.SysRole;
/**
* VO:通过此对象封装角色以及角色对应的菜单 id
* @author ta
*/
public class SysRoleMenuVo implements Serializable{
private static final long serialVersionUID = 3609240922718345518L;
private Integer id;
private String name;
private String note;
/** 角色对应的菜单 id*/
private List<Integer> menuIds;
public Integer getId() {return id;}
public void setId(Integer id) {this.id= id;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public String getNote() {return note;}
public void setName(String note) {this.note = note;}
public List<Integer> getMenuIds() {return menuIds;}
public void setMenuIds(List<Integer> menuIds) {this.menuIds = menuIds;}
}
7.2.2 DAO 接口定义
▪ 业务形容与设计实现
负责基于 id 执行角色数据的查问操作。
▪ 要害代码设计与实现
在 SysRoleDao 接口中定义数据长久化办法:
<select id="findObjectById"
resultMap="sysRoleMenuVo">
select id,name,note
from sys_roles
where id=#{id}
</select>
7.2.3 Mapper 文件定义
▪ 业务形容与设计实现
基于 SysRoleDao 中 findObjectById 办法的定义,在映射文件中增加对应的角色查问元素。
▪ 要害代码设计与实现
第一步:在 SysRoleMapper.xml 中增加 findObjectById 元素,要害代码如下:
<select id="findObjectById"
resultMap="sysRoleMenuVo">
select id,name,note
from sys_roles
where id=#{id}
</select>
第二步:在 SysRoleMapper.xml 中增加第一步中 resultMap 属性定义的后果映射元素,要害代码如下:
<!-- resultMap 个别用于自定义映射或一些关联查问中 -->
<resultMap type="com.cy.pj.sys.vo.SysRoleMenuVo"
id="sysRoleMenuVo">
<!-- 如果基于 id 做再次执行查问,又心愿将 id 值存储到值对象,能够对 id 进行专门映射 -->
<id property="id" column="id"/>
<!-- collection 个别利用于 one2many 查问 -->
<collection property="menuIds"
select="com.cy.pj.sys.dao.SysRoleMenuDao.findMenuIdsByRoleId"
column="id">
</collection>
</resultMap>
第三步:在 SysRoleMenuMapper.xml 中增加第二步中 collection 元素外部 select 属性对应的查问元素。要害代码如下:
<select id="findMenuIdsByRoleId"
resultType="int">
select menu_id
from sys_role_menus
where role_id=#{id}
</select>
7.2.4 Service 接口定义及实现
▪ 业务形容与设计实现
基于管制层申请,调用数据层办法,查问对应的角色及相干信息。
▪ 要害代码设计与实现
第一步:在 SysRoleService 接口中,增加基于 id 查问对应角色及相干信息的办法。要害代码如下:
SysRoleMenuVo findObjectById(Integer id) ;
第二步:在 SysRoleService 接口对应的实现类 SysRoleServiceImpl 中增加 findObjectById 的具体实现。要害代码如下:
@Override
public SysRoleMenuVo findObjectById(Integer id) {
//1. 合法性验证
if(id==null||id<=0)
throw new IllegalArgumentException("id 的值不非法");
//2. 执行查问
SysRoleMenuVo result=sysRoleDao.findObjectById(id);
//3. 验证后果并返回
if(result==null)
throw new ServiceException("此记录曾经不存在");
return result;
}
7.2.5 Controller 类定义
▪ 业务形容与设计实现
基于管制层申请,调用数据层办法,查问对应的角色及相干信息。
▪ 要害代码设计与实现
在 SysRoleController 类中定义基于角色 ID 查问角色的办法。要害代码如下:
@RequestMapping("doFindObjectById")
public JsonResult doFindObjectById(Integer id){return new JsonResult(sysRoleService.findObjectById(id));
}
7.3 客户端要害业务及代码实现
7.3.1 列表页面批改按钮事件处理
▪ 业务形容与设计实现
在角色批改按钮上进行事件注册,点击页面批改按钮时,基于角色 id 向服务端发动异步申请获取角色相干数据,而后加载批改页面。
▪ 要害代码设计与实现
第一步:页面加载实现,进行批改按钮事件注册,要害代码如下:
$(function(){
…
// 如果是批改
$(".input-group-btn")
.on("click","btn-update",doLoadEditUI);
});
第二步:批改按钮事件处理函数定义或批改,要害代码如下:
function doLoadEditUI(){// 定义页面题目(内容可能是增加角色也可能是批改角色)
var title;
// 断定要执行的操作(是增加还是批改)
if($(this).hasClass("btn-add")){
title="增加角色";
doLoadPageUI(title);
}else{
title="批改角色";
// 获取以后行的 id 值
var id=$(this).parents("tr").data("id");
// 依据 id 查找记录,断定记录是否存在
var url="role/doFindObjectById";
var data={"id":id};
$.getJSON(url,data,function(result){if(result.state==1){$("#mainContentId").data("data",result.data)
loadPageUI(title);
}else{alert(result.message);
}
});
}
}
第三步:定义或批改加载编辑页面的办法。要害代码如下:
function doLoadPageUI(title){$("#mainContentId")
.load("role/role_edit",function(){$(".box-title").html(title);
});
}
7.3.2 编辑页面菜单数据出现
▪ 业务形容与设计实现
页面加载实现,获取编辑页面数据,而后在页面指定地位进行数据出现数据。
▪ 要害代码设计与实现
第一步:在角色编辑页面中,菜单数据加载实现当前,获取角色编辑页面中须要的表单数据,而后进行页面数据初始化。要害代码如下:
function doLoadSysMenus(){
var url="menu/doFindZTreeNodes"
$.getJSON(url,function(result){if(result.state==1){
zTree=$.fn.zTree.init($("#menuTree"),setting,result.data);
var data=$("#mainContentId").data("data");
if(data){doInitEditFormData(data);
}
}else{alert(result.message);
}
})
}
第三步:定义编辑页面数据初始化办法。要害代码如下:
function doInitEditFormData(data){$("#nameId").val(data.name);
$("#noteId").val(data.note);
// 开展所有节点
zTree.expandAll(true);
// 勾选角色所领有的菜单
var menuIds = data.menuIds;
for(var i=0; i<menuIds.length; i++) {// 获取 key 为 id 值为 menuIds[i]的节点
var node = zTree.getNodeByParam("id",menuIds[i]);
// 选中以后节点
zTree.checkNode(node,true,false);
}
}
8 角色数据更新实现
8.1 业务时序剖析
点击角色编辑页面的更新按钮,其时序剖析,如图所示:
8.2 服务端要害业务及代码实现
8.2.1 DAO 接口实现
▪ 业务形容与设计实现
获取角色编辑页面数据,而后异步提交到服务端,将角色信息以及角色对应的菜单关系数据更新到数据库。
▪ 要害代码设计与实现
在 SysRoleDao 接口中增加数据更新办法,要害代码如下:
int updateObject(SysRole entity);
8.2.2 Mapper 文件定义
▪ 业务形容与设计实现
基于 SysRoleDao 中 updateObject 办法的定义,编写用于实现角色更新的 SQL 元素。
▪ 要害代码设计与实现
在 SysRoleMapper.xml 中增加 updateObject 元素,用于更新菜单信息。要害代码如下:
<update id="updateObject"
parameterType="com.cy.pj.sys.entity.SysRole">
update sys_roles
set
name=#{name},
note=#{note},
modifiedUser=#{modifiedUser},
modifiedTime=now()
where id=#{id}
</update>
8.2.3 Service 接口及实现
▪ 业务形容与设计实现
基于管制层申请,对数据进行校验并调用数据层对象将角色信息以及角色菜单关系数据更新到数据库中。
▪ 要害代码设计与实现
第一步:在 SysRoleService 接口中,增加用于更新角色对象的办法。要害代码如下:
int updateObject(SysRole entity,Integer[] menuIds)
第二步:在 SysRoleServiceImpl 类中,实现更新角色操作。要害代码如下:
@Override
public int updateObject(SysRole entity,Integer[] menuIds) {
//1. 合法性验证
if(entity==null)
throw new IllegalArgumentException("更新的对象不能为空");
if(entity.getId()==null)
throw new IllegalArgumentException("id 的值不能为空");
if(StringUtils.isEmpty(entity.getName()))
throw new IllegalArgumentException("角色名不能为空");
if(menuIds==null||menuIds.length==0)
throw new IllegalArgumentException("必须为角色指定一个权限");
//2. 更新数据
int rows=sysRoleDao.updateObject(entity);
if(rows==0)
throw new ServiceException("对象可能曾经不存在");
sysRoleMenuDao.deleteObjectsByRoleId(entity.getId());
sysRoleMenuDao.insertObject(entity.getId(),menuIds);
//3. 返回后果
return rows;
}
8.2.4 Controller 类定义
▪ 业务形容与设计实现
首先接管客户端提交的角色数据,并对其进行封装,而后调用业务层对象对角色信息进行更行更新,最初将业务层处理结果响应到客户端。
▪ 要害代码设计与实现
在 SysRoleController 类中定义更新角色的办法。要害代码如下:
@RequestMapping("doUpdateObject")
public JsonResult doUpdateObject(SysRole entity,
Integer[] menuIds){sysRoleService.updateObject(entity,menuIds);
return new JsonResult("update ok");
8.3 客户端要害业务及代码实现
8.3.1 编辑页面更新按钮事件处理
▪ 业务形容与设计实现
点击页面 save 按钮时,将页面上输出的角色编辑信息提交到服务端。
▪ 要害代码设计与实现
第一步:在角色编辑页面中定义获取角色编辑页面表单数据的函数,要害代码如下:
function doSaveOrUpdate(){
//1. 获取表单数据
var params=doGetEditFormData();
var rowData=$("#mainContentId").data("rowData");
//2. 定义 url
var insertUrl="menu/doSaveObject";
var updateUrl="menu/doUpdateObject";
var url=rowData?updateUrl:insertUrl;
if(rowData)params.id=rowData.id;
//3. 异步提交数据
$.post(url,params,function(result){if(result.state==1){alert(result.message);
doCancel();}else{alert(result.message);
}
});
}
第二步:定义或批改提交编辑页面表单数据办法,要害代码如下:
// 点击保留按钮时执行此办法
function doSaveOrUpdate(){//insert/update
// 获取表单数据
var params=doGetEditFormData();
// 如果以后页面.container-fluid 对象上绑定着值阐明是批改
var data=$("#mainContentId").data("data");
if(data){params.id=data.id;// 批改时表单数据中须要增加 id}
// 依据当前页面上是否绑定着值来定义 url
var insertUrl="role/doSaveObject";
var updateUrl="role/doUpdateObject";
var url=data?updateUrl:insertUrl;
// 异步提交数据
$.post(url,params,function(result){if(result.state==1){alert(result.message);
doCancel();}else{alert(result.message);
}
})
}
9 总结
9.1 重难点剖析
▪ 角色数据的删除操作?(关系表中数据的删除)
▪ 一对多数据的保留?(保留角色的同时也要保留角色和菜单的关系数据)
▪ 一对多数据的查问映射?(基于角色 id 查问角色信息并将对应的菜单信息也查问进去)
9.2 FAQ 剖析
▪ 角色与菜单之间是什么关系?(Many2Many)
▪ 角色与用户之间是什么关系?(Many2Many)
▪ 形容一下角色删除业务的实现?
▪ 形容一下角色增加业务的实现?
▪ 形容一下角色更新业务的实现?
▪ 角色和菜单的关系数据如何更新?
9.3 BUG 剖析
▪ 视图解析问题,如图所示:
问题剖析:
1) 查看对应的办法上是否增加 @ResponseBody 注解。
2) 查看管制层对象办法的映射门路配置是否正确。