SSM權限管理系統

    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>
相關文章
相關標籤/搜索