权限管理子系统
角色模块

1. 角色列表页面呈现 1-3
1.1. 服务端实现 1-3
1.1.1. Controller实现 1-3
1.2. 客户端实现 1-3
1.2.1. 定义角色列表页面 1-3
1.2.2. 首页页面菜单事件处理 1-4
1.3. 角色分页div内容加载 1-4
2. 角色列表数据呈现 2-5
2.1. 服务端实现 2-5
2.1.1. Entity类实现 2-5
2.1.2. Dao接口实现 2-6
2.1.3. Mapper实现 2-7
2.1.4. Service层对象 2-9
2.1.5. Controller 实现 2-11
2.2. 客户端实现 2-11
2.2.1. 角色页面数据呈现 2-12
2.2.2. 列表页面role_list.html信息查询实现 2-14
3. 角色删除模块实现 3-15
3.1. 服务端实现 3-15
3.1.1. DAO实现 3-16
3.1.2. Mapper实现 3-17
3.1.3. Service实现 3-18
3.1.4. Controller实现 3-18
3.2. 客户端实现 3-19
3.2.1. 角色列表页面删除操作实现 3-19
4. 角色添加页面呈现 4-20
4.1. 服务端实现 4-20
4.1.1. 角色Controller对象的实现 4-20
4.2. 客户端实现 4-21
4.2.1. 角色列表添加按钮事件处理 4-21
4.2.2. 角色添加页面菜单信息呈现 4-21
5. 角色添加操作实现 5-22
5.1. 服务端实现 5-22
5.1.1. Dao实现 5-22
5.1.2. Mapper实现 5-23
5.1.3. Service实现 5-24
5.1.4. Controller实现 5-25
5.2. 客户端实现 5-26
5.2.1. 角色编辑页面按钮事件处理 5-26
6. 角色修改页面呈现 6-27
6.1. 服务端实现 6-27
6.1.1. Dao实现 6-27
6.1.2. Mapper实现 6-28
6.1.3. Service实现 6-29
6.1.4. Controller实现 6-30
6.2. 服务端实现(扩展) 6-30
6.2.1. VO定义 6-31
6.2.2. Dao实现 6-32
6.2.3. Mapper实现 6-32
6.2.4. Service实现 6-34
6.2.5. Controller实现 6-35
6.3. 客户端实现 6-35
6.3.1. 角色列表页面实现 6-35
6.3.2. 角色编辑页面实现 6-37
7. 角色修改操作实现 7-38
7.1. 服务端实现 7-38
7.1.1. Dao实现 7-38
7.1.2. Mapper实现 7-38
7.1.3. Service实现 7-40
7.1.4. Controller实现 7-40
7.2. 客户端实现 7-41
7.2.1. 角色编辑页面数据的更新 7-41
8. 总结 8-43
8.1. 重点和难点分析 8-43
8.2. 常见FAQ 8-43

角色列表页面呈现

服务端实现

Controller实现

业务描述
创建角色控制层对象,并添加相关返回具体view.
页面实现

  1. Controller类的创建

  2. 包名 com.db.sys.controller

  3. 类名 SysRoleController

  4. 映射 @RequestMapping(“/role/“)

  5. Controller 类中方法定义,并返回role_list页面

  6. 方法名 doRoleListUI

  7. 参数列表()

  8. 返回值 String

  9. 映射 @RequestMapping(“doRoleListUI”)

代码实现:

@Controller
@RequestMapping(“/role/“)
public class SysRoleController {
@RequestMapping(“doRoleListUI”)
public String doRoleListUI(){
return “sys/role_list”;
}
}

客户端实现

定义角色列表页面

在WEB-INF/pages/sys目录下定义role_list.html页面.

首页页面菜单事件处理

业务描述

1)在starter.html页面中注册角色管理的点击事件
2)在starter.html页面中定义事件处理函数,异步加载菜单列表页面

业务实现

  1. 在$(function(){})追加事件处理函数的调用loadUI()

关键代码实现:
$(function(){
doLoadUI(“load-role-id”,”role/doRoleListUI.do”);
});

角色分页div内容加载

页面描述
角色列表页面加载完成异步加载分页页面

业务实现
在role_list.html页面底部添加JS异步加载分页页面的实现

关键代码实现

$(function(){
$(“#pageId”).load(“doPageUI.do”);
})

角色列表数据呈现

服务端实现

时序图分析:
角色模块 - 图1

Entity类实现

业务描述:
定义实体封装从数据库查询的数据

业务实现
构建与sys_roles表对应的实体类型

  1. 包名 com.db.sys.entity

  2. 类名 SysRole(实现序列化接口,并定义序列化id)

  3. 属性 与表(sys_roles)中字段有对应关系

  4. 方法 set/get

关键代码实现:

public class SysRole implements Serializable{
private static final long serialVersionUID = -2113802202295967078L;
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;
}

}

Dao接口实现

业务描述:(核心-查询当前页显示的数据以及总记录数)

  1. 接收业务层参数数据

  2. 基于参数进行数据查询

  3. 将查询结果进行封装

  4. 将结果返回给业务层对象

业务实现:创建Dao接口并定义相关方法。

  1. Dao接口定义

  2. 包名: com.db.sys.dao

  3. 名字: SysRoleDao

  1. 方法定义:负责基于条件查询当前页数据

  2. 方法名:findPageObjects

  3. 参数列表:(String name,Integer startIndex,Integer pageSize)

  4. 返回值:List

  1. 方法定义:负责基于条件查询总记录数

  2. 方法名:getRowCount

  3. 参数列表:(String name)

  4. 返回值:int

思考:DAO中方法的参数在mapper中如何获取?

代码实现:

public interface SysRoleDao {
/
分页查询角色信息
@param startIndex 上一页的结束位置
*
@param pageSize 每页要查询的记录数
*
@return
*/
List findPageObjects(
@Param(“name”)String name,
@Param(“startIndex”)Integer startIndex,
@Param(“pageSize”)Integer pageSize);
/

查询记录总数
@return
/
*int
getRowCount(@Param(“name”)String name);

}

Mapper实现

业务描述

  1. 基于Dao接口创建映射文件

  2. 基于Dao方法在映射文件中创建映射元素建映射元素

业务实现:

  1. 创建映射文件

  2. 包名:mapper.sys

  3. 文件名:SysRoleMapper.xml

  4. 命名空间 com.db.sys.dao.SysRoleDao

  1. 创建映射元素实现翻页查询操作

  2. 元素名 select

  3. 元素id findPageObjects

  4. 参数类型 (不写)

  5. 结果类型 com.db.sys.entity.SysRole

  6. SQL定义 select * from sys_roles where name like ? limit ?,?

  1. 创建映射元素实现查询统计操作

  2. 元素名 select

  3. 元素id getRowCount

  4. 参数类型 (不写)

  5. 结果类型 int

  6. SQL定义 select count(*) from sys_roles where name like ?

代码实现:


resultType=“com.db.sys.entity.SysRole”>
select
from sysroles
<include refid=
“queryWhereId”/>
order by createdTime desc
limit #{startIndex},#{pageSize}

<select id=
“getRowCount”
resultType=
“int”_>
select count(
)
from sysroles
<include refid=
“queryWhereId”/>

<sql id=
“queryWhereId”>

<if test=
“name!=null and name!=’’”_>
name like concat(“%”,#{name},”%”)


Service层对象

业务描述:核心业务就是分页查询数据并对数据进行封装。

  1. 通过参数变量接收控制层数据

  2. 对数据进行合法验证

  3. 基于参数数据进行总记录数查询

  4. 基于参数数据进行当前页记录的查询

  5. 对数据进行封装

  6. ……….

业务实现:

  1. Service接口定义

  2. 包名:com.db.sys.service

  3. 接口名:SysRoleService

  1. 接口方法定义:

  2. 方法名: findPageObjects

  3. 参数列表:(String name,Integer pageCurrent)

  4. 返回值:PageObject (通过此对象封装当前页数据,分页信息)

  1. 接口实现类定义

  2. 包名: com.db.sys.service.impl

  3. 类名: SysRoleServiceImpl (实现SysRoleService接口)

关键代码实现:

业务接口定义
public interface SysRoleService {
/
本方法中要分页查询角色信息,并查询角色总记录数据
@param pageCurrent 当表要查询的当前页的页码值
*
@return* 封装当前实体数据以及分页信息
/
PageObject findPageObjects(
String name,Integer pageCurrent);


}

业务实现类定义
@Service
public class SysRoleServiceImpl implements SysRoleService{
@Autowired
private SysRoleDao sysRoleDao;
@Override
public PageObject findPageObjects(
String name, Integer pageCurrent) {
//1.验证参数合法性
//1.1验证pageCurrent的合法性,
//不合法抛出IllegalArgumentException异常
if(pageCurrent==null||pageCurrent<1)
throw new IllegalArgumentException(“当前页码不正确”);
//2.基于条件查询总记录数
//2.1) 执行查询
int rowCount=sysRoleDao.getRowCount(name);
//2.2) 验证查询结果,假如结果为0不再执行如下操作
if(rowCount==0)
throw new ServiceException(“记录不存在”);
//3.基于条件查询当前页记录(pageSize定义为2)
//3.1)定义pageSize
int pageSize=2;
//3.2)计算startIndex
int startIndex=(pageCurrent-1)pageSize;
//3.3)执行当前数据的查询操作
List records=
sysRoleDao.findPageObjects(name, startIndex, pageSize);
//4.对分页信息以及当前页记录进行封装
//4.1)构建PageObject对象
PageObject pageObject=new PageObject<>();
//4.2)封装数据
pageObject.setPageCurrent(pageCurrent);
pageObject.setPageSize(pageSize);
pageObject.setRowCount(rowCount);
pageObject.setRecords(records);
//5.返回封装结果。
*return
pageObject;
}

Controller 实现

业务描述:核心业务是处理客户端请求

  1. 接收客户端请求中的数据

  2. 基于请求调用业务方法进行请求处理

  3. 对处理结果进行封装(JsonResult)

  4. 将结果转换为json格式的字符串

  5. 将字符串通过服务器输出到客户端。

业务实现:
控制层对象SysRoleController类中方法定义

  1. 方法名 doFindPageObjets

  2. 参数列表 (String name,Integer pageCurrent)

  3. 返回值 JsonResult

  4. 映射 doFindPageObjets

关键代码实现:

@Controller
@RequestMapping(“/role/“)
public class SysRoleController {
@Autowired
private SysRoleService sysRoleService;
@RequestMapping(“doRoleListUI”)
public String doRolelistUI(){
return “sys/role_list”;
}
@RequestMapping(“doFindPageObjects”)
@ResponseBody
public JsonResult doFindPageObjects(
String name,pageCurrent){
PageObject pageObject=
sysRoleService.findPageObjects(name,pageCurrent);
return new JsonResult(pageObject);
}
}

测试:部署测试
http://localhost:8080/CGB-DB-SYS-V1.01/role/doFindPageObjects.do?pageCurrent=1

客户端实现

角色页面数据呈现

业务描述:

  1. 页面加载完成发起异步请求加载配置信息

  2. 通过服务端返回的数据更新当前列表页面

业务实现

  1. 定义doGetObjects()函数,通过此函数执行异步加载操作。

  2. 分页页面加载完成以后调用doGetObjects().

代码实现:

定义页面加载完成以后的事件处理
$(function(){
$(“#pageId”).load(“doPageUI.do”,function(){
//异步加载服务端数据然后进行呈现
doGetObjects();
});
})

定义分页查询函数
function doGetObjects(){
//debugger;//断点调试
//1.定义url和参数
var url=”role/doFindPageObjects.do”
//? 请问data函数的含义是什么?(从指定元素上获取绑定的数据)
//此数据会在何时进行绑定?(setPagination,doQueryObjects)
var pageCurrent=$(“#pageId”).data(“pageCurrent”);
//为什么要执行如下语句的判定,然后初始化pageCurrent的值为1
//pageCurrent参数在没有赋值的情况下,默认初始值应该为1.
if(!pageCurrent) pageCurrent=1;
var params={“pageCurrent”:pageCurrent};
//2.发起异步请求
//请问如下ajax请求的回调函数参数名可以是任意吗?可以,必须符合标识符的规范
$.getJSON(url,params,function(result){
//JsonResult->PageObject->List+…
//请问result是一个字符串还是json格式的js对象?对象
doHandleResponseResult(result);
}
);
}

设置异步响应结果
function doHandleResponseResult(result){

if(result.state==1){
doSetTableBodyRows(result.data.records);
doSetPagination(result.data);
}else{
doSetTableBodyErrors(result.message);
}
}

将异步响应结果呈现在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=$(““);
//2.2 构建tds对象
var tds=doCreatedTds(records[i]);
//2.3 将tds追加到tr中
tr.append(tds);
//2.4 将tr追加到tbody中
tBody.append(tr);
}
}

function doCreateTds(row){
var tds=”“+row.name+”“+
““+row.note+”“+
““+new Date(row.createdTime).toLocaleString()+”“+
““+new Date(row.modifiedTime).toLocaleString()+”“+
““+row.createdUser+”“+
““+row.modifiedUser+”“+
delete“+
“ update“;
return tds;
}

function doSetTableBodyErrors(message){
//获取body对象并清空
var tBody=$(“#tbodyId”);
tBody.empty();
//创建tr对象
var tr=$(““);
//创建td对象
//var len=$(“table thead”).find(“tr”).find(“th”).length;
var len=$(“table th”).length;
var td=$(““);
td.prop(“colspan”,len);
td.append(message);
tr.append(td);
//将tr追加到tbody
tBody.append(tr);
}

列表页面role_list.html信息查询实现

业务说明

  1. 列表查询按钮事件注册

  2. 列表查询按钮事件处理函数定义

  3. 列表查询参数获取以及传递

业务实现:

  1. 在$(function(){})回调函数中追加查询按钮的事件注册。

  2. 定义查询按钮的事件处理函数doQueryObjects

  3. 重用doGetObjects函数并添加查询参数name

关键代码实现:

查询按钮事件注册
$(“.input-group-btn”).on(“click”,”.btn-search”,doQueryObjects)

查询按钮事件处理函数定义
function doQueryObjects(){
//为什么要在此位置初始化pageCurrent的值为1?
//数据查询时页码的初始位置也应该是第一页
$(“#pageId”).data(“pageCurrent”,1);
//为什么要调用doGetObjects函数?
//重用js代码,简化jS代码编写。
doGetObjects();
}

在分页查询函数中追加name参数定义
function doGetObjects(){
//debugger;//断点调试
//1.定义url和参数
var url=”role/doFindPageObjects.do”
//? 请问data函数的含义是什么?(从指定元素上获取绑定的数据)
//此数据会在何时进行绑定?(setPagination,doQueryObjects)
var pageCurrent=$(“#pageId”).data(“pageCurrent”);
//为什么要执行如下语句的判定,然后初始化pageCurrent的值为1
//pageCurrent参数在没有赋值的情况下,默认初始值应该为1.
if(!pageCurrent) pageCurrent=1;
var params={“pageCurrent”:pageCurrent};
//为什么此位置要获取查询参数的值?
//一种冗余的应用方法,目的时让此函数在查询时可以重用。
var name=$(“#searchNameId”).val();
//如下语句的含义是什么?动态在js对象中添加key/value,
if(name) params.name=name;//查询时需要
//2.发起异步请求
//请问如下ajax请求的回调函数参数名可以是任意吗?可以,必须符合标识符的规范
$.getJSON(url,params,function(result){
//请问result是一个字符串还是json格式的js对象?对象
doHandleResponseResult(result);
}
);
}

角色删除模块实现

服务端实现

核心业务:本项目中规定在删除角色自身信息将角色信息与菜单的关系数据,角色与用户的关系数据一起删除。

DAO实现

业务描述:

  1. 接收业务层数据(id)

  2. 根据id删除角色自身信息(sys_roles)

  3. 根据id删除角色与菜单的关系数据(sys_role_menus)

  4. 根据id删除角色与用户的关系数据(sys_user_roles)

业务实现

  1. 在SysRoleDao接口中添加删除对象的方法

  2. 方法名 deleteObject;

  3. 参数列表(Integer id)

  4. 返回值int

  1. 在SysRoleMenuDao接口中添加删除对象的方法

  2. 方法名 deleteObjectsByRoleId;

  3. 参数列表(Integer roleId)

  4. 返回值int

  1. 在SysUserRoleDao接口中添加删除对象的方法

  2. 方法名 deleteObjectsByRoleId;

  3. 参数列表(Integer roleId)

  4. 返回值int

关键代码实现

SysRoleDao 接口中方法定义
int deleteObject(Integer id);

SysRoleMenuDao接口中方法定义
int deleteObjectsByRoleId(Integer roleId);

SysUserRoleDao接口方法定义
int deleteObjectsByRoleId(Integer roleId);

Mapper实现

业务描述:

  1. 基于SysRoleDao中删除方法,定义SQL元素

  2. 基于SysRoleMenuDao中删除方法,定义SQL元素

  3. 基于SysUserRoleDao中删除方法,定义SQL元素

业务实现:

  1. 在SysRoleMapper中添加对应的删除元素

  2. 元素名 delete

  3. 元素id deleteObject

  4. 参数类型(int)

  5. SQL定义 (delete from sys_roles where id=#{id})

  1. 在SysRoleMenuMapper中添加对应的删除元素

  2. 元素名 delete

  3. 元素id deleteObjectsByRoleId

  4. 参数类型(int)

  5. SQL定义 (delete from sys_role_menus where role_id=#{roleId})

  1. 在SysUserRoleMapper中添加对应的删除元素

  2. 元素名 delete

  3. 元素id deleteObjectsByRoleId

  4. 参数类型(int)

  5. Sql定义(delete from sys_user_roles where id=#{id})

关键代码实现

SysRoleMapper文件中方法定义
parameterType=“int”>
delete
from sys_roles
where id=#{id}

SysRoleMenuMapper中方法定义
parameterType=“int”>
delete
from sys_role_menus
where role_id=#{roleId}

SysUserRoleMapper 接口中方法定义
parameterType=“int”>
delete
from sys_user_roles
where role_id=#{roleId}

Service实现

业务描述

  1. 接收控制层数据(id),并对数据进行合法性验证.

  2. 调用dao方法,执行删除操作

  3. 根据结果验证,反馈相关信息

业务实现(在SysRoleService接口中定义方法并在实现类中进行实现.)

  1. 方法名 deleteObject

  2. 参数列表 (Integer id)

  3. 返回值 int

代码实现:

@Override
public int deleteObject(Integer id) {
//1.验证参数的合法性
if(id==null||id<1)
throw new ServiceException(“id的值不正确,id=”+id);
//2.执行dao操作
int rows=sysRoleDao.deleteObject(id);
if(rows==0)
throw new ServiceException(“数据可能已经不存在”);
sysRoleMenuDao.deleteObjectsByRoleId(id);
sysUserRoleDao.deleteObjectsByRoleId(id);
//3.返回结果
return rows;
}

Controller实现

业务描述

  1. 接收客户端请求数据id

  2. 调用业务层方法删除数据

  3. 返回响应结果.

业务实现(在SysRoleController中定义删除方法)

  1. 方法名 doDeleteObject

  2. 参数列表 Integer id

  3. 返回值 JsonResult

代码实现:

@RequestMapping(“doDeleteObject”)
@ResponseBody
public JsonResult doDeleteObject(Integer id){
sysRoleService.deleteObject(id);
return new JsonResult(“delete Ok”);
}

客户端实现

角色列表页面删除操作实现

业务描述
点击每行的delete按钮时执行删除角色的操作

业务实现

  1. 页面加载完成以后在删除按钮上注册点击事件

  2. 事件处理函数doDeleteObject定义

关键代码实现:

function doDeleteObject(){
//1.获取选中的值(分页显示记录时在tr上要绑定id的值)
var id=$(this).parents(“tr”).data(“id”);
//2.构建参数对象
var params={id:id};
//3.异步请求执行删除
var url=”role/doDeleteObject.do”;
$.post(url,params,function(result){
if(result.state==1){
alert(result.message);
doGetObjects();
}else{
alert(result.message);
}
})
}

角色添加页面呈现

服务端实现

角色Controller对象的实现

业务描述
基于客户端的请求返回一个页面(role_edit.html)

业务实现

  1. 方法名 doRoleEditUI

  2. 参数列表 ()

  3. 返回值 String

  4. 映射 @RequestMapping(“doRoleEditUI”)

代码实现

@RequestMapping(“doRoleEditUI”)
public String doRoleEditUI(){
return “sys/role_edit”;
}

客户端实现

角色列表添加按钮事件处理

业务描述
点击角色列表页面中的添加按钮时呈现角色添加页面.

业务实现:

  1. 添加按钮注册点击事件

  2. 定义事件处理函数(异步加载角色编辑页面)

代码实现:

$(“.input-group-btn”).on(“click”,”.btn-add”,doLoadEditUI);

//异步加载编辑页面
function doLoadEditUI(){
var title;
//hasClass函数用于判定对象中是否包含某个样式
if($(this).hasClass(“btn-add”)){
title=”角色添加”;
}else{
title=”角色修改”;
}
loadPageUI(url);
}

function loadPageUI(title){
$(“#mainContentId”)
.load(“role/doRoleEditUI.do”,function(){
$(“.box-title”).html(title);
});
}

角色添加页面菜单信息呈现

业务描述
页面加载完成,加载菜单信息,并通过菜单数据初始化菜单树(ZTree)

业务实现
定义doLoadSysMenus方法(负责加载ztree信息并初始化树结构)

关键代码实现
定义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.do”
$.getJSON(url,function(result){
if(result.state==1){
zTree=$.fn.zTree.init(
$(“#menuTree”),setting,result.data);
}else{
alert(result.message);
}
});
}

角色添加操作实现

服务端实现

Dao实现

业务描述

  1. 将角色自身信息保存到数据库

  2. 将角色与菜单的关系数据保存到数据库

业务实现

  1. 在SysRoleDao接口中添加一个方法,用于将角色信息写入到数据库
  1. 方法名 insertObject

  2. 参数列表(SysRole entity)

  3. 返回值 int

  1. 在SysRoleMenuDao中添加插入角色菜单关系数据的方法
  1. 方法名 insertObject

  2. 参数列表(Integer roleId, Integer[] menuIds)

  3. 返回值 int

代码实现

SysUserDao接口中方法定义

int insertObject(SysRole entity);

SysRoleMenuDao接口中方法定义(不存在则创建)
int insertObject(
@Param(“roleId”)Integer roleId,
@Param(“menuIds”)Integer[] menuIds);

Mapper实现

业务描述

  1. 基于SysRoleDao接口中insertObject方法定义相关元素

  2. 基于SysRoleMenuDao接口中insertObject方法定义相关元素

业务实现

  1. 在SysRoleMapper中定义插入数据的元素

  2. 元素名 insert

  3. 元素id insertObject

  4. 参数类型 com.db.sys.entity.SysRole

  5. SQL定义 (insert into sys_roles (….) values(….))

  1. 在SysRoleMenuMapper中定义插入数据的元素
  1. 元素名 insert

  2. 元素id insertObject

  3. 参数类型 (无)

  4. SQL定义 (insert into sys_role_menus (….) values(….))

关键代码实现:

SysRoleMapper中元素定义
parameterType=“com.db.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})

SysRoleMenuMapper中元素定义


insert into sysrole_menus
(role_id,menu_id)
values
<foreach collection=
“menuIds”
separator=
“,”
item=
“item”_>
(#{roleId},#{item})

Service实现

业务描述

  1. 通过参数变量接收控制层数据

  2. 对参数数据进行合法性验证.

  3. 保存角色自身信息数据到数据库

  4. 保存角色与菜单的关系数据到数据库

  5. 返回业务实现结果

业务实现
在SysRoleService接口中定义插入数据的方法

  1. 方法名 saveObject

  2. 参数列表 SysRole entity,Integer[] menuIds

  3. 返回值 int

关键代码实现

@Override
public int saveObject(SysRole entity,Integer[] menuIds) {
//1.合法性验证
if(entity==null)
throw new ServiceException(“保存数据不能为空”);
if(StringUtils.isEmpty(entity.getName()))
throw new ServiceException(“角色名不能为空”);
if(menuIds==null||menuIds.length==0)
throw new ServiceException(“必须为角色赋予权限”);
//2.保存数据
int rows=sysRoleDao.insertObject(entity);
sysRoleMenuDao.insertObject(
entity.getId(),menuIds);
//3.返回结果
return rows;
}

Controller实现

业务描述

  1. 接收客户端请求数据并对数据进行封装

  2. 调用业务层方法将数据写入数据库

  3. 对控制层数据进行封装(JsonResult),并返回

业务实现
在SysRoleController中定义请求处理方法

  1. 方法名 doSaveObject

  2. 参数列表 (SysRole entity,Integer[] menuIds)

  3. 返回值 JsonResult

  4. 映射 @RequestMapping(“doSaveObject”)

关键代码实现:

@RequestMapping(“doSaveObject”)
@ResponseBody
public JsonResult doSaveObject(
SysRole entity,Integer[] menuIds){
sysRoleService.saveObject(entity,menuIds);
return new JsonResult(“save ok”);
}

客户端实现

角色编辑页面按钮事件处理

业务描述

  1. 点击cancel按钮时,退出编辑页面进入列表页面.

  2. 点击save按钮时,将数据异步提交到服务端进行保存,保存ok时返回列表页面.

业务实现(cancel按钮事件处理)

function doCancel(){
$(“#mainContentId”)
.load(“role/doRoleListUI.do”,function(){
//移除绑定的数据(修改时会用)
$(“#mainContentId”).removeData();
});
}

业务实现(save按钮事件处理)

function doSaveOrUpdate(){
//1.获取表单数据
var params=doGetEditFormData();
//2.异步提交表单数据
var insertUrl=”role/doSaveObject.do”;
$.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;
}

角色修改页面呈现

服务端实现

Dao实现

业务描述

  1. 基于角色id查询角色信息

  2. 基于角色id查询菜单信息

业务实现(通过两次dao查询获取角色和菜单信息)

  1. 在SysRoleDao中定义基于基于角色id查询角色信息的方法

  2. 方法名 findObjectById

  3. 参数列表 Integer id

  4. 返回值 SysRole

  1. 在SysRoleMenuDao中定义基于角色查询菜单id的方法

  2. 方法名 findMenuIdsByRoleId

  3. 参数列表 Integer roleId

  4. 返回值 List

关键代码实现

SysRoleDao中方法定义

SysRole findObjectById(Integer id);

SysRoleMenuDao中方法定义

List findMenuIdsByRoleId(Integer roleId);

Mapper实现

业务描述

  1. 基于SysRoleDao接口中方法的定义编写基于角色id执行查询角色的元素

  2. 基于SysRoleMenuDao接口中方法的定义编写基于角色id查询菜单id的方法

业务实现

  1. SysRoleMapper中元素定义

  2. 元素名 select

  3. 元素id findObjectById

  4. 参数类型 (int)

  5. 结果类型 com.db.sys.entity.SysRole

  6. SQL定义 select * from sys_roles where id=?

  1. SysRoleMenuMapper中元素定义
  1. 元素名 select

  2. 元素id findMenuIdsByRoleId

  3. 参数类型 (int)

  4. 结果类型 int

  5. SQL定义 select menu_id from sys_role_menus where role_Id=?

关键代码实现

SysRoleMapper中元素定义
resultType=“com.db.sys.entity.SysRole”>
select *
from sys_roles
where id=#{id}

SysRoleMenuMapper中元素定义
resultType=“int”>
select menu_id
from sys_role_menus
where role_id=#{roleId}

Service实现

业务描述:基于角色id查询角色及关联的菜单信息

  1. 通过参数变量接收控制层数据

  2. 对数据进行合法验证

  3. 基于参数数据查询角色信息

  4. 基于参数数据查询菜单信息

  5. 对数据进行封装并返回

业务实现:
在SysRoleService接口及实现类中定义基于id查询的方法

关键代码实现

接口中方法定义
Map findObjectById(Integer id) ;

实现类中方法的实现
@Override
public Map findObjectById(Integer id) {
//1.合法性验证
if(id==null||id<=0)
throw new ServiceException(“id的值不合法”);
//2.执行查询
SysRole role=sysRoleDao.findObjectById(id);
//3.验证结果并返回
if(role==null)
throw new ServiceException(“此记录已经不存在”);
List menuIds=sysRoleMenuDao.findMenuIdsByRoleId(id);
Map map=new HashMap();
map.put(“role”, role);
map.put(“menuIds”, menuIds);
return map;
}

Controller实现

业务描述:核心业务是处理客户端请求

  1. 接收客户端请求中的数据(id)

  2. 基于请求调用业务方法进行请求处理

  3. 对处理结果进行封装(JsonResult)

  4. 将结果转换为json格式的字符串

  5. 将字符串通过服务器输出到客户端。

业务实现:
控制层对象SysRoleController类中方法定义

  1. 方法名 doFindObjectById

  2. 参数列表 (Integer id)

  3. 返回值 JsonResult

  4. 映射 doFindObjectById

关键代码实现

@RequestMapping(“doFindObjectById”)
@ResponseBody
public JsonResult doFindObjectById(Integer id){
Map map=
sysRoleService.findObjectById(id);
return new JsonResult(map);
}

服务端实现(扩展)

这个扩展主要是要体现与6.1方式在数据封装方面的不同,同时加强resultMap映射方式的使用。
核心业务:查询角色信息时将角色信息与对应的菜单关系数据封装到到一个值对象,然后传递到客户端在修改页面进行呈现。

VO定义

业务描述:

  1. 封装角色自身信息

  2. 封装角色对应的菜单信息

业务实现(定义角色菜单值对象)

  1. 包名:com.db.sys.vo

  2. 类名:SysRoleMenuResult

代码实现:

package com.db.sys.vo;
import java.util.List;
import com.db.sys.entity.SysRole;
/
VO:通过此对象封装角色以及角色对应的菜单id
@author ta
*/
public class SysRoleMenuResult {
/
角色对象/
private SysRole role;
/**角色对应的菜单id
/
private List menuIds;
public SysRole getRole() {
return role;
}
public void setRole(SysRole role) {
this.role = role;
}
public List getMenuIds() {
return menuIds;
}
public void setMenuIds(List menuIds) {
this.menuIds = menuIds;
}
}

Dao实现

业务描述

  1. 基于角色id查询角色信息

  2. 基于角色id查询菜单信息

业务实现(通过两次dao查询获取角色和菜单信息)

  1. 在SysRoleDao中定义基于基于角色id查询角色信息的方法

  2. 方法名 findObjectById

  3. 参数列表 Integer id

  4. 返回值 SysRoleMenuResult

  1. 在SysRoleMenuDao中定义基于角色查询菜单id的方法

  2. 方法名 findMenuIdsByRoleId

  3. 参数列表 Integer roleId

  4. 返回值 List

关键代码实现

SysRoleDao中方法定义

SysRoleMenuResult findObjectById(Integer id);

SysRoleMenuDao中方法定义

List findMenuIdsByRoleId(Integer roleId);

Mapper实现

业务描述

  1. 基于SysRoleDao接口中方法的定义编写基于角色id执行查询角色的元素

  2. 基于SysRoleMenuDao接口中方法的定义编写基于角色id查询菜单id的方法

业务实现

  1. SysRoleMapper中元素定义

  2. 元素名 select

  3. 元素id findObjectById

  4. 参数类型 (int)

  5. 结果映射 resultMap

  6. SQL定义 select * from sys_roles where id=?

  1. SysRoleMenuMapper中元素定义
  1. 元素名 select

  2. 元素id findMenuIdsByRoleId

  3. 参数类型 (int)

  4. 结果类型 int

  5. SQL定义 select menu_id from sys_role_menus where role_Id=?

关键代码实现

SysRoleMapper中元素定义
id=“roleMenuResult”>








column=“id”
select=“com.db.sys.dao.SysRoleMenuDao.findMenuIdsByRoleId”>



resultMap=“roleMenuResult”>
select id,name,note
from sys_roles
where id=#{id}

SysRoleMenuMapper中元素定义
resultType=“int”>
select menu_id
from sys_role_menus
where role_id=#{roleId}

Service实现

业务描述:基于角色id查询角色及关联的菜单信息

  1. 通过参数变量接收控制层数据

  2. 对数据进行合法验证

  3. 基于参数数据查询角色信息

  4. 基于参数数据查询菜单信息

  5. 对数据进行封装并返回

业务实现:
在SysRoleService接口及实现类中定义基于id查询的方法

关键代码实现

接口中方法定义
SysRoleMenuResult findObjectById(Integer id) ;

实现类中方法的实现
@Override
public SysRoleMenuResult findObjectById(Integer id) {
//1.合法性验证
if(id==null||id<=0)
throw new ServiceException(“id的值不合法”);
//2.执行查询
SysRoleMenuResult result=sysRoleDao.findObjectById(id);
//3.验证结果并返回
if(result==null)
throw new ServiceException(“此记录已经不存在”);
return result;
}

Controller实现

业务描述:核心业务是处理客户端请求

  1. 接收客户端请求中的数据(id)

  2. 基于请求调用业务方法进行请求处理

  3. 对处理结果进行封装(JsonResult)

  4. 将结果转换为json格式的字符串

  5. 将字符串通过服务器输出到客户端。

业务实现:
控制层对象SysRoleController类中方法定义

  1. 方法名 doFindObjectById

  2. 参数列表 (Integer id)

  3. 返回值 JsonResult

  4. 映射 doFindObjectById

关键代码实现

@RequestMapping(“doFindObjectById”)
@ResponseBody
public JsonResult doFindObjectById(Integer id){
return new JsonResult(sysRoleService.findObjectById(id));
}

客户端实现

角色列表页面实现

业务描述

  1. 点击列表页面修改按钮时基于id查询异步角色信息

  2. 通过角色信息初始化编辑页面数据

业务实现

  1. 列表页面修改按钮事件注册

  2. 列表页面修改按钮事件处理函数定义(与添加操作公用一个方法并进行适当修改)

关键代码实现

$(“tbody”).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.do”;
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/doRoleEditUI.do”,function(){
$(“.box-title”).html(title);
});
}

角色编辑页面实现

业务描述
1)菜单树初始化完成,获取绑定数据
2)通过绑定数据初始化表单
代码实现:
菜单树初始化完成,获取绑定数据,初始化表单

关键代码

function doLoadSysMenus(){
var url=”menu/doFindZTreeNodes.do”
$.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.role.name);
$(“#noteId”).val(data.role.note);
//展开所有节点
zTree.expandAll(true);
//勾选角色所拥有的菜单
var menuIds = data.menuIds;
for(var i=0; i //获取key为id值为menuIds[i]的节点
var node = zTree.getNodeByParam(“id”,menuIds[i]);
//选中当前节点
zTree.checkNode(node,true,false);
}
}

角色修改操作实现

服务端实现

Dao实现

业务描述
修改角色自身信息
修改角色与菜单的关系数据

业务实现:
1)在SysRoleDao方法中添加角色修改的方法

  1. 方法名 updateObject

  2. 参数列表 (SysRole entity)

  3. 返回值 int

2)在SysRoleMenuDao中添加根据角色id删除关系数据的方法

  1. 方法名 deleteObjectsByRoleId (假如已经存在则无需再次定义)

  2. 参数(Integer roleId)

  3. 返回值 int

关键代码实现:

SysRoleDao中方法定义
int updateObject(SysRole entity);

SysRoleMenuDao中方法定义
int deleteObjectsByRoleId(Integer roleId);

Mapper实现

业务描述

基于SysRoleDao中updateObject方法的定义编写对应sql元素
基于SysRoleMenuDao中deleteObjectsByRoleId方法的定义编写对应sql元素

业务实现

1)在SysRoleMapper文件中添加update元素,定义角色信息修改的sql语句

  1. 元素名 update

  2. 元素id updateObject

  3. 参数类型 com.db.sys.entity.SysRole

  4. Sql定义(update sys_roles set…. where ….)

2)在SysRoleMenuMapper中添加删除数据的元素

  1. 元素名 delete

  2. 元素id deleteObjectsByRoleId

  3. 参数类型 int

  4. Sql 定义 delete from sys_role_menus where role_id=#{roleId};

代码实现:

SysRoleMapper元素定义

update sysroles


<if test=
“name!=null and name!=’’”>
name=#{name},

<if test=
“note!=null and note!=’’”>
note=#{note},

<if test=
“modifiedUser!=null and modifiedUser!=’’”_>
modifiedUser=#{modifiedUser},

modifiedTime=now()

where id=#{id}

SysRoleMenuMapper 元素定义(假如已有则不用再写)
parameterType=“int”>
delete from sys_role_menus
where role_id=#{roleId}

Service实现

业务描述

  1. 接收控制层数据,对数据进行合法验证.

  2. 调用dao层方法更新数据

  3. 验证结果,并返回.

业务实现(在SysRoleService接口及实现类中定义方法及实现.)

  1. 方法名 updateObject

  2. 参数列表 SysRole entity,Integer[] menuIds

  3. 返回值 int

代码实现:

@Override
public int updateObject(SysRole entity,Integer[] menuIds) {
//1.合法性验证
if(entity==null)
throw new ServiceException(“更新的对象不能为空”);
if(entity.getId()==null)
throw new ServiceException(“id的值不能为空”);

if(StringUtils.isEmpty(entity.getName()))
throw new ServiceException(“角色名不能为空”);
if(menuIds==null||menuIds.length==0)
throw new ServiceException(“必须为角色指定一个权限”);

//2.更新数据
int rows=sysRoleDao.updateObject(entity);
if(rows==0)
throw new ServiceException(“对象可能已经不存在”);
sysRoleMenuDao.deleteObjectsByRoleId(entity.getId());
sysRoleMenuDao.insertObject(entity.getId(),menuIds);

//3.返回结果
return rows;
}

Controller实现

业务描述

  1. 接收客户端请求数据(角色信息,以及菜单id)

  2. 调用业务层对象处理业务

  3. 对结果进行封装

  4. 将响应结果转换为json输出

业务实现(在SysRoleController中定义修改方法)

  1. 方法名 doUpdateObject

  2. 参数列表(SysRole entity)

  3. 返回值 JsonResult

  4. 映射 @RequestMapping(“doUpdateObject”)

代码实现:

@RequestMapping(“doUpdateObject”)
@ResponseBody
public JsonResult doUpdateObject(SysRole entity,
String menuIds){
sysRoleService.updateObject(entity,menuIds);
return new JsonResult(“update ok”);

客户端实现

角色编辑页面数据的更新

业务描述:用户点击保存按钮时异步提交表单数据

  1. 获取表单数据(相对于添加操作应该再添加一个id)

  2. 异步提交(post)表单数据(修改和添加不是同一个url)

  3. 关闭页面,显示列表页面

业务实现:

  1. 修改doSaveOrUpdate方法与添加操作共用此方法

  2. 与添加操作共用一个获取表单的方法

关键代码实现

修改doSaveOrUpdate函数(与保存操作共享一个函数)
//点击保存按钮时执行此方法
function doSaveOrUpdate(){//insert/update
//获取表单数据
var params=doGetEditFormData();
//假如当前页面.container-fluid对象上绑定着值说明是修改
var data=$(“#mainContentId”).data(“data”);
if(data){
params.id=data.role.id;//修改时表单数据中需要添加id
}
//根据当前页面上是否绑定着值来定义url
var insertUrl=”role/doSaveObject.do”;
var updateUrl=”role/doUpdateObject.do”;
var url=data?updateUrl:insertUrl;

//异步提交数据
$.post(url,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);
for(var i in checkedNodes){
menuIds.push(checkedNodes[i].id)
}
params.menuIds=menuIds.toString();
return params;
}

总结

重点和难点分析

1.角色业务处理流程(持久层,业务层,控制层,表示层)
2.角色业务数据封装(SysRole,PageObject,JsonResult)
3.角色业务异常的统一处理(统一异常处理类的定义)
4.角色日期数据的格式转换(3种方案)
5.角色页面中JS实现(业务,方法的应用,编写,调试)
6.角色查询业务实现流程(持久层,mapper,业务层,控制层,表示层)
7.角色删除业务的具体实现流程(……….)
8.角色列表页面如何获取选中的checkbox对应的id值
9.角色列表页面如何实现全选和取消全选操作.(扩展实现)
10.业务总结分析

角色模块 - 图2
角色模块 - 图3

角色模块 - 图4

角色模块 - 图5

常见FAQ

  1. 为什么要定义实体类?(实现和表之间的映射,更好的封装数据)

  2. 类为什么要实现序列化接口?(已知)

  3. 类实现序列化接口以后为什么要添加序列化版本id?(已知道)

  4. 如何实现对象的序列化时的粒度控制?(哪些属性要序列化,哪些属性不需要序列化)(已知)

  5. 类对象序列化时内容如何加密?(已知)

  6. 角色业务层查询到的数据是如何封装的?(PageObject)

  7. 角色控制层数据是如何封装的?(JsonResult)

  8. 角色控制层异常是如何处理的?(全局统一处理)

  9. 角色控制层方法返回的对象是如何转换为JSON串的?(jackson)

  10. 角色控制层日期类型的数据是如何处理的?

  11. 实体对象SysRole的set/get方法何时有调用?

  12. 映射文件中的sql元素用于做什么?(提取sql共性)

  13. 映射文件中的动态sql元素常用的有哪些?(foreach,where,if,set,…)