智能供销系统5_登录界面,角色

今日目标 : 完成登录页面和角色角色添加

[toc]
# 一.登录
## 1.1 准备登录页面(随便找一个即可)
> 位置:webapp/WEB-INF/views/login.jsp

js代码部分
```
 //登录功能

function submitForm(){
    $('#loginForm').form('submit', {
        url:"/login",
        onSubmit: function(){
            return $(this).form('validate');
        },
        success:function(data){
            var result = JSON.parse(data);
            if(result.success){
                //成功后跳转到主页面
                window.location.href = "/main";
            }else{
                $.messager.alert("提示",result.msg,"error");
            }
        }
    });
}


```

## 1.2 LoginController功能

### 1.2.1 两个login方法
> 一个用于跳转(/login,get),一个用于登录(/login,post)```

@RequestMapping(value="/login",method = RequestMethod.GET)
public String index(){
    return "login";
}

/**
 * 是一个Ajax的登录请求,它会返回{success:true/false,msg:xxx}
 * @return
 */
@RequestMapping(value="/login",method = RequestMethod.POST)
@ResponseBody
public JsonResult login(String username, String password){
  ...
}


```

### 1.2.2完成登录的功能
```

@RequestMapping(value="/login",method = RequestMethod.POST)
@ResponseBody
public JsonResult login(String username, String password){
    //1.拿到当前用户
    Subject currentUser = SecurityUtils.getSubject();
    //2.如果没有登录,进行登录
    if(!currentUser.isAuthenticated()){
        //3.准备令牌
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        //4.实现登录
        try {
            currentUser.login(token);
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            return new JsonResult(false, "用户名不存在!");
        } catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            return new JsonResult(false, "账号或密码错误!");
        } catch (AuthenticationException e) {
            e.printStackTrace();
//                System.out.println("这个问题有点意思...)");
            return new JsonResult(false, "系统出错(联系管理员)!");
        }
    }
    //登录成功成功令牌
    return new JsonResult();
}


```

## 1.3 登录细节

### 1.3.1 数据库的密码设置
> 要有一套自己的密码规则(md5,10次,盐值:xxxxx)

#### a.MD5Util```

public class MD5Util {

    public static final String SALT = "xxxxx";
    public static final Integer HASHITERATIONS = 10;

    //密码加密
    public static String changePwd(String password){
        SimpleHash hash = new SimpleHash("MD5",password,SALT,HASHITERATIONS);
        return  hash.toHex();
    }
}


```

#### b.添加用户密码加密
> controller或者service中都可以进行[我们选择service]

```

@Override
public void save(Employee employee) {
    if(employee.getId()==null){
        //添加功能就进行密码修改
        employee.setPassword(MD5Util.changePwd(employee.getPassword()));
    }
    employeeRepository.save(employee);
}


```
#### c.加密的判断必需和规则一致

> applicationContext-shiro.xml(编码方式与次数)

```

<!-- 被引用的realm(一定会写一个自定义realm) -->
<bean id="jpaRealm" class="cn.itsource.aisell.shiro.JpaRealm">
    <!-- 为这个realm设置相应的匹配器 -->
    <property name="credentialsMatcher">
        <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
            <!-- 设置加密方式 -->
            <property name="hashAlgorithmName" value="md5"/>
            <!-- 设置加密次数 -->
            <property name="hashIterations" value="10" />
        </bean>
    </property>
</bean>
```


> JpaRealm(加盐一致)
```

//身份认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    //1.拿用户名与密码
    UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
    String username = token.getUsername();
    //2.根据用户名拿到相应的对象
    Employee loginUser = employeeService.findByUsername(username);
    if(loginUser==null){
        return null; //如果用户用空代表用户名不存在
    }
    String password = loginUser.getPassword();
    //返回认证信息
    //准备盐值
    //传的第一个值就是主体(username名称做的主体)
    ByteSource salt = ByteSource.Util.bytes(MD5Util.SALT);
    SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username,password,salt,getName());
    return authenticationInfo;
}


```

### 1.3.2 其它细节#### a.静态资源放行
> 有些地方没有登录也可以直接使用(FilterChainDefinitionMapFactory)
```

public Map<String,String> createFilterChainDefinitionMap(){
        //注:LinkedHashMap是有序的
        Map<String,String> filterChainDefinitionMap = new LinkedHashMap<>();

        filterChainDefinitionMap.put("/s/login.jsp", "anon");
        filterChainDefinitionMap.put("/login", "anon");
        .....

        //把所有静态资源进行放行
        filterChainDefinitionMap.put("*.js", "anon");
        filterChainDefinitionMap.put("*.css", "anon");
        filterChainDefinitionMap.put("/easyui/**", "anon");
        filterChainDefinitionMap.put("/images/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");

        filterChainDefinitionMap.put("/s/permission.jsp", "perms[user:index]");
        filterChainDefinitionMap.put("/**", "authc");

        return filterChainDefinitionMap;
    }


```

#### b.登录过期
> login.jsp
```

// 检查自己是否是顶级页面
if (top != window) {// 如果不是顶级
    //把子页面的地址,赋值给顶级页面显示
    window.top.location.href = window.location.href;
}


```

#### c.回车登录
> login.jsp
```

$(document.documentElement).on("keyup", function(event) {
    //console.debug(event.keyCode);
    var keyCode = event.keyCode;
    console.debug(keyCode);
    if (keyCode === 13) { // 捕获回车
        submitForm(); // 提交表单
    }
});


```

#### d.展示用户名与注销
> main.jsp
```

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
...
 <div style="text-align: right;margin-right: 20px;">
    欢迎您,亲爱的用户:<shiro:principal />
    <a href="/logout">注销</a>
</div>


```
> LoginController
```

@RequestMapping("/logout")
public String logout(){
    Subject currentUser = SecurityUtils.getSubject();
    currentUser.logout();
    return "redirect:/login";
}


```


# 二.角色管理

>先使用代码生成器生成Role,Permission
>设置多对多的关系(set/List都可以)

```

//Employee
@ManyToMany
@JoinTable(name = "employee_role",
        joinColumns = @JoinColumn(name="employee_id"),
        inverseJoinColumns = @JoinColumn(name="role_id"))
private Set<Role> roles = new HashSet<>();

 

//Role
@ManyToMany
@JoinTable(name="role_permission",
        joinColumns = @JoinColumn(name="role_id"),
        inverseJoinColumns = @JoinColumn(name="permission_id"))
private List<Permission> permissions = new ArrayList<>();


```

## 2.1 角色中(权限的展示)

> role.jsp
```

<table id="roleGrid" class="easyui-datagrid" fit="true"
    ...
    ">
    <thead>
    <tr>
     ...
        <th data-options="field:'permissions',width:100,formatter:formatPerms">权限</th>
    </tr>
    </thead>
</table>


```

> role.js
```

//返回权限展示的方法
//v:当前数据  r:当前行数据 i:行索引
function formatPerms(v,r,i){
    var permsName = "";
    for(let o of v){
        permsName += o.name +" ";
    }
    return permsName;
}


```

## 2.1 添加权限

### 2.1.1 form弹出布局
> 左(当前权限)右(所有权限)都有一个grid
```

<!-- 一个弹出框,里面要装一个form表单 -->
<div id="editDlg" class="easyui-dialog" title="功能操作"
     data-options="iconCls:'icon-save',closed:true,modal:true"
     style="padding:10px;width: 850px;">
    <form id="editForm" method="post">
        <!-- 修改的话,这个id是必需的 -->
        <input id="roleId" name="id" type="hidden"/>
        <table cellpadding="5">
            <tr>
                <td>
                    名称:<input class="easyui-validatebox" type="" name="name"
                              data-options="required:true"></input>
                    编码:<input class="easyui-validatebox" type="text" name="sn"
                              data-options="required:true"></input>
                </td>
            </tr>
        </table>
        <div class="easyui-layout" style="width:100%;height:400px;">
            <div data-options="region:'west'" style="width:50%;">
                <table id="rolePermissionGrid">
                    <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="allPermissionGrid">
                    <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 style="text-align:center;padding:5px">
        <!-- 如果这里我改成提交按钮,它就会提交整个页面 -->
        <a href="javascript:void(0)" class="easyui-linkbutton" data-method="save">提交</a>
        <a href="javascript:void(0)" class="easyui-linkbutton" onclick="$('#editDlg').dialog('close')">关闭</a>
    </div>
</div>


```

### 2.1.2 为角色添加/删除权限

```

...
var rolePermissionGrid = $("#rolePermissionGrid");
var allPermissionGrid = $("#allPermissionGrid");
...
 itsource = {
        add(){
         ...
            //清空grid中的数据
            //loadData:加载本地数据,旧的行将被移除
            rolePermissionGrid.datagrid("loadData",[]);
         ...
        },
        edit(){
           ...
            if(row){
               ...
                //拷备对应的权限数组
                var copyPerms = [...row.permissions];
                //解决Grid加显问题
                rolePermissionGrid.datagrid("loadData",copyPerms);
            }else {
              ...
        },
        //通过javascript进行保存
        save(){
           ...
            editForm.form('submit', {
                //form提交的路径
                url:url,
                //提交之前你要做什么事件
                onSubmit: function(param){
                    //添加一些提交的额外参数
                    //1.拿到grid中所有的值
                    var allRows = rolePermissionGrid.datagrid("getRows");
                    //2.循环把值放进去
                    for(var i=0;i<allRows.length;i++){
                        var row = allRows[i];
                        param[`permissions[${i}].id`] = row.id;
                    }
                    return $(this).form('validate');
                },
               ...
            });
        },
       ...
        //添加一个权限
        addPerms(index, row){
            //先拿到角色的所有权限
            var allRows = rolePermissionGrid.datagrid("getRows");
            //遍历进行比较
            for(let o of allRows){
                //如果两个权限相等,就什么都不做了
                if(o.id == row.id){
                    $.messager.show({
                        title:'注意事项',
                        msg:'这个权限已经存在,无需再进行添加!',
                        timeout:2000,
                        showType:'slide'
                    });
                    return;
                }
            }
            rolePermissionGrid.datagrid("appendRow",row);
        },
        //删除对应权限
        delPerms(index,row){
            rolePermissionGrid.datagrid("deleteRow",index);
        }
    };

    //创建当前角色对应的权限(grid控件)
    rolePermissionGrid.datagrid({
        fit:true,
        fitColumns:true,
        singleSelect:true,
        border:false,
        onDblClickRow:itsource.delPerms
    })

    //创建拿到所有的权限的grid控件
    allPermissionGrid.datagrid({
        fit:true,
        url:'/permission/page',
        fitColumns:true,
        singleSelect:true,
        pagination:true,
        border:false,
        onDblClickRow:itsource.addPerms
    })

```

### 2.1.3 只增不减的问题
> 修改的时候只能添加不能减少

```

@ModelAttribute("editRole")
public Role beforeEdit(Long id,String cmd){
    //修改的时候才查询(只要有id会就进行一次查询,这是不对的)
    if(id!=null && "update".equals(cmd)) {
        Role role = roleService.findOne(id);
        //把要传过来的关联对象都清空,就可以解决n-to-n的问题
        role.getPermissions().clear();
        return role;
    }
    return null;
}
 @ModelAttribute("editRole")
    public Role beforeEdit(Long id,String cmd){
        if(id!=null && "_update".equals(cmd)){
            //修改才执行这个代码
            Role dbRole = roleService.findOne(id);
            //解决n-to-n的问题,把关联对象设置为null
            dbRole.getPermissions().clear();
            return  dbRole;
        }
        return null;
    }


```

 

转载于:https://my.oschina.net/u/4108086/blog/3073627

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值