项目的权限管理模块
在上一个博客中(71章博客),我们完成了广告管理模块和用户管理模块,接下来我们完成最后的权限管理模块
权限管理模块 :
权限概念介绍:
权限:权利(能做的)和限制(不能做的),在权限范围内做好自己的事情,不该看的不看,不该做的不做
认证: 验证用户名密码是否正确的过程
授权: 对用户所能访问的资源进行控制(动态显示菜单、url级别的权限控制)
为什么要实现权限系统 :
首先系统需要进行登陆才能访问
其次不同登陆用户要有不同的权利
而且要有不同的菜单(例如财务经理针对系统中财务相关模块进行操作,人事经理针对系统中人事模块进行操作)
权限控制基本原理 :
ACL(Access Control Lists,缩写ACL):
ACL是最早也是最基本的一种访问控制机制
它的原理非常简单:每一项资源,都配有一个列表,这个
列表记录的就是哪些用户可以对这项资源执行CRUD中的那些操作。当系统试图访问这项资源时,会首
先检查这个列表中是否有关于当前用户的访问权限,从而确定当前用户可否执行相应的操作
总得来说,ACL是一种面向资源的访问控制模型,它的机制是围绕"资源"展开的
基于角色的访问控制RBAC(Role-Based Access Control):
RBAC是把用户按角色进行归类,通过用户的角色来确定用户能否针对某项资源进行某项操作
RBAC相对于ACL最大的优势就是它简化了用户与权限的管理,通过对用户进行分类,使得角色与权限关联起来
而用户与权限变成了间接关联
RBAC模型使得访问控制,特别是对用户的授权管理变得非常简单和易于维护,因此有广泛的应用
可以发现ACL在进行判断是否有对应权限时,会查询多条数据(多个对应)
而若使用RBAC,只需要查一条数据即可,执行速度变快,这样就简化了查询(虽然硬盘空间多了,但是可以忽略不计)
实际上就是将一个表进行数据关联,而我们与这个表进行关联
规则一:每个登陆的用户,可以有多个角色
规则二:每个角色又可以拥有多个权限(包含菜单和资源)
权限管理模块功能分析:
权限模块主要细分为角色模块、菜单模块、资源模块
将针对细分的三个模块进行具体功能实现
权限管理模块:
实现以下功能:
管理模块里面的可以直接叫做模块
角色列表查询和条件查询一起操作(角色模块),但凡有条件的,基本也是可以进行查询所有的
所有到达页面可以进行不传参数,使得查询所有,也就能使得一个接口,都可以操作了
如前面的课程管理模块的多条件查询和用户的分页和条件查询和广告的分页查询 ,也没有对应的查询所有
而广告位由于没有对应的条件或者分页查询使得顺便查询所有,所以就只能操作查询所有了
新增角色(角色模块)
回显角色(角色模块)
修改角色(角色模块)
分配菜单(包含查询菜单以及对应角色菜单的显示和保存分配的菜单,角色模块)
删除角色(角色模块)
菜单列表查询(菜单模块)
回显菜单(菜单模块)
包含对应父菜单回显和全部菜单信息回显,即添加和修改都需要回显,他们共用父菜单回显,修改操作单独使用全部菜单信息回显
新增菜单(菜单模块)
修改菜单(菜单模块)
删除菜单(菜单模块)
资源分类,分页及其多条件查询(资源模块)
下面三个就是与前面用户管理模块联系的:
用户登陆(用户管理模块)
动态菜单展示(权限管理模块,也可以说成用户管理模块)
用户关联角色(用户管理模块)
对应数据库表已经在71章博客里面说明了
表关系介绍 :
ER图 :
权限管理模块的角色模块实现 :
角色列表查询
需求分析
需求:点击角色列表按钮进行角色列表展示
Dao层:RoleMapper :
package com. lagou. dao ;
import com. lagou. domain. Role ;
import java. util. List ;
public interface RoleMapper {
public List < Role > findAllRole ( Role role) ;
}
对应映射配置(RoleMapper.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.lagou.dao.RoleMapper" >
< select id = " findAllRole" parameterType = " Role" resultType = " Role" >
SELECT * FROM roles
< where>
< if test = " name != null and name != ''" >
and name = #{name}
</ if>
</ where>
</ select>
</ mapper>
Service层:RoleService及其实现类 :
package com. lagou. service ;
import com. lagou. domain. Role ;
import java. util. List ;
public interface RoleService {
public List < Role > findAllRole ( Role role) ;
}
package com. lagou. service. impl ;
import com. lagou. dao. RoleMapper ;
import com. lagou. domain. Role ;
import com. lagou. service. RoleService ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. stereotype. Service ;
import java. util. List ;
@Service
public class RoleServiceImpl implements RoleService {
@Autowired
private RoleMapper roleMapper;
public List < Role > findAllRole ( Role role) {
List < Role > allRole = roleMapper. findAllRole ( role) ;
return allRole;
}
}
Web层:RoleController :
package com. lagou. controller ;
import com. lagou. domain. ResponseResult ;
import com. lagou. domain. Role ;
import com. lagou. service. RoleService ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. web. bind. annotation. RequestBody ;
import org. springframework. web. bind. annotation. RequestMapping ;
import org. springframework. web. bind. annotation. RestController ;
import java. util. List ;
@RestController
@RequestMapping ( "/role" )
public class RoleController {
@Autowired
private RoleService roleService;
@RequestMapping ( "/findAllRole" )
public ResponseResult findAllRole ( @RequestBody Role role) {
List < Role > allRole = roleService. findAllRole ( role) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "查询角色成功" , allRole) ;
return responseResult;
}
}
使用Postman测试接口
接下来我们操作新增角色
Dao层:添加部分RoleMapper :
public void saveRole ( Role role) ;
添加部分RoleMapper.xml:
< insert id = " saveRole" parameterType = " Role" >
insert into roles
values (null, #{code}, #{name}, #{description}, #{createdTime}, #{updatedTime}, #{createdBy},
#{updatedBy})
</ insert>
Service层:添加部分RoleService及其实现类 :
public void saveRole ( Role role) ;
@Override
public void saveRole ( Role role) {
Date date = new Date ( ) ;
role. setCreatedTime ( date) ;
role. setUpdatedTime ( date) ;
role. setCreatedBy ( "system" ) ;
role. setUpdatedBy ( "system" ) ;
roleMapper. saveRole ( role) ;
}
Web层:添加部分RoleController :
@RequestMapping ( "/saveOrUpdateRole" )
public ResponseResult saveOrUpdateRole ( @RequestBody Role role) {
roleService. saveRole ( role) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "添加角色成功" , null ) ;
return responseResult;
}
使用Postman测试接口
在这里说明一下Postman对应的表单类型
其中对于表单来说
form-data:相当于multipart/form-data,传递二进制或者键值对,具体获取数据可以查看56章博客的流程
x-www-form-urlencoded:相当于application/x-www-form-urlencoded(这是表单默认的形式),只能传递键值对
但后台根据这些数据有不同的读取方式,所以有些方法只能操作对应类型,如getParameter()方法
可以得到x-www-form-urlencoded对应的键值对数据,而得不到form-data对应的键值对数据,即一般都是返回null值
raw:通常用来操作json数据,即传递字符串数据
binary:相当于相当于Content-Type:application/octet-stream,只能操作二进制数据,没有键值对(即不能操作键值对)
在修改角色之前,我们需要回显:
Dao层:添加部分RoleMapper :
public Role findRoleById ( Integer id) ;
添加部分RoleMapper.xml:
< select id = " findRoleById" parameterType = " int" resultType = " Role" >
SELECT * FROM roles
where id = #{id}
</ select>
Service层:添加部分RoleService及其实现类 :
public Role findRoleById ( Integer id) ;
@Override
public Role findRoleById ( Integer id) {
Role roleById = roleMapper. findRoleById ( id) ;
return roleById;
}
Web层:添加部分RoleController :
@RequestMapping ( "/findRoleById" )
public ResponseResult findRoleById ( Integer id) {
Role roleById = roleService. findRoleById ( id) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "根据id查询角色成功" , roleById) ;
return responseResult;
}
使用Postman测试接口
回显操作完毕后,我们可以进行修改操作了
Dao层:添加部分RoleMapper :
public void updateRole ( Role role) ;
添加部分RoleMapper.xml:
< update id = " updateRole" parameterType = " Role" >
update roles
< trim prefix = " set" suffixOverrides = " ," >
< if test = " code != null and code != ''" >
code = #{code},
</ if>
< if test = " name != null and name != ''" >
name = #{name},
</ if>
< if test = " description != null and description != ''" >
description = #{description},
</ if>
< if test = " createdTime != null" >
created_time = #{createdTime},
</ if>
< if test = " updatedTime != null" >
updated_time = #{updatedTime},
</ if>
< if test = " createdBy != null and createdBy != ''" >
created_by = #{createdBy},
</ if>
< if test = " updatedBy != null and updatedBy != ''" >
updated_by = #{updatedBy},
</ if>
</ trim>
< where>
< if test = " id != null" >
and id = #{id}
</ if>
</ where>
</ update>
Service层:添加部分RoleService及其实现类 :
public void updateRole ( Role role) ;
@Override
public void updateRole ( Role role) {
role. setUpdatedTime ( new Date ( ) ) ;
roleMapper. updateRole ( role) ;
}
Web层:修改部分RoleController(扩展saveOrUpdateRole方法):
@RequestMapping ( "/saveOrUpdateRole" )
public ResponseResult saveOrUpdateRole ( @RequestBody Role role) {
ResponseResult responseResult;
if ( role. getId ( ) == null ) {
roleService. saveRole ( role) ;
responseResult = new ResponseResult ( true , 200 , "添加角色成功" , null ) ;
} else {
roleService. updateRole ( role) ;
responseResult = new ResponseResult ( true , 200 , "修改角色成功" , null ) ;
}
return responseResult;
}
使用Postman测试接口
分配菜单
需求分析
需求:点击分配菜单,回显可选择菜单信息,并回显选中状态
具体分析:
首先先得到所有的菜单节点信息,然后再根据角色id查询关联的菜单节点信息
这两个操作,统称为菜单的回显,最后再进行操作保存
那么我们就首先操作菜单的回显
代码编写思路:
对应图解:
在回显之前,我们先分析一下对应menu表(这是对应菜单表)
id是菜单对应的id,parent_id表示对应父菜单是哪个id
根据表来看,parent_id等于-1的基本都是父菜单,相当与基本没有父菜单了,所有基本就是最父级(顶级)的菜单
其余的都是子菜单
我们发现,这个表中,对应顶级菜单(父级菜单)和子菜单是在同一个表中,而由于前端需要有对应的父子关系
那么我们直接的select * from menu语句是很难满足前端要形成父子关系的需求的
因为查询的结果都是同级,也就是在同级的List中(不嵌套的关系)
那么前端必须通过逻辑来进行父子联系(如对应parent_id与id进行判断是否相等来实现),使得出现层级关系
但是我们可以通过语句来直接实现这样的关系,降低了对应代码量的操作
对应sql语句操作如下:
select * from menu where parent_id = - 1
select * from menu where parent_id = 1
对应的添加部分Menu类:
private List < Menu > subMenuList;
public List < Menu > getSubMenuList ( ) {
return subMenuList;
}
public void setSubMenuList ( List < Menu > subMenuList) {
this . subMenuList = subMenuList;
}
好了现在开始菜单的回显:
先进行菜单节点的查询
Dao层:MenuMapper:
package com. lagou. dao ;
import com. lagou. domain. Menu ;
import java. util. List ;
public interface MenuMapper {
public List < Menu > findSubMenuListByPid ( Integer pid) ;
}
对应映射配置(MenuMapper.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.lagou.dao.MenuMapper" >
< resultMap id = " menuResult" type = " Menu" >
< id column = " id" property = " id" > </ id>
< result column = " href" property = " href" > </ result>
< result column = " icon" property = " icon" > </ result>
< result column = " name" property = " name" > </ result>
< result column = " parent_id" property = " parentId" > </ result>
< result column = " description" property = " description" > </ result>
< result column = " orderNum" property = " order_num" > </ result>
< result column = " shown" property = " shown" > </ result>
< result column = " created_time" property = " createdTime" > </ result>
< result column = " updated_time" property = " updatedTime" > </ result>
< result column = " created_by" property = " createdBy" > </ result>
< result column = " updated_by" property = " updatedBy" > </ result>
< collection property = " subMenuList" ofType = " Menu" select = " findSubMenuListByPid" column = " id" >
</ collection>
</ resultMap>
< select id = " findSubMenuListByPid" parameterType = " int" resultMap = " menuResult" >
select *
from menu
where parent_id = #{id} order by order_num
</ select>
</ mapper>
Service层:MenuService及其实现类 :
package com. lagou. service ;
import com. lagou. domain. Menu ;
import java. util. List ;
public interface MenuService {
public List < Menu > findSubMenuListByPid ( Integer pid) ;
}
package com. lagou. service. impl ;
import com. lagou. dao. MenuMapper ;
import com. lagou. domain. Menu ;
import com. lagou. service. MenuService ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. stereotype. Service ;
import java. util. List ;
@Service
public class MenuServiceImpl implements MenuService {
@Autowired
private MenuMapper menuMapper;
@Override
public List < Menu > findSubMenuListByPid ( Integer pid) {
List < Menu > subMenuListByPid = menuMapper. findSubMenuListByPid ( pid) ;
return subMenuListByPid;
}
}
Web层:MenuController :
package com. lagou. controller ;
import com. lagou. domain. Menu ;
import com. lagou. domain. ResponseResult ;
import com. lagou. service. MenuService ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. web. bind. annotation. RequestMapping ;
import org. springframework. web. bind. annotation. RestController ;
import java. util. HashMap ;
import java. util. List ;
@RestController
@RequestMapping ( "/menu" )
public class MenuController {
@Autowired
private MenuService menuService;
@RequestMapping ( "/findAllMenu" )
public ResponseResult findSubMenuListByPid ( ) {
List < Menu > subMenuListByPid = menuService. findSubMenuListByPid ( - 1 ) ;
HashMap < String , Object > objectObjectHashMap = new HashMap < > ( ) ;
objectObjectHashMap. put ( "parentMenuList" , subMenuListByPid) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "查询所有的父子菜单信息成功" ,
objectObjectHashMap) ;
return responseResult;
}
}
使用Postman测试接口
当我们进行查询所有的父子菜单信息后,那么就需要对应角色id关联的菜单显示了
需求分析:
根据角色ID查询关联菜单ID
Dao层:添加部分MenuMapper:
public List < Integer > findMenuByRoleId ( Integer roleid) ;
添加部分MenuMapper.xml:
< select id = " findMenuByRoleId" parameterType = " int" resultType = " int" >
SELECT m.id FROM roles r INNER JOIN role_menu_relation rl ON r.id = rl.role_id
INNER JOIN menu m ON m.id = rl.menu_id WHERE r.id = #{id}
</ select>
Service层:添加部分MenuService及其实现类 :
public List < Integer > findMenuByRoleId ( Integer roleid) ;
@Override
public List < Integer > findMenuByRoleId ( Integer roleid) {
List < Integer > menuByRoleId = menuMapper. findMenuByRoleId ( roleid) ;
return menuByRoleId;
}
Web层:添加部分MenuController :
@RequestMapping ( "/findMenuByRoleId" )
public ResponseResult findMenuByRoleId ( Integer roleId) {
List < Integer > menuByRoleId = menuService. findMenuByRoleId ( roleId) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "根据角色id查询菜单信息成功" ,
menuByRoleId) ;
return responseResult;
}
使用Postman测试接口
到这里对应菜单的回显就完成了
那么就到了最后操作保存分配的菜单了
需求分析:
开始进行保存的代码编写
Dao层:添加部分MenuMapper:
public void deleteRoleContextMenu ( Integer roleid) ;
public void roleContextMenu ( Role_menu_relation role_menu_relation) ;
添加部分MenuMapper.xml:
< delete id = " deleteRoleContextMenu" parameterType = " int" >
DELETE FROM role_menu_relation WHERE role_id = #{id}
</ delete>
< insert id = " roleContextMenu" parameterType = " Role_menu_relation" >
insert into role_menu_relation values(null,#{menuId},#{roleId},
#{createdTime},#{updatedTime},#{createdBy},#{updatedby})
</ insert>
在写Service层之前,我们需要一个类
来存放前端传递过来的参数(当然也可以不使用,但这是为了以后的扩展,除非确定是固定的)
package com. lagou. domain ;
import java. util. List ;
public class RoleMenuVo {
private Integer roleId;
private List < Integer > menuIdList;
private String createdBy;
private String updatedBy;
public Integer getRoleId ( ) {
return roleId;
}
public void setRoleId ( Integer roleId) {
this . roleId = roleId;
}
public List < Integer > getMenuIdList ( ) {
return menuIdList;
}
public void setMenuIdList ( List < Integer > menuIdList) {
this . menuIdList = menuIdList;
}
public String getCreatedBy ( ) {
return createdBy;
}
public void setCreatedBy ( String createdBy) {
this . createdBy = createdBy;
}
public String getUpdatedBy ( ) {
return updatedBy;
}
public void setUpdatedBy ( String updatedBy) {
this . updatedBy = updatedBy;
}
}
编写好后,接下了编写Service层的代码
Service层:添加部分MenuService及其实现类 :
public void roleContextMenu ( RoleMenuVo roleMenuVo) ;
@Override
public void roleContextMenu ( RoleMenuVo roleMenuVo) {
menuMapper. deleteRoleContextMenu ( roleMenuVo. getRoleId ( ) ) ;
for ( Integer menuId : roleMenuVo. getMenuIdList ( ) ) {
Role_menu_relation role = new Role_menu_relation ( ) ;
role. setMenuId ( menuId) ;
role. setRoleId ( roleMenuVo. getRoleId ( ) ) ;
role. setCreatedBy ( roleMenuVo. getCreatedBy ( ) ) ;
role. setUpdatedby ( roleMenuVo. getUpdatedBy ( ) ) ;
Date date = new Date ( ) ;
role. setCreatedTime ( date) ;
role. setUpdatedTime ( date) ;
menuMapper. roleContextMenu ( role) ;
}
}
Web层:添加部分MenuController :
@RequestMapping ( "/roleContextMenu" )
public ResponseResult roleContextMenu ( @RequestBody RoleMenuVo roleMenuVo) {
menuService. roleContextMenu ( roleMenuVo) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "角色分配菜单成功" , null ) ;
return responseResult;
}
使用Postman测试接口
删除角色
需求分析
需求:点击删除按钮,将选中的角色信息删除
Dao层:添加部分MenuMapper:
public void deleteRole ( Integer id) ;
添加部分MenuMapper.xml:
< delete id = " deleteRole" parameterType = " int" >
delete from roles
where id = #{id}
</ delete>
Service层:添加部分MenuService及其实现类 :
public void deleteRole ( Integer id) ;
@Autowired
private MenuMapper menuMapper;
@Override
public void deleteRole ( Integer id) {
menuMapper. deleteRoleContextMenu ( id) ;
roleMapper. deleteRole ( id) ;
}
Web层:添加部分MenuController :
@RequestMapping ( "/deleteRole" )
public ResponseResult deleteRole ( Integer id) {
roleService. deleteRole ( id) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "删除角色成功" , null ) ;
return responseResult;
}
使用Postman测试接口
权限管理(菜单模块)实现 :
菜单列表查询
需求分析
需求:点击菜单列表,对菜单信息进行列表展示
Dao层:添加部分MenuMapper:
public List < Menu > findAllMenu ( ) ;
添加部分MenuMapper.xml:
< select id = " findAllMenu" resultType = " Menu" >
select * from menu;
</ select>
Service层:添加部分MenuService及其实现类 :
public List < Menu > findAllMenu ( ) ;
@Override
public List < Menu > findAllMenu ( ) {
List < Menu > allMenu = menuMapper. findAllMenu ( ) ;
return allMenu;
}
Web层:添加部分MenuController :
@RequestMapping ( "/findAllMenuList" )
public ResponseResult findAllMenu ( ) {
List < Menu > allMenu = menuService. findAllMenu ( ) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "查询所有菜单信息成功" , allMenu) ;
return responseResult;
}
使用Postman测试接口
回显菜单信息
需求分析
需求:
点击添加菜单按钮,跳转到添加菜单页面,回显当前添加菜单可以选择的上级菜单信息
点击编辑按钮,也进行对应回显操作(但有对应其他的信息,也可以说是所有信息,即如包括上级菜单信息和本身其他信息)
具体分析:
根据需求,我们发现,添加和修改都有对应回显,这个同样的回显都是查询所有父菜单信息
虽然我们使用了对应父子菜单查询结果当作对应根据id查询角色信息来进行回显,但我们可以不使用子菜单信息
实际上你也可以自己创建一个查询语句进行调用
但这里我们就进行复用了,而复用了,那么对应父菜单回显sql语句就不需要编写了
也就是说,寻常的根据parent_id查询父菜单信息也就不需要写了
虽然修改和添加有同样的回显操作,但修改却需要回显对应具体其他信息
对应修改回显操作的代码编写如下:
Dao层:添加部分MenuMapper:
public Menu findMenuById ( Integer id) ;
添加部分MenuMapper.xml:
< select id = " findMenuById" parameterType = " int" resultType = " Menu" >
select * from menu where id = #{id}
</ select>
Service层:添加部分MenuService及其实现类 :
public Menu findMenuById ( Integer id) ;
@Override
public Menu findMenuById ( Integer id) {
Menu menuById = menuMapper. findMenuById ( id) ;
return menuById;
}
编写好后,我们可以将添加和修改的回显信息放在一个方法里进行判断操作
而不用分开在Web层创建两个方法了(当然也可以进行分开)
之所以有这样的方式,在表里面可以有体现,如id
菜单信息里面id一般都是大于等于1的整数,这是表的设计,也就是说,基本是可以使用特有的负数(如-1)来进行判断操作
Web层:添加部分MenuController :
@RequestMapping ( "/findMenuInfoById" )
public ResponseResult findMenuInfoById ( Integer id) {
ResponseResult responseResult;
HashMap < Object , Object > objectObjectHashMap;
List < Menu > subMenuListByPid = menuService. findSubMenuListByPid ( - 1 ) ;
if ( id == - 1 ) {
objectObjectHashMap = new HashMap < > ( ) ;
objectObjectHashMap. put ( "menuInfo" , null ) ;
objectObjectHashMap. put ( "parentMenuList" , subMenuListByPid) ;
responseResult = new ResponseResult ( true , 200 , "添加菜单信息回显成功" ,
objectObjectHashMap) ;
} else {
Menu menu = menuService. findMenuById ( id) ;
objectObjectHashMap = new HashMap < > ( ) ;
objectObjectHashMap. put ( "menuInfo" , menu) ;
objectObjectHashMap. put ( "parentMenuList" , subMenuListByPid) ;
responseResult = new ResponseResult ( true , 200 , "修改菜单信息回显成功" ,
objectObjectHashMap) ;
}
return responseResult;
}
使用Postman测试接口
这下我们就将对应添加和修改的回显操作完毕了,接下来我们进行添加和修改的直接操作
添加操作:
Dao层:添加部分MenuMapper:
public void saveMenu ( Menu menu) ;
添加部分MenuMapper.xml:
< insert id = " saveMenu" parameterType = " Menu" >
insert into menu values(null,#{parentId},#{href},#{icon},#{name},#{description},#{orderNum},
#{shown},#{level},#{createdTime},#{updatedTime},
#{createdBy},#{updatedBy})
</ insert>
Service层:添加部分MenuService及其实现类 :
public void saveMenu ( Menu menu) ;
@Override
public void saveMenu ( Menu menu) {
Date date = new Date ( ) ;
menu. setCreatedTime ( date) ;
menu. setUpdatedTime ( date) ;
menuMapper. saveMenu ( menu) ;
}
Web层:添加部分MenuController :
@RequestMapping ( "/saveOrUpdateMenu" )
public ResponseResult saveOrUpdateMenu ( @RequestBody Menu menu) {
menuService. saveMenu ( menu) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "添加菜单成功" , null ) ;
return responseResult;
}
回显操作已经操作完了,所有可以直接进行修改操作了
使用Postman测试接口
修改操作:
Dao层:添加部分MenuMapper:
public void updateMenu ( Menu menu) ;
添加部分MenuMapper.xml:
< update id = " updateMenu" parameterType = " Menu" >
update menu
< trim prefix = " SET" suffixOverrides = " ," >
< if test = " parentId != 0" >
parent_id = #{parentId},
</ if>
< if test = " href != null and href != ''" >
href = #{href},
</ if>
< if test = " icon != null and icon != ''" >
icon = #{icon},
</ if>
< if test = " name != null and name != ''" >
name = #{name},
</ if>
< if test = " description != null and description != ''" >
description = #{description},
</ if>
< if test = " orderNum != 0" >
order_num = #{orderNum},
</ if>
< if test = " shown != 0" >
shown = #{shown},
</ if>
< if test = " level != 0" >
level = #{level},
</ if>
< if test = " createdTime != null" >
created_time = #{createdTime},
</ if>
< if test = " updatedTime != null" >
updated_time = #{updatedTime},
</ if>
< if test = " createdBy != null and createdBy != ''" >
created_by = #{createdBy},
</ if>
< if test = " updatedBy != null and updatedBy != ''" >
updated_by = #{updatedBy}
</ if>
</ trim>
< where>
< if test = " id != null" >
id = #{id}
</ if>
</ where>
</ update>
Service层:添加部分MenuService及其实现类 :
public void updateMenu ( Menu menu) ;
@Override
public void updateMenu ( Menu menu) {
menu. setUpdatedTime ( new Date ( ) ) ;
menuMapper. updateMenu ( menu) ;
}
Web层:修改部分MenuController (扩展saveOrUpdateMenu方法):
@RequestMapping ( "/saveOrUpdateMenu" )
public ResponseResult saveOrUpdateMenu ( @RequestBody Menu menu) {
ResponseResult responseResult;
if ( menu. getId ( ) == null ) {
menuService. saveMenu ( menu) ;
responseResult = new ResponseResult ( true , 200 , "添加菜单成功" , null ) ;
} else {
menuService. updateMenu ( menu) ;
responseResult = new ResponseResult ( true , 200 , "修改菜单成功" , null ) ;
}
return responseResult;
}
使用Postman测试接口
最后我们来实现删除菜单的操作
Dao层:添加部分MenuMapper:
public void deleteMenu ( Integer id) ;
添加部分MenuMapper.xml:
< delete id = " deleteMenu" parameterType = " int" >
delete from menu where id = #{id}
</ delete>
Service层:添加部分MenuService及其实现类 :
public void deleteMenu ( Integer id) ;
@Override
public void deleteMenu ( Integer id) {
menuMapper. deleteMenu ( id) ;
}
Web层:添加部分MenuController :
@RequestMapping ( "/deleteMenu" )
public ResponseResult deleteMenu ( Integer id) {
menuService. deleteMenu ( id) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "删除菜单成功" , null ) ;
return responseResult;
}
使用Postman测试接口
权限管理(资源模块)实现 :
资源分类,分页及其多条件查询
需求分析
需求:资源列表及分页多条件组合查询
根据需求我们需要5个参数,那么就创建一个类来存放
ResourceVo类:
package com. lagou. domain ;
public class ResourceVo {
private Integer currentPage;
private Integer pageSize;
private String name;
private Integer categoryId;
private String url;
public Integer getCurrentPage ( ) {
return currentPage;
}
public void setCurrentPage ( Integer currentPage) {
this . currentPage = currentPage;
}
public Integer getPageSize ( ) {
return pageSize;
}
public void setPageSize ( Integer pageSize) {
this . pageSize = pageSize;
}
public String getName ( ) {
return name;
}
public void setName ( String name) {
this . name = name;
}
public Integer getCategoryId ( ) {
return categoryId;
}
public void setCategoryId ( Integer categoryId) {
this . categoryId = categoryId;
}
public String getUrl ( ) {
return url;
}
public void setUrl ( String url) {
this . url = url;
}
}
接下来进行代码编写:
首先我们操作分页多条件查询
Dao层:ResourceMapper:
package com. lagou. dao ;
import com. lagou. domain. Resource ;
import com. lagou. domain. ResourceVo ;
import java. util. List ;
public interface ResourceMapper {
public List < Resource > findAllResourceByPage ( ResourceVo resourceVo) ;
}
对应映射配置文件(ResourceMapper.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.lagou.dao.ResourceMapper" >
< select id = " findAllResourceByPage" parameterType = " ResourceVo" resultType = " Resource" >
select * from resource
< where>
< if test = " name != null and name != ''" >
and name like '%${name}%'
</ if>
< if test = " url != null and url != ''" >
and url = #{url}
</ if>
< if test = " categoryId != null" >
and category_id = #{categoryId}
</ if>
</ where>
</ select>
</ mapper>
Service层:ResourceService及其实现类 :
package com. lagou. service ;
import com. github. pagehelper. PageInfo ;
import com. lagou. domain. Resource ;
import com. lagou. domain. ResourceVo ;
import java. util. List ;
public interface ResourceService {
public PageInfo < Resource > findAllResourceByPage ( ResourceVo resourceVo) ;
}
package com. lagou. service. impl ;
import com. github. pagehelper. Page ;
import com. github. pagehelper. PageHelper ;
import com. github. pagehelper. PageInfo ;
import com. lagou. dao. ResourceMapper ;
import com. lagou. domain. Resource ;
import com. lagou. domain. ResourceVo ;
import com. lagou. service. ResourceService ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. stereotype. Service ;
import java. util. List ;
@Service
public class ResourceServiceImpl implements ResourceService {
@Autowired
private ResourceMapper resourceMapper;
@Override
public PageInfo < Resource > findAllResourceByPage ( ResourceVo resourceVo) {
PageHelper . startPage ( resourceVo. getCurrentPage ( ) , resourceVo. getPageSize ( ) ) ;
List < Resource > allResourceByPage = resourceMapper. findAllResourceByPage ( resourceVo) ;
PageInfo < Resource > resourcePageInfo = new PageInfo < > ( allResourceByPage) ;
return resourcePageInfo;
}
}
Web层:ResourceController :
package com. lagou. controller ;
import com. github. pagehelper. PageInfo ;
import com. lagou. domain. Resource ;
import com. lagou. domain. ResourceVo ;
import com. lagou. domain. ResponseResult ;
import com. lagou. service. ResourceService ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. web. bind. annotation. RequestBody ;
import org. springframework. web. bind. annotation. RequestMapping ;
import org. springframework. web. bind. annotation. RestController ;
@RestController
@RequestMapping ( "/resource" )
public class ResourceController {
@Autowired
private ResourceService resourceService;
@RequestMapping ( "/findAllResourceByPage" )
public ResponseResult findAllResourceByPage ( @RequestBody ResourceVo resourceVo) {
PageInfo < Resource > allResourceByPage = resourceService. findAllResourceByPage ( resourceVo) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "资源信息分页多条件查询成功" ,
allResourceByPage) ;
return responseResult;
}
}
使用Postman测试接口
分页多条件查询后,我们再操作资源分类查询
代码编写如下:
Dao层:添加部分ResourceMapper:
public List < ResourceCategory > findAllResourceCategory ( ) ;
添加部分ResourceMapper.xml:
< select id = " findAllResourceCategory" resultType = " ResourceCategory" >
select * from resource_category
</ select>
Service层:添加部分ResourceService及其实现类 :
public List < ResourceCategory > findAllResourceCategory ( ) ;
@Override
public List < ResourceCategory > findAllResourceCategory ( ) {
List < ResourceCategory > allResourceCategory = resourceMapper. findAllResourceCategory ( ) ;
return allResourceCategory;
}
Web层:添加部分ResourceController :
@RequestMapping ( "/findAllResourceCategory" )
public ResponseResult findAllResourceCategory ( ) {
List < ResourceCategory > allResourceCategory = resourceService. findAllResourceCategory ( ) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "查询所有资源分类信息成功" ,
allResourceCategory) ;
return responseResult;
}
使用Postman测试接口
在71章博客里说过,有些代码编写,需要权限模块说明后,才进行编写,现在我们就开始编写这些代码
登陆及动态菜单展示 :
动态显示图解:
根据权限显示对应的管理模块,后面会再次说明
登陆 :
需求分析
需求:输入用户名密码,点击登陆按钮,进行用户登陆
在进行登录之前,说明一下加密算法MD5介绍
什么是MD5:
MD5加密全程是Message-Digest Algoorithm 5(信息-摘要算法)
它对信息进行摘要采集,再通过一定的位运算,最终获取加密后的MD5的对应字符串
MD5有哪些特点:
MD5加密的特点主要有以下几点:
1:针对不同长度待加密的数据、字符串等等,其都可以返回一个固定长度的MD5加密字符串(通常32位的16进制字符串)
2:其加密过程几乎不可逆,所以登录的密码也会在服务器里进行加密来操作查询,使得登录是否成功
当然加盐也是一样,只要有不可逆的操作时,对应登录的对应输入,如密码
也就会在服务器里进行加密,然后查询数据库,进行判断是否正确)
除非维护一个庞大的Key-Value数据库来进行碰撞破解或者暴力破解
碰撞破解:也就是查询对应数据库是否有对应数据,暴力破解:将数据库对应的key-value依次进行试验
如用户名和密码的多次试验(暴力破解),或者对应的MD5加密后的数据对应(碰撞破解)
不同的场景,对应的key-value不同,看如下解释:
而对于MD5加密后的数据对应解释(碰撞破解,key一般是密码,value一般是加密后的数据):
比如我们通过key,经过MD5加密得到了value,如123456lagou经过MD5加密变成f00485441dfb815c75a13f3c3389c0b9
然后将这一组数据保存到数据库里面(当然若是在开发中,存放在数据库的就是用户名和f00485441dfb815c75a13f3c3389c0b9)
即将123456lagou和f00485441dfb815c75a13f3c3389c0b9存放在数据库中,这样存放后
我们就可以通过加密后的f00485441dfb815c75a13f3c3389c0b9得到123456lagou这个真正的密码
我们通过这样的操作,进行多组的存放
即入侵对方数据库后,根据数据库MD5加密的value找到对应的key,并不是逆向破解MD5算法
而是一个庞大的MD5的key-value数据库查询,即很多个key-value来进行操作
对于用户名和密码的多次试验解释(暴力破解,key一般是用户名,value一般是密码):
我们可以通过同样的用户名和密码的key-value数据库来进行暴力破解
但现在的用户名和密码的碰撞操作基本有次数限制,实际上也可以跳过这个限制(但很难),所以基本不做考虑
我们发现,在没有对应的key-value庞大数据库时
就算我们得到了对应MD5加密的value,基本也得不到对应的key(密码)
所以几乎无法解开,当然无论是什么加密,那么一定有对应的逆过程,所以这里说的是几乎
因为MD5算法好像被某软件小组破解了,早在2010年,美国软件工程学会也认为MD5算法已被破解,但普通人是基本不可能破解的
2:运算简便,且可实现方式多样,而由于有庞大的Key-Value数据库来进行碰撞破解
所以我们通常需要通过一定的处理方式来避免碰撞破解
如:
加盐(专业术语,加盐:给没有加密的字符串拼接上随机字符串,一般随机的字符串不会出现相同的,如操作UUID等等)
强加密(强加密:对加密再次进行加密,如给加密的字符串进行加盐)
对于强加密的解释如下:
即在原来的加密字符串上拼接上随机的字符串进行加密
也可以操作拼接方式,而不只是直接拼接在后面,一般可能会拼接在后面
而拼接时,因为是在服务器里面操作的,所以这个拼接方式基本不可能被获得(除非内部人员)
使得原来加密字符串变长,并将得到的随机字符串存放在对应用户名的那一条数据的某个字段里面
而在登录时,登录的对应密码在服务器中也要进行加密
因为MD5加密的对应密码字符串基本不可逆,所以我们需要在加密后,进行对应查询(这里使用了加盐)
然后取出对应存放好的随机字符串与加密后的输入的字符串进行对应拼接(服务器的拼接方式)
使得判断是否与对应拼接后的字符串一致
若一致,则登录成功,而由于是随机的(自己定义随机出现的字符串)
那么就算被别人入侵了数据库得到了对应随机出来的字符串后
就算使用的是超级庞大的MD5的key-value数据库(经过随机字符串的拼接),那么也是很难破解的
因为就算知道了对应拼接的随机字符串数,也要知道对应的拼接方式
这样的基数(数据库的总条数)就非常大了,所以基本很难碰撞破解
因为对应的key-value可能存放不了这么多数据,或者没有对应的key-value
所以,强加密是可以进行更加的安全效果的
对于加盐的的解释如下:
加盐的安全效果与强加密差不多,都是可以进行更加的安全效果的
与强加密不同的是,这里是给没有加密的字符串进行随机字符串拼接
但我们可以发现,若随机字符串不拼接在后面,而是随机字符串的每个字符进行整体拼接
那么使用加盐,增加的个数是对于原字符串和随机字符串的排列组合
而使用强加密,是加密字符串和随机字符串的排列组合
所以这两种实际上添加的个数是按照加密字符串和原字符串的位数来决定的
即添加的个数也基本都是不同的,但我们可以发现,只要原字符串大于MD5加密的32位字符串位数,加盐的排列组合就多
即这时我们可以使用加盐,若是直接拼接在后面的,那么强加密的模式的随机字符串是没有作用的
因为只需要对前32位进行查询即可,而使用加盐,那么排列组合就是随机字符串的排列组合了
所以在不需要非常复杂的加密时
一般都是使用加盐,而不是强加密
因为只需要对前32位进行查询即可,而复杂的加密却需要随机字符串的每个字符都进行随机拼接
而不能直接拼接到后面,这是很麻烦的
如何使用那一种看你的操作,这里我们就直接使用加盐
因为一般不会进行复杂的加密,若使用复杂的加密,则上限高,但实际上对于原字符串一般都不会超过32位
那么由于都是使用随机的字符串,使得个数变多,且由于随机(自己定义的随机),那么对应的key-value也是基本很难找到的
因为不同的程序员使用的随机字符串获得方式也基本不会相同,也很难猜到会使用那种随机方式
而就算是拼基数(数据库的总条数),对于是最少32位排列组合也是非常大的
但要完全的安全,基本不可能,因为只要可以登录
那么就一定有对应的Key-Value数据(正好碰到,或者庞大的Key-Value数据库)
换言之就是能进去,那么就一定可以被破解,我们只能提高安全,但不能完全安全
4:对于一个固定的字符串,数字等等,MD5加密后的字符串是固定的(这是基本必须的,因为我们需要登录)
也就是说不管MD5加密多少次,都是同样的结果
加盐在注册时进行拼接,在登录时,是直接获得后再拼接
也就是说注册后,对应的随机字符串也就固定了
而由于是对加密字符串进行拼接,所以我们也可以称作加盐是加强MD5算法的操作
图解:
从图中看,登录时的对应密码的确在服务器里也进行加密了
Java代码中如何使用MD5:
添加依赖:
< dependency>
< groupId> org.apache.commons</ groupId>
< artifactId> commons-lang3</ artifactId>
< version> 3.3.2</ version>
</ dependency>
< dependency>
< groupId> commons-codec</ groupId>
< artifactId> commons-codec</ artifactId>
< version> 1.3</ version>
</ dependency>
添加工具类:
package com. lagou. utils ;
import org. apache. commons. codec. digest. DigestUtils ;
import java. util. UUID ;
public class Md5 {
public final static String md5key = "lagou" ;
public static String md5 ( String text, String key) throws Exception {
String encodeStr= DigestUtils . md5Hex ( text+ key) ;
System . out. println ( "MD5加密后的字符串为:encodeStr=" + encodeStr) ;
return encodeStr;
}
public static boolean verify ( String text, String key, String md5) throws Exception {
String md5Text = md5 ( text, key) ;
if ( md5Text. equalsIgnoreCase ( md5) )
{
System . out. println ( "MD5验证通过" ) ;
return true ;
}
return false ;
}
public static void main ( String [ ] args) throws Exception {
String s = md5 ( "123456" , md5key) ;
System . out. println ( s) ;
boolean verify = verify ( "123456" , md5key, s) ;
System . out. println ( verify) ;
}
}
到了这里,我们就可以来实现登录操作了:
首先再分析一下登录代码编写:
这时用户的操作,所以操作的是User类,即对应的接口也是User的
Dao层:添加部分UserMapper:
public User login ( User user) ;
添加部分UserMapper.xml:
< select id = " login" parameterType = " User" resultType = " User" >
select * from user where phone = #{phone}
</ select>
Service层:添加部分UserService及其实现类 :
public User login ( User user) throws Exception ;
@Override
public User login ( User user) throws Exception {
User pass = userMapper. login ( user) ;
if ( pass!= null && Md5 . verify ( user. getPassword ( ) , "lagou" , pass. getPassword ( ) ) ) {
return pass;
} else {
return null ;
}
}
Web层:添加部分UserController :
@RequestMapping ( "/login" )
public ResponseResult login ( User user, HttpServletRequest request) throws Exception {
ResponseResult responseResult;
User login = userService. login ( user) ;
if ( login!= null ) {
HttpSession session = request. getSession ( ) ;
String access_token = UUID . randomUUID ( ) . toString ( ) ;
session. setAttribute ( "access_token" , access_token) ;
session. setAttribute ( "User_id" , login. getId ( ) ) ;
HashMap < Object , Object > objectObjectHashMap = new HashMap < > ( ) ;
objectObjectHashMap. put ( "access_token" , access_token) ;
objectObjectHashMap. put ( "User_id" , login. getId ( ) ) ;
responseResult = new ResponseResult ( true , 200 , "用户登录成功" , objectObjectHashMap) ;
} else {
responseResult = new ResponseResult ( true , 400 , "用户名或密码错误" , null ) ;
}
return responseResult;
}
使用Postman测试接口
在这里补充一下,我们改造一下上面的login方法
Web层:修改部分UserController (扩展login方法):
@RequestMapping ( "/login" )
public ResponseResult login ( User user, HttpServletRequest request) throws Exception {
ResponseResult responseResult;
User login = userService. login ( user) ;
if ( login!= null ) {
HttpSession session = request. getSession ( ) ;
String access_token = UUID . randomUUID ( ) . toString ( ) ;
session. setAttribute ( "access_token" , access_token) ;
session. setAttribute ( "User_id" , login. getId ( ) ) ;
HashMap < Object , Object > objectObjectHashMap = new HashMap < > ( ) ;
objectObjectHashMap. put ( "access_token" , access_token) ;
objectObjectHashMap. put ( "User_id" , login. getId ( ) ) ;
objectObjectHashMap. put ( "user" , login) ;
responseResult = new ResponseResult ( true , 1 , "用户登录成功" , objectObjectHashMap) ;
} else {
responseResult = new ResponseResult ( false , 400 , "用户名或密码错误" , null ) ;
}
return responseResult;
}
分配角色操作:
首先我们先查询出对应用户已经关联的角色
需求分析
需求:点击分配角色,将该用户所具有的角色信息进行回显
可以发现这个已经关联的角色只有两个,而后面的可以操作的角色前面有对应sql可以得到
所以我们现在编写查询对应用户关联的角色
Dao层:添加部分UserMapper:
public List < Role > findUserRelationRoleById ( Integer id) ;
添加部分UserMapper.xml:
< select id = " findUserRelationRoleById" parameterType = " Integer" resultType = " Role" >
SELECT * FROM roles r INNER JOIN user_role_relation ul ON r.id = ul.role_id WHERE ul.user_id =
#{userid}
</ select>
Service层:添加部分UserService及其实现类 :
public List < Role > findUserRelationRoleById ( Integer id) ;
@Override
public List < Role > findUserRelationRoleById ( Integer id) {
List < Role > userRelationRoleById = userMapper. findUserRelationRoleById ( id) ;
return userRelationRoleById;
}
Web层:添加部分UserController :
@RequestMapping ( "/findUserRelationRoleById" )
public ResponseResult findUserRelationRoleById ( Integer id) {
List < Role > userRelationRoleById = userService. findUserRelationRoleById ( id) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "查询用户关联角色成功" ,
userRelationRoleById) ;
return responseResult;
}
使用Postman测试接口
分配角色
需求分析
需求:点击确定按钮,真正实现用户角色关联
具体分析:
Dao层:添加部分UserMapper:
public void deleteUserContextRole ( Integer id) ;
public void userContextRole ( User_Role_relation user_role_relation) ;
添加部分UserMapper.xml:
< select id = " deleteUserContextRole" parameterType = " int" >
delete
from user_role_relation
where user_id = #{userid}
</ select>
< insert id = " userContextRole" parameterType = " User_Role_relation" >
insert into user_role_relation
values (null, #{userId}, #{roleId},
#{createdTime}, #{updatedTime}, #{createdBy}, #{updatedBy})
</ insert>
再编写Service层之前,我们需要创建一个类来存放对应参数
创建UserRoleVo类:
package com. lagou. domain ;
import java. util. List ;
public class UserRoleVo {
private List < Integer > roleIdList;
private Integer userId;
public List < Integer > getRoleIdList ( ) {
return roleIdList;
}
public void setRoleIdList ( List < Integer > roleIdList) {
this . roleIdList = roleIdList;
}
public Integer getUserId ( ) {
return userId;
}
public void setUserId ( Integer userId) {
this . userId = userId;
}
}
接下来我们来编写Service层代码:
Service层:添加部分UserService及其实现类 :
public void userContextRole ( UserRoleVo userRoleVo) ;
@Override
public void userContextRole ( UserRoleVo userRoleVo) {
userMapper. deleteUserContextRole ( userRoleVo. getUserId ( ) ) ;
for ( Integer roleId: userRoleVo. getRoleIdList ( ) ) {
User_Role_relation user_role_relation = new User_Role_relation ( ) ;
user_role_relation. setUserId ( userRoleVo. getUserId ( ) ) ;
user_role_relation. setRoleId ( roleId) ;
Date date = new Date ( ) ;
user_role_relation. setCreatedTime ( date) ;
user_role_relation. setUpdatedTime ( date) ;
user_role_relation. setCreatedBy ( "system" ) ;
user_role_relation. setUpdatedBy ( "system" ) ;
userMapper. userContextRole ( user_role_relation) ;
}
}
Web层:添加部分UserController :
@RequestMapping ( "/userContextRole" )
public ResponseResult userContextRole ( @RequestBody UserRoleVo userRoleVo) {
userService. userContextRole ( userRoleVo) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "分配角色成功" , null ) ;
return responseResult;
}
使用Postman测试接口
动态菜单显示
需求分析
需求:登陆成功后,根据用户所拥有的权限信息,进行菜单列表动态展示
具体分析:
对上图分析,我们发现要在Dao层编写四个方法,但其中的第一个方法我们已经编写过了
虽然前面编写过的方法中,有实现了父子菜单的方法,和根据角色id查询所有菜单id的方法
但却没有只查询父菜单的方法和只查询子菜单的方法,所以复用不到,那么为什么我们不使用实现了父子菜单的方法的结果呢
主要是因为实现了父子菜单的方法的结果只是给出对应权限的关系,而不能说明这个权限是否是这个用户的
当然了,你也可以利用他的结果的菜单id,来进行关联,但发现,还不如分开的两个方法,因为实现了父子菜单的方法是嵌套的
且对应的sql编写虽然简单了(只需要编写一个方法,而不需要编写两个了)
但后台还需要对应sql语句来判断封装
如判断对应id是否相等,相等则进行新的list集合封装,同样的则进行覆盖,这样就得到了对应的用户的权限的父子菜单信息了
但这里需要我们编写后台逻辑代码,这是非常麻烦的,所以一般能使用sql语句能做到的事情,后台尽量少做
使用sql语句即可以方便,也可以更好维护,更加的可以减少逻辑代码(基本都是这样,但也有特殊,如你的sql语句不好)
如查询所有,你偏偏就只写查询一条语句的代码,然后通过循环1到100(或者更大的)的id来进行多次查询每条语句
直到查询为null时,才结束,这是非常不好的使用sql语句
即这里我们就编写第二个和第三个方法
第四个也需要编写,没有复用的,即我们就编写后面三个方法
Dao层:添加部分UserMapper:
public List < Menu > findParentMenuByRoleId ( List < Integer > ids) ;
public List < Menu > findSubMenuByPid ( Integer pid) ;
public List < Resource > findResponseByRoleId ( List < Integer > ids) ;
添加部分UserMapper.xml:
< select id = " findParentMenuByRoleId" parameterType = " list" resultType = " Menu" >
SELECT DISTINCT m.*
FROM roles r
INNER JOIN role_menu_relation rl ON r.id = rl.role_id
INNER JOIN menu m ON m.id = rl.menu_id
WHERE m.parent_id = -1 AND r.id IN
< foreach collection = " list" item = " item" open = " (" close = " )" separator = " ," >
#{item}
</ foreach>
</ select>
< select id = " findSubMenuByPid" parameterType = " int" resultType = " Menu" >
SELECT * FROM menu m WHERE m.parent_id = #{pid};
</ select>
< select id = " findResponseByRoleId" parameterType = " list" resultType = " Resource" >
SELECT DISTINCT rs.* FROM roles r INNER JOIN role_resource_relation rr ON r.id = rr.role_id
INNER JOIN resource rs ON rs.id = rr.resource_id
WHERE r.id IN
< foreach collection = " list" item = " item" open = " (" close = " )" separator = " ," >
#{item}
</ foreach>
</ select>
Service层:添加部分UserService及其实现类 :
public ResponseResult getUserPermissions ( Integer userid) ;
@Override
public ResponseResult getUserPermissions ( Integer userid) {
List < Role > userRelationRoleById = userMapper. findUserRelationRoleById ( userid) ;
ArrayList < Integer > roleIds = new ArrayList < > ( ) ;
for ( Role role : userRelationRoleById) {
roleIds. add ( role. getId ( ) ) ;
}
List < Menu > parentMenuByRoleId = userMapper. findParentMenuByRoleId ( roleIds) ;
for ( Menu menu: parentMenuByRoleId) {
List < Menu > subMenuByPid = userMapper. findSubMenuByPid ( menu. getId ( ) ) ;
menu. setSubMenuList ( subMenuByPid) ;
}
List < Resource > responseByRoleId = userMapper. findResponseByRoleId ( roleIds) ;
HashMap < String , Object > hashMap = new HashMap < > ( ) ;
hashMap. put ( "menuList" , parentMenuByRoleId) ;
hashMap. put ( "resourceList" , responseByRoleId) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "获取用户权限信息成功" ,
hashMap) ;
return responseResult;
}
Web层:添加部分UserController :
@RequestMapping ( "/getUserPermissions" )
public ResponseResult getUserPermissions ( HttpServletRequest request) {
String header_token = request. getHeader ( "Authorization" ) ;
String access_token = ( String ) request. getSession ( ) . getAttribute ( "access_token" ) ;
ResponseResult responseResult;
if ( header_token. equals ( access_token) ) {
Integer user_id = ( Integer ) request. getSession ( ) . getAttribute ( "User_id" ) ;
responseResult = userService. getUserPermissions ( user_id) ;
} else {
responseResult = new ResponseResult ( false , 400 , "获取菜单信息失败" , null ) ;
}
return responseResult;
}
使用Postman测试接口