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散列密碼 散列密碼 概述 散列算法通常用於生成數據的摘要信息,是一種不可逆的算法 通常適合存儲密碼之類的數據,常見的散列算法如MD五、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>