aisell_登录与角色

一、登录功能

(1)准备一个加密算法的工具类

package cn.itsource.aisell.common;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.hibernate.loader.plan.spi.Return;
/*
* 这是一个加密算法的工具类。
*   加盐(随意定的source)、加密方式、加密次数(随机定的遍历10次)
* */
public class MD5Util {
    //1.设置盐值的常量---SALT
    private static final String SALT="source";
    //2.准备一个加密次数的常量--HASHITERATIONS
    private static final int HASHITERATIONS=10;
    //3.提供一个加密的方法,将密码参数传过来
    public static String creatMD5(String pwd){
        //4.传入加密方式、密码、盐值、加密次数4个参数
        SimpleHash hash=new SimpleHash("MD5",pwd,SALT,HASHITERATIONS);
        //5.返回一个经过MD5编码的值
        return hash.toString();
    }
}

(2)为了测试方便,通过算法来修改数据库的密码。
使数据库中的用户名个密码相同

package cn.itsource.aisell.service;
import cn.itsource.aisell.BaseSpringTest;
import cn.itsource.aisell.common.MD5Util;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

public class EmployeeServiceTest extends BaseSpringTest{
    //注入IEmployeeService对象
    @Autowired
    private IEmployeeService iEmployeeService;

    //测试查询所有员工
    @Test
    public void myTestFindAll() throws  Exception{
        iEmployeeService.findAll().forEach(e-> System.out.println(e));
    }

    //将数据库中的用户和密码一致,并且密码加密加盐值
    @Test
    public void myTestFindAllAndUpdatePwd() throws  Exception{
        //从数据库中查询出所有的员工对象集合,并遍历
        iEmployeeService.findAll().forEach(e-> {
            //通过遍历出来的用户获取到用户名
            String username=e.getUsername();
            //设置加密后的密码到用户对象e中去--调用加密算法工具类的加密方法,将查询到的用户名设置为密码(用户名和密码一致,方便测试)
            e.setPassword(MD5Util.creatMD5(username));
            //将e对象再保存到数据库中
            iEmployeeService.save(e);
        });
    }
}

(3)员工添加和修改保存操作与密码之间
根据id判断是添加保存还是修改保存操作
在employeeServiceImpl中写覆写父类的sava方法,新增自己的功能

//覆写service层实现类的父类的sava方法---扩展功能:添加员工的时候将密码加密
    //添加或者修改的保存
    @Override
    public void save(Employee employee) {
        //根据id判断是添加还是修改保存操作
        if(employee.getId()==null){
            //id为空就是添加保存,给密码加密
            employee.setPassword(MD5Util.creatMD5(employee.getPassword()));
        }
        //保存到数据库中
        employeeRepository.save(employee);
    }

(4)准备一个登录页面,并写上相应的js代码

<%--
  Created by IntelliJ IDEA.
  User: zhaoyi
  Date: 2018/10/14
  Time: 下午4:27
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    源码智销系统
    <%--引入已经引入easyui样式的head.jsp文件--%>
    <%@ include file="/WEB-INF/views/head.jsp"%>

    




用户名:
密 码:
登陆 重置

(5)修改登录的controller层:LoginController
大体的改动地方:
使用GET和POST两种请求方式处理登录路径。
GET:负责跳转到登录页面
POST:在登录的jsp中,表单提交使用的post方式,还使用ajax交互技术,请求后台路径,请求成功就返回后台的json数据给前台,前台处理成功后页面的跳转,请求失败也返回相应的json数据给前台捕获处理。
注意点:
ajax交互技术不能跳转页面,只能返回json数据,交给前台处理

package cn.itsource.aisell.controller;
import cn.itsource.aisell.common.JsonResult;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class LoginController {

    //跳转到login登录页面--用GET请求方式
    @RequestMapping(value = "/login",method = RequestMethod.GET)
    public String index(){
        return "/login";
    }

    /*
    * 在js中使用ajax请求返回数据,千万不要跳转页面。需要返回的数据{success:true/false,msg:xxx},就是将JsonResult中的字段返回去
    *       若ajax请求跳转了,那么:会返回跳转的页面当前字符串回来或者直接报错
    *   使用前台ajax交互技术,请求后台路径,请求成功就返回后台的json数据给前台,前台处理成功后页面的跳转,请求失败也返回相应的json数据给前台捕获处理
    * */
    //实现登录功能--用POST请求(form表单)
    @RequestMapping(value = "/login",method = RequestMethod.POST)
    @ResponseBody//返回json数据(不要忘记这个注解,返回给前台都返回json数据)
    public JsonResult login(String username, String password){
        //当前台登录页面输入数据时会提交到后台来
//        System.out.println(username+":"+password);

        /*
        * 已经叫给spring去管理shiro了,所以此处就不用再创建核心对象securityManager了,
        * 也不需要拿到凭证适配器、设置加密方式、设置加密次数了,同样也不用拿自定义的realm类和
        * 核心对象securityManager发生关系,也不用将核心对象securityManager放到上下文中去
        * */

        //1.直接拿到当前的用户
        Subject currentName = SecurityUtils.getSubject();
        //2.如果当前用户没有登录,就给他个令牌叫他登录
            //currentName.isAuthenticated():布尔类型。false表示没有登录,反之则登录
        if(!currentName.isAuthenticated()){
            try {
                //3.给个令牌,将前台传过来的参数传进去
                UsernamePasswordToken token = new UsernamePasswordToken(username, password);
                //4.用户登录
                currentName.login(token);
            } catch (UnknownAccountException e) {
                e.printStackTrace();
//                System.out.println("用户名错误");
                return new JsonResult(false,"用户名错误!");
            }catch (IncorrectCredentialsException e) {
                e.printStackTrace();
//                System.out.println("密码错误");
                return new JsonResult(false,"密码错误");
            }catch (AuthenticationException e) {
                e.printStackTrace();
//                System.out.println("未知错误");
                return new JsonResult(false,"未知错误");
            }
        }
        //成功后直接跳转到主页面。用redirect跳转,就不受mvc视图解析配置(自动生成路径)的影响了
//        return "redirect:/jsp/main.jsp";
        //用ajax请求,返回数据,交由前台处理
        return new JsonResult();
    }


    //用户名登录注销
    @RequestMapping("/logout")
    public String logout() {
        //直接拿到用户名
        Subject subject = SecurityUtils.getSubject();
        //注销登录
        subject.logout();
        //注销后直接跳转到登录页面
        return "redirect:/s/login.jsp";
    }
}

(6)由于登录页面有静态资源,所以要在FilterChainDefinitionMapBuilder类中(解决权限路径在applicationcontext-shiro.xml中写死问题)放行静态资源,不予拦截

		//设置静态资源放行
        filterChainDefinitionMap.put("*.js","anon");
        filterChainDefinitionMap.put("*.css","anon");
        filterChainDefinitionMap.put("/css/**","anon");
        filterChainDefinitionMap.put("/js/**","anon");
        filterChainDefinitionMap.put("/easyui/**","anon");
        filterChainDefinitionMap.put("/images/**","anon");

(7)登录的用户名和密码直接从数据库中查询。
之前在自定义realm类中使用的是模拟的数据库用户名和密码,用于登录测试。

//登录验证方法
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //1.拿到令牌。将authenticationToken令牌强转为usernamepasswordToken类型的令牌
        UsernamePasswordToken token=(UsernamePasswordToken)authenticationToken;
        //2.根据令牌拿到用户名
        String username = token.getUsername();

//        //3.再根据用户名去数据库(模拟的数据库)拿到对应的密码
//        String password=getByName(username);

        //3.根据用户名直接去数据库中查找相应的用户
        Employee employee = employeeService.findByUsername(username);
        //4.判断如果用户为空
        if(employee==null){
            //返回空,代表登录失败,shiro会自动报UnknownAccountException异常
            return null;
        }

        //5.准备好盐值
        ByteSource salt = ByteSource.Util.bytes("source");
        //6.返回AuthenticationInfo对象。通过SimpleAuthenticationInfo类,参数(用户名、密码、盐值、随意的realm名字)
            //用户名与密码放进去-注:它会自动的比数据库获取的密码与你前台传过来的密码----employee.getPassword():数据库查询出来的用户的密码
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username, employee.getPassword(), salt, getName());
        return authenticationInfo;
    }


   /* 从数据库中查询用户,就不用模拟的了
   //根据当前登录用户拿到密码(模拟数据库)--456经过加盐遍历10此得到的加密密码42a02ed97752caf987d13d1a5cb53847
    private String getByName(String username){
        if("admin".equals(username)){
            return "42a02ed97752caf987d13d1a5cb53847";
        }else if("it".equals(username)){
            return "42a02ed97752caf987d13d1a5cb53847";
        }
        return null;
    }*/

(8)扩展:在login.jsp登录页面使用回车键登录功能

//扩展:回车键登录功能
        //keyup:键盘事件监听  event:事件对象
        $(document.documentElement).on("keyup", function(event) {
            //不同的按键会打印出不同的值
            console.debug(event.keyCode);
            var keyCode = event.keyCode;
            console.debug(keyCode);
            if (keyCode === 13) { // 捕获回车键(13就是回车键对应的值)
                submitForm(); // 调用上面的提交表单方法
            }
        });

(9)扩展:检查自己是否是顶级页面

// 扩展:检查自己是否是顶级页面 /login--解决页中还有页的问题
        if (top != window) {// 如果不是顶级
            //把子页面的地址,赋值给顶级页面显示
            window.top.location.href = window.location.href;
        }

(10)在主页面main.jsp上面展示用户名和注销功能新
先在主页面引入shiro的标签

<%--引入shiro标签:--%>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

再通过shiro标签获取到用户名
新建一个div标签,被包含于外面的div标签

		
智能销售系统 <%--:使用引入的shiro标签获取用户名--%>
欢迎您, 注销

"/logout"注销路径。在LoginController登录中

//用户名登录注销
    @RequestMapping("/logout")
    public String logout() {
        //直接拿到用户名
        Subject subject = SecurityUtils.getSubject();
        //注销登录
        subject.logout();
        //注销后直接跳转到登录页面
        return "redirect:/login";
    }

(11)角色role和权限permission通过代码生成器生成

(12)配置多对多关系。都是单向
员工和角色多对多关系
在Employee.java中:

/*
    * 员工和角色role是多对多关系 @ManyToMany后面可以配置个懒加载,但是list集合默认就是懒加载,所以可以不管
    * name = "employee_role":生成的中间表的名字
    * joinColumns = @JoinColumn(name = "employee_id"):中间表中的当前类的id
    * inverseJoinColumns = @JoinColumn(name = "role_id"):中间表中的另一个类的id
    *
    * */
    @ManyToMany
    @JoinTable(name = "employee_role",joinColumns = @JoinColumn(name = "employee_id"),inverseJoinColumns = @JoinColumn(name = "role_id"))
    private List roles=new ArrayList<>();

    //提供get/set方法。跟其他表有关联的字段不要覆写tostring
    public List getRoles() {
        return roles;
    }
    public void setRoles(List roles) {
        this.roles = roles;
    }

角色与权限之间是多对多关系。单向
在Role.java中;

 /*
    * 角色和权限之间是单向多对多关系  @ManyToMany后面可以配置个懒加载,但是list集合默认就是懒加载,所以可以不管
    *name = "role_permission":生成的中间表的名字
    * joinColumns = @JoinColumn(name = "role_id"):中间表中的当前类的id
    *inverseJoinColumns = @JoinColumn(name ="permission_id" ):中间表中的另一个类的id
    * */
    @ManyToMany
    @JoinTable(name = "role_permission",joinColumns = @JoinColumn(name = "role_id"),inverseJoinColumns = @JoinColumn(name ="permission_id" ))
    private List permissions=new ArrayList<>();

    //提供get/set方法,注意:与其他表有关联的字段不要覆写tostring
    public List getPermissions() {
        return permissions;
    }
    public void setPermissions(List permissions) {
        this.permissions = permissions;
    }

(13)在角色Role.jsp页面上展示权限数据
使用formatter属性。灵活在展示数据库中的数据
先在Role.jsp中添加formatter属性。

	
		<%--要在角色中拿到权限。formatter:更加灵活的显示数据库中的数据--%>
        权限
        

在role.js中提供方法,返回并展示数据在Role.jsp页面上

//formatter:灵活在展示数据库中的数据---在role.jsp中的formatter:formatPerms属性
//value;当前格子中的值(权限名的值)  row:当前行的值  index:当前行的下标(索引)
function formatPerms(value,row,index) {
    //先定义一个空的权限值
    var permsSt="";
    //value:所有角色对应的array数组形式的permission权限值(包括id、name、url,有的都查出来)
    // console.debug(value);
    //遍历数组Array类型的value--使用ES6新语法,变量let相当于var
        //let perm in value:拿到的是下标,取值value[perm]    let perm of value:拿到的是对象,取值直接对象.字段
    for(let perm of value){
        //遍历后赋值给permsSt,并每个中间隔一个空格(" "),也可以空字符串等等其他的
        permsSt+=perm.name+" "
    }
    //将值返回展示在页面上
    return permsSt;
}

(14)角色Role.jsp添加数据的弹出框效果
aisell_登录与角色_第1张图片
(15)在Role.jsp中准备上面图片的弹出框
注意:使用javaScript的方式创建两个数据表格,就不需要class=“easyui-datagrid”,直接js,以便于方便注册事件

Role.jsp部分:

<%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2019/3/15
  Time: 11:11
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title
    <%@include file="/WEB-INF/views/head.jsp" %>
    <%--引入role特有的js--%>
    



<%--toolbar:'#gridToolBar':与上面的添加、删除、修改按钮的div相关联--%>

        <%--要在角色中拿到权限。formatter:更加灵活的显示数据库中的数据--%>
        
角色名称 角色编码权限
<%--表单弹出框--%>
角色名称: 角色编码:
<%--准备一个layout布局。只要左边和中间的页面,并在每个页面中加上数据表格--%>
<%--这个是左边的页面:要添加角色和权限部分--%>
权限名称 权限路径 权限编码
<%--右边页面:这个是所有的权限部分,通过role.js中的url路径到后台去查询权限数据--%>
权限名称 权限路径 权限编号
<%--弹出框(表单)操作--%>

role.js中用js创建左边数据表格(包含角色权限信息)和右边数据表格(包含所有权限信息)

$(function () {
	//获取到常用的组件
		//左边数据表格组件
	var LeftrolePermissionDataGrid=$("#LeftrolePermissionDataGrid");
		//右边数据表格组件
	var RightpermissionDataGrid=$("#RightpermissionDataGrid");//右边的数据表格
	
	//左边数据表格LeftrolePermissionDataGrid。当前角色所有权限
    LeftrolePermissionDataGrid.datagrid({
        fit:true,
        fitColumns:true,
        singleSelect:true,
        onDblClickRow:itsource.removePerms
    })

	//右边数据表格RightpermissionDataGrid。所有权限---使用js创建数据表格
	    RightpermissionDataGrid.datagrid({
	        //通过url路径到后台去查询所有权限
	        url:'/permission/page',
	        fit:true,
	        fitColumns:true,
	        singleSelect:true,
	        pagination:true,
    })
}

(16)就上面的两个数据表格完成一个功能;当双击右边的所有权限数据表格中的一条数据时,会自动将这个数据添加到左边角色所有权限数据表格中去。并且左边数据表格有的,双击右边表格时不能重复添加

在Role.js中的代码:

$(function () {
	//获取到常用的组件
	//右边数据表格组件
	var RightpermissionDataGrid=$("#RightpermissionDataGrid");
	itsource = {
		//当双击的时候,添加权限到左边数据表格中(当前角色权限)
            //onDblClickRow事件的两个参数:index:点击的行的索引值,该索引值从0开始。  row:对应于点击行的记录。
        addPerms(index,rightRows){
            //1。获取到左边表格的所有值。--当左边表格已经有权限了,而双击右边的表格添加权限,如果是一样的就不用再添加到左边去。根据id判断是否重复
           var leftRows=LeftrolePermissionDataGrid.datagrid("getRows");
            //2.遍历左边的数据行,根据id判断是否跟右边的一致
            for(let r of leftRows){
                //若果两边的id相同,就在屏幕右下方给出提示
                if(r.id==rightRows.id){
                    $.messager.show({
                        title:'温馨提示',
                        msg:'已存在相同的权限!',
                        showType:'show'
                    });
                    //返回
                    return;
                }
            }
            //3.否则就把右边的权限添加到左边去
            LeftrolePermissionDataGrid.datagrid("appendRow",rightRows);
        },
	}

	
	//右边数据表格RightpermissionDataGrid。所有权限---使用js创建数据表格
    RightpermissionDataGrid.datagrid({
        //通过url路径到后台去查询所有权限
        url:'/permission/page',
        fit:true,
        fitColumns:true,
        singleSelect:true,
        pagination:true,
        //onDblClickRow事件:在用户双击一个单元格的时候触发。itsource.addPerms:触发事件后就调用这个方法
        onDblClickRow:itsource.addPerms
    })
}

(17)功能;双击左边角色的所有权限的时候,删除双击的行。

$(function () {
		//常用的控件先获取
		//左边数据表格组件
   		 var LeftrolePermissionDataGrid=$("#LeftrolePermissionDataGrid");
	 itsource = {
		//双击左边角色所有权限行,删除权限的方法
        removePerms(index,row){
            LeftrolePermissionDataGrid.datagrid("deleteRow",index);
        }
	}

//左边数据表格LeftrolePermissionDataGrid。当前角色所有权限
    LeftrolePermissionDataGrid.datagrid({
        fit:true,
        fitColumns:true,
        singleSelect:true,
        //删除权限的方法。双击左边角色所有权限表格的时候,调用itsource.removePerms方法删除选中的行
        onDblClickRow:itsource.removePerms
    })	
}

(18)提交保存。角色与权限是多对多关系,关联对象权限permissions是个集合
问题:无法将权限提交到数据库中。
分析;传权限是以何种方式、何种结构传的。以前都是传的对象,而现在权限permissions是个List集合。
解决:使用form表单的提交额外参数的方式。param参数:form表单提交额外的参数,它的数据也会进行提交。可以提交List、Set、Array等集合、数组形式的参数

$('#ff').form('submit', {    
    url:...,    
    onSubmit: function(param){    
        param.p1 = 'value1';    
        param.p2 = 'value2';    
    }    
});  

在role.js中写js代码处理提交集合参数。

//保存功能
        save(){
            //根据id确定是添加路径还是修改路径
            var url = "/role/save";
            var id = $("#roleId").val();
            if(id){
                url = "/role/update?cmd=update";
            }
            roleForm.form('submit', {
                url:url,


                /*
                * 解决权限保存提交问题:原来是提交的对象。而现在权限是集合的方式,怎么提交?
                *   使用form表单的提交额外参数,param参数。可以提交集合参数:List、Set、Array都行
                * */
                //提交表单前的方法。parm参数:form表单提交额外的参数,它的数据也会进行提交
                onSubmit: function(param){
                    // param.a="Xx";
                    // param.name="张";
                    //1.先拿到左边角色所有权限的数据表格
                   var rows=LeftrolePermissionDataGrid.datagrid("getRows");
                   //2.提交集合参数,遍历集合。---角色和权限是多对多关系。关联的是list集合形式的permissions权限
                    for(let i in rows){//拿到的是array数组的下标
                        //3.拼接相应的传过去。permissions[0].id = 1,  permissions[1].id = 2
                        //将左边表格的数据行id赋值给param参数提交到后台去--使用到了ES6新语法
                        param[`permissions[${i}].id`]=rows[i].id;

                    }
                    return $(this).form('validate');
                    
                },
                //操作成功后的回调 {success:true,msg:xxx}
                success:function(data){
                    //返回的是JSON字符串,我们需要把转成一个JSON对象
                    var result = JSON.parse(data);
                    if(result.success){
                        //成功后刷新
                        roleDataGrid.datagrid("reload");
                        //关闭窗口
                        roleDialog.dialog("close");
                    }else{
                        //把失败信息做一个提示
                        $.messager.alert("提示",`你出错了! 原因是:${result.msg}`,"error");
                    }
                }
            });

(19)清空上次左边数据表格中添加的权限数据,达到新点击添加时,左边表格中的数据时空的
使用数据表格datagrid中的loadData方法 : 加载本地数据,旧的行将被移除。需要传个参数data加载,提供一个[] 就相当于加载空的(清空)。
在role.js中的add()方法中:

itsource = {
        add(){
            //把所有带data-show的元素显示起来
            $("*[data-show]").show();
            $("*[data-show] input").validatebox("enable");
            //打开对话框
            roleDialog.dialog("center").dialog("open");
            //把form中的数据清空
            roleForm.form("clear");
            //把左边的datagird表格中值进行清空--添加时清空表格中上次添加的数据
                //loadData方法:加载本地数据,旧的行将被移除。需要传个参数data加载,提供一个[] 就相当于加载空的(清空)
            LeftrolePermissionDataGrid.datagrid("loadData",[]);
        },

(20)修改角色信息时的回显。重点又是权限数据的回显
修改时,将角色的权限回显在左边的数据表格中
使用数据表格datagrid的loadData方法。

		 //修改按钮功能
        edit(){
            var row = roleDataGrid.datagrid("getSelected");
            if(!row){
                $.messager.alert("提示","选中再来!瓜!","info");
                return;
            }
            //把所有带data-show的元素隐藏起来
            $("*[data-show]").hide();
            $("*[data-show] input").validatebox("disable");
            //打开对话框
            roleDialog.dialog("center").dialog("open");
            //把form中的数据清空
            roleForm.form("clear");


            //完成修改的回显--load方法:读取数据填充到表单中
            roleForm.form("load",row);
            //修改时,左边表格回显角色的权限数据。loadData方法:加载本地数据,旧的行将被移除。需要传个参数data加载。
            LeftrolePermissionDataGrid.datagrid("loadData",row.permissions);
        },

(21)上面修改出现的问题:
当修改时,双击回显的左边的数据,会被删除。当关闭修改页面后再次修改同一角色时,回显的权限数据没有之前双击的那个数据行。但是数据库中没有删除。只是不能再回显出当初的那行数据
分析:

LeftrolePermissionDataGrid.datagrid("loadData",row.permissions);
row.permissions:回显到数据表格中的角色权限
datagrid:角色原本的权限         
理解:
这两个共用了一个数据表格,修改时,双击增加或删除权限后关闭页面,再次修改时都会是关闭页面之前操作的数据。但是数据库中角色的权限没有变化

解决思路:
拷贝一份权限数据表格的副本,专门用于操作。这样就不影响原本的权限数据

			//完成修改的回显--load方法:读取数据填充到表单中
            roleForm.form("load",row);

            // 会出现问题:
            //修改时,左边表格回显角色的权限数据。loadData方法:加载本地数据,旧的行将被移除。需要传个参数data加载。
            // LeftrolePermissionDataGrid.datagrid("loadData",row.permissions);

            //解决上述问题:拷贝一份数据表格副本拿去操作-- ES6的新语法(拷备一个数组)
            var copyPermissions=[...row.permissions];
            LeftrolePermissionDataGrid.datagrid("loadData",copyPermissions);

(22)问题:点击确认按钮保存时,数据库中并没有更改数据。
permissions权限集合是关联对象。
记住:关联对象修改保存的时候,都先清空

在RoleController类中:

/**
     * 在执行任何一个路径(方法) 之前都会先执行这个方法
     */
    @ModelAttribute("editRole")
    public Role beforeEdit(Long id,String cmd){
        //只有修改才做查询
        if(id!=null && "update".equals(cmd)){
            Role dbRole = roleService.findOne(id);
            //解决n-to-n的问题(凡是要传过来的关联对象,都把它清空)
            dbRole.getPermissions().clear();
            return dbRole;
        }
        return null;
    }

你可能感兴趣的:(aisell_登录与角色)