操作bootstrap table的js代码总结

采用requireJS实现js的模块化开发,集成各种bootstrap插件来实现对用户数据的管理

enter description here

添加功能:

enter description here
修改功能(类似下图):

enter description here

main.js

require.config({
//    baseUrl : 'js',
    paths : {
        jquery : 'lib/jquery.min',
        'css' : 'lib/css.min',
        'common' : 'app/common',
        'table' : 'app/table',
        'role' : 'app/role',
        'bootstrap' : 'lib/bootstrap.min',
        'bootstrapTable' : 'lib/bootstrap-table',
        'tableExport' : 'lib/tableExport',
        'tableLanguage' : 'lib/bootstrap-table-zh-CN',
        'bootstrapTableExport' : 'lib/bootstrap-table-export',
        'bootstrap-dialog' : 'lib/bootstrap-dialog.min',
        'jquery.base64' : 'lib/jquery.base64',
        'confirm' : 'lib/jquery-confirm.min',
        'bootstrapValidator' : 'lib/bootstrapValidator.min',
        'select2' : 'lib/select2.full.min'
    },
    shim : {
        'jquery' : {
            init : function() {
                return jquery.noConflict(true);
            },
            exports : 'jquery'
        },
        'common' : {
            deps : [ 'jquery', 'bootstrap',
                    'bootstrapValidator', 'select2', 'confirm' ,'bootstrap-dialog'],
            exports : 'common'
        },
        'table' : {
            exports : 'table'
        },
        'bootstrap' : {
            deps : [ 'jquery','css!../css/bootstrap.min.css' ],
            exports : "$.fn.popover"
        },
        'bootstrapTable' : {
            deps : [ 'jquery', 'bootstrap', 'css!../css/bootstrap-table.css'],
            exports : '$.fn.bootstrapTable'
        },
        'tableExport' : {
            deps : [ 'jquery' ],
            exports : '$.fn.extend'
        },
        'tableLanguage' : {
            deps : [ 'jquery', 'bootstrapTable' ],
            exports : '$.fn.bootstrapTable.defaults'
        },
        'bootstrapTableExport' : {
            deps : [ 'jquery', 'bootstrapTable' ],
            exports : '$.fn.bootstrapTable.defaults'
        },
        'bootstrap-dialog' : {
            deps:['css!../css/bootstrap-dialog.min.css'],
        },
        'confirm' : {
            deps : [ 'jquery' ,'css!../css/jquery-confirm.min.css'],
            exports : 'confirm'
        },
        'select2' : {
            deps : [ 'jquery','css!../css/select2.min.css' ],
            exports : 'select2'
        },
        'bootstrapValidator' : {
            deps : [ 'jquery', 'css!../css/bootstrapValidator.min.css'],
            exports : '$.fn.bootstrapValidator'
        }
    },
    waitSeconds : 0,
//    enforceDefine : true,
// skipDataMain:true
});
function operateFormatter(value, row, index) {
    return [
            '<a class="edit ml10" id="edit" href="#" data-toggle="modal" data-target="#editUserModal" title="Edit" data-whatever="修改终端">',
            '<i class="glyphicon glyphicon-edit"></i>', '</a>&nbsp;' ].join('');
}
require([ 'jquery', 'bootstrap-dialog', 'common', 'table', 'lib/domReady!'],
        function(jquery, BootstrapDialog, common, userTable, domReady) {
            userTable.init();
        /*    if ($('.glyphicon-user').text() != "admin") {
                $('#custom-toolbar').children().attr("disabled", "true").css({
                    "background-color" : "#DEDEDE",
                    "border-color" : "#DCDCDC"
                });
                $("#edit").attr("disabled","true").css({
                    "background-color" : "#DEDEDE",
                    "border-color" : "#DCDCDC"
                });
            }*/

            window.operateEvents = {
                'click .edit' : function(e, value, row, index) {
                    userTable.editGroup(row, index);
                },
                'click .remove' : function(e, value, row, index) {
                    userTable.deleteOneGroup(row.uid);
                }
            };
            $('#adduser').click(function() {
                common.openDialog('添加用户', 'addUser.html', false);
            });
            $('#deluser').click(function() {
                userTable.deleteUser();
            });
            $("#logout").click(function() {
                common.logout();
            });
            $('#changePasswd').click(function() {
                common.changePasswd();
            });
        });

table.js 主要功能实现

define([ 'jquery', 'bootstrap','tableExport', 'bootstrapTable', 'bootstrapValidator',
        'select2', 'bootstrap-dialog', 'confirm', 'common', 'tableLanguage'
        , 'bootstrapTableExport','role' ], function(jquery, bootstrap,tableExport,
        bootstrapTable, bootstrapValidator, select2, BootstrapDialog, confirm,
        common,tableLanguage,bootstrapTableExport,role) {
    var userTable = {};
    common.initPage();
    userTable.init = function() {
        userTable.queryAll();
        $table = $('#table');
        common.organList("#oid-change");
        userTable.selectUser();
        common.role("#uduty");
    };

    userTable.selectUser = function(){
        $.getJSON("js/config.json", function(result) {
            var approval = result.approval;
            $("#isapproval").select2({
                data : approval,
                minimumResultsForSearch : -1,// 禁用搜索
                placeholder : "审批",
                allowClear : true
            });
        });
    };

    userTable.addUser = function(form) {
        $.ajax({
            url : "/JDJ/rest/user/saveUser",
            type : "post",
            dataType : 'json',
            data : $(form).serializeArray(),
            success : function(result) {
                $('#adduserModal').modal('hide');
                if (result) {
                    common.alertConfirm("添加成功!");
                } else {
                    common.alertView("添加失败!");
                }
            },
        });
    };
    userTable.deleteUser = function() {
        var ids = $.map($table.bootstrapTable('getSelections'), function(row) {
            return row.uid;
        });

        if (ids == "") {
            common.alertView("请选择删除项");
            return;
        }
        userTable.delUser(ids);
    };
    userTable.deleteOneUser = function(ids) {
        $table.bootstrapTable('remove', {
            field : "id",
            values : ids
        });
        userTable.delUser(ids);
    };
    userTable.delUser = function(ids) {
        $.ajax({
            url : "../rest/user/delUser",
            type : "post",
            traditional : true,// 这样就能正常发送数组参数了
            data : {
                "ids" : ids,
            },
            success : function(result) {
                if (result) {
                    common.alertView("删除成功!!");
                    $table.bootstrapTable('remove', {
                        field : "uid",
                        values : ids
                    });
                } else
                    common.alertView("删除失败!!");
            },
            error : function() {
                common.alertView("删除失败!!");
            }
        });
    };
    userTable.queryAll = function() {
        $.ajax({
            url : "../rest/user/queryAllUser",
            type : "get",
            dataType : 'json',
            success : function(data) {
                if (data != null) {
                    userTable.OwnerName(data);
                }
            },
            error:function(){
                common.alertView("数据返回出错");
            }
        });
    };
    userTable.OwnerName = function(list) {
        var arraylist = [];
        for ( var i = 0; i < list.length; i++) {
            var obj = {};
            obj["uid"] = list[i].uid;
            obj["uname"] = list[i].uname;
            obj["uphone"] = list[i].uphone;
            obj["upassword"] = list[i].upassword;
            obj["oid"] = list[i].organ.oid;
            obj["oname"] = list[i].organ.oname;
            obj["rid"] = list[i].roles[0].rid;
            obj["rname"] = list[i].roles[0].rname;
            if(list[i].isapproval=="1"){
                obj["isapproval"] = "通过";
            }
            else{
                obj["isapproval"] = "未通过";
            }
            arraylist.push(obj);
        }
        $('#table').bootstrapTable({
            data : arraylist
        });
    };

    //open edit modal
    userTable.editGroup = function(row, index) {
        index1 = index;
        $('#editUserModal').on('show.bs.modal', function() {
            console.dir(row);
            var modal = $(this);
            modal.find('#uid').val(row.uid);
            modal.find('#uname').val(row.uname);
            modal.find('#uname').val(row.uname);
            modal.find('#uduty').val(row.rid);
            $("#uduty").val(row.rid).trigger("change");
            modal.find('#oid-change').val(row.oid);
            $("#oid-change").val(row.oid).trigger("change");
            modal.find('#upassword').val(row.upassword);
            modal.find('#uphone').val(row.uphone);
            if((row.isapproval)=="通过"){
                modal.find('#isapproval').val("1");
                $("#isapproval").val("1").trigger("change");
            }else{
                modal.find('#isapproval').val("0");
                $("#isapproval").val("0").trigger("change");

            }

            $("#editUserSubmit").click(function(){
                userTable.edit();
            });
        });
    };

    //edit submit
    userTable.edit = function() {
//        var uid = $('#uid').val();
        var uname = $('#uname').val();
        if(uname==""){
            common.alertView("用户名不能为空");
            return;
        }
//        var upassword = $('#upassword').val();
        var oid = $('#oid-change').val();
        var uphone = $('#uphone').val();
        var uduty = $('#uduty').val();
        var isapproval = $('#isapproval').val();
        $table.bootstrapTable('updateRow', {
            index : index1,
            row : {
                uname : uname,
//                upassword : upassword,
                oid : oid,
                uphone : uphone,
                uduty : uduty,
                isapproval: isapproval
            }
        });

        $.ajax({
            type : "post",
            url : "../rest/user/updateUser",
            cache : false,
            dataType : 'json',
            data : $("#editUserForm").serializeArray(),
            success : function(result) {
                $('#editUserModal').modal('hide');
                if (result) {
                    common.alertConfirm("修改成功!!");
                } else {
                    common.alertView("修改失败!");
                }
            },
            error : function() {
                $('#editUserModal').modal('hide');
                common.alertView("修改失败!");
            }
        });
    };

    //edit valiator
    userTable.valiatorEditUser = function() {
        $('#editUserForm').bootstrapValidator({
            message : '无效值',
            feedbackIcons : {
                valid : 'glyphicon glyphicon-ok',
                invalid : 'glyphicon glyphicon-remove',
                validating : 'glyphicon glyphicon-refresh'
            },
            submitHandler : function(validator, form, submitButton) {
                userTable.edit(form);
            },
            fields : {
                uname : {
                    validators : {
                        notEmpty : {
                            message : '用户名不能为空'
                        }
                    }
                },
                upassword : {
                    validators : {
                        notEmpty : {
                            message : '密码不能为空'
                        },
                        stringLength : {
                            min : 1,
                            max : 30,
                            message : '密码长度为1到30位'
                        }
                    }
                },
                uphone : {
                    validators : {
                        notEmpty : {
                            message : '电话不能为空'
                        },
                        regexp : {
                            regexp : /^[0-9]+$/,
                            message : '格式不正确'
                        }
                    }
                },
            }
        });
    };

    //add user valiator
    userTable.valiatorAddUser = function() {
        $('#addForm').bootstrapValidator({
            message : '无效值',
            feedbackIcons : {
                valid : 'glyphicon glyphicon-ok',
                invalid : 'glyphicon glyphicon-remove',
                validating : 'glyphicon glyphicon-refresh'
            },
            submitHandler : function(validator, form, submitButton) {
                userTable.addUser(form);
            },
            fields : {
                uname : {
                    validators : {
                        notEmpty : {
                            message : '用户名不能为空'
                        }
                    /*
                     * , regexp : { regexp : /^[a-zA-Z0-9_\.]+$/, message :
                     * '用户名只能由字母,数字,圆点和下划线组成' }
                     */
                    }
                },
                upassword : {
                    validators : {
                        notEmpty : {
                            message : '密码不能为空'
                        },
                        stringLength : {
                            min : 1,
                            max : 30,
                            message : '密码长度为1到30位'
                        },
                        identical : {
                            field : 'password2',
                            message : '密码与确认密码不一致'
                        },
                    }
                },
                password2 : {
                    validators : {
                        notEmpty : {
                            message : '确认密码不能为空'
                        },
                        stringLength : {
                            min : 1,
                            max : 30,
                            message : '密码长度为1到30位'
                        },
                        identical : {
                            field : 'upassword',
                            message : '密码与确认密码不一致'
                        }
                    }
                },
                uphone : {
                    validators : {
                        notEmpty : {
                            message : '电话不能为空'
                        },
                        regexp : {
                            regexp : /^[0-9]+$/,
                            message : '格式不正确'
                        }
                    }
                },
            }
        });
    };
    return userTable;
});

select2实现三级联动

最近根据项目需求要求实现数据分类,分类数据分为三级,考虑使用select2来实现三级联动效果
enter description here

Model

private Integer cid;
private String cname;
private String level;//所在层级
private String parent;//夫类ID

html

三个select标签,初始将后两个select隐藏
Tips小技巧: 若使用$.show(),$.hide()方法无法直接将select隐藏,则将它的上层标签隐藏,或者包裹在span中,将span隐藏。

<span id="one"> <select id="levelOne" name="levelOne" placeholder="分类" style="width: 100px">
</select></span> 
<span id="two" > <select id="levelTwo" name="levelTwo"
    placeholder="分类" style="width: 100px; display: none;">
</select>
</span> <span id="three"> <select id="levelThree" name="levelThree"
    placeholder="分类" style="width: 160px;  display: none;">
</select>
</span>

<button type="button" class="btn btn-info" id="save"
    style="margin-top: 5px; padding: 3px 12px">
    <i class="">保存</i>
</button>

js

分解功能,首次加载有几级数据显示几级数据,点击一类数据,对应的展示二类数据及第一个二类数据对应的三类数据,没有的让其隐藏

$(function() {
    var oneselect,twoselect,threeselect;
    selectAll();
    selectInit();
})
//初始化加载
function selectInit(){
    selectOne();

    $("#levelOne").on("select2:select", function (e) {
        var levelOne = $("#levelOne").val();
        selectTwo(levelOne);
    });

    $('#levelTwo').on("select2:select",function(){
        var levelTwo = $("#levelTwo").val();
        selectThree(levelTwo);
    });
}
//获取所有数据,分类保存到全局数组中,以方便后面使用
function selectAll(){
    $.ajax({
        url : "rest/category/queryAll",
        type : "get",
        async: false,//注意,必须是同步,不然全局变量取不到值
        dataType : 'json',
        success : function(result) {
            var oneLevel = [];
            var twoLevel = [];
            var threeLevel = [];
            for (var i = 0; i < result.length; i++) {
                if (result[i].level == "1") {
                    oneLevel.push(result[i]);
                } else if (result[i].level == "2") {
                    twoLevel.push(result[i]);
                } else if (result[i].level == "3") {
                    threeLevel.push(result[i]);
                }
            }
            oneselect = oneLevel;
            twoselect = twoLevel;
            threeselect = threeLevel;
        }
    });
}

//取第一类数据
function selectOne(){

    select2Show("#levelOne", oneselect);

    selectTwo(oneselect[0].cid);
}
//取对应的第二层数据
function selectTwo(parent){
    var twoTmp = [];
    for (var j = 0; j < twoselect.length; j++) {
        if (twoselect[j].parent == parent) {
            twoTmp.push(twoselect[j])
        }
    };
    if (twoTmp.length != 0) {
        $("#two").show();
        select2Show("#levelTwo", twoTmp);

        selectThree(twoTmp[0].cid);

    } else {
        twoHide();
        threeHide();
    }
}
//取对应的第三层数据
function selectThree(parent){
    var threeTmp = [];
    for (var m = 0; m < threeselect.length; m++) {
        if (parent == threeselect[m].parent) {
            threeTmp.push(threeselect[m]);
        }
    };
    if (threeTmp.length != 0) {
        $("#three").show();
        select2Show("#levelThree", threeTmp);
    } else {
        threeHide();
    }
}

function twoHide(){
    $("#levelTwo").empty();
    $("#two").hide();
}
function threeHide(){
    $("#levelThree").empty();
    $("#three").hide();
}
function select2Show(id,result){
    if(result.length!=0){
        var data=[];

        for ( var i = 0; i < result.length; i++) {
            var tmp = {};
            tmp["id"] = result[i].cid;
            tmp["text"] = result[i].cname;
            data.push(tmp);
        }

        $(id).empty();
        $(id).select2({
            data : data,
        });
    }
}

值得注意的是,某层类别需要隐藏时清空select2的数据,在保存分类时就可以获取类别id,如下代码所示
enter description here

function save(){
    var ids = $.map($table.bootstrapTable('getSelections'), function(row) {
        return row.id;
    });

    if (ids == "") {
        alertView("请选择待归类信息");
        return;
    }
    alert(ids);
    if($("#levelThree").val()!=null){
        saveData($("#levelThree").val(),ids);
    }else {
        if($("#levelTwo").val()!=null){
            saveData($("#levelTwo").val(),ids);
        }else {
            saveData($("#levelOne").val(),ids);
        }
    }
}

function saveData(id,ids){
    //数据保存,将数据值用ajax传到后台,进行保存
    $.ajax({
        url:"rest/category/saveClassfi",
        type:"post",
        data:{
            "id":id,
            "ids":ids
        },
        dataType:"json",
        success:function(result){

        }
    })
}

下图是获取到的待归类数据ID
enter description here
若未选择则弹出提示框:
enter description here

ajax请求

[TOC]

一次发送多个ajax请求

$.when($.ajax("../rest/Uploadinfo/queryAgencyCount"),
    $.ajax("../rest/Uploadinfo/queryBackCount"),
    $.ajax("../rest/Uploadinfo/queryHandlingCount"),
    $.ajax("../rest/Uploadinfo/queryNoUseCount"),
    $.ajax("../rest/Uploadinfo/querySpvCount"),
    $.ajax("../rest/Uploadinfo/queryUrgetCount"),
    $.ajax("../rest/Uploadinfo/queryEndCount")).done(
    function(a1, a2, a3, a4, a5, a6, a7) {
        $("#agencyCaseCount").html(" (" + a1[0] + ")");
        $("#backCount").html(" (" + a2[0] + ")");
        $("#handlingCount").html(" (" + a3[0] + ")");
        $("#noUseCount").html(" (" + a4[0] + ")");
        $("#spvCount").html(" (" + a5[0] + ")");
        $("#urgetCount").html(" (" + a6[0] + ")");
        $("#endCount").html(" (" + a7[0] + ")");
    })

参数

$.ajax({
    url : "delTerminalAction.action/config.json",
    type : "post/get",
    async : false,//表示同步
    traditional : true,// 这样就能正常发送数组参数了
    dataType : "json/xml/text/html",
    contentType: "application/x-www-form-urlencoded; charset=utf-8",//设置编码
    data : {
        "ids" : ids,
    },    
    success : function(data) {
        $.each(data , funtion(i, item){
            alert(item[i]);
            //或者是
            alert(item.tagName);
        });
    },
    error : function() {
        alert("删除失败!!");
    }
});

$.ajaxSetup()

jQuery的$.ajaxSetup方法可以设置AJAX请求的全局默认参数选项,当程序中需要发起多个AJAX请求时,则不用再为每一个请求配置请求的参数。
既然是全局默认选项,所以,该项中设置的参数会影响所有的$.ajax请求,如$.get(),$.post(),$.ajax等

$.ajaxSetup({  
    contentType : 'application/json'  
}); 

扩展

get了一个新技能,mark一下。

options = {
    type : "get/post",
    datatype:"json",
    success : function(){
        alert("success");
    }
}
$.ajax($.extend(options,{
    url : "rest/user/queryAll",
    data : {
        "name":"chenchen"
    }
}))

$.getJSON

// $.getJSON相当于$.ajax方法中dataType值为json时的简化
$.getJSON(url, function(data){
    ...
})

$.get

//可获取int型非json数据
$.get(url,function(){

})

原文不定时更新,具体详情请查看ajax总结

SpringMVC框架原理及项目配置

[TOC]

SpringMVC

SpringMVC框架基于WEB MVC的一个轻量级框架,转发过程图:

enter description here

enter description here

enter description here
涉及到几个重要的处理过程:

  • DispatcherServlet
  • HandlerMapping
  • HandleAdapter
  • ViewResolver

Question:

  1. 请求如何发到DispatcherServlet(前端控制器)?
    web.xml中配置DispatcherServlet(如下的步骤2),即可拦截请求。
  2. DispatcherServlet如何根据请求信息选择不同的处理器进行处理? HandlerMapping,里面包含一儿handler和多个拦截器HandlerInterceptor,通过策略模式,很容易添加新拦截器。
  3. 如何支持多种页面处理器?
    HandleAdapter(适配器模式)将根据适配结果调用真正的处理器进行处理。

Spring控制器DispatcherServlet

SpringMVC是一个基于DispatcherServlet的MVC框架,所有的请求都是首先提交给DispatcherServlet,DispatcherServlet负责转发每一个Request请求给相应的Handler。DispatcherServlet是继承自HttpServlet的。
web.xml中配置

<!-- 1.Spring配置 -->
<listener>
    <listenerclass>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>

ContextLoaderListener初始化的上下文加载的Bean是对于整个应用程序共享的
,Spring监听器。会自动找到所有配置在applicationContext.xml中的Spring Beans。简单来说它的作用就是启动Web容器时,自动装配ApplicationContext的配置信息

<!-- 2.springMVC式rest -->
<servlet>
    <servlet-name>rest</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<!--可以自定义servlet.xml配置文件的位置和名称,默认为WEB-INF目录下,名称为[<servlet-name>]-servlet.xml,如rest-servlet.xml-->

    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:rest-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>rest</servlet-name>
    <url-pattern>/rest/*</url-pattern>
</servlet-mapping>


contextConfigLocation
classpath:applicationContext.xml

以上是基本配置。
<url-pattern>表示哪些请求交给Spring Web MVC处理, “/” 是用来定义默认servlet映射的

rest-servlet.xml的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context <a href="http://www.springframework.org/schema/context/spring-context-3.0.xsd">http://www.springframework.org/schema/context/spring-context-3.0.xsd</a>">

<!-- 启用spring mvc 注解 -->
<context:annotation-config />

<!-- 设置使用注解的类所在的jar包 -->
<context:component-scan base-package="com.cc"></context:component-scan>

<!-- 完成请求和注解POJO的映射 -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
  
<!-- 对ModelAndView中的转向页面的路径解析,自动路径添加prefix:前缀, suffix:后缀 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/jsp/" p:suffix=".jsp" />
</beans>

参考文献:
第二章 Spring MVC入门

spring浅析及配置实现

主页:http://spring.io/,进入projects,找到spring framework,进入的spring framework页,即可找到spring包及下载spring框架版本对jdk的要求

简单理解

Spring其实就是一个管理框架的容器,你不用再考虑你new对象了,它会帮你做,降低了层与层之间的耦合度。Spring里面有很多的思想,IOC就是控制反转,注入。AOP是面向切面的,有点像拦截器。

spring的jar包

Spring框架的jar包依赖于commons-logging.jar
如果是web项目就需要spring-web,在web.xml中配置的ContextLoaderListener监听器(listen)就需要用到spring-web。
如果是web项目并且要使用spring mvc技术,就需要用到spring-webmvc

spring技术介绍

Ioc: 依赖注入,解耦service层和DAO层
AOP: 切面开发

事务

事务是数据库中的概念,为了保证数据的一致和完整。是指单个逻辑功能单元执行的一系列操作,要么完整执行,要么都不执行。

四大特性

  • 原子性:事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行;
  • 一致性:事务在完成时,必须使所有的数据都保持一致状态;
  • 隔离性:由并发事务所作的修改必须与任何其它并发事务所作的修改隔离;
  • 持久性:事务完成之后,它对于系统的影响是永久性的。

Spring支持事务管理

Spring的事务管理分为声明式跟编程式。声明式就是在Spring的配置文件中进行相关配置;编程式就是用注解的方式写到代码里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!--开启注解方式-->
<context:annotation-config />

<!-- 配置sessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="configLocation">
<value>classpath:config/hibernate.cfg.xml</value>
</property>
<property name="packagesToScan">
<list>
<value>com.entity</value>
</list>
</property>
</bean>

<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>

<!-- 第四种配置事务的方式,注解 -->
<tx:annotation-driven transaction-manager="transactionManager"/>

注解配置

  • 是spring提供的注解的方式,注入使用时需要导入spring目录common-annotations.jar这个包。
  • 3.1版本开始有这个配置 ,会自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter 两个bean,是spring MVC为@Controllers分发请求所必须的。

declares support for general annotations such as @Required, @Autowired, @PostConstruct, and so on.

is actually rather pointless. It declares explicit support for annotation-driven MVC controllers (i.e.@RequestMapping, @Controller, etc), even though support for those is the default behaviour.

My advice is to always declare , but don’t bother with <mvc:annotation-driven /unless you want JSON support via Jackson.

事务配置

在dao层类、方法上面添加@Transactional注解,为默认事务配置

package com.dao;

@Transactional
public class UserDaoImpl_BAK extends HibernateTemplate {

    @Transactional(propagation=Propagation.REQUIRED,rollbackForClassName="Exception")
    public void addUser(User user) throws Exception {
        this.save(user);
    }

    @Transactional(propagation=Propagation.REQUIRED,rollbackForClassName="Exception")
    public void modifyUser(User user) {
        this.update(user);
    }

    @Transactional(propagation=Propagation.REQUIRED,rollbackForClassName="Exception")
    public void delUser(String username) {
        this.delete(this.load(User.class, username));
    }

    @Transactional(readOnly=true)
    public void selectUser() {
    }
}    

applicationContext.xml 公共配置

<!-- 配置sessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="configLocation">
        <value>classpath:hibernate.cfg.xml</value>
    </property>
    <property name="packagesToScan">
        <list>
            <value>com.entity</value>
        </list>
    </property>
</bean>

<!-- 配置事务管理器(声明式的事务) -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"></property>
</bean>

<!-- 配置DAO --> 
<bean id="userDao" class="com.dao.UserDaoImpl">
    <property name="sessionFactory" ref="sessionFactory"></property>
</bean>

使用BootstrapPaginator插件数据分页

根据项目需要在信息展示列表页面进行分页显示由于数据时一次性取出分页展示,在数据量大的时候数据获取时速度慢的问题,后续改进取数据的方法,每次只取一页的数据。

居中显示

首先,在信息展示的列表页面上添加分页按钮

<nav style="text-align: center">
    <ul class="pagination" id="pageUl"></ul>
</nav>

前台控制分页

js中配置分页按钮参数,并进行启用。这种方法相当于把数据拿到前台,在前台控制分页

var element = $('#pageUl');//对应下面ul的ID  
var options = { 
    size:"normal",
    alignment:"center",
    bootstrapMajorVersion:3,  
    currentPage: 1,//当前页面  
    numberOfPages: 5,//一页显示几个按钮(在ul里面生成5个li)  
    totalPages:22, //总页数  
    itemTexts: function(type, page, current) { //修改显示文字
        switch (type) {
        case "first":
            return "第一页";
        case "prev":
            return "上一页";
        case "next":
            return "下一页";
        case "last":
            return "最后一页";
        case "page":
            return page;
        }
    }, 
    onPageClicked: function (event, originalEvent, type, page) { //换页
        paginator(msg,page);
        $('#infolist').html('');
        $('#infolist').append(str);
    },
}  
//分页启动
element.bootstrapPaginator(options); 
paginator(msg,1);
//分页
function paginator(arrData, page) {
    var str="";
    var name;
    for (i = (page - 1) * 5; i < page * 5; i++) {
        if(i<arrData.length){
            var param = "content.jsp?id="+ arrData[i].id;
            var content = arrData[i].content;
            var s = content.substr(0, 7);
            if(arrData[i].telephone==""){
                name="匿名用户"
            }
            else{
                name=arrData[i].telephone;
            }
         str += '<div class="wz"><h3><a href="'
                + param
                + '" title="'
                + arrData[i].title
                + ""
                + '">'
                + s
                + "..."
                + '</a></h3><dl><dt>'
                + '<a href="'
                + param
                + '"  style="margin-top: 0px;" title="阅读全文"><img src="'
                + 'picture/'+arrData[i].picturepath1
                + '" width="200" height="123" alt=""></a></dt><dd>'
                + '<p class="dd_text_1">'
                + arrData[i].content
                + '</p><p class="dd_text_2">'
                + '    <span class="left author" >'
                + name
                + '</span><span class="left sj" style="padding-left:80px;">'
                + arrData[i].dataTime
                + '</span>'
                + '<span class="left yd"><a href="'
                + param
                + '"  title="阅读全文" style="margin-left: auto";>阅读全文</a></span>'
                + '<div class="clear"></div></p></dd><div class="clear"></div></dl></div>';

            $('#infolist').html(''); 
            $('#infolist').append(str);
        }
        else {
            break;
        }
    }
}

后台分页控制

  1. MySQL分页语句

    "select * from test.uploadinfo order by id desc limit "+ ((pageNow-1)*pageSize)+","+pageSize;
    
  2. rest服务

    @RequestMapping(value = "/onePageData", method = RequestMethod.POST)
    @ResponseBody
    public JSONArray onePageData(@RequestParam("pageNow") String pageNow, @RequestParam("pageSize") int pageSize) {
        List<Uploadinfo> itemList = itemServiceImpl.onePage(Integer.parseInt(pageNow), pageSize);
        JSONArray itemJSONList = JSONArray.fromObject(itemList, Common.getJsonConfig());
        return itemJSONList;
    }
    
  3. service

sql语句

@Override
public List<Uploadinfo> onePage(int pageNow, int pageSize) {
    // TODO Auto-generated method stub
    String sql = "select * from test.uploadinfo order by id desc limit "+ ((pageNow-1)*pageSize)+","+pageSize*pageNow;
    List<Uploadinfo> infolist = itemDaoImpl.getSQLQuery(sql).list();
    return infolist;
}

hibernate中调用原生SQL语句,ajax数据回调报500错误,转成JSONArray返回数据时,不是对象类型前台无法识别数据,导致不知道rest服务是否调用成功,从而报500。转而使用HQL语句查询即可解决。
HQL语句中limit无效还是会把所有数据查出来,不支持limit,替代方法如下

@Override
public List<Uploadinfo> onePage(int pageNow, int pageSize) {
    // TODO Auto-generated method stub
    String sql = "from Uploadinfo";
    Query query = itemDaoImpl.getQuery(sql);
    query.setFirstResult((pageNow-1)*pageSize);
    query.setMaxResults(pageSize*pageNow);
    List<Uploadinfo> infolist = query.list(); 
    return infolist;
}

js调用

$(function(){
    queryAll("rest/Uploadinfo/totlePages");
})
function queryAll(url){
$.ajax({
    type : "GET",
    url :  url,
    dataType : "text",
    success : function(msg) {
        var pages = Math.ceil(msg/5); 
        var element = $('#pageUl');//对应下面ul的ID  
        var options = { 
            size:"normal",
            alignment:"center",
            bootstrapMajorVersion:3,  
            currentPage: 1,//当前页面  
            numberOfPages: 5,//一页显示几个按钮(在ul里面生成5个li)  
            totalPages: pages, //总页数  
            itemTexts: function(type, page, current) { //修改显示文字
                switch (type) {
                case "first":
                    return "第一页";
                case "prev":
                    return "上一页";
                case "next":
                    return "下一页";
                case "last":
                    return "最后一页";
                case "page":
                    return page;
                }
            }, 
            onPageClicked: function (event, originalEvent, type, page) { //换页
                paginator(page);
            },
        }  
        //分页启动
       element.bootstrapPaginator(options); 
       paginator(1);
    }
});
}

//分页
function paginator(pageNow) {
$.ajax({
    type : "post",
    url :  "rest/Uploadinfo/onePageData",
    dataType : "json",
    data:{
        "pageNow":pageNow,
        "pageSize":5
    },
    success : function(arrData) {
        console.dir(arrData)
        var str="";
        var name;
        for(var i=0; i<5; i++){
            if(i<arrData.length){
                var param = "content.jsp?id="+ arrData[i].id;
                var content = arrData[i].content;
                var s = content.substr(0, 7);
                if(arrData[i].telephone==""){
                    name="匿名用户"
                }
                else{
                    name=arrData[i].telephone;
                }
                str += '<div class="wz"><h3><a href="'
                    + param
                    + '" title="'
                    + arrData[i].title
                    + ""
                    + '">'
                    + s
                    + "..."
                    + '</a></h3><dl><dt>'
                    + '<a href="'
                    + param
                    + '"  style="margin-top: 0px;" title="阅读全文"><img src="'
                    + 'picture/'+arrData[i].picturepath1
                    + '" width="200" height="123" alt=""></a></dt><dd>'
                    + '<p class="dd_text_1">'
                    + arrData[i].content
                    + '</p><p class="dd_text_2">'
                    + '    <span class="left author" >'
                    + name
                    + '</span><span class="left sj" style="padding-left:80px;">'
                    + arrData[i].dataTime
                    + '</span>'
                    + '<span class="left yd"><a href="'
                    + param
                    + '"  title="阅读全文" style="margin-left: auto";>阅读全文</a></span>'
                    + '<div class="clear"></div></p></dd><div class="clear"></div></dl></div>';

                $('#infolist').html(''); 
                $('#infolist').append(str);
            }
        }
    }
});

}

Spring注解

[TOC]

model层

  1. catalog: 数据库名
  2. schema: postgreSQL数据库中的模式
@Table(name = "category", catalog = "users")
@Table(name = "roles", schema = "public")

dao层(数据访问层,持久层)

@Repository
Spring2.0引入,为简化spring开发。用于将dao层的类标识为Spring Bean,同时为了Spring 扫描时,识别出@Repository注解。所有标注了 @Repository 的类都将被注册为 Spring Bean。
为什么 @Repository 只能标注在 DAO 类上呢?
这是因为该注解的作用不只是将类识别为Bean,同时它还能将所标注的类中抛出的数据访问异常封装为 Spring 的数据访问异常类型。 Spring本身提供了一个丰富的并且是与具体的数据访问技术无关的数据访问异常结构,用于封装不同的持久层框架抛出的异常,使得异常独立于底层的框架。

service层和控制层

Spring2.5开始引入@Component、@Service、@Constroller,它们分别用于软件系统的不同层次:

@Service用于标注业务层组件(我们通常定义的service层就用这个)
@Controller用于标注控制层组件(如struts中的action)
@Repository用于标注持久层数据访问组件,即DAO组件
@Component 泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。

@Resource与@service

当需要定义某个类为一个bean,则在这个类的类名前一行使用@Service(“XXX”),就相当于将这个类定义为一个bean,bean名称为XXX;
当某类中需要引入这个对象时,则该对象定义的时候上面加@Resource。

@Service
public class UserServiceImpl implements IUserService {
    @Resource
    private IUserDao userDaoImpl;
    @Resource
    private IRolesDao rolesImpl;

    ...
}

  @Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按 byName自动注入罢了。@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
  @Resource装配顺序
  1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
  2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
  3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
  4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。  

spring bean

spring本身就是一个bean的工厂,完成bean的创建、配置。Spring容器集中管理bean。
bean的5种作用域:

  1. Singleton:单例模式。在整个SpringIoC容器中,使用singleton定义的Bean将只有一个实例。
  2. Prototype:原型模式。每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例。
  3. request:对于每次HTTP请求,使用request定义的Bean都将产生一个新的实例,即每次HTTP请求都会产生不同的Bean实例。当然只有在WEB应用中使用Spring时,该作用域才真正有效。
  4. session:对于每次HTTPSession,使用session定义的Bean都将产生一个新的实例时,即每次HTTP 5.Session都将产生不同的Bean实例。同HTTP一样,只有在WEB应用才会有效。
    global session:每个全局的HTTPSession对应一个Bean实例。仅在portlet Context的时候才有效。
    常用singleton、prototype作用域。如果不指定Bean的作用域,则Spring会默认使用singleton作用域。

shiro角色配置

[TOC]

角色验证

数据库表

  • tuser:用户表
    uid + uname + upassword
  • roles:角色表
    rid + rname
  • user_to_role:用户角色表,hibernate会自动建立
    user_id + role_id

roles

@Entity
@Table(name = "roles", schema = "public")
public class Roles implements java.io.Serializable {
    private Integer rid;
    private String rname;
//    private Set<User> user;

    public Roles() {
    }
    /** full constructor */
    public Roles(String rname) {
        this.rname = rname;
    }

    @Id
    @GeneratedValue
    @Column(name = "rid", unique = true, nullable = false)
    public Integer getRid() {
        return rid;
    }

    public void setRid(Integer rid) {
        this.rid = rid;
    }

    @Column(name = "rname", length = 20)
    public String getRname() {
        return rname;
    }

    public void setRname(String rname) {
        this.rname = rname;
    }

    /*    @ManyToMany(cascade = CascadeType.MERGE, fetch = FetchType.EAGER)
    @JoinTable(name = "user_to_role",   
        joinColumns ={@JoinColumn(name = "role_id") },   
        inverseJoinColumns = { @JoinColumn(name = "user_id")
    })
        public Set<User> getUser() {
        return user;
    }

    public void setUser(Set<User> user) {
        this.user = user;
    }*/

    }

为防止转化成json时出现循环,ManyToMany配置是只在依赖方配置,即只在user端进行配置。

user

@Entity
@Table(name = "tuser")
public class User implements java.io.Serializable {

    private Integer uid;
    private String uname;
    private String upassword;
    //一个用户具有多个角色 
    private Set<Roles> roles = new HashSet<Roles>();

    public User() {
    }

    // Property accessors
    @Id
    @GeneratedValue
    @Column(name = "uid", unique = true, nullable = false)
    public Integer getUid() {
        return uid;
    }

    public void setUid(Integer uid) {
        this.uid = uid;
    }

    @Column(name = "uname", length = 20)
    public String getUname() {
        return this.uname;
    }
    public void setUname(String uname) {
        this.uname = uname;
    }

    @Column(name = "upassword", length = 20)
    public String getUpassword() {
        return this.upassword;
    }

    public void setUpassword(String upassword) {
        this.upassword = upassword;
    }

    @ManyToMany(cascade={CascadeType.MERGE}, fetch=FetchType.EAGER)
    @JoinTable(name = "user_to_role",   
        joinColumns= { @JoinColumn(name = "user_id")},
        inverseJoinColumns ={@JoinColumn(name = "role_id")  
    })
    public Set<Roles> getRoles() {
        return roles;
    }

    public void setRoles(Set<Roles> roles) {
        this.roles = roles;
    }
}

此例子比较简单,没有涉及到权限permission
如果涉及到权限则需要建立权限表及对应的POJO

  • permission:权限表
    id + permissionname + role_id
    在role中添加:
1
2
3
4
5
6
7
8
9
private List<Permission> permissionList;//一个角色对应多个权限
...
@OneToMany(mappedBy="role")
public List<Permission> getPermissionList() {
return permissionList;
}
public void setPermissionList(List<Permission> permissionList) {
this.permissionList = permissionList;
}

Permission pojo

@Entity  
@Table(name="t_permission")  
public class Permission {  

    private Integer id;  
    private String permissionname;  
    private Role role;//一个权限对应一个角色  

    @Id  
    @GeneratedValue(strategy=GenerationType.IDENTITY)  
    public Integer getId() {  
        return id;  
    }  
    public void setId(Integer id) {  
        this.id = id;  
    }  
    public String getPermissionname() {  
        return permissionname;  
    }  
    public void setPermissionname(String permissionname) {  
        this.permissionname = permissionname;  
    }  
    @ManyToOne  
    @JoinColumn(name="role_id")  
    public Role getRole() {  
        return role;  
    }  
    public void setRole(Role role) {  
        this.role = role;  
    }  

} 

index.jsp

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags"%>
...
<ul class="nav navbar-nav navbar-right">
<li><a>
    <shiro:user>
        欢迎你:<shiro:principal />
    </shiro:user>
    <!-- 没有登录,就认为是Guest,显示注册链接 --> 
    <shiro:guest>
        <a href="register.jsp">注册</a>
    </shiro:guest></a>
</li>
<li>
    <shiro:hasRole name="管理员">  
        <a href="manager/index.jsp">后台管理</a>  
    </shiro:hasRole>

    //示例,具有两个中任一个权限时有操作权限
     <shiro:hasAnyRoles name="管理员,普通用户">
         操作
     </shiro:hasAnyRoles>
</li>
<li><a href="javascript:void(0)" id="exitBtn" type="button">退出</a></li>
</ul>

配置文件

<!-- Shiro Filter 拦截器相关配置 -->
<!--shiro过滤器配置,bean的id值须与web中的filter-name的值相同 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <!-- securityManager -->
    <property name="securityManager" ref="securityManager" />
    <!-- 登录路径 -->
    <property name="loginUrl" value="/login.jsp" />
    <!-- 登录成功后跳转路径 -->
    <property name="successUrl" value="/manager/index.jsp" />
    <!-- 授权失败跳转路径 -->
    <property name="unauthorizedUrl" value="/login.jsp" />
    <!-- 过滤链定义 -->
    <property name="filterChainDefinitions">
        <value>
            /login.jsp* = anon
            /logout* = anon
            /*.js = anon
            /*.css = anon
            <!-- 表示需要认证的链接 -->
            /manager/** = authc,roles["管理员"]
            /index.jsp = authc
        </value>
    </property>
</bean>

myRealm

权限验证和登陆验证

public class myRealm extends AuthorizingRealm {
    @Resource
    private IUserService userManagerImpl;
    /**
     * 权限验证
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principals) {
        // TODO Auto-generated method stub
        String userName = (String) principals.fromRealm(getName()).iterator().next();
        //根据用户名查找拥有的角色
        User user = userManagerImpl.queryByName(userName).get(0);
        Set<Roles> roles = user.getRoles();
        if (roles != null) {
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

            for (Roles role : roles) {
                info.addRole(role.getRname());
            }

            return info;
        } else {
            return null;
        }

    }

    /**
     * 登录验证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken authcToken) throws AuthenticationException {

        // 令牌——基于用户名和密码的令牌
        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
        // 令牌中可以取出用户名密码
        String userName = token.getUsername();
        String passWord = new String(token.getPassword());
        User user = userManagerImpl.queryByName(userName).get(0);
        String passwd = user.getUpassword();
        String approval = user.getIsapproval();
        if(user.getUid() == null){
            System.out.println("没有找到用户 ");
            throw new UnknownAccountException("没有找到用户 [" + userName + "]");
        }
        if(!passwd.equals(passWord)){
            System.out.println("密码错误!!");
            throw new IncorrectCredentialsException("密码错误!!");
        }
        if(approval.equals("0")){
            System.out.println("审批未通过");
            throw new IncorrectCredentialsException("审批未通过!!");
        }
        //将正确的用户信息,请求登录用户的用户名和正确的密码,创建AuthenticationInfo对象并返回  
        AuthenticationInfo authinfo = new SimpleAuthenticationInfo(userName,
                passWord, getName());
        return authinfo;
    }
}

ManyToOne, ManyToMany注解

[TOC]

关系注解的配置

hibernate配置相互关系的原则:

  • 在依赖方(many方)配置,单向依赖,这样可以避免出现循环。
  • one是关系维护方,many是被维护方。在关系被维护端,即many端需要通过@JoinColumn建立外键列指向关系维护端的主键列。

    • manyTomany中@JoinColumn注解的都是在“主控方”,都是本表指向外表的外键名称。
    • 一对多的@JoinColumn注解在“被控方”,即一的一方,指的是外表中指向本表的外键名称。
    • 多对多中,joinColumns写的都是本表在中间表的外键名称,
      inverseJoinColumns写的是另一个表在中间表的外键名称。
  • mappedBy

    • 用来定义双向关系,如果是单向关系,则不用定义。用来指定主控方。
  • optional
    • 属性是定义该关联类是否必须存在。默认true,被维护方可以不存在。若为false则双方都必须存在,否则查询结果为null。
  • 无论是一对多还是多对一关系,都是在多的一方维护关系。

manyToMany

user-role关系,单向只在user(依赖方)方配置

@ManyToMany(cascade={CascadeType.MERGE}, fetch=FetchType.EAGER)
@JoinTable(name = "user_to_role",   
    joinColumns= { @JoinColumn(name = "user_id")},
    inverseJoinColumns ={@JoinColumn(name = "role_id")  
})

ManyToOne

user-onganization关系,单向只在user(依赖方)方配置

@ManyToOne(targetEntity = Organization.class, cascade = { CascadeType.MERGE })
@JoinColumn(name = "oid")

json死循环

net.sf.json.JSONException: There is a cycle in the hierarchy!错误解决方案

JsonConfig config = new JsonConfig();
config.setExcludes(new String[]{"roles"});//除去roles属性
JSONArray userJSONList2 = JSONArray.fromObject(dataList,config);

或者用以下方法解除循环

@RequestMapping(value = "/queryAllOrgan", method = RequestMethod.GET)
@ResponseBody
public JSONArray queryAllOrgan() {
    JSONArray userJSONList;
    JsonConfig jsonConfig = new JsonConfig();
    jsonConfig.setIgnoreDefaultExcludes(false);
    jsonConfig.setCycleDetectionStrategy(CycleDetectionStrategy.LENIENT);
    jsonConfig.setExcludes(new String[] { "handler","hibernateLazyInitializer" });
    jsonConfig.setJsonPropertyFilter(new PropertyFilter() {
        public boolean apply(Object obj, String name, Object value) {
        //if(value instanceof Organization && name.equals("organ")){
        if(name.equals("user")){
                return true;
            } else {
                return false;
            }
        }
    });
    List<Organization> dataList = organServiceImpl.queryAll();
    userJSONList = JSONArray.fromObject(dataList,jsonConfig) ;
    return userJSONList;
    }

出现这种错误@ManyToOne 与@OneToMany是否配置正确,有没有配反

//mappedBy:这个为manytoone中的对象名,这个不要变哦
//    @OneToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY,mappedBy="user")
//    @OneToMany(targetEntity = Roles.class, mappedBy = "user", cascade = { CascadeType.MERGE })

shiro入门配置

基础配置

使用shiro的步骤

  1. 导入JAR包
  2. web.xml配置

    <!-- Shiro配置 -->    
    <filter>    
        <filter-name>shiroFilter</filter-name>    
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>    
    </filter>    
    <filter-mapping>    
        <filter-name>shiroFilter</filter-name>    
        <url-pattern>/*</url-pattern>    
    </filter-mapping>
    
  3. applicationContext.xml配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
       <!-- ehcache 的配置 -->
    <cache:annotation-driven cache-manager="cacheManager" />
    <bean id="cacheManagerFactory"
    class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
    <property name="configLocation">
    <value>classpath:ehcache.xml</value>
    </property>
    </bean>
    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
    <property name="cacheManager" ref="cacheManagerFactory" />
    </bean>

    <!-- 自定义Realm实现 -->
    <bean id="myRealm" class="com.lbs.login.myRealm">
    <!-- <property name="cacheManager" ref="shiroEhcacheManager" /> -->
    </bean>
    <!-- 用户授权/认证信息Cache, 采用EhCache 缓存 -->
    <bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
    <property name="cacheManagerConfigFile" value="classpath:ehcache.xml" />
    <!-- <property name="cacheManager" ref="cacheManager" /> -->
    </bean>
    <!-- securityManager -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="realm" ref="myRealm" />
    <property name="cacheManager" ref="shiroEhcacheManager" />
    </bean>

    <!-- Shiro生命周期处理器,保证实现了Shiro内部lifecycle函数的bean执行 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

    <!-- Shiro Filter 拦截器相关配置 -->
    <!--shiro过滤器配置,bean的id值须与web中的filter-name的值相同 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <!-- securityManager -->
    <property name="securityManager" ref="securityManager" />
    <!-- 登录路径 -->
    <property name="loginUrl" value="/login.jsp" />
    <!-- 登录成功后跳转路径 -->
    <property name="successUrl" value="/manager/index.jsp" />
    <!-- 授权失败跳转路径 -->
    <property name="unauthorizedUrl" value="/login.jsp" />
    <!-- 过滤链定义 -->
    <property name="filterChainDefinitions">
    <value>
    /login.jsp* = anon
    /logout* = anon
    /*.js = anon
    /*.css = anon
    /manager/** = authc,roles["管理员"]<!-- 表示需要认证的链接 -->
    /index.jsp = authc
    </value>
    </property>
    </bean>
  4. 建立myRealm.java,重写以下两种方法

    doGetAuthorizationInfo()方法可以理解为是权限验证
    doGetAuthenticationInfo(AuthenticationToken token)理解为登陆验证。

shiro 授权

Shiro支持三种方式实现授权过程:

  • 编码实现
  • 注解实现
  • JSP Taglig实现

角色授权

当需要验证用户是否拥有某个角色时,可以调用Subject实例的hasRole*方法验证。

Subject currentUser = SecurityUtils.getSubject();
if (currentUser.hasRole("administrator")) {
    //show the admin button
} else {
    //don't show the button?  Grey it out?
}
|