智销系统day06-登录&角色

1.添加时密码加密

当用户添加密码时,在service层对密码进行加密,然后添加到数据库

@Service
public class EmployeeServiceImpl extends BaseServiceImpl<Employee,Long> implements IEmployeeService{
    @Override
    public void save(Employee employee) {
        //判断只有添加的时候才对密码进行加密
        if(employee.getId() == null){
            //对添加的密码进行加密
            employee.setPassword(MD5Utils.createPwd(employee.getPassword()));
        }
        super.save(employee);
    }
}

2.登录功能

①准备登录页面

将login页面放到views文件夹下(通过controller层访问)
在这里插入图片描述
shiroFilter过滤器中,配置没有登录前访问的路径/login
applicationContext-shiro.xml

<!-- 如果没有登录成功,就会进入这个页面 -->
<property name="loginUrl" value="/login"/>

前台登录页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>源码智销系统</title>
    <%--引入头部文件--%>
    <%@include file="/WEB-INF/views/head.jsp"%>
</head>
<body>
    <div align="center" style="margin-top: 100px;">
        <div class="easyui-panel" title="智销系统用户登陆" style="width: 350px; height: 240px;">
            <form id="loginForm" class="easyui-form" method="post">
                <table align="center" style="margin-top: 15px;">
                    <tr height="20">
                        <td>用户名:</td>
                    </tr>
                    <tr height="10">
                        <td><input name="username" class="easyui-validatebox" required="true" value="admin" /></td>
                    </tr>
                    <tr height="20">
                        <td>&emsp;:</td>
                    </tr>
                    <tr height="10">
                        <td><input name="password" type="password" class="easyui-validatebox" required="true" value="0" /></td>
                    </tr>
                    <tr height="40">
                        <td align="center"><a href="javascript:;" class="easyui-linkbutton">登录</a>
                            <a href="javascript:;" class="easyui-linkbutton" onclick="resetForm();">重置</a></td>
                    </tr>
                </table>
            </form>
        </div>
    </div>
</body>
</html>

静态资源放行

但是页面格式图片等静态资源无法访问(css,js,images…)
需要对静态资源进行放行
厂中配置放行的资源路径

public class FilterChainDefinitionMapFactory {
    /**
     * 这个方法就会返回咱们的权限数据(它是有顺序)
     */
    public Map<String,String> creatMap(){
        //注意:这里的map是有顺序的
        Map<String,String> map = new LinkedHashMap<>();
        map.put("/login","anon");
        /*
        * 静态资源放行
        * */
        map.put("/*.css","anon");
        map.put("/*.js","anon");
        map.put("/easyui/**","anon");
        map.put("/css/**","anon");
        map.put("/images/**","anon");
        map.put("/js/**","anon");
        //map.put("/json/**","anon");
        map.put("/s/permission.jsp","perms[employee:save]");
        map.put("/**","authc");
        return map;
    }
}

②完成前台登录代码

前台登录使用ajax请求的方式实现

  • 为登录链接添加,点击事件
  • 完成前台登录代码
  • 登录成功跳转页面:location.href = “/main”;
<script>
     function submitForm() {
         $('#loginForm').form('submit', {
             url:"/login",
             onSubmit: function(){
                 return $(this).form('validate');
             },
             success:function(data){
                 //将返回的json字符串转换为json对象
                 var result = JSON.parse(data);
                 //判断登录是否成功
                 if(result.success){
                     //登录成功跳转到main首页
                     location.href = "/main";
                 }else{
                     //提示登录错误
                     $.messager.alert('提示','登录失败!!!<br>'+result.msg);
                 }
             }
         });
     }
</script>
<a href="javascript:;" class="easyui-linkbutton" onclick="submitForm();">登录</a>

③完成登录的controller层(登录验证)

准备两个/login映射路径(RESTFUL风格)

RESTFUL风格

  • 相同的路径请求方式不同,可能访问的资源也不一样
  • 登录验证后,因为是ajax,所以需要返回json格式(JpaResult结果对象)
@RequestMapping(value = "/login",method = RequestMethod.GET)
public String login1(String username,String password){
    //进入登录界面
    return "login";
}

@RequestMapping(value = "/login",method = RequestMethod.POST)
@ResponseBody
public JpaResult login(String username,String password){
    System.out.println(username+"...."+password);
    //获取当前用户
    Subject subject = SecurityUtils.getSubject();
    try {
        //将用户名和密码封装进令牌中
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);
        //登录
        subject.login(token);
    } catch (UnknownAccountException e) {
        //UnknownAccountException(不知道用户异常)
        System.out.println("用户名错误!!!");
        e.printStackTrace();
        return new JpaResult(false,"用户名错误!!!");
    }catch (IncorrectCredentialsException e){
        //IncorrectCredentialsException(不正确凭证(密码错误)异常)
        System.out.println("密码错误!!!");
        e.printStackTrace();
        return new JpaResult(false,"用户名或者密码错误!!!");
    }catch (AuthenticationException e){
        System.out.println("sorry!!!");
        e.printStackTrace();
        return new JpaResult(false,"神秘错误!!!");
    }
    //登录成功返回一个结果
    return new JpaResult();
}

④真实数据(登录)

  • Realm类中,查询数据库真实数据验证登录是否成功
  • service层准备**Employee findByUsername(String username);通过用户名查询用户对象**

IEmployeeService接口

public interface IEmployeeService extends IBaseService<Employee,Long>{
    //根据用户名查询
    Employee findByUsername(String username);
}

EmployeeServiceImpl实现类 重写findByUsername(String username)方法

@Service
public class EmployeeServiceImpl extends BaseServiceImpl<Employee,Long> implements IEmployeeService{
    @Autowired
    private EmployeeRepository employeeRepository;
    @Override
    public void save(Employee employee) {
        //判断只有添加的时候才对密码进行加密
        if(employee.getId() == null){
            //对添加的密码进行加密
            employee.setPassword(MD5Utils.createPwd(employee.getPassword()));
        }
        super.save(employee);
    }

    @Override
    public Employee findByUsername(String username) {
        //通过用户名查询用户
        return employeeRepository.findByUsername(username);

    }
}

AisellRealm类查询真实用户

public class AisellRealm extends AuthorizingRealm {
    @Autowired
    private IEmployeeService employeeService;
    
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //拿到用户名密码令牌(强转)
        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
        //获取用户名(传过来的)
        String username = token.getUsername();
        //根据用户名到数据库,查询对应的用户----------------------
        Employee loginUser = employeeService.findByUsername(username);
        //如果用户为null,表示用户不存在
        if (loginUser == null){
            return null;
        }
        //判断密码是否正确
        //shiro做准备了一个工具直接让我们把数据变成 ByteSource格式
        ByteSource salt = ByteSource.Util.bytes(MD5Utils.SALT);
        AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(loginUser,loginUser.getPassword(),salt,getRealmName());
        return authenticationInfo;
    }

    private String getRealmName(){
        return "myRealm";
    }

}

1.细节-回车登录

//监听回车登录事件 keyup释放键盘
$(document.documentElement).on("keyup",function (event) {
    var keyCode = event.keyCode;
    if(keyCode == 13){//捕获回车
        submitForm();//提交表单
    }
});

2.细节-过期登录(窗口嵌套错误)

模拟:用户过期后重新访问时,在嵌套的窗口中显示了登录页面
在这里插入图片描述
在这里插入图片描述
如果当前页面(windw)不是顶层页面(top),当前页面改为顶层

//如果当前页面(windw)不是顶层页面(top)
if(top != window){
    //跳转到顶层页面 
    top.location.href = window.location.href;
}

3.细节-注销

main.jsp页面
引入shiro标签库

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

通过实体 取实体的属性username的值

<%----%>
<div data-options="region:'north'" style="height:120px;">
    <h1 style="margin-top: 38.767px;margin-right: 0px;margin-left: 47px;">智销系统</h1>
    <div style="text-align: right;padding-right: 20px" >
        欢迎您,亲爱的:<shiro:principal property="username"/> <a href="/logout">注销</a>
    </div>
</div>

3.完成角色与权限的增删改查

与员工类似,首页有不同
/role/index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>首页</title>
    <%--引入头部文件--%>
    <%@include file="/WEB-INF/views/head.jsp"%>
    <%--引入当前模块js文件--%>
    <script type="text/javascript" src="/js/model/role.js"></script>

</head>
<body>

    <div id="tb" style="padding:5px;height:auto">
        <div style="margin-bottom:5px">
            <a href="#" data-method="add" class="easyui-linkbutton" iconCls="icon-add" plain="true">添加</a>
            <a href="#" data-method="update" class="easyui-linkbutton" iconCls="icon-edit" plain="true">修改</a>
            <a href="#" data-method="delete" class="easyui-linkbutton" iconCls="icon-remove" plain="true">删除</a>
        </div>
        <%--查询表单--%>
        <form id="searchForm" method="post">
            角色名: <input name="name" class="easyui-textbox" style="width:80px">
            <a href="#" data-method="search" class="easyui-linkbutton" iconCls="icon-search">查询</a>
        </form>
    </div>
    <%--数据表格(展示当前模块数据)--%>
    <table id="datagrid" class="easyui-datagrid" style="width:400px;height:250px"
           data-options="url:'/role/page',fitColumns:true,singleSelect:true,fit:true,pagination:true,toolbar:'#tb'">
        <thead>
        <tr>
            <th data-options="field:'sn',width:20">编码</th>
            <th data-options="field:'name',width:20">名称</th>
            <th data-options="field:'permissions',width:100,formatter:permsFormat">权限</th>
        </tr>
        </thead>
    </table>

    <%--添加或保存对话框--%>
    <div id="dialog" class="easyui-dialog" title="角色管理" style="width:700px"
         data-options="iconCls:'icon-save',resizable:true,modal:true,closed:true,buttons:'#buttons'">
        <%--信息表单--%>
        <form id="editForm" method="post">
            <table cellpadding="5">
                <input id="roleId" type="hidden" name="id"/>
                <tr>
                    <td>
                        编码:<input class="easyui-textbox" type="text" name="sn" data-options="required:true"/>
                        角色名称:<input class="easyui-textbox" type="text" name="name" data-options="required:true"/>
                    </td>
                </tr>
            </table>
            <div id="cc" class="easyui-layout" style="width:100%;height:400px;">
                <div data-options="region:'west'" style="width:50%;">
                    <%--角色的权限--%>
                    <table id="rolePermsGird">
                        <thead>
                            <tr>
                                <th data-options="field:'name',width:100">权限名</th>
                                <th data-options="field:'sn',width:100">编码</th>
                                <th data-options="field:'url',width:100">资源路径</th>
                            </tr>
                        </thead>
                    </table>
                </div>
                <div data-options="region:'center'" >
                    <%--所有的权限--%>
                    <table id="allPermsGird">
                        <thead>
                        <tr>
                            <th data-options="field:'name',width:100">权限名</th>
                            <th data-options="field:'sn',width:100">编码</th>
                            <th data-options="field:'url',width:100">资源路径</th>
                        </tr>
                        </thead>
                    </table>
                </div>
            </div>
        </form>

    </div>
    <%--保存/取消按钮--%>
    <div id="buttons">
        <a href="#" data-method="save" class="easyui-linkbutton c3">保存</a>
        <a href="#" data-method="close" class="easyui-linkbutton c4">关闭</a>
    </div>
</body>
</html>

/permission/index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>首页</title>
    <%--引入头部文件--%>
    <%@include file="/WEB-INF/views/head.jsp"%>
    <%--引入当前模块js文件--%>
    <script type="text/javascript" src="/js/model/permission.js"></script>
</head>
<body>
    <%--顶部工具栏--%>
    <div id="tb" style="padding:5px;height:auto">
        <div style="margin-bottom:5px">
            <a href="#" data-method="add" class="easyui-linkbutton" iconCls="icon-add" plain="true">添加</a>
            <a href="#" data-method="update" class="easyui-linkbutton" iconCls="icon-edit" plain="true">修改</a>
            <a href="#" data-method="delete" class="easyui-linkbutton" iconCls="icon-remove" plain="true">删除</a>
        </div>
        <%--查询表单--%>
        <form id="searchForm" method="post">
            权限名: <input name="name" class="easyui-textbox" style="width:80px">
            <a href="#" data-method="search" class="easyui-linkbutton" iconCls="icon-search">查询</a>
        </form>
    </div>
    <%--数据表格(展示当前模块数据)--%>
    <table id="datagrid" class="easyui-datagrid" style="width:400px;height:250px"
           data-options="url:'/permission/page',fitColumns:true,singleSelect:true,fit:true,pagination:true,toolbar:'#tb'">
        <thead>
        <tr>
            <th data-options="field:'name',width:100">权限名</th>
            <th data-options="field:'sn',width:100">编码</th>
            <th data-options="field:'url',width:100">资源路径</th>
            <th data-options="field:'descs',width:100">描述</th>
        </tr>
        </thead>
    </table>

    <%--添加或保存对话框--%>
    <div id="dialog" class="easyui-dialog" title="权限管理"
         data-options="iconCls:'icon-save',resizable:true,modal:true,closed:true,buttons:'#buttons'">
        <%--信息表单--%>
        <form id="editForm" method="post">
            <table cellpadding="5">
                <input id="permissionId" type="hidden" name="id"/>
                <tr>
                    <td>权限名称:</td>
                    <td><input class="easyui-textbox" type="text" name="name" data-options="required:true"></input></td>
                </tr>
                <tr>
                    <td>编码:</td>
                    <td><input class="easyui-textbox" type="text" name="sn" data-options="required:true"></input></td>
                </tr>
                <tr>
                    <td>资源路径:</td>
                    <td><input class="easyui-textbox" type="text" name="url" data-options="required:true"></input></td>
                </tr>
                <tr>
                    <td>权限描述:</td>
                    <td><input class="easyui-textbox" type="text" name="descs" data-options="required:true"></input></td>
                </tr>
            </table>
        </form>

    </div>
    <%--保存/取消按钮--%>
    <div id="buttons">
        <a href="#" data-method="save" class="easyui-linkbutton c3">保存</a>
        <a href="#" data-method="close" class="easyui-linkbutton c4">关闭</a>
    </div>

</body>
</html>

4.员工-角色-权限(多对多配置)

Employee(员工)
员工与角色是多对多的关系

@Entity
@Table(name = "employee")
public class Employee extends BaseDomain{
    private String username;
    private String password;
    private String email;
    private Integer age;

    private String headImage;
    //多个员工对应一个部门
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "department_id")
    private Department department;
    /*
    * 员工与角色是多对多的关系
    * JoinTable:关连表
    * joinColumns:当前这个表对应中间表的外键
    * inverseJoinColumns:关连的对应的表的外键
    * */
    @ManyToMany
    @JoinTable(name = "employee_role",
            joinColumns = @JoinColumn(name = "employee_id"),
            inverseJoinColumns = @JoinColumn(name = "role_id")
    )
    private List<Role> roles = new ArrayList<>();

	//getter,setter,toString...
}

Role(角色)
角色与权限是多对多的关系

@Entity
@Table(name = "role")
public class Role extends BaseDomain{
    //角色名称
    private String name;
    //角色编码
    private String sn;
    /*
    * 角色与权限是多对多关系
    * */
    @ManyToMany
    @JoinTable(name = "role_permission",
            joinColumns = @JoinColumn(name = "role_id"),
            inverseJoinColumns = @JoinColumn(name = "permission_id")
    )
    private List<Permission> permissions = new ArrayList<>();

	//getter,setter,toString...
}

角色与资源是(各种关系都有)
本项目是采用一对一,权限与资源一张表

5.角色

①角色查询(权限显示)

为权限的显示进行格式化

<%--数据表格(展示当前模块数据)--%>
<table id="datagrid" class="easyui-datagrid" style="width:400px;height:250px"
       data-options="url:'/role/page',fitColumns:true,singleSelect:true,fit:true,pagination:true,toolbar:'#tb'">
    <thead>
    <tr>
        <th data-options="field:'sn',width:20">编码</th>
        <th data-options="field:'name',width:20">名称</th>
        <th data-options="field:'permissions',width:100,formatter:permsFormat">权限</th>
    </tr>
    </thead>
</table>

js代码
遍历数组,拼接所有权限名

function permsFormat(v) {
    //这里v是一个数组,里面装的permission对象
    /*
    * for(var p in v){} 取的数组角标
    * for(var p of v){} 取的数组里的元素
    * */
    var ps = "";
    //遍历数组,拼接
    for(var p of v){
        ps += p.name+" ";
    }
    return ps;
}

②添加角色

角色添加-布局

使用js创建两个DataGrid(当前角色权限与所有权限)
在这里插入图片描述
js代码

//创建两个datagird
    //当前角色拥有权限
    rolePermsGird.datagrid({
        fitColumns:true,
        singleSelect:true,
        fit:true,
        onDblClickRow:itsource.removePerms
    });
    //所有的权限
    allPermsGird.datagrid({
        url:'/permission/list',
        fitColumns:true,
        singleSelect:true,
        fit:true,
        onDblClickRow:itsource.addPerms
    });

/role/index.jsp

<%--添加或保存对话框--%>
<div id="dialog" class="easyui-dialog" title="角色管理" style="width:700px"
     data-options="iconCls:'icon-save',resizable:true,modal:true,closed:true,buttons:'#buttons'">
    <%--信息表单--%>
    <form id="editForm" method="post">
        <table cellpadding="5">
            <input id="roleId" type="hidden" name="id"/>
            <tr>
                <td>
                    编码:<input class="easyui-textbox" type="text" name="sn" data-options="required:true"/>
                    角色名称:<input class="easyui-textbox" type="text" name="name" data-options="required:true"/>
                </td>
            </tr>
        </table>
        <div id="cc" class="easyui-layout" style="width:100%;height:400px;">
            <div data-options="region:'west'" style="width:50%;">
                <%--角色的权限--%>
                <table id="rolePermsGird">
                    <thead>
                        <tr>
                            <th data-options="field:'name',width:100">权限名</th>
                            <th data-options="field:'sn',width:100">编码</th>
                            <th data-options="field:'url',width:100">资源路径</th>
                        </tr>
                    </thead>
                </table>
            </div>
            <div data-options="region:'center'" >
                <%--所有的权限--%>
                <table id="allPermsGird">
                    <thead>
                    <tr>
                        <th data-options="field:'name',width:100">权限名</th>
                        <th data-options="field:'sn',width:100">编码</th>
                        <th data-options="field:'url',width:100">资源路径</th>
                    </tr>
                    </thead>
                </table>
            </div>
        </div>
    </form>

</div>

角色添加-追加权限

  • 需要判断追加是否重复(遍历所有行判断,getRows)
  • rolePermsGird.datagrid(“appendRow”,row);添加行
itsource = {
	addPerms(index,row){
	    //获取当前角色所有行
	    var rows =rolePermsGird.datagrid("getRows");
	    //遍历所有行
	    for(var r of rows){
	        if(r.id == row.id){
	            $.messager.show({
	                title:'错误',
	                msg:'你已经添加过了,不能重复添加!!!',
	                showType:'slide',
	                style:{
	                    right:'',
	                    top:document.body.scrollTop+document.documentElement.scrollTop,
	                    bottom:''
	                }
	            });
	            return;
	        }
	    }
	    rolePermsGird.datagrid("appendRow",row);
	},
	...
}

//所有的权限
allPermsGird.datagrid({
    url:'/permission/list',
    fitColumns:true,
    singleSelect:true,
    fit:true,
    onDblClickRow:itsource.addPerms
});

角色添加-双击移除权限

itsource = {
removePerms(index){
        rolePermsGird.datagrid("deleteRow",index);
    }
}

//创建两个datagird
//当前角色拥有权限
rolePermsGird.datagrid({
    fitColumns:true,
    singleSelect:true,
    fit:true,
    onDblClickRow:itsource.removePerms
});

角色添加=清空DataGrid

  • 添加前清空角色权限的DataGrid
  • loadData方法,加载本地数据覆盖之前数据(加载空数组,实现清空)
itsource = {
    add(){
        ...
        //清理rolePermsGird中的所有行(利用空数组)
        rolePermsGird.datagrid("loadData",[]);
    }
}

角色添加-权限传参

示例图:
在这里插入图片描述

  • 前台权限信息是一个数组装的,直接传到后台,后台处理很麻烦
  • DataGrid不是表单元素,不能表单提交,需要以表单额外参数方式提交
  • SpringMVC,有特殊的传参方式:
 param[`permissions[${i}].id`] = p.id;
save(){
    //默认添加路径
    var url = "/role/save";
    //获取id
    var roleId = $("#roleId").val();
    if(roleId){
        url = "/role/update?_cmd=update";
    }
    editForm.form('submit', {
        url:url,
        onSubmit: function(param){
            //表单提交额外参数,param是空的,(给它加啥,他就会往后台传啥)
            //获取当前角色的所有行
            var rows = rolePermsGird.datagrid("getRows");
            //遍历所有行
            for(var i = 0;i<rows.length;i++){
                var p = rows[i];
                param[`permissions[${i}].id`] = p.id;
            }
            //提交前执行的操作  一般用于验证
            return $(this).form("validate");
        },
        success:function(data){
            //从后台获取到json格式的字符串{"success":true,"msg":null}
            //将json格式字符串转换为json对象
            var result = JSON.parse(data);
            //如果添加成功
            if(result.success){
                //重新加载数据
                datagrid.datagrid("reload");
            }else{
                //添加失败返回失败信息
                $.messager.alert('提示',`添加失败了,原因是:${result.msg}`,'error');
                //$.messager.alert('提示','添加失败了,原因是:'+result.msg,'error');
            }
            //关闭对话框
            itsource.close();
        }
    });
}

角色修改-回显权限

  • 注意不能直接获取row.permissions进行回显,应该复制一份用于回显
    因为直接加载row的话,是操作的同一个数据(row),下次回显的是上次修改过后的数据
    复制数组的代码:
var perms = [...row.permissions];

分析图:
在这里插入图片描述
回显代码

//回显权限数据
//复制数组
var perms = [...row.permissions];
console.debug(perms)
rolePermsGird.datagrid("loadData",perms);
update(){
    //修改时,需要判断是否选中一行
    //获取行
    var row = datagrid.datagrid("getSelected");
    if(!row){
        //提示选中
        $.messager.alert('提示','请选中一行再删除','warning');
        return;
    }

    //修改时,不需要修改密码,设置标识,隐藏密码项
    $("*[shower]").hide();
    //禁用密码,不让让传值
    $("*[shower]>td>input").textbox("disable");
    //点击添加,弹出对话框
    dialog.window("open").window("center");
    //每次打开对话框先清理表单数据
    editForm.form("clear");
    //回显
    editForm.form("load",row);
    //回显权限数据
    //复制数组
    var perms = [...row.permissions];
    console.debug(perms)
    rolePermsGird.datagrid("loadData",perms);

}

角色修改-no to no错误

  • 修改了持久化对象id
  • 将权限集合清空
    controller层
@ModelAttribute("editRole")
public Role aaa(Long id,String _cmd){
    if(id != null && "update".equals(_cmd)){//只有修改数据,才返回查找的对象
        Role role = roleService.findOne(id);
        //将关连对象设置为null,集合的话就清空
        role.getPermissions().clear();
        return role;
    }
    return null;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值