1 SSM权限管理系统-项目环境搭建
在创建Maven项目时,添加archetypeCatalog=internal
配置pom.xml的mvean依赖,添加逆向生成工具.
创建需要的目录domain,mapper,service,web,resources
替换web.xml,修改为3.0的约束
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0"
metadata-complete="false">
<absolute-ordering/>
<display-name>web</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!--配置前端控制器-->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!--加载的主配置文件-->
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<!-- 项目启动就加载框架 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 编码过滤器 -->
<filter>
<filter-name>CharacterEncoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
2. SSM权限管理-EasyUI主页框架
EasyUI主页
1.在目录当中引入EasyUI相关JS与css
2.在首页当中引入所需要的js与css
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/static/plugins/easyui/uimaker/easyui.css">
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/static/plugins/easyui/uimaker/icon.css">
<script type="text/javascript" src="${pageContext.request.contextPath}/static/plugins/easyui/jquery.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/static/plugins/easyui/jquery.easyui.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/static/plugins/easyui/easyui-lang-zh_CN.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/static/js/index.js"></script>
3.编写body所首页框架格式
<body class="easyui-layout">
<%--顶部--%>
<div data-options="region:'north'" style="height:100px; background: #ec4e00; padding: 20px 20px">
<img src="static/images/main_logo.png" alt="">
</div>
<%--底部--%>
<div data-options="region:'south'" style="height:50px; border-bottom: 3px solid #ec4e00">
<p align="center" style="font-size: 14px">撩课学院</p>
</div>
<%--左侧菜单--%>
<div data-options="region:'west',split:true" style="width:300px;">
<div id="aa" class="easyui-accordion" data-options="fit:true">
<div title="菜单" data-options="iconCls:'icon-save',selected:true" style="overflow:auto;padding:10px;">
<!--tree-->
<ul id="tree"></ul>
</div>
<div title="公告" data-options="iconCls:'icon-reload'" style="padding:10px;">
</div>
</div>
</div>
<%--右侧主区域--%>
<div data-options="region:'center'" style="background:#eee;">
<!--标签-->
<div id="tabs" style="overflow: hidden" ></div>
</div>
</body>
4.创建首页index.js引入
$(function () {
$("#tabs").tabs({
fit:true
})
$('#tree').tree({
url:'/getTreeData',
lines:true,
onSelect: function(node){
/*在添加之前, 做判断 判断这个标签是否存在 */
var exists = $("#tabs").tabs("exists",node.text);
if(exists){
/*存在,就让它选中*/
$("#tabs").tabs("select",node.text);
}else {
if (node.url !=''&& node.url !=null){
/*如果不存在 ,添加新标签*/
$("#tabs").tabs("add",{
title:node.text,
/*href:node.attributes.url,*/ /*href 引入的是body当中*/
content:"<iframe src="+node.url+" frameborder='0' width='100%' height='100%'></iframe>",
closable:true
})
}
}
},
onLoadSuccess: function (node, data) {
console.log(data[0].children[0].id);
if (data.length > 0) {
//找到第一个元素
var n = $('#tree').tree('find', data[0].children[0].id);
//调用选中事件
$('#tree').tree('select', n.target);
}
}
});
});
3. 菜单标签跳转
创建3个controller
EmployeeController MenuController RoleController
控制拦截url为employee,role,menu
跳转到相应的页面,比如EmployeeController
@Controller
public class EmployeeController {
@RequestMapping("/employee")
public String employee(){
return "employee";
}
}
index.js上面的
onLoadSuccess: function (node, data) {
console.log(data[0].children[0].id);
if (data.length > 0) {
//找到第一个元素
var n = $('#tree').tree('find', data[0].children[0].id);
//调用选中事件
$('#tree').tree('select', n.target);
}
}
});
表示在页面初始时调用一个元素.让页面初始时右侧不为空.
注意需要清空缓存.
4. 主页数据表格添加
将共用的scrpit和link抽成一个包.
common.jsp
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/static/plugins/easyui/uimaker/easyui.css">
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/static/plugins/easyui/uimaker/icon.css">
<script type="text/javascript" src="${pageContext.request.contextPath}/static/plugins/easyui/jquery.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/static/plugins/easyui/jquery.easyui.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/static/plugins/easyui/easyui-lang-zh_CN.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/static/js/base.js"></script>
在index.jsp中引用
<head>
<title>权限管理系统</title>
<%@include file="/static/common/common.jsp"%>
<script type="text/javascript" src="${pageContext.request.contextPath}/static/js/index.js"></script>
</head>
index.js属于index.jsp独有的.
在employee.jsp中引用
<head>
<title>Title</title>
<%@include file="/static/common/common.jsp"%>
</head>
给employee页面添加employee.js
$(function(){
$("#dg").datagrid({
url:"/employeeList",
columns:[[
{field:'username',title:'姓名',width:100,align:'center'},
{field:'inputtime',title:'入职时间',width:100,align:'center'},
{field:'tel',title:'电话',width:100,align:'center'},
{field:'email',title:'邮箱',width:100,align:'center'},
{field:'department',title:'部门',width:100,align:'center'},
{field:'state',title:'状态',width:100,align:'center'},
{field:'admin',title:'管理员',width:100,align:'center'},
]],
fit:true, /*是否需要填满*/
fitColumns:true, /*是否自动伸缩*/
rownumbers:true, /*是否需要显示行号*/
pagination:true /*是否需要分页*/
})
});
5. 员工表建立
设计数据库的表.
建立新的数据库promission
修改逆向工程的generatorConfig.xml,修改配置中的数据库名和表名.
逆向生成Employee,EmployeeMapper,EmployeeMapper.xml
注意把EmployeeMapper.xml需要放在resources下面新建的com.itlike.mapper.
6. 员工列表查询
创建一个业务接口service,employeeService.实现类employeeServiceImpl.
将其标记为@Service
public class employeeServiceImpl implements employeeService {
@Autowired
private EmployeeMapper employeeMapper;
@Override
public void getEmployee() {
System.out.println("来到业务层");
/*调用mapper查询员工*/
employeeMapper.selectAll();
}
}
修改controller层,注入service,添加@RequestMapping("/employeeList")
EmployeeController
@Controller
public class EmployeeController {
/*注入业务层*/
@Autowired
private employeeService employeeService;
@RequestMapping("/employee")
public String employee(){
return "employee";
}
@RequestMapping("/employeeList")
public void employeeList(){
/*调用业务层查询员工*/
employeeService.getEmployee();
}
}
注意修改db.properties下面的数据库名jdbc.url=jdbc:mysql://localhost:3306/promission?characterEncoding=utf-8
新建一个PageListRes的domain类.
由于easyUI的datagrid需要有total分页和rows数组类型的json
PageListRes类.
@Getter@Setter
public class PageListRes {
private Long total;
private List<?> rows=new ArrayList<>();
}
修改employeeServiceImpl,使用pageHelper来进行分页
@Service
public class employeeServiceImpl implements employeeService {
@Autowired
private EmployeeMapper employeeMapper;
@Override
public PageListRes getEmployee() {
/*调用mapper查询员工*/
/*设置分页total*/
Page<Object> page = PageHelper.startPage(1, 5);
List<Employee> employees = employeeMapper.selectAll();
/*封装成pageList*/
PageListRes pageListRes = new PageListRes();
pageListRes.setTotal(page.getTotal());
pageListRes.setRows(employees);
return pageListRes;
}
}
修改接口employeeService,将返回值类型改为PageListRes
前端控制器修改EmployeeController
@Controller
public class EmployeeController {
/*注入业务层*/
@Autowired
private employeeService employeeService;
@RequestMapping("/employeeList")
@ResponseBody
public PageListRes employeeList(){
/*调用业务层查询员工*/
PageListRes pageListRes = employeeService.getEmployee();
return pageListRes;
}
使用@ResponseBody获取json数据
7. 日期格式化
由于上一节已经可以取到数据,并且显示在前端页面,但是日期格式不对,需要格式化日期数据
在employee.js做数据格式化
$(function(){
$("#dg").datagrid({
url:"/employeeList",
columns:[[
{field:'username',title:'姓名',width:100,align:'center'},
{field:'inputtime',title:'入职时间',width:100,align:'center'},
{field:'tel',title:'电话',width:100,align:'center'},
{field:'email',title:'邮箱',width:100,align:'center'},
{field:'department',title:'部门',width:100,align:'center'},
{field:'state',title:'状态',width:100,align:'center',formatter:function (value,row,index) {
if (row.state){
return "在职";
}else {
return "<font style='color:red'>离职</font>"
}
}},
{field:'admin',title:'管理员',width:100,align:'center',formatter:function (value,row,index) {
if (row.admin){
return "是";
}else {
return "否";
}
}},
]],
fit:true, /*是否需要填满*/
fitColumns:true, /*是否自动伸缩*/
rownumbers:true, /*是否需要显示行号*/
pagination:true /*是否需要分页*/
})
});
添加管理员和状态的判断,true为在职和是,false为离职和否.
在domain的实体类中添加注解
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date inputtime;
设置时间格式为GMT+8小时.
或者使用 @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
8. 部门表创建
包含id和name,在employee表建立外键dep_id
参考表department参考字段id.
逆向生成domain和mapper,mapper.xml.
将xml放在resources下面.
9. 员工部门关联查询.
修改Employee的部门字段,需要修改为和employee.js的字段相同.
private Department department;
修改数据库查询语句,使用左连接当两个表id相等时.
<select id="selectAll" resultMap="BaseResultMap" >
select e.id, e.username, e.inputtime, e.tel, e.email, e.state, e.admin ,
d.id as d_id,
d.`name` as d_name
from employee as e
LEFT JOIN department as d
ON e.dep_id=d.id;
</select>
修改 <result column="dep_id" property="dep_id" jdbcType="bigint" />为下面的
注意columnPrefix="d_",因为上面使用了as修改了别名,所有要加上d_,不然无法映射
<association property="department" javaType="com.itlike.domain.Department" columnPrefix="d_">
<result property="id" column="id"/>
<result property="name" column="name"/>
</association>
实现了查询部门名称,接下来再在前端去使用数据.
注意需要删除上面查询语句中的dep_id
注意SQL语句结尾不能添加; 否则sql语句不会执行.
修改前端的js,如果有部门则显示名字,注意使用value.
{field:'department',title:'部门',width:100,align:'center',formatter:function (value,row,index) {
if(value.name){
return value.name;
}else {
return "无部门";
}
}},
在多表查询有字段名相同时,起一个别名,在封装时注意使用columnPrefix.
10. 添加对话框搭建
列表添加工具栏目
employee.jsp
<body>
<div id="tb">
<a href="#" class="easyui-linkbutton" data-options="iconCls:'icon-add',plain:true" id="add">添加</a>
<a href="#" class="easyui-linkbutton" data-options="iconCls:'icon-edit',plain:true" id="edit">编辑</a>
<a href="#" class="easyui-linkbutton" data-options="iconCls:'icon-remove',plain:true" id="delete">删除</a>
<a href="#" class="easyui-linkbutton" data-options="iconCls:'icon-reload',plain:true" id="reload">刷新</a>
</div>
<table id="dg"></table>
</body>
修改前端样式,添加对话框
<%--对话框--%>
<div id="dialog">
<table align="center" style="border-spacing: 0px 10px">
<tr>
<td>用户名:</td>
<td><input type="text" class="easyui-validatebox" data-options="required:true"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" class="easyui-validatebox" data-options="required:true"></td>
</tr>
<tr>
<td>手机:</td>
<td><input type="text" class="easyui-validatebox" ></td>
</tr>
<tr>
<td>邮箱:</td>
<td><input type="text" class="easyui-validatebox" ></td>
</tr>
<tr>
<td>入职日期:</td>
<td><input type="text" class="easyui-datebox"></td>
</tr>
<tr>
<td>部门:</td>
<td><select id="department"></select></td>
</tr>
<tr>
<td>是否管理员:</td>
<td><select id="state"></select></td>
</tr>
</table>
</div>
添加增删编辑刷新按钮.
employee.js 监听添加按钮点击
/*对话框*/
$("#dialog").dialog({
width:350,
height:350,
closed:true //初始默认为隐藏
});
/*监听添加按钮点击*/
$("#add").click(function () {
$("#dialog").dialog("open"); //监听点击时open
})
11. 下拉列表placeholder处理
修改jsp中的页面,将select改为input,添加placeholder属性
<tr>
<td>部门:</td>
<td><input id="department" placeholder="请选择部门"/></td>
</tr>
<tr>
<td>是否管理员:</td>
<td><input id="state" placeholder="是否为管理员"/></td>
</tr>
在js中添加下拉列表,选中id为state和department的行
/*部门选择 下拉列表*/
$("#department").combobox({
width:150,
panelHeight:'auto'
});
/*是否为管理员 下拉列表*/
$("#state").combobox({
width:150,
panelHeight: 'auto',
textField:'label',
valueField:'value',
editable:false, //editable 是否可以输入
data:[{
label:'是',
value:'true'
},{
label:'否',
value:'false'
}],
onLoadSuccess:function () {/*数据加载完毕后回调显示提示*/
$("#state").each(function(i){
var span =$(this).siblings("span")[i];
var targetInput = $(span).find("input:first");
if(targetInput) {
$(targetInput).attr("placeholder", $(this).attr("placeholder"));
}
})
}
});
12. 下拉列表部门数据加载
先建立一个controller
DepartmentController
@Controller
public class DepartmentController {
/*注入DepartmentService业务层*/
@Autowired
private DepartmentService departmentService;
//部门下拉查询部门
@RequestMapping("/departList")
@ResponseBody
public List<Department> departList(){
List<Department> departmentList = departmentService.getDepartmentList();
return departmentList;
}
}
创建它依赖的业务层接口DepartmentService
创建业务层DepartmentServiceImpl
@Service
public class DepartmentServiceImpl implements DepartmentService {
/*注入mapper*/
@Autowired
private DepartmentMapper departmentMapper;
@Override
public List<Department> getDepartmentList() {
List<Department> departments = departmentMapper.selectAll();
return departments;
}
}
修改employee.jsp
/*部门选择 下拉列表*/
$("#department").combobox({
width:150,
panelHeight:'auto',
editable:false,
url:'departList',
textField:'name',
valueField:'id',
onLoadSuccess:function () {/*数据加载完毕后回调显示提示*/
$("#department").each(function(i){
var span =$(this).siblings("span")[i];
var targetInput = $(span).find("input:first");
if(targetInput) {
$(targetInput).attr("placeholder", $(this).attr("placeholder"));
}
})
}
});
13. 添加表单提交
修改对话框,添加两个按钮
/*对话框*/
$("#dialog").dialog({
width:350,
height:350,
closed:true,
buttons:[{
/*提交表单*/
$("#employeeForm").form("submit",{
url:"saveEmployee",
success:function(data){
console.log(data);
}
});
}
},{
text:'关闭',
handler:function() {
}
}]
});
给.jsp的对话框添加form表单属性
<%--对话框--%>
<div id="dialog">
<form id="employeeForm">
</form>
</div>
给对话框内的所有参数添加name属性
<td><input type="text" name="username" class="easyui-validatebox" data-options="required:true"></td>
<td><input type="text" name="password" class="easyui-validatebox" data-options="required:true"></td>
在EmployeeController层添加接收表单
/*接收员工添加表单*/
@RequestMapping("/saveEmployee")
public void saveEmployee(Employee employee){
System.out.println("提交表单成功");
System.out.println(employee);
}
让后台可以接收到属性
14. 添加表单提交
由于前面设计表时没有添加密码,需要在数据库添加password字段
在controller层
/*接收员工添加表单*/
@RequestMapping("/saveEmployee")
public void saveEmployee(Employee employee){
/*调用业务层,保存用户*/
employeeService.saveEmployee(employee);
}
service层
@Transactional
/*保存员工*/
@Override
public void saveEmployee(Employee employee) {
employeeMapper.insert(employee);
}
注意是添加,所以需要添加事务的注释.
修改mapper
<!--添加员工-->
<insert id="insert" parameterType="com.itlike.domain.Employee" >
insert into employee (id, username, password, inputtime,
tel, email, state, admin,
dep_id)
values (#{id}, #{username},#{password}, #{inputtime},
#{tel}, #{email}, #{state}, #{admin},
#{department.id})
</insert>
由于dep_id是从department.id获取的值,所以修改values.并且添加password字段.
state还未设置,需要添加设置在service层
/*接收员工添加表单*/
@RequestMapping("/saveEmployee")
public void saveEmployee(Employee employee){
/*调用业务层,保存用户*/
employee.setState(true);
employeeService.saveEmployee(employee);
}
添加一个domain类AjaxRes,用来接收参数.
用来表明接收失败还是成功,还有message.
.parseJSON()函数
用于将格式完好的JSON字符串转为与之对应的JavaScript对象。
AjaxRes
@Component
@Getter@Setter@ToString
public class AjaxRes {
private boolean success;
private String msg;
}
EmployeeController
@Autowired
private AjaxRes ajaxRes;
/*接收员工添加表单*/
@RequestMapping("/saveEmployee")
@ResponseBody
public AjaxRes saveEmployee(Employee employee){
try {
/*调用业务层,保存用户*/
employee.setState(true);
employeeService.saveEmployee(employee);
ajaxRes.setMsg("保存成功");
ajaxRes.setSuccess(true);
}catch (Exception e){
ajaxRes.setSuccess(false);
ajaxRes.setMsg("保存失败");
}
return ajaxRes;
}
修改employee.js
success:function(data){
data = $.parseJSON(data);
if(data.success){
$.messager.alert("温馨提示",data.msg);
/*关闭对话框*/
$("#dialog").dialog("close");
/*重新加载数据表格*/
$("#dg").datagrid("reload");
}else {
$.messager.alert("温馨提示",data.msg);
}
}
15. 编辑数据回显.
先添加关闭按钮的响应
text:'关闭',
handler:function() {
$("#dialog").dialog("close");
}
然后添加按钮的打开时清空.
/*监听添加按钮点击*/
$("#add").click(function () {
$("#employeeForm").form("clear"); 使用.form(clear)
$("#dialog").dialog("open");
});
-----------------------------------------------------------------------
/*监听添加按钮点击*/
$("#add").click(function () {
$("#dialog").dialog("setTitle","编辑员工");
/*清空对话框中的数据*/
$("#employeeForm").form("clear");
/*打开对话框*/
$("#dialog").dialog("open");
});
/*员工数据列表*/
$("#dg").datagrid({
singleSelect:true, /*只能选择一行*/
striped:true, /*斑马线显示,隔行变色*/}
如果需求是不能编辑密码,那么选择编辑时隐藏密码选项
在jsp页面给tr添加id为password
<tr id="password">
<td>密码:</td>
<td><input type="text" name="password" class="easyui-validatebox" data-options="required:true"></td>
</tr>
/*监听编辑按钮点击*/
$("#edit").click(function () {
/*获取当前选中的行*/
var rowData = $("#dg").datagrid("getSelected");
console.log(rowData);
if(!rowData){
$.messager.alert("提示","请选择一行数据进行编辑");
return;
}
/*隐藏密码选项*/
$("#password").hide();
/*弹出对话框*/
$("#dialog").dialog("setTitle","编辑员工");
$("#dialog").dialog("open");
/*设置部门,由于部门是department.id,所以需要设置,不能直接回调*/
rowData["department.id"] = rowData["department"].id;
/*设置管理员回显*/
rowData["admin"]=rowData["admin"]+"";
/*选中数据的回显*/
$("#employeeForm").form("load",rowData);
})
16. 编辑提交
由于是使用的同一个对话框dialog,所以在提交表单之前,需要判断是新增还是添加.
在jsp页面的form标签下添加一个隐藏域
jsp页面
<form id="employeeForm">
<%--添加一个隐藏域用于区分添加和编辑--%>
<input type="hidden" name="id">
employee.js
handler:function(){
/*判断当前是新增还是编辑*/
var id = $("[name='id']").val();
/*由于要区分新增和编辑,下面url不能写死.*/
var url;
if(id){
/*如果有id则为编辑操作*/
url = "updateEmployee"
}else{
/*如果没有则为添加*/
url = "saveEmployee"
}
/*提交表单*/
$("#employeeForm").form("submit",{
url:url,
由于采用的对话框编辑和添加时同一个,而编辑没有密码的选项,但是密码属于data-options="required:true"
是必填项,所以需要取消密码校验.
在employee.js /*监听编辑按钮点击*/下添加
/*取消密码的验证*/
$("[name= 'password']").validatebox({required:false}); //validatebox验证盒设置必需为否
/*隐藏密码选项*/
$("#password").hide();
然后在添加时需要去增加密码验证
/*监听添加按钮点击*/
$("#add").click(function () {
/*添加密码验证*/
$("[name='password']").validatebox({required: true});
在EmployeeController添加 @RequestMapping("/updateEmployee")
/*编辑员工数据*/
@RequestMapping("/updateEmployee")
public void updateEmployee(){
System.out.println("编辑员工数据");
}
17. 更新员工
EmployeeController
/*编辑员工数据*/
@RequestMapping("/updateEmployee")
@ResponseBody
public AjaxRes updateEmployee(Employee employee){
try {
employeeService.updateEmployee(employee);
ajaxRes.setMsg("编辑成功");
ajaxRes.setSuccess(true);
}catch (Exception e){
ajaxRes.setSuccess(false);
ajaxRes.setMsg("编辑失败");
}
return ajaxRes;
}
employeeService
/*编辑员工*/
public void updateEmployee(Employee employee);
employeeServiceImpl
@Override
public void updateEmployee(Employee employee) {
/*调用业务层更新员工*/
employeeMapper.updateByPrimaryKey(employee);
}
18. 设置离职状态
先监听按钮的点击
/*设置离职按钮的点击*/
$("#delete").click(function () {
/*获取当前选中的行*/
var rowData =$("#dg").datagrid("getSelected");
console.log(rowData);
if(!rowData){
$.messager.alert("请选择一行数据进行删除");
return;
}
/*提醒用户是否做离职操作*/
$.messager.confirm("确认","是否做离职操作",function (res) {
if(res){
/*点击确认,返回值为true,点击取消返回值为false,做离职的操作*/
$.get("/updateState?id="+rowData.id,function (data) {
/* data = $.parseJSON(data);由于前面时使用get方式提交,所有不再需要转换json格式*/
if(data.success){
$.messager.alert("温馨提示",data.msg);
/*重新加载数据表格*/
$("#dg").datagrid("reload");
}else {
$.messager.alert("温馨提示",data.msg);
}
})
}
})
});
EmployeeController
/*离职操作请求*/
@RequestMapping("/updateState")
@ResponseBody
public AjaxRes updateState(Long id){
try {
/*设置员工离职状态*/
employeeService.updateState(id);
ajaxRes.setMsg("删除成功");
ajaxRes.setSuccess(true);
}catch (Exception e){
ajaxRes.setSuccess(false);
ajaxRes.setMsg("删除失败");
}
return ajaxRes;
}
employeeService
/*离职员工*/
public void updateState(Long id);
employeeServiceImpl
@Override
public void updateState(Long id) {
/*员工离职状态*/
employeeMapper.updateState(id);
}
EmployeeMapper
void updateState(Long id);
EmployeeMapper.xml
<!--设置员工离职状态-->
<update id="updateState">
update employee set state=false where id=#{id}
</update>
19. 离职按钮状态设置
需求,状态设置为离职后,选择该条数据不能再点击离职.
employee.js/*员工数据列表*/下面最后添加
onClickRow:function (rowIndex,rowData) {
/*判断当前行是否是离职状态*/
if(!rowData.state){
/*是离职,把离职按钮禁用*/
$("#delete").linkbutton("disable");
}else{
/*未离职,启用*/
$("#delete").linkbutton("enable");
}
}
但是disable还是可以点击,esayUI的bug.
添加一个base.js覆盖重写linkbutton方法扩展
把base.js放在js目录下.
20. 分页添加
添加一个domain QueryVo接收页面的两个参数
由于前端页面设定的form data 有两个参数page:1 rows:10.
QueryVo
@Getter@Setter@ToString
public class QueryVo {
private int page;
private int rows;
}
在EmployeeController层
@RequestMapping("/employeeList")
@ResponseBody
public PageListRes employeeList(QueryVo vo){
/*调用业务层查询员工*/
PageListRes pageListRes = employeeService.getEmployee(vo);
return pageListRes;
}
传入一个vo参数.
employeeService
/*查询员工*/
public PageListRes getEmployee(QueryVo vo);
employeeServiceImpl
@Override
public PageListRes getEmployee(QueryVo vo) {
/*调用mapper查询员工*/
/*设置分页total*/
Page<Object> page = PageHelper.startPage(vo.getPage(), vo.getRows());
就可以通过页面设置每页的数据条数,自动分页.
pageList:[10,20,30,50], /*设置每页显示行数*/
21. 搜索操作
在工具栏添加一个查询框
<input type="text" name="keyword" style="width: 200px; height: 30px;padding-left: 5px;">
<a class="easyui-linkbutton" iconCls="icon-search" id="searchbtn">查询</a>
监听按钮点击employee.js
/*监听搜索按钮点击*/
$("#searchbtn").click(function () {
/*获取搜索框内容*/
var keyword = $("[name='keyword']").val();
/*重新加载列表 把参数传过去*/
$("#dg").datagrid("load",{keyword:keyword});
})
QueryVo中添加
private String keyword;
employeeServiceImpl在查询中传入参数vo
List<Employee> employees = employeeMapper.selectAll(vo);
EmployeeMapper添加参数vo
List<Employee> selectAll(QueryVo vo);
EmployeeMapper.xml改写sql语句,引用sql片段
添加sql片段
<sql id="where_sql" >
<where>
<if test="keyword !=null and keyword!=''">
and e.username like concat('%',#{keyword},'%')
or e.tel like concat('%',#{keyword},'%')
or e.email like concat('%',#{keyword},'%')
</if>
</where>
</sql>
<!--员工关联部门查询-->
<select id="selectAll" resultMap="BaseResultMap" >
select e.id, e.username, e.inputtime, e.tel, e.email, e.state, e.admin,
d.id as d_id,
d.`name` as d_name
from employee as e
LEFT JOIN department as d
ON e.dep_id=d.id
<include refid="where_sql"/> //引用sql片段
order by e.id //根据id排序
</select>
22. 刷新操作
直接在js上添加一个刷新按钮的监控就行了,然后清空搜索框内容,再重载一下.
/*监听刷新点击*/
$("#reload").click(function () {
/*清空搜索内容*/
var keyword = $("[name='keyword']").val('');
/*重新加载数据*/
$("#dg").datagrid("load",{});
})
23 角色权限关系表建立
建立角色与权限的表
为多对多关系
角色表
权限表
角色与权限中间表
使用代码生成器生成相关mapper
建立权限表permission,三个字段pid,pname,presource. pid为主键自增
建立角色表role,三个字段rid,rname,rnum. rid为主键自增
角色与权限中间表rid和pid为双主键
然后用代码逆向工程生成相关的domain,mapper,mapper.xml
24. 角色列表展示
前端创建role.jsp
<body>
<%--数据表格--%>
<div id="role_dg"></div>
</body>
创建JS role.js
$(function () {
/*角色数据列表*/
$("#role_dg").datagrid({
url:"/getRoles",
columns:[[
{field:'rnum',title:'角色编号',width:100,align:'center'},
{field:'rname',title:'角色名称',width:100,align:'center'},
]],
fit:true, /*是否需要填满*/
fitColumns:true, /*是否自动伸缩*/
rownumbers:true, /*是否需要显示行号*/
pagination:true, /*是否需要分页*/
pageList:[10,20,30,50], /*设置每页显示行数*/
singleSelect:true, /*只能选择一行*/
striped:true, /*斑马线显示,隔行变色*/
/* toolbar:"#tb", /!*添加工具栏标签*!/*/
});
});
前端控制器 RoleController
/*注入业务层*/
@Autowired
private RoleService roleService;
@RequestMapping("/role")
public String Role(){
return "role";
}
/*接收请求角色列表*/
@RequestMapping("/getRoles")
@ResponseBody
public PageListRes getRoles(QueryVo vo){
/*调用业务层 查询角色列表*/
PageListRes roles = roleService.getRoles(vo);
return roles;
}
RoleService
public interface RoleService {
/*查询角色列表*/
public PageListRes getRoles(QueryVo vo);
}
RoleServiceImpl
@Service
public class RoleServiceImpl implements RoleService {
/*注入mapper*/
@Autowired
private RoleMapper roleMapper;
@Override
public PageListRes getRoles(QueryVo vo) {
/*调用mapper查询数据*/
Page<Object> page = PageHelper.startPage(vo.getPage(), vo.getRows());
List<Role> roles = roleMapper.selectAll();
/*封装成pageList*/
PageListRes pageListRes = new PageListRes();
pageListRes.setTotal(page.getTotal());
pageListRes.setRows(roles);
return pageListRes;
}
}
25. 添加角色对话框
添加工具栏
<%--工具栏--%>
<div id="toolbar">
<a href="#" class="easyui-linkbutton" data-options="iconCls:'icon-add',plain:true" id="add">添加</a>
<a href="#" class="easyui-linkbutton" data-options="iconCls:'icon-edit',plain:true" id="edit">编辑</a>
<a href="#" class="easyui-linkbutton" data-options="iconCls:'icon-remove',plain:true" id="remove">删除</a>
</div>
添加对话框
<%--添加/编辑对话框--%>
<div id="dialog">
<form id="myform">
<table align="center" style="border-spacing: 20px 30px">
<input type="hidden" name="id">
<tr align="center">
<td>角色编号:<input type="text" name="username" class="easyui-validatebox"></td>
<td>角色名称:<input type="text" name="username" class="easyui-validatebox"></td>
</tr>
<tr>
<td><div id="role_data1"></div></td>
<td><div id="role_data2"></div></td>
</tr>
</table>
</form>
</div>
修改role.js
/*添加编辑对话框*/
$("#dialog").dialog({
width:500,
height:550
});
/*添加角色*/
$("#add").click(function () {
});
/*权限列表*/
$("#role_data1").datagrid({
title:"所有权限",
width:200,
height:300,
fitColumns: true,
columns: [[
{field:'pname',title:'权限名称',width:100,align:'center'}
]]
});
/*选中权限*/
$("#role_data2").datagrid({
title:"已选权限",
width:200,
height:300,
fitColumns: true,
columns: [[
{field:'pname',title:'权限名称',width:100,align:'center'}
]]
});
26. 修改EasyUI默认样式
<style>
#dialog #myform .panel-header{
height:20px;
}
#dialog #myform .panel-title{
color: black;
margin-top: -5px;
text-align: center;
}
</style>
单独对某部分的样式进行修改,复写css样式
27. 加载权限列表
/*权限列表*/
$("#role_data1").datagrid({
title:"所有权限",
width:200,
height:300,
fitColumns: true,
singleSelect:true,
url:'/permissionList',
columns: [[
{field:'pname',title:'权限名称',width:100,align:'center'}
]]
});
新建一个PermissionController
@Controller
public class PermissionController {
/*注入业务*/
@Autowired
private PermissionService permissionService;
@RequestMapping("/permissionList")
@ResponseBody
public List<Permission> permissionList(){
List<Permission> permission = permissionService.getPermission();
return permission;
}
}
PermissionService
public interface PermissionService {
public List<Permission> getPermission();
}
PermissionServiceImpl
@Service
public class PermissionServiceImpl implements PermissionService {
@Autowired
private PermissionMapper permissionMapper;
@Override
public List<Permission> getPermission() {
List<Permission> permissions = permissionMapper.selectAll();
return permissions;
}
}
由于权限选项不多,不用做分页,直接使用list<permission>接收值,不用使用pageListRes
28. 添加权限.
给第一个权限列表添加点击响应
/*权限列表*/
$("#role_data1").datagrid({
onClickRow:function (rowIndex,rowData) {/*点击一行时回调*/
/*判断是否已经存在该权限*/
/*取出所有的已选权限*/
var allRows = $("#role_data2").datagrid("getRows");
/*取出每一个进行判断*/
for(var i=0;i<allRows.length;i++){
/*取出每一行*/
var row = allRows[i];
if(rowData.pid == row.pid){/*已经存在该权限*/
/*让已经存在权限称为选中状态*/
/*获取已经称为选中状态当前角标*/
var index = $("#role_data2").datagrid("getRowIndex",row);
/*让该行成为选中状态*/
$("#role_data2").datagrid("selectRow",index);
return;
}
}
/*把当前选中的,添加到已选权限*/
$("#role_data2").datagrid("appendRow",rowData);
}}
});
给第二个选中权限添加点击响应
/*已经选中的权限*/
$("#role_data2").datagrid({
onClickRow:function (rowIndex,rowData) {
/*是否删除当前选中的行*/
$("#role_data2").datagrid("deleteRow",rowIndex);
}
});
29. 保存角色提交
role.js里添加保存和关闭按钮
/*添加编辑对话框*/
$("#dialog").dialog({
width:500,
height:550,
buttons:[{
text: '保存',
handler: function () {
/*提交表单*/
$("#myform").form("submit",{
url:"saveRole",
onSubmit:function(param){ /*传递额外参数,已选择的权限*/
/*获取已选权限*/
var allRows = $("#role_data2").datagrid("getRows");
/*遍历出每一个权限*/
for(var i=0; i<allRows.length; i++){
/*取出每一个权限*/
var row = allRows[i];
/*封装到集合中*/
param["permissions["+i+"].pid"] =row.pid;
}
},
success:function (data) {
}
});
}
},{
text:'关闭',
handler:function () {
$("#dialog").dialog("close");
}
}]
});
RoleController里添加
/*接收 保存角色请求地址*/
@RequestMapping("/saveRole")
@ResponseBody
public void saveRole(Role role){
System.out.println(role);
}
由于role还需要接收权限所有修改Role.java添加一个参数,使用一个ArrayList来接收权限.
/*一个角色可以有多个权限*/
private List<Permission> permissions =new ArrayList<>();
关键点学习使用onSubmit:function(param){ /*传递额外参数*/传递额外的参数.}
30. 保存角色与权限
RoleController.java里,使用roleService.saveRole方法进行保存
/*接收 保存角色请求地址*/
@RequestMapping("/saveRole")
@ResponseBody
public void saveRole(Role role){
/*调用业务层,保存角色和权限*/
roleService.saveRole(role);
}
RoleService
/*保存角色和权限*/
public void saveRole(Role role);
@Transactional
RoleServicelmpl
/*保存角色和权限*/
@Override
public void saveRole(Role role) {
/*1.保存角色*/
roleMapper.insert(role); /*rid:3 pid:1,2*/
/*2.保存权限之间的关系*/
for (Permission permission : role.getPermissions()) {
roleMapper.insertRoleAndPermission(role.getRid(),permission.getPid());
}
}
RoleMapper.java 记得使用@Param不然只能使用param1,param2.
/* 保存角色与权限关系*/
void insertRoleAndPermission(@Param("rid") Long rid, @Param("pid") Long pid);
修改RoleMapper.xml添加一个useGeneratedKeys="true"获取生成的key 和keyProperty="rid" 赋值给哪个属性
<!--保存角色-->
<insert id="insert" parameterType="com.itlike.domain.Role" useGeneratedKeys="true" keyProperty="rid">
insert into role (rid, rnum, rname)
values (#{rid,jdbcType=BIGINT}, #{rnum,jdbcType=VARCHAR}, #{rname,jdbcType=VARCHAR})
</insert>
<!--保存角色与权限关系-->
<insert id="insertRoleAndPermission">
insert into role_permission_rel(rid,pid)values (#{rid},#{pid})
</insert>
再在Controller层注入
/*注入一个AjaxRes类*/
@Autowired
private AjaxRes ajaxRes;
添加一个ajaxRes回调提示成功与否.
/*接收 保存角色请求地址*/
@RequestMapping("/saveRole")
@ResponseBody
public AjaxRes saveRole(Role role){
try {
/*调用业务层,保存角色和权限*/
roleService.saveRole(role);
ajaxRes.setMsg("保存成功");
ajaxRes.setSuccess(true);
}catch (Exception e){
ajaxRes.setMsg("保存失败");
ajaxRes.setSuccess(false);
}
return ajaxRes;
}
在js页面提示数据转换成json格式然后提示并重载
success:function (data) {
data=$.parseJSON(data)
if(data.success){
$.messager.alert("温馨提示",data.msg);
/*关闭对话框*/
$("#dialog").dialog("close");
/*重载数据表格*/
$("#role_dg").datagrid("reload");
}else {
$.messager.alert("温馨提示",data.msg);
}
}
添加一个 closed:true,让对话框开始为关闭,点击时才打开.
31. 角色编辑回显
让对话框添加时为空,而编辑角色时,才有回显.
修改role.js,让添加时为空
/*添加角色*/
$("#add").click(function () {
/*清空表单*/
$("#myform").form("clear");
/*清空已选权限*/
$("#role_data2").datagrid("loadData",{rows:[]});
/*设置标题*/
$("#dialog").dialog("setTitle","添加角色");
/*打开对话框*/
$("#dialog").dialog("open");
});
role.js 让编辑时回显.
/*监听编辑按钮*/
$("#edit").click(function () {
var rowData = $("#role_dg").datagrid("getSelected");
console.log(rowData);
if(!rowData){
$.messager.alert("提示","选择一行数据进行编辑");
return;
}
/*回显表单*/
$("#myform").form("load",rowData);
/*设置标题*/
$("#dialog").dialog("setTitle","编辑角色");
/*打开对话框*/
$("#dialog").dialog("open");
});
32. 角色权限回显
前面只实现了角色编号和角色名称的回显,本次需要实现角色已选权限的回显.
role.js
/*监听编辑按钮*/
$("#edit").click(function () {
var rowData = $("#role_dg").datagrid("getSelected");
console.log(rowData);
if(!rowData){
$.messager.alert("提示","选择一行数据进行编辑");
return;
}
/*加载当前角色的权限*/
var options = $("#role_data2").datagrid("options");
options.url="/getPermissionByRid?rid="+rowData.rid;
/*重新加载数据*/
$("#role_data2").datagrid("load");
/*回显表单*/
$("#myform").form("load",rowData);
/*设置标题*/
$("#dialog").dialog("setTitle","编辑角色");
/*打开对话框*/
$("#dialog").dialog("open");
});
在控制器PermissionController写对应的requestMapping
/*根据角色查询对应权限*/
@RequestMapping("/getPermissionByRid")
@ResponseBody
public List<Permission> getPermissionByRid(Long rid){
System.out.println(rid);
List<Permission> permissions= permissionService.getPermissionByRid(rid);
return permissions;
}
service层PermissionService
/*根据角色查询对应的权限*/
public List<Permission> getPermissionByRid(Long rid);
impl PermissionServiceImpl
/*根据角色查询对应的权限*/
@Override
public List<Permission> getPermissionByRid(Long rid) {
List<Permission> permissions = permissionMapper.selectPermissionByRid(rid);
return permissions;
}
Mapper
/*根据角色查询对应的权限*/
List<Permission> selectPermissionByRid(Long rid);
PermissionMapper.xml
<!--根据角色查询对应的权限-->
<select id="selectPermissionByRid" resultType="com.itlike.domain.Permission">
SELECT pid,pname,presource from permission where pid in(SELECT pid FROM role_permission_rel where rid=#{rid});
</select>
33. 更新角色权限
在role.js中保存按钮时,判断它到底是保存还是编辑
buttons:[{
text: '保存',
handler: function () {
/*判断当前是保存还是编辑*/
var rid = $("[name='rid']").val();
var url;
if(rid){
/*如果rid有值则是编辑操作*/
url="updateRole";
}else {
/*如果rid没值则是保存操作*/
url="saveRole";
}
/*提交表单*/
$("#myform").form("submit",{
url:url,
controller层
/*更新操作*/
@RequestMapping("/updateRole")
@ResponseBody
public AjaxRes updateRole(Role role){
/*调用更新角色业务*/
try {
roleService.updateRole(role);
ajaxRes.setMsg("更新成功");
ajaxRes.setSuccess(true);
}catch (Exception e){
ajaxRes.setSuccess(false);
ajaxRes.setMsg("保存失败");
}
return ajaxRes;
}
service
/*更新角色*/
void updateRole(Role role);
impl实现类
/*更新角色*/
@Override
public void updateRole(Role role) {
/*先打破角色与权限的关系,先删除*/
roleMapper.deletePermissionRel(role.getRid());
/*更新角色*/
roleMapper.updateByPrimaryKey(role);
/*重新建立与权限的关系*/
for (Permission permission : role.getPermissions()) {
roleMapper.insertRoleAndPermission(role.getRid(),permission.getPid());
}
}
mapper
/*先打破角色与权限的关系,先删除*/
void deletePermissionRel(Long rid);
mapper.xml
<!--先打破角色与权限的关系,先删除-->
<delete id="deletePermissionRel">
delete from role_permission_rel where rid=#{rid};
</delete>
34. 删除角色
role.js监听删除按钮
/*监听删除点击*/
$("#remove").click(function () {
/*获取当前选中行*/
var rowData = $("#role_dg").datagrid("getSelected");
console.log(rowData);
if(!rowData){
$.messager.alert("提示","选择一行数据进行删除")
return;
}
/*提示一次是否确认删除*/
$.messager.confirm("确认","是否删除",function (res) {
if(res) {
$.get("/deleteRole?rid=" + rowData.rid, function (data) {
if (data.success) {
$.messager.alert("温馨提示", data.msg);
/*关闭对话框*/
$("#dialog").dialog("close");
/*重载数据表格*/
$("#role_dg").datagrid("reload");
} else {
$.messager.alert("温馨提示", data.msg);
}
})
}
});
})
roleController
/*删除操作*/
@RequestMapping("/deleteRole")
@ResponseBody
public AjaxRes deleteRole(Long rid){
/*删除角色业务*/
try{
roleService.deleteRole(rid);
ajaxRes.setMsg("删除成功");
ajaxRes.setSuccess(true);
}catch (Exception e){
ajaxRes.setSuccess(false);
ajaxRes.setMsg("删除失败");
}
return ajaxRes;
}
roleService
/*删除角色*/
void deleteRole(Long rid);
roleServiceImpl
/*删除角色*/
@Override
public void deleteRole(Long rid) {
/*删除关联权限*/
roleMapper.deletePermissionRel(rid);
/*删除角色*/
roleMapper.deleteByPrimaryKey(rid);
}
35. 添加员工角色加载
employee.jsp添加一行
<tr>
<td>选择角色:</td>
<td><input id="role" name="role.rid" placeholder="选择角色"></td>
</tr>
employee.js
/*选择角色 下拉列表*/
$("#role").combobox({
width:150,
panelHeight:'auto',
editable:false,
url:'roleList',
textField:'rname',
valueField:'rid',
multiple:true,/*是否支持多选*/
onLoadSuccess:function () {/*数据加载完毕后回调显示提示*/
$("#role").each(function(i){
var span =$(this).siblings("span")[i];
var targetInput = $(span).find("input:first");
if(targetInput) {
$(targetInput).attr("placeholder", $(this).attr("placeholder"));
}
})
}
});
roleController
/*获取角色列表 在employee中使用*/
@RequestMapping("/roleList")
@ResponseBody
public List<Role> roleList(){
return roleService.roleList();
}
roleService
/*查询角色列表,不做分页*/
List<Role> roleList();
roleServiceImpl
@Override
public List<Role> roleList() {
return roleMapper.selectAll();
}
36. 保存员工角色关系
先让选择角色支持多选
multiple:true,/*是否支持多选*/
设置一个员工角色关系表,eid和rid为双主键
包含eid,rid,eid关联employee的id,rid关联role的rid.
在Employee中添加相关字段.
private List<Role> roles = new ArrayList<>();;
修改employee.js
/*提交表单*/
$("#employeeForm").form("submit",{
url:url,
onSubmit:function(param){/*添加额外参数*/
/*获取选中角色*/
var values = $("#role").combobox("getValues");
for(var i=0;i<values.length;i++){
var rid = values[i];
param["roles["+i+"].rid"] =rid;
}
},
给EmployeeMapper.xml的保存员工添加参数
<!--添加员工-->
<insert id="insert" parameterType="com.itlike.domain.Employee" useGeneratedKeys="true" keyProperty="id">
insert into employee (id, username, password, inputtime,
tel, email, state, admin,
dep_id)
values (#{id}, #{username},#{password}, #{inputtime},
#{tel}, #{email}, #{state}, #{admin},
#{department.id})
</insert>
添加useGeneratedKeys和keyProperty
修改employeeServiceImpl,添加保存角色关系表
/*保存员工*/
@Override
public void saveEmployee(Employee employee) {
/*保存员工*/
employeeMapper.insert(employee);
/*保存角色关系表*/
for (Role role : employee.getRoles()) {
employeeMapper.insertEmployeeAndRoleRel(employee.getId(),role.getRid());
}
}
EmployeeMapper
/*保存员工和角色关系*/
void insertEmployeeAndRoleRel(@Param("id") Long id, @Param("rid") Long rid);
EmployeeMapper.xml
<!--保存员工和角色 关系-->
<insert id="insertEmployeeAndRoleRel">
insert into employee_role_rel(eid,rid) values (#{id},#{rid});
</insert>
37. 编辑员工角色回显
在编辑按钮中设置回显employee.js
/*设置角色的回显 根据当前用户id查询当前角色id*/
$.get("/getRoleByEid?id="+rowData.id,function (data) {
/*设置下拉列表数据回显*/
$("#role").combobox("setValues",data);
})
RoleController
/*根据用户id查询对应的角色*/
@RequestMapping("/getRoleByEid")
@ResponseBody
public List<Long> getRoleByEid(Long id){
return roleService.getRoleByEid(id);
}
RoleService
/*根据用户id查询对应的角色*/
List<Long> getRoleByEid(Long id);
RoleServiceImpl
/*根据用户id查询对应的角色*/
@Override
public List<Long> getRoleByEid(Long id) {
return roleMapper.getRoleWithId(id);
}
RoleMapper
/*根据用户id查询对应的角色*/
List<Long> getRoleWithId(Long id);
RoleMapper.xml
<!-- 根据用户id查询对应的角色 -->
<select id="getRoleWithId" resultType="java.lang.Long">
select rid from employee_role_rel where eid=#{id};
</select>
38. 编辑员工角色更新
修改serviceImpl层
/*编辑员工*/
@Override
public void updateEmployee(Employee employee) {
/*打破和角色间的关系*/
employeeMapper.deleteRoleRel(employee.getId());
/*调用业务层更新员工*/
employeeMapper.updateByPrimaryKey(employee);
/*更新角色与员工的关系*/
for (Role role : employee.getRoles()) {
employeeMapper.insertEmployeeAndRoleRel(employee.getId(),role.getRid());
}
}
添加Mapper
/*打破角色与员工的关系*/
void deleteRoleRel(Long id);
Mapper.xml
<!--打破员工与角色关系-->
<delete id="deleteRoleRel">
delete from employee_role_rel where eid=#{id}
</delete>
39. Shiro概述
apache shiro Java的安全框架 轻量级
spring中有spring security,但是过于依赖spring,没有shiro使用简单
权限管理实现用户访问系统的控制
用户可以访问而且只能访问自己被授权的资源
只要有用户和密码的系统,权限管理几乎都会出现
权限管理分为
登录认证:对于需要访问控制的资源用,首先经过身份认证
判断一个用户是否为合法用户的处理过程.
授权:认证通过用户具有资源的访问权限-方可访问
控制能够访问哪些资源
shrio概述
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。
使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
40. Shiro核心概念
核心类:
Authentication(认证) 身份认证/登录,验证用户是否拥有相应身份
Authorization(授权) 授权,即授权验证,验证某个已认证用户是否拥有某个权限
前两个是重点
Session Manager 会话管理,用户登录后就是一次会话,没有退出前,所有信息都在会话里
Cryptography 加密,保护数据安全
Web Support Web支持,可以非常容易的集成到web环境
Caching 缓存,比如用户登录后,其用户信息,拥有权限/角色不用每次检查,提高效率
Concurrency shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去.
Testing 提供测试支持
Run As 允许一个用户假装另外一个用户(如果他们允许)的身份进行访问
Remember Me 记住我,这个是非常常见的功能,即一次登录后,下次再来不用登录了
主要概念:
Subject: 当前的操作用户:可以是人,爬虫,当前跟软件交互的东西
在shiro当中我们可以统称"用户"
在代码的任何地方,你都能轻易的获取shiro Subject.
一旦获取subject,你就可以立即获得你希望用shiro为当前用户做的90%的事情
SecurityManager: SecurityManager则管理所有用户的安全操作
引用了多个内部嵌套安全组件,是shiro框架的核心
你可以把它看成DispatcherServlet前端控制器(springmvc)
用于调度各种shiro框架的服务
Realms: realms则是用户的信息认证器和用户的权限认证器
执行认证(登录)和授权(访问控制)时,shiro会从应用配置的realm中查找很多内容
realm可以理解为读取用户信息,角色及权限的DAO
SecurityManager要验证用户身份和权限,那么它需要从Realm获取相应的信息进行比较以确定用户身份是否合法
可以将Realm看成dateSource,即安全数据源.
Shiro框架:
subject主体: 主体可以是程序,主体要访问系统,系统需要对主体进行认证,授权
securityManager安全管理器:
authenticator认证器:
authorizer授权器:
sessionManager会话管理
sessionDao:
cacheManager缓存管理器
realm领域
cryptography密码管理:
41. Shiro工程依赖添加
什么是认证: 身份认证,就是判断一个用户是否为合法用户的处理过程
通过核对用户输入的用户名和口令,看其是否与系统中存储的该用户的用户名和口令一致,来判断用户身份是否正确
关键对象:
subject主体 用户
Principal 身份信息 是主体Subject进行身份认证的标识,标识必须具有唯一性,如用户名,手机号,邮箱地址等
credential 凭证信息 是只有主体自己知道的安全信息,如密码,证书等.
使用ini完成认证: 1.在Maven中添加依赖jar包
2.添加shiro.ini配置文件
3.登录与退出
创建一个shiro项目 maven quickstart
添加shiro相关依赖
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.24</version>
</dependency>
添加ini文件
[users]
itlike=1234
my=1234
42. shiro认证
public static void main( String[] args )
{
/*1.构建securityManager工厂 ini 加载配置*/
IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
/*2.通过工厂创建securityManager*/
SecurityManager securityManager = factory.getInstance();
/*3.将securityManager设置到运行环境中*/
SecurityUtils.setSecurityManager(securityManager);
/*4.创建一个Subject实例*/
Subject subject = SecurityUtils.getSubject();
/*5.创建token令牌*/
UsernamePasswordToken token = new UsernamePasswordToken("itlike", "1234");
/*6.用户登录*/
try {
subject.login(token);
}catch (UnknownAccountException e) {
System.out.println("账号不存在");
e.printStackTrace();
}catch (IncorrectCredentialsException e){
System.out.println("密码错误");
e.printStackTrace();
}
/*如果成功为true,反之为false*/
System.out.println("是否认证成功"+subject.isAuthenticated());
/*7.用户退出*/
subject.logout();
System.out.println("是否认证成功"+subject.isAuthenticated());
}
43 Shiro认证流程源码分析
构造SecurityManager环境
Subject.login()提交认证
SecurityManage.login()执行认证
Authentictor执行认证
Realm根据身份获取认证信息
1.调用subject.login方法进行登录,其会自动委托给securityManager.login方法进行登录;
2.securityManager通过Authenticator(认证器)进行认证;
3.Authenticator的实现ModularRealmAuthenticator调用realm从ini配置文件取用户真实的账号和密码
4.IniRealm先根据token中的账号去ini中找该账号,如果找不到则给ModularRealmAuthenticator返回null,如果找到则匹配密码,匹配密码成功则认证通过。
5、最后调用Subject.logout进行退出操作。
44. Shiro自定义realm
1.创建一个类继承AuthorizingRealm
2.覆盖doGetAuthenticationInfo方法,在此方法当中数据库获取用户,交有验证器去验证
public class MyRealm extends AuthorizingRealm {
/*认证*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
/*判断当前用户是否存在*/
/*获取用户名*/
String username = (String) token.getPrincipal();
/*从数据库查出用户名和密码 真实需要从数据库取*/
String name="itlike";
String password="123456";
if(!name.equals(username)){
return null;
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password, this.getName());
return info;
}
/*授权*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
}
3.在ini文件当中进行配置
myRealm=com.itlike.MyRealm
securityManager.realms=$myRealm
就可以在前面的app实例中使用自己的realm了.
45. Shiro散列密码
散列密码
概述
散列算法一般用于生成数据的摘要信息,是一种不可逆的算法
一般适合存储密码之类的数据,常见的散列算法如MD5、SHA等
使用shiro进行散列密码
Md5Hash
SimpleHash
Md5Hash 示例
public static void main(String[] args){
/*散列密码 每次加密结果一致*/
/*itlike是加盐值,3是3次散列*/
Md5Hash md5Hash = new Md5Hash("1234","itlike",3);
System.out.println(md5Hash);
/*使用SimpleHash*/
SimpleHash simpleHash = new SimpleHash("md5","1234","itlike",3);
System.out.println(simpleHash);
}
46. Shiro认证添加散列密码
realm中配置散列
在ini文件当中进行散列
[main]
#定义凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#散列算法
credentialsMatcher.hashAlgorithmName=md5
#散列次数
credentialsMatcher.hashIterations=3
#指定realm
myRealm=com.itlike.MyRealm
#配置散列
myRealm.credentialsMatcher=$credentialsMatcher
#配置自定义散列
securityManager.realms=$myRealm
要保证数据库中的密码是经过散列之后的
还需要在MyRealm中添加盐值
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
/*判断当前用户是否存在*/
/*获取用户名*/
String username = (String) token.getPrincipal();
/*从数据库查出用户名和密码 真实需要从数据库取*/
String name="itlike";
String password="c4d626db1e96e4c058c3f088e9f2fc13";
if(!name.equals(username)){
return null;
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password, ByteSource.Util.bytes("itlike"), this.getName());
return info;
}
在SimpleAuthenticationInfo中添加ByteSource.Util.bytes("itlike")盐值为itlike
47. Shiro授权
什么是授权
授权,即访问控制,控制谁能访问哪些资源。
主体进行身份认证后需要分配权限,方可访问系统的资源,对于某些资源没有权限是无法访问的。
使用ini形式配置权限信息
在ini文件中用户、角色、权限的配置规则
用户名=密码,角色1,角色2...
首先根据用户名找角色,再根据角色找权限,角色是权限集合。
权限字符串的规则
“资源标识符:操作:资源实例标识符”
对哪个资源的哪个实例具有什么操作
:”是资源/操作/实例的分割符
权限字符串也可以使用*通配符
新建一个shiro-permission.ini
[users]
#用户itlike的密码是1234,此用户具有role1和role2两个角色
itlike=1234,role1,role2
myxq=1234,role2
[roles]
#角色role1对资源user拥有create、update权限
role1=user:create,user:update
#角色role2对资源user拥有create、delete权限
role2=user:create,user:delete
#角色role3对资源user拥有create权限
role3=user:create,user:edit
授权实例:
public static void main( String[] args )
{
/*1.构建securityManager工厂 ini 加载配置*/
IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro-permission.ini");
/*2.通过工厂创建securityManager*/
SecurityManager securityManager = factory.getInstance();
/*3.将securityManager设置到运行环境中*/
SecurityUtils.setSecurityManager(securityManager);
/*4.创建一个Subject实例*/
Subject subject = SecurityUtils.getSubject();
/*5.创建token令牌*/
UsernamePasswordToken token = new UsernamePasswordToken("itlike", "1234");
/*6.用户登录*/
try {
subject.login(token);
}catch (UnknownAccountException e) {
System.out.println("账号不存在");
e.printStackTrace();
}catch (IncorrectCredentialsException e){
System.out.println("密码错误");
e.printStackTrace();
}
/*如果成功为true,反之为false*/
System.out.println("是否认证成功"+subject.isAuthenticated());
/*认证成功之后才做授权*/
/*判断当前用户是否有某一个角色或者权限*/
boolean role1 = subject.hasRole("role1");
/*判断当前用户是否有某一个角色或者权限*/
System.out.println("判断当前用户是否拥有权限1:"+subject.hasRole("role1"));
System.out.println("判断当前用户是否拥有权限2:"+subject.hasRole("role2"));
System.out.println("判断当前用户是否拥有权限3:"+subject.hasRole("role3"));
/*判断当前用户是否同时具备多个角色 必须同时具备才显为true*/
System.out.println(subject.hasAllRoles(Arrays.asList("role1","role2","role3")));
/*判断是否有某一个权限*/
System.out.println(subject.isPermitted("user:create"));
/*判断是否有多个权限*/
System.out.println(subject.isPermittedAll("user:delete","user:update","user:create"));
}
48. Shiro自定义realm授权
修改MyRealm.java
重写它的AuthorizationInfo的返回值,手动赋值给它
/*授权*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
/*获取当前的身份信息*/
Object primaryPrincipal = principalCollection.getPrimaryPrincipal();
/*假设 用户的角色 授权*/
ArrayList<String> roles=new ArrayList<>();
roles.add("role1");
roles.add("role2");
ArrayList<String> permissions = new ArrayList<>();
permissions.add("user:create");
permissions.add("user:delete");
/*把角色和权限给添加添加到授权当中*/
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRoles(roles);
info.addStringPermissions(permissions);
return info;
}
在App中测试可用.
49. 整合web工程认证校验
拷贝一个登陆页面login.jsp
需求,需要认证后才能登陆index.jsp,否则只能在login.jsp
添加shiro的pom相关依赖
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.24</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
1.登录拦截,如果没有登录,跳转到登录页面
1.在web.xml当中配置过滤器拦截所有请求,进行处理
<!-- 拦截到所有请求,使用spring一个bean来进行处理 -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<!-- 是否filter中的init和 destroy-->
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2.在spring当中配置shiro过滤器和安全管理器
在resources中新建application-shiro.xml
然后在applicationContext中导入配置文件
<!--导入shiro-->
<import resource="classpath:application-shiro.xml"/>
application-shiro.xml中配置shiro过滤器
<!-- 配置shiro过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"></property>
<!-- 配置shiro过滤器pattern -->
<property name="filterChainDefinitions">
<value>
/static/** = anon <!--不需要登录验证--> //anon就是不需要验证可以匿名登陆
/login.jsp = anon <!--不需要登录验证-->
/**=authc <!--除指定请求外,其它所有的请求都需要身份验证--> //authc就是需要验证 /**就是除了以上全部需要
</value>
</property>
</bean>
<!-- 配置shiro安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"></bean>
50. 配置loginUrl认证路径
由于scrpit比较少直接写在login.jsp中
<script>
$(function () {
$("#loginBtn").click(function () {
/*发送请求,做登录认证*/
$.post("/login",$("form").serialize(),function (data) {
console.log(data)
})
})
})
</script>
配置application-shiro
<!-- 配置shiro过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!--
index
其它的请求 会判断 当前有没有认证过
默认情况 ,没有认证,会跳转到login.jsp
如果配置了 loginUrl 没有认证 执行对应的login请求
login
loginUrl:如果发现请求是loginUrl值 会去做认证
配置登录认证的路径
-->
<property name="loginUrl" value="/login"/>
<property name="securityManager" ref="securityManager"></property>
<!-- 配置shiro过滤器pattern -->
<property name="filterChainDefinitions">
<value>
/static/** = anon <!--不需要登录验证-->
/login.jsp = anon <!--不需要登录验证-->
/**=authc <!--除指定请求外,其它所有的请求都需要身份验证-->
</value>
</property>
</bean>
51. 配置员工realm
在web下创建一个新的包realm
创建一个新的类EmployeeRealm 继承AuthorizingRealm
重写它的认证方法AuthorizationInfo和授权方法AuthenticationInfo
然后在application_shiro.xml中配置realm
<!--自定义realm-->
<bean id="employeeRealm" class="com.itlike.web.realm.EmployeeRealm"></bean>
<!-- 配置shiro安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!--注入realm-->
<property name="realm" ref="employeeRealm"/>
</bean>
修改认证EmployeeRealm
public class EmployeeRealm extends AuthorizingRealm {
@Autowired
private employeeService employeeService;
/*认证*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("来到认证------");
/*获取身份信息*/
String username=(String)token.getPrincipal();
System.out.println(username);
/*到数据库查询是否有当前用户*/
Employee employee = employeeService.getEmployeeWithUserName(username);
if (employee == null){
return null;
}
/*认证*/
/*参数:主体,正确的密码,加的盐值*/
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(employee,employee.getPassword(),this.getName());
return null;
}
}
52 登录用户查询
employeeService.getEmployeeWithUserName(username);方法的实现
serviceimpl层
@Override
public Employee getEmployeeWithUserName(String username) {
return employeeMapper.getEmployeeWithUserName(username);
}
mapper层
<!--根据用户名查询-->
<select id="getEmployeeWithUserName" resultType="com.itlike.domain.Employee">
select * from employee where username=#{username}
</select>
53. 监听登录认证结果
在web层添加一个过滤器
MyFormFilter
继承一个FormAuthenticationFilter 方法,重写它的onLoginSuccess和onLoginFailure
public class MyFormFilter extends FormAuthenticationFilter {
/*当认证成功时,调用*/
protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
/*响应给浏览器*/
System.out.println("认证成功");
return false;
}
/*认证失败时,调用*/
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
/*响应给浏览器*/
System.out.println("认证失败");
return false;
}
}
在application-shiro.xml中配置
先将过滤器交给spring来管理
<!-- 配置过滤器-->
<bean id="myFormFilter" class="com.itlike.web.filter.MyFormFilter"/>
然后它添加到shiro过滤器中去
<!-- 配置shiro过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!--
index
其它的请求 会判断 当前有没有认证过
默认情况 ,没有认证,会跳转到login.jsp
如果配置了 loginUrl 没有认证 执行对应的login请求
login
loginUrl:如果发现请求是loginUrl值 会去做认证
配置登录认证的路径
-->
<property name="loginUrl" value="/login"/>
<!--配置表单监听的过滤器-->
<property name="filters">
<map>
<entry key="authc" value-ref="myFormFilter"/>
</map>
</property>
<property name="securityManager" ref="securityManager"></property>
<!-- 配置shiro过滤器pattern -->
<property name="filterChainDefinitions">
<value>
/static/** = anon <!--不需要登录验证-->
/login.jsp = anon <!--不需要登录验证-->
/**=authc <!--除指定请求外,其它所有的请求都需要身份验证-->
</value>
</property>
</bean>
54. 登录成功处理.
*Ajax发送请求,做登录认证,是没办法跳转服务器当中的请求只能通过在浏览器当中来做跳转
前端的js修改
$(function () {
$("#loginBtn").click(function () {
/**Ajax发送请求,做登录认证,是没办法跳转服务器当中的请求
* 只能通过在浏览器当中来做跳转*/
$.post("/login",$("form").serialize(),function (data) {
/*把data json格式的字符串 转为json数据*/
data = $.parseJSON(data);
if (data.success) {
/*成功跳转到首页*/
window.location.href ="/index.jsp"
}else {
}
})
})
})
MyFormFilter
/*当认证成功时,调用*/
protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
/*响应给浏览器*/
response.setCharacterEncoding("utf-8");
System.out.println("认证成功");
AjaxRes ajaxRes = new AjaxRes();
ajaxRes.setSuccess(true);
ajaxRes.setMsg("登录成功");
/*把对象转成json格式字符串*/
String jsonString = new ObjectMapper().writeValueAsString(ajaxRes);
response.getWriter().print(jsonString);
return false;
}
55. 登录失败处理
MyFormFilter
/*认证失败时,调用*/
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
/*响应给浏览器*/
System.out.println("认证失败");
AjaxRes ajaxRes = new AjaxRes();
ajaxRes.setSuccess(false);
if (e!=null){
/*获取异常名称*/
String name = e.getClass().getName();
if (name.equals(UnknownAccountException.class.getName())){
/*没有账号*/
ajaxRes.setMsg("账号错误");
}else if (name.equals(IncorrectCredentialsException.class.getName())){
/*密码错误*/
ajaxRes.setMsg("密码错误");
}else {
ajaxRes.setMsg("未知异常");
/*未知异常*/
}
}
try {
/*把对象转成json格式字符串*/
String jsonString = new ObjectMapper().writeValueAsString(ajaxRes);
response.setCharacterEncoding("utf-8");
response.getWriter().print(jsonString);
} catch (IOException e1) {
e1.printStackTrace();
}
return false;
}
然后前端jsp
在else
alert(data.msg)
56 退出功能
index.jsp
添加shiro的标签库在顶部
<%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro" %>
<%--顶部--%>
<div data-options="region:'north'" style="height:100px; background: #ec4e00; padding: 20px 20px; position: relative;">
<img src="static/images/main_logo.png" alt="">
<div style="position: absolute; right: 50px; top: 30px;">
<img src="./static/images/user.png" style="vertical-align: middle; margin-right: 10px;" >
<%--显示当前登录用户名--%>
<span style="color: white; font-size: 20px; margin-right: 5px;"><shiro:principal property="username" /> </span>
<%--取消认证 跳转到 登录页面 在shiro配置文件当中 配置 /logout = logout --%>
<a style="font-size: 18px; color: white;text-decoration: none;" href="${pageContext.request.contextPath}/logout">注销</a>
</div>
</div>
引用shiro的标签<shiro:principal property="username" />
在application-shiro.xml的配置中
添加 /logout = logout <!--取消认证 注销功能-->
这个路径请求的时候logout
在前端页面index.jsp中
<%--取消认证 跳转到 登录页面 在shiro配置文件当中 配置 /logout = logout --%>
<a style="font-size: 18px; color: white;text-decoration: none;" href="${pageContext.request.contextPath}/logout">注销</a>
57. 注解授权添加
EmpoleeController中添加注解 @RequiresPermissions("employee:index")
@RequestMapping("/employee")
@RequiresPermissions("employee:index")
public String employee(){
return "employee";
}
EmpoleeRealm
/** 授权
web doGetAuthorizationInfo 什么时候调用
1.发现访问路径对应的方法上面有授权的注解 就会调用doGetAuthorizationInfo授权方法
2.页面中有授权的标签 也会调用doGetAuthorizationInfo授权方法
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("授权调用index---------");
return null;
}
1.在配置文件application-shiro.xml当中添加Shiro注解扫描
<!--
配置为true即使用cglib继承的方式,
false为jdk的接口动态代理 控制器没有实现接口
-->
<aop:config proxy-target-class="true" ></aop:config>
<!-- 使用第三方去扫描shiro的注解 -->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor ">
<property name="securityManager" ref="securityManager"></property>
</bean>
58. 授权角色添加
在realm中添加授权信息
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("授权调用index---------");
/*获取用户的身份信息*/
Employee employee = (Employee) principals.getPrimaryPrincipal();
/*根据当前用户,查询角色权限*/
List<String> roles = new ArrayList<>();
List<String> permissions = new ArrayList<>();
/*查询角色*/
roles = employeeService.getRolesById(employee.getId());
/*给授权信息*/
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRoles(roles);
info.addStringPermissions(permissions);
return info;
}
employeeService
/*根据id查询角色*/
List<String> getRolesById(Long id);
employeeServicelmpl
/*根据id查询角色编号名称*/
@Override
public List<String> getRolesById(Long id) {
return employeeMapper.getRolesById(id);
}
EmployeeMapper
/*根据id查询用户角色编号*/
List<String> getRolesById(Long id);
EmployeeMapper.xml
<!--根据用户id查询角色编号-->
<select id="getRolesById" resultType="java.lang.String">
SELECT r.rnum FROM employee_role_rel as er
LEFT JOIN role as r
ON er.rid=r.rid WHERE eid=#{id}
</select>
59. 授权权限添加
EmployeeRealm 添加 /*查询权限*/permissions = employeeService.getPermissionsById(employee.getId());
/** 授权
web doGetAuthorizationInfo 什么时候调用
1.发现访问路径对应的方法上面有授权的注解 就会调用doGetAuthorizationInfo授权方法
2.页面中有授权的标签 也会调用doGetAuthorizationInfo授权方法
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("授权调用index---------");
/*获取用户的身份信息*/
Employee employee = (Employee) principals.getPrimaryPrincipal();
/*根据当前用户,查询角色权限*/
List<String> roles = new ArrayList<>();
List<String> permissions = new ArrayList<>();
/*查询角色*/
roles = employeeService.getRolesById(employee.getId());
System.out.println("role==="+roles);
/*查询权限*/
permissions = employeeService.getPermissionsById(employee.getId());
/*给授权信息*/
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRoles(roles);
info.addStringPermissions(permissions);
return info;
}
employeeService
/*根据id查询权限名称*/
List<String> getPermissionsById(Long id);
employeeServicelmpl
/*根据id查询权限*/
@Override
public List<String> getPermissionsById(Long id) {
return employeeMapper.getPermissionsById(id);
}
employeeMapper.xml SQL语句通过DISTINCT 去除重复的值
<!--根据用户id查询权限资源名称-->
<select id="getPermissionsById" resultType="java.lang.String">
SELECT DISTINCT p.presource FROM role_permission_rel as rp
LEFT JOIN permission as p ON rp.pid = p.pid
where rid in (SELECT rid FROM employee_role_rel where eid=#{id});
</select>