spring+hibernate+shiro+Ehcache 项目分享

这篇文章,我将 把一个 spring+hibernate+shiro+Ehcache 完整的集成流程记录下来,源码亦将分享出来(项目源码地址: http://download.csdn.net/download/u011998835/10038869 点击打开链接)。但是好像csdn传资源必须要指定积分的,所以我不得已选择了2分。但这里不要在意细节了。我主要是记录,遇到问题和开发心得。

那么我们开始使用工具编写项目了。




因为DAdmin这个项目我已经新建过了,所以接下来有些演示 就用DDAdmin来替代了。


先打开File,找到Project Structure 先设置一些东西


新建java文件夹

指定java作为java代码的源码目录


新建test目录

指定成为测试目录



不要忘了设定jdk7了,默认是用jdk5编译的,哪怕你提供了jdk环境,但编译用jdk5,那么有些泛型新写法就不能使用了。

然后OK或者apply


然后看到的项目结构如下。


写配置pom.xml吧(这个 过程 就是 在把相关的jar包导入)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.dashuai</groupId>
    <artifactId>DAdmin</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <java_version>1.7</java_version>
        <java-encoding_version>UTF-8</java-encoding_version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring_version>4.3.12.RELEASE</spring_version>
        <hibernate_version>4.3.11.Final</hibernate_version>
        <shiro_version>1.3.2</shiro_version>
        <mysql_connector_version>5.1.44</mysql_connector_version>
        <druid-version>1.0.31</druid-version>
    </properties>
    <repositories>
        <repository>
            <id>alimaven</id>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>alimaven</id>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>
    <dependencies>
        <!-- Junit 4 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!-- Common libs start -->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.4</version>
        </dependency>
        <!-- Common libs end -->
        <!--启动CGlib -->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib-nodep</artifactId>
            <version>2.2.2</version>
        </dependency>
        <!-- log日志  start  -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.25</version>
        </dependency>
        <!-- log日志  end  -->
        <!-- Spring相关jar包  start -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring_version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.11</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.11</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.1</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.1</version>
        </dependency>
        <!-- Spring相关jar包  end -->
        <!--mysql 驱动包 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql_connector_version}</version>
        </dependency>
        <!-- 数据源 druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>${druid-version}</version>
        </dependency>
        <!--json GSON 包 -->
        <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.5</version>
        </dependency>
        <!-- jsp,servlet,jstl -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <!--工具包,加密算法 -->
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.4</version>
        </dependency>
        <!-- Hibernate  start -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>${hibernate_version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-commons-annotations</artifactId>
            <version>3.2.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-ehcache</artifactId>
            <version>${hibernate_version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.0-api</artifactId>
            <version>1.0.1.Final</version>
        </dependency>
        <!-- Hibernate END -->
        <!--Hibernate与spring 集成所依赖的 -->
        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.20.0-GA</version>
        </dependency>
      <!-- shiro -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>${shiro_version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>${shiro_version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>${shiro_version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>${shiro_version}</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>DAdmin</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.0</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <skip>true</skip>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>3.0.0</version>
                <configuration>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <path>/</path>
                    <charset>UTF-8</charset>
                    <uriEncoding>UTF-8</uriEncoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

先看一下未来呈现的项目结构


我们一样一样的来写。

先新建java的文件夹,就是各种package。

然后新建resource目录下的文件,暂时先新建着空文件。然后再填东西。


好,接下来,我们先从web.xml入手。

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
  <display-name>Spring-Hibernate Web Application</display-name>
  <welcome-file-list>
    <welcome-file></welcome-file>
  </welcome-file-list><!--暂不指定欢迎页面-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
          classpath:spring-shiro.xml,
          classpath:spring/applicationContext.xml
    </param-value>
  </context-param>
  <!--spring与shiro配置的spring-shiro.xml一定要指定,不然shiro不一定发挥作用-->
  <!-- // Hibernate4 延迟加载策略 -->
  <filter>
    <filter-name>openSessionInViewFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
    <init-param>
      <param-name>singleSession</param-name>
      <param-value>true</param-value>
    </init-param>
    <init-param>
      <param-name>sessionFactoryBeanName</param-name>
      <param-value>sessionFactory</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>openSessionInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <!-- 防止发生java.beans.Introspector内存泄露,应将它配置在ContextLoaderListener的前面 -->
  <listener>
    <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
  </listener>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
  </listener>
  <!-- /Spring MVC支持配置 ///-->
  <servlet>
    <servlet-name>spring</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring/applicationContext-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>spring</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
  <!-- /Spring 解决乱码问题/// -->
  <filter>
    <filter-name>SpringEncodingFilter</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>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>SpringEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <!-- //阿里巴巴数据连接池 Druid的监控/// -->
  <filter>
    <filter-name>druidWebStatFilter</filter-name>
    <filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
    <init-param>
      <param-name>exclusions</param-name>
      <param-value>
        /css/*,/style/*,/js/*,*.js,*.css,/druid*,/attached/*,*.jsp
      </param-value>
    </init-param>
    <init-param>
      <param-name>principalSessionName</param-name>
      <param-value>sessionUser</param-value>
    </init-param>
    <init-param>
      <param-name>profileEnable</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>druidWebStatFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <!-- //druid监控页面,使用${pageContext.request.contextPath}/druid/index.html访问/ -->
  <servlet>
    <servlet-name>druidStatView</servlet-name>
    <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>druidStatView</servlet-name>
    <url-pattern>/druid/*</url-pattern>
  </servlet-mapping>
  <!-- shiroFilter 不能放在 Hibernate的filter之前,或者druid之前,建议放在最后面-->
    <filter>
      <filter-name>shiroFilter</filter-name>
      <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
      <async-supported>true</async-supported>
      <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>
    <session-config>
      <session-timeout>120</session-timeout>
    </session-config>
</web-app>


ehcache.xml

<ehcache name="shiro_ehcache" updateCheck="false">
    <diskStore path="../DAdmin_Ehcache"/>
    <!-- hibernate ehcache 和 shiro_ehcache 必须放在同一个xml中配置
      不要分开放,不然只会有一个生效。name="shiro_ehcache",可以不用配置。(我当时分开使用了)
     -->
    <!-- hibernate ehcache-->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
    />
    <cache name="org.hibernate.cache.spi.UpdateTimestampsCache"
           maxElementsInMemory="5000"
           eternal="true"
           overflowToDisk="true"/>
    <cache name="org.hibernate.cache.internal.StandardQueryCache"
           maxElementsInMemory="10000"
           eternal="false"
           timeToLiveSeconds="120"
           overflowToDisk="true"/>
    <!-- shiro ehcache-->
    <!-- 登录记录缓存 锁定10分钟 -->
    <cache name="passwordRetryCache"
           maxElementsInMemory="2000" eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>
    <cache name="authorizationCache"
           maxElementsInMemory="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>
    <cache name="authenticationCache"
           maxElementsInMemory="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>
    <cache name="shiro-activeSessionCache"
           maxElementsInMemory="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>
    <cache name="shiro_cache"
           maxElementsInMemory="2000"
           eternal="false"
           timeToIdleSeconds="0"
           timeToLiveSeconds="0"
           maxElementsOnDisk="0"
           overflowToDisk="true"
           memoryStoreEvictionPolicy="FIFO"
           statistics="true">
    </cache>
</ehcache>


log4j.properties:

log4j.rootLogger=INFO,CONSOLE,DAILY_ALL
#console log
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %l - %m%n
log4j.appender.CONSOLE.Target=System.out
#all log
log4j.appender.DAILY_ALL=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DAILY_ALL.layout=org.apache.log4j.PatternLayout
log4j.appender.DAILY_ALL.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %l - %m%n
log4j.appender.DAILY_ALL.File=../logs/DAdmin.log

hibernate的log配置

#log4j.logger.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
#log4j.loggerorg.hibernate.type.descriptor.sql.BasicExtractor=TRACE
#log4j.logger.org.hibernate.engine.QueryParameters=DEBUG
#log4j.logger.org.hibernate.engine.query.HQLQueryPlan=DEBUG
#log4j.logger.org.hibernate.cache=DEBUG


database.properties

hibernate.show_sql=true
hibernate.format_sql=true
hibernate.dialect=org.hibernate.dialect.MySQLDialect
driverClassName=com.mysql.jdbc.Driver
jdbc_url=jdbc\:mysql\://localhost\:3306/dadmin?useUnicode\=true&characterEncoding\=UTF-8
jdbc_username=root
jdbc_password=123456
hibernate.hbm2ddl.auto=update
hibernate.query.substitutions=true 1, false 0
hibernate.default_batch_fetch_size=16
hibernate.max_fetch_depth=2
hibernate.generate_statistics=false
hibernate.enable_lazy_load_no_trans=true
initialSize=3
maxActive=50
minIdle=1
maxWait=60000
validationQuery=SELECT 1
testOnBorrow=false
testOnReturn=false
testWhileIdle=true
timeBetweenEvictionRunsMillis=60000
minEvictableIdleTimeMillis=25200000
removeAbandoned=false
removeAbandonedTimeout=1800
logAbandoned=true
filters=mergeStat

applicationContext.xml

<?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:aop="http://www.springframework.org/schema/aop"
	   xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
	<context:component-scan base-package="com.dashuai.service,com.dashuai.dao,com.dashuai.shiro"/>
	<!-- //强制启用CGliB 替换JDK的动态代理 在反射动态生成时 效率更高/// -->
	<aop:aspectj-autoproxy proxy-target-class="true" />
	<!-- 读取数据库基本连接配置 -->
	<context:property-placeholder location="classpath:database.properties" />
	<!-- 阿里巴巴的Druid数据库连接池日志过滤 下面 baseDataSource会使用到的 -->
	<bean id="statFilter" class="com.alibaba.druid.filter.stat.StatFilter"
		  lazy-init="true">
		<property name="logSlowSql" value="true" />
		<property name="mergeSql" value="true" />
	</bean>
	<!-- 数据库连接池的配置base dataSource -->
	<bean name="baseDataSource" class="com.alibaba.druid.pool.DruidDataSource"
		  destroy-method="close">
		<!-- 初始化连接大小 -->
		<property name="initialSize" value="${initialSize}" />
		<!-- 连接池最大使用连接数量 -->
		<property name="maxActive" value="${maxActive}" />
		<!-- 连接池最小空闲 -->
		<property name="minIdle" value="${minIdle}" />
		<!-- 获取连接最大等待时间 -->
		<property name="maxWait" value="${maxWait}" />
		<property name="validationQuery" value="${validationQuery}" />
		<property name="testOnBorrow" value="${testOnBorrow}" />
		<property name="testOnReturn" value="${testOnReturn}" />
		<property name="testWhileIdle" value="${testWhileIdle}" />
		<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
		<property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}" />
		<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
		<property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}" />
		<!-- 打开removeAbandoned功能 -->
		<!-- 配置removeAbandoned对性能会有一些影响,建议怀疑存在泄漏之后再打开。 在上面的配置中,如果连接超过30分钟未关闭, 就会被强行回收,并且日志记录连接申请时的调用堆栈。 -->
		<property name="removeAbandoned" value="${removeAbandoned}" />
		<!-- 1800秒,也就是30分钟 -->
		<property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" />
		<!-- 关闭abanded连接时输出错误日志 -->
		<property name="logAbandoned" value="${logAbandoned}" />
		<!-- 合并多个DruidDataSource的监控数据 -->
		<property name="useGlobalDataSourceStat" value="true" />
		<property name="proxyFilters">
			<list>
				<ref bean="statFilter" />
			</list>
		</property>
	</bean>
	<bean name="master-dataSource" parent="baseDataSource"
		  init-method="init">
		<property name="name" value="master" />
		<property name="driverClassName" value="${driverClassName}" />
		<property name="url" value="${jdbc_url}" />
		<property name="username" value="${jdbc_username}" />
		<property name="password" value="${jdbc_password}" />
		<property name="filters" value="${filters}" />
	</bean>
	<!-- 配置sessionFactory 并配置二级缓存 -->
	<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
		<property name="dataSource" ref="master-dataSource" />
		<property name="packagesToScan">
			<list>
				<value>com.dashuai.entity</value>
			</list>
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="javax.persistence.validation.mode">none</prop>
				<prop key="hibernate.dialect">${hibernate.dialect}</prop>
				<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
				<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
				<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
				<prop key="hibernate.query.substitutions">${hibernate.query.substitutions}</prop>
				<prop key="hibernate.default_batch_fetch_size">${hibernate.default_batch_fetch_size}</prop>
				<prop key="hibernate.max_fetch_depth">${hibernate.max_fetch_depth}</prop>
				<prop key="hibernate.generate_statistics">${hibernate.generate_statistics}</prop>
				<prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate4.SpringSessionContext</prop>
				<prop key="hibernate.enable_lazy_load_no_trans">${hibernate.enable_lazy_load_no_trans}</prop>
				<prop key="hibernate.cache.provider_configuration_file_resource_path">classpath:ehcache.xml</prop>
				<!-- 开启查询缓存 -->
				<prop key="hibernate.cache.use_query_cache">true</prop>
				<!-- 开启二级缓存 -->
				<prop key="hibernate.cache.use_second_level_cache">true</prop>
				<!-- 高速缓存提供程序 -->
				<!-- 由于spring也使用了Ehcache, 保证双方都使用同一个缓存管理器 -->
				<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</prop>
			</props>
		</property>
	</bean>
	<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
		<property name="configLocation">
			<value>classpath:ehcache.xml</value>
		</property>
		<!-- 由于hibernate也使用了Ehcache, 保证双方都使用同一个缓存管理器 -->
		<property name="shared" value="true"/>
	</bean>
	<!-- 开启事务 配置transactionManager -->
	<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory"></property>
	</bean>
	<aop:config>
		<aop:pointcut id="serviceMethod" expression="execution(* com.dashuai.service..*Impl.*(..))" />
		<aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice" />
	</aop:config>
	<!-- 设置所有方法都使用事务 -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="get*" read-only="true" propagation="REQUIRED"/><!--之前是NOT_SUPPORT-->
			<tx:method name="list*" read-only="true" propagation="REQUIRED"/>
			<tx:method name="find*" read-only="true" propagation="REQUIRED"/>
			<tx:method name="query*" read-only="true" propagation="REQUIRED"/>
			<tx:method name="save*" propagation="REQUIRED"/>
			<tx:method name="update*" propagation="REQUIRED"/>
			<tx:method name="remove*" propagation="REQUIRED"/>
			<tx:method name="add*" propagation="REQUIRED"/>
			<!--默认其他方法都是REQUIRED-->
			<tx:method name="*"/>
		</tx:attributes>
	</tx:advice>
</beans>
  

applicationContext-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
		 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
		 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    <context:component-scan base-package="com.dashuai.controller"/>
	<!-- 启用springmvc 的注解 -->
	<mvc:annotation-driven />  
    <!-- 避免IE执行AJAX时,返回JSON出现下载文件 -->  
    <bean id="mappingJacksonHttpMessageConverter"  
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">  
        <property name="supportedMediaTypes">  
            <list>  
                <value>text/html;charset=UTF-8</value>  
            </list>  
        </property>  
    </bean>  
	<!-- Model与View 的切换配置 -->
	<bean id="defaultViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="contentType" value="text/html"/>
        <property name="prefix" value="/WEB-INF/page/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
	<!-- 不拦截静态请求,如css,js -->
	<mvc:default-servlet-handler />
    <!-- 上传文件的配置 虽然本项目没有用到上传文件-->
    <bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    </bean>
    <mvc:view-controller path="/" view-name="front/index"/>
    <mvc:view-controller path="/admin" view-name="admin/index"/>
    <mvc:view-controller path="/admin/" view-name="admin/index"/>
    <mvc:view-controller path="/user" view-name="front/user/index"/>
    <mvc:view-controller path="/user/" view-name="front/user/index"/>
</beans>

spring-shiro.xml 这个复杂,我们一点点的看。 首先web.xml中配置了shiroFilter,所以一定有shiroFilter。然后就是spring和shiro集成之后的配置。

 <!-- 安全认证过滤器 -->
   <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager" />
        <property name="filters">
            <map>
                <!--自定义两个 登录 过滤器 第一个是 后台登陆认证过滤,第二个是前台 登录认证过滤 -->
                <entry key="authsys" value-ref="systemAuthFilter"></entry>
                <entry key="authnor" value-ref="normalAuthFilter"></entry>
            </map>
        </property>
        <property name="filterChainDefinitions">
            <value>
                /res_admin/**=anon
                /res_front/**=anon
                /plugins/**=anon
                /login.html=anon
                /admin/login.*=anon
                /admin/**=authsys
                /user/**=authnor
                /**=anon
            </value>
        </property>
    </bean>

<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

这两个必须要有的。

然后就是一点点看了。
<!-- 定义Shiro安全管理配置 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="cacheManager" ref="memoryConstrainedCacheManager" />
        <property name="authenticator" ref="defineModularRealmAuthenticator" />
        <!-- 这里主要是设置自定义的单Realm应用,若有多个Realm,可使用'realms'属性代替 -->
        <!-- <property name="realm" ref="loginRealm"/> -->
        <property name="realms"  >
            <list>  <!-- 前台和后台的登录认证和权限授权认证 --> 
                <ref bean="systemUserRealm" />
                <ref bean="normalUserRealm"/>
            </list>
        </property>
        <property name="sessionManager" ref="sessionManager" />
        <property name="rememberMeManager" ref="rememberMeManager"/>
    </bean>

我们在接着看memoryConstrainedCacheManer。

<bean id="memoryConstrainedCacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" />
 <bean id="defineModularRealmAuthenticator" class="com.dashuai.shiro.DefautModularRealm">
        <property name="definedRealms">
            <map>
                <entry key="systemAuthorizingRealm" value-ref="systemUserRealm" />
                <entry key="normalAuthorizingRealm" value-ref="normalUserRealm" />
            </map>
        </property>
        <property name="authenticationStrategy">
            <bean class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"></bean>
        </property>
    </bean>
 <!-- Realm 域 授权和认证的判断 -->
    <bean id="systemUserRealm" class="com.dashuai.shiro.SystemUserRealm" />
    <bean id="normalUserRealm" class="com.dashuai.shiro.NormalUserRealm" />

// 下面的java代码有的我注释了,是因为注释的代码 是需要根据不同需求自行编写的。

package com.dashuai.shiro;
import org.apache.log4j.Logger;
import org.apache.shiro.ShiroException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.util.CollectionUtils;
import java.util.Collection;
import java.util.Map;
/**
 * 管理多个Realms
 */
public class DefautModularRealm extends ModularRealmAuthenticator {
    private static final Logger log = Logger.getLogger(DefautModularRealm.class);
    private Map<String, Object> definedRealms;
    /**
     * 多个realm实现
     */
    @Override
    protected AuthenticationInfo doMultiRealmAuthentication(Collection<Realm> realms, AuthenticationToken token) {
        return super.doMultiRealmAuthentication(realms, token);
    }
    /**
     * 调用单个realm执行操作
     */
    @Override
    protected AuthenticationInfo doSingleRealmAuthentication(Realm realm,AuthenticationToken token) {
        log.info("DefautModularRealm doSingleRealmAuthentication Shiro 认证执行的第 3 步 " +token);
        // 如果该realms不支持(不能验证)当前token
        if (!realm.supports(token)) {
            throw new ShiroException("token错误!");
        }
        AuthenticationInfo info = realm.getAuthenticationInfo(token);
        log.info("DefautModularRealm doSingleRealmAuthentication info " +info);
        return info;
    }
    /**
     * 判断登录类型执行操作
     */
    @Override
    protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken)throws AuthenticationException {
        log.info("DefautModularRealm doAuthenticate Shiro 认证执行的第二步 ");
        this.assertRealmsConfigured();
        Realm realm = null;
        CustomUsernamePasswordToken token = (CustomUsernamePasswordToken) authenticationToken;
        //判断是否是后台用户
        if (token.getLoginType()==CustomUsernamePasswordToken.LOGIN_ADMIN_TYPE) {
            realm = (Realm) this.definedRealms.get("systemAuthorizingRealm");// 查看shiro的配置
        }
        else if (token.getLoginType()==CustomUsernamePasswordToken.LOGIN_FRONT_TYPE){
            realm = (Realm) this.definedRealms.get("normalAuthorizingRealm");
        }
        log.info("doAuthenticate ==> "+realm);
        return this.doSingleRealmAuthentication(realm, authenticationToken);
    }
    /**
     * 判断realm是否为空
     */
    @Override
    protected void assertRealmsConfigured() throws IllegalStateException {
        this.definedRealms = this.getDefinedRealms();
        if (CollectionUtils.isEmpty(this.definedRealms)) {
            throw new ShiroException("值传递错误!");
        }
    }
    public Map<String, Object> getDefinedRealms() {
        return this.definedRealms;
    }
    public void setDefinedRealms(Map<String, Object> definedRealms) {
        this.definedRealms = definedRealms;
    }
}

package com.dashuai.shiro;
import org.apache.shiro.authc.UsernamePasswordToken;
public class CustomUsernamePasswordToken extends UsernamePasswordToken {
    public static final int LOGIN_ADMIN_TYPE=1000; // 后台
    public static final int LOGIN_FRONT_TYPE=999;  // 前台
    private int loginType; // 是否是系统后台用户还是前台用户
    public int getLoginType() {
        return loginType;
    }
    public void setLoginType(int loginType) {
        this.loginType = loginType;
    }
    public CustomUsernamePasswordToken (String username, String password, boolean rememberMe, int loginType) {
        super(username, password, rememberMe);
        this.loginType = loginType;
    }
}

package com.dashuai.shiro;
import com.dashuai.entity.system.SystemRole;
import com.dashuai.entity.system.SystemUser;
import com.dashuai.service.system.SystemRoleService;
import com.dashuai.service.system.SystemUserRoleService;
import com.dashuai.service.system.SystemUserService;
import com.dashuai.util.ConstantUtil;
//import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
 * 系统用户领域(后台用户操作)
 */
public class SystemUserRealm extends AuthorizingRealm {
    private static final Logger log = LoggerFactory.getLogger(SystemUserRealm.class);
//    @Autowired
//    private SystemUserService systemUserService;
//    @Autowired
//    private SystemRoleService systemRoleService;
//    @Autowired
//    private SystemUserRoleService systemUserRoleService;
    /**
     * Shiro权限认证,即权限授权
     * 会进入授权方法一共有三种情况!
     1、subject.hasRole(“admin”) 或 subject.isPermitted(“admin”):自己去调用这个是否有什么角色或者是否有什么权限的时候;
     2、@RequiresRoles("admin") :在方法上加注解的时候;
     3、[@shiro.hasPermission name = "admin"][/@shiro.hasPermission]:在页面上加shiro标签的时候,即进这个页面的时候扫描到有这个标签的时候。
     */
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        log.info("SystemUserRealm Shiro请求授权 ");
//        SystemUser systemUser = (SystemUser) SecurityUtils.getSubject().getPrincipal();
//        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//        if(systemUser.getIsRoot().equals(ConstantUtil.IS_ROOT)){
//            Collection<String> roles = new ArrayList<>();
//            List<SystemRole> list = systemRoleService.getRootAllRoles();
//            for(SystemRole systemRole:list){
//                roles.add(systemRole.getRoleName());
//            }
//            info.addRoles(roles);
//            log.info("SystemUserRealm Root 获取角色:{} ", Arrays.toString(info.getRoles().toArray()));
//        }else{
//            // 非root用户
//            info.addRoles(systemUserRoleService.getAllRolesNameByUserId(systemUser.getUuid()));
//            log.info("SystemUserRealm 后台 非ROOT 获取角色: {}", Arrays.toString(info.getRoles().toArray()));
//        }
//        return info;
        return null;
    }
    /**
     * 用户认证,登录认证
     */
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws UnknownAccountException,IncorrectCredentialsException {
//        log.info("SystemUserRealm doGetAuthenticationInfo Shiro 认证执行的第 4 步 " );
//        CustomUsernamePasswordToken token = (CustomUsernamePasswordToken) authenticationToken;
//        String username = token.getUsername();
//        log.info("SystemUserRealm token username: {}, password: {}",username,new String(token.getPassword()));
//        SystemUser systemUser = systemUserService.findUserByUsername(username);
//        log.info("SystemUserRealm  systemUser: {}",systemUser);
//        if(null==systemUser){
//            throw new UnknownAccountException("SystemUserRealm 提示: 用户名不存在");
//        }else if(!systemUser.getPassword().equals(new String(token.getPassword()))){
//            throw new IncorrectCredentialsException("SystemUserRealm 提示:密码错误");
//        }else if(systemUser.getStatus()==1){
//            throw new AccountException("SystemUserRealm 提示: 账号被禁用");
//        }else{
//            return new SimpleAuthenticationInfo(systemUser,systemUser.getPassword(),getName());
//        }
        return null;
    }
}


package com.dashuai.shiro;
import com.dashuai.entity.system.SystemUser;
import com.dashuai.service.system.SystemUserRoleService;
import com.dashuai.service.system.SystemUserService;
import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Arrays;
/**
 * 这里验证多个 Realm,前后台 分开验证
 */
public class NormalUserRealm extends AuthorizingRealm {
    private static final Logger log = Logger
            .getLogger(SystemUserRealm.class);
//    @Autowired
//    private SystemUserService systemUserService;
//    @Autowired
//    private SystemUserRoleService systemUserRoleService;
    /**
     * Shiro权限认证,即权限授权
     *
     * 关于多个Realm授权的问题。对于本项目配置而言是这样的。
     * 本项目配置了两个: SystemUserRealm;NormalUserRealm;
     *  它会按配置顺序执行。先SystemUserRealm;
     *  如果在先SystemUserRealm发现了想要的角色或者权限,那么不执行NormalUserRealm;
     *  如果在SystemUserRealm没有找到,那么继续执行NormalUserRealm中授权方法。
     *
     */
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        log.info("前台用户 NormalUserRealm Shiro 请求授权");
//        SystemUser systemUser = (SystemUser) SecurityUtils.getSubject().getPrincipal();
//        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//        info.addRoles(systemUserRoleService.getAllRolesNameByUserId(systemUser.getUuid()));
//        log.info("NormalUserRealm 前台用户  获取角色: "+ Arrays.toString(info.getRoles().toArray()));
//        return info;
        return null;
    }
    /**
     * 用户认证,登录认证
     */
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        log.info("前台用户 NormalUserRealm 用户认证 Shiro 认证执行的第 4 步 " );
//        CustomUsernamePasswordToken token = (CustomUsernamePasswordToken) authenticationToken;
//        String username = token.getUsername();
//        log.info("NormalUserRealm token username: "+username+", password: "+new String(token.getPassword()));
//        SystemUser systemUser = systemUserService.findUserByUsername(username);
//        log.info("NormalUserRealm  systemUser: "+systemUser);
//        if(null==systemUser){
//            throw new UnknownAccountException("NormalUserRealm tips: 用户名不存在");
//        }else if(!systemUser.getPassword().equals(new String(token.getPassword()))){
//            throw new IncorrectCredentialsException("NormalUserRealm tips: 密码错误,请重试");
//        }else if(systemUser.getStatus()==1){
//            throw new AccountException("NormalUserRealm tips: 账号被禁用");
//        }else{
//            return new SimpleAuthenticationInfo(systemUser,systemUser.getPassword(),getName());
//        }
        return null;
    }
}

这样 如下部分我们都看完了。
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="cacheManager" ref="memoryConstrainedCacheManager" />
<property name="authenticator" ref="defineModularRealmAuthenticator" />
<!-- 这里主要是设置自定义的单Realm应用,若有多个Realm,可使用'realms'属性代替 -->
<!-- <property name="realm" ref="loginRealm"/> -->
<property name="realms" >
<list> <!-- 前台和后台的登录认证和权限授权认证 -->
<ref bean="systemUserRealm" />
<ref bean="normalUserRealm"/>
</list>
</property>
还有未看完的。
<property name="sessionManager" ref="sessionManager" />
<property name="rememberMeManager" ref="rememberMeManager"/>
现在看sessionManager

<bean id="sessionManager"
class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
        <property name="sessionDAO" ref="sessionDAO" />
        <!-- 会话超时时间,单位:毫秒 -->
        <property name="globalSessionTimeout" value="1800000" />
        <!-- 定时清理失效会话, 清理用户直接关闭浏览器造成的孤立会话 -->
        <property name="sessionValidationInterval" value="1800000" />
        <property name="sessionValidationSchedulerEnabled" value="true" />
        <property name="sessionIdCookie" ref="simpleCookie" />
        <property name="sessionIdCookieEnabled" value="true" />
    </bean>
    <!-- 会话Cookie模板 -->
    <bean id="simpleCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
        <constructor-arg name="name" value="shiro.sesssion"/>
        <property name="path" value="/"/>
    </bean>
<bean id="sessionDAO"
class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
        <property name="cacheManager" ref="shiroCacheManager" />
    </bean>
 <!-- 定义授权缓存管理器 -->
    <bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <property name="cacheManagerConfigFile" value="classpath:ehcache.xml" />
    </bean>

<!-- rememberMe管理器 -->
    <bean id="rememberMeManager"
class="org.apache.shiro.web.mgt.CookieRememberMeManager">
        <property name="cipherKey"
                  value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}"/>
        <property name="cookie" ref="rememberMeCookie"/>
    </bean>
<bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
        <constructor-arg value="rememberMe"/>
        <property name="httpOnly" value="true"/>
        <property name="maxAge" value="604800"/><!-- 7天 -->
    </bean>


最后在看shiroFilter 中 filter的配置:

<bean id="systemAuthFilter" class="com.dashuai.shiro.SystemFormAuthFilter" >
        <property name="loginUrl" value="/admin/login.html" />
        <property name="successUrl" value="/admin/index.html" />
    </bean>
    <bean id="normalAuthFilter" class="com.dashuai.shiro.NormalFormAuthFilter" >
        <property name="loginUrl" value="/login.html" />
        <property name="successUrl" value="/index.html" />
    </bean>


package com.dashuai.shiro;
import org.apache.log4j.Logger;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
 * 后台的用户登录认证
 */
public class SystemFormAuthFilter extends FormAuthenticationFilter {
    private static final Logger log = Logger
            .getLogger(SystemFormAuthFilter.class);
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        log.info("SystemFormAuthFilter onAccessDenied Shiro 认证执行的第一步 ");
        return super.onAccessDenied(request, response);
    }
    /*@Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
        log.info("SystemFormAuthFilter onLoginSuccess  ");
        //我们登录成功之后要跳到一个固定的页面,通常是跳到首页,
        WebUtils.getAndClearSavedRequest(request);
WebUtils.redirectToSavedRequest(request,response,"admin/index.html");
        return super.onLoginSuccess(token, subject, request, response);
    }*/
}

package com.dashuai.shiro;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
 * 前台 用户登录的验证
 */
public class NormalFormAuthFilter extends FormAuthenticationFilter {
    private static final Logger log = LoggerFactory
            .getLogger(SystemFormAuthFilter.class);
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        log.info("NormalFormAuthFilter onAccessDenied Shiro 前台 认证执行的第一步 ");
        return super.onAccessDenied(request, response);
    }
}

这样shiro的配置就完成了。

项目中 总有存在5张表


/**
 *  用户表。(通用用户,能否访问后台,看是否有后台角色)
 */
@Entity
@Table(name="system_user")
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class SystemUser implements Serializable {
    @Id
    @GenericGenerator(name = "systemUUID", strategy = "uuid")
    @GeneratedValue(generator = "systemUUID")
    @Column(name = "uuid",updatable = false, nullable = false)
    private String uuid;     // 表主键
    @Column
    private String username; // 登录用户名
    @Column
    private String password; // 登录密码
    @Column
    private String isRoot; // 最高权限管理员; "1":root "0": notRoot
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @Column
    private Date registerDate;
    @Column
    private Integer status; // 账号状态: 0:正常;1:禁用

@Entity
@Table(name="system_role")
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class SystemRole implements Serializable{
    @Id
    @GenericGenerator(name = "systemUUID", strategy = "uuid")
    @GeneratedValue(generator = "systemUUID")
    @Column(name = "uuid",updatable = false, nullable = false)
    private String uuid;     // 表主键
    @Column(name="role_name")
    private String roleName;
    @Column(name="role_desc")
    private String roleDesc;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @Column(name = "create_date",updatable=false)
    private Date createDate;// 创建日期
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @Column(name = "update_date")
    private Date updateDate;// 更新日期
    public Date getCreateDate() {
        return createDate;
    }

/**
 * 菜单表,你可以理解为 权限表
 */
@Entity
@Table(name="system_menu")
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class SystemMenu implements Serializable {
    @Id
    @GenericGenerator(name = "systemUUID", strategy = "uuid")
    @GeneratedValue(generator = "systemUUID")
    @Column(name = "uuid",updatable = false, nullable = false)
    private String uuid;
    // 父类ID
    @Column(name = "pId", length = 64)
    private String pid;
    // 资源名称
    @Column(name = "name", length = 32)
    private String name;
    // 资源类型
    @Column(name="type")
    private String type;//权限类型,0.表示目录 1,表示菜单.2,表示按扭..
    // 资源排序
    @Column(name = "seq", length = 4)
    private int seq;
    // 资源的URL
    @Column(name = "resUrl", length = 128)
    private String resUrl;//URL地址.例如:/videoType/query  不需要项目名和http://xxx:8080
    // 资源状态
    @Column(name = "status", length = 2)
    private int status;// 这个变量含义定义为: 0:可修改删除 1:不可修改删除
    //层级
    @Column(name="level", length = 4)
    private int level;
    // 资源说明
    @Column(name = "descript", length = 128)
    private String descript;
    // 资源图标
    @Column(name = "iconCls", length = 128)
    private String iconCls;

@Entity
@Table(name="system_user_role")
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class SystemUserRole implements Serializable{
    @Id
    @GenericGenerator(name = "systemUUID", strategy = "uuid")
    @GeneratedValue(generator = "systemUUID")
    @Column(name = "uuid",updatable = false, nullable = false)
    private String uuid;     // 表主键
    @Column
    private String sysUserId;
    @Column
    private String sysRoleId;

@Entity
@Table(name="system_role_menu")
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class SystemRoleMenu implements Serializable{
    @Id
    @GenericGenerator(name = "systemUUID", strategy = "uuid")
    @GeneratedValue(generator = "systemUUID")
    @Column(name = "uuid",updatable = false, nullable = false)
    private String uuid;
    @Column
    private String sysRoleId;
    @Column
    private String sysMenuId;

具体的太长了,所以我讲讲项目中的心得体会吧。

1. shiro+hibernate+ehcache 这三个用的时候配置需要注意,ehcache.xml要合到一起。

2. log4j和slf4j的依赖是

 <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.25</version>
  </dependency>
为什么我要说这个,因为 我被别人误导了,别人导入了 log4j,slf4j相关依赖,就是没有上面的,导致我只能用 log4j显示日志,slf4j却没有效果,郁闷半天。


3. hibernate的二级缓存用法

<prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate4.SpringSessionContext</prop>
<prop key="hibernate.cache.provider_configuration_file_resource_path">classpath:ehcache.xml</prop>
<!-- 开启查询缓存 -->
<prop key="hibernate.cache.use_query_cache">true</prop>
<!-- 开启二级缓存 -->
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<!-- 高速缓存提供程序 -->
<!-- 由于spring也使用了Ehcache, 保证双方都使用同一个缓存管理器 -->
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</prop>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
    <property name="configLocation">
      <value>classpath:ehcache.xml</value>
    </property>
    <!-- 由于hibernate也使用了Ehcache, 保证双方都使用同一个缓存管理器 -->
    <property name="shared" value="true"/>
  </bean>

@Entity
@Table(name="system_role")
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class SystemRole implements Serializable{
 
 

实体类加上注解,表示该实体类需要使用二级缓存。模式可选 read_write也可以是 read_only。但据说 read_only效率高些。 list()方法的调用,如果要用缓存,需要setCacheable(true)

@Override
public GridPageResult<SystemRole> getPageRoles(Pager pager) {
    List<SystemRole> rows = getByHQL(true,"from SystemRole order by updateDate desc",null,pager.getPage(),pager.getRows());
    long total = countByHQL(true,"select count(*) from SystemRole",null);
    return new GridPageResult<>(total,rows);
}
public List<T> getByHQL(boolean withCache, String hql, Map<String, Object> params) {
		Query q = getCurrentSession().createQuery(hql);
		if (params != null && !params.isEmpty()) {
			for (String key : params.keySet()) {
				q.setParameter(key, params.get(key));
			}
		}
		return q.setCacheable(withCache).list();
	}
	public List<T> getByHQL(boolean withCache, String hql, Map<String, Object> params, int page, int rows) {
		Query q = getCurrentSession().createQuery(hql);
		if (params != null && !params.isEmpty()) {
			for (String key : params.keySet()) {
				q.setParameter(key, params.get(key));
			}
		}
		return q.setCacheable(withCache).setFirstResult((page - 1) * rows)//
				.setMaxResults(rows)//
				.list();
	}
	public long countByHQL(boolean withCache, String hql, Map<String, Object> params) {
		Query q = getCurrentSession().createQuery(hql);
		if (params != null && !params.isEmpty()) {
			for (String key : params.keySet()) {
				q.setParameter(key, params.get(key));
			}
		}
		return (Long) q.setCacheable(withCache).uniqueResult();
	}
	public long countBySQL(boolean withCache, String sql, Map<String, Object> params) {
		SQLQuery q = getCurrentSession().createSQLQuery(sql);
		if (params != null && !params.isEmpty()) {
			for (String key : params.keySet()) {
				q.setParameter(key, params.get(key));
			}
		}
		return (Long) q.setCacheable(withCache).uniqueResult();
	}
	public List<Map<String, Object>> getResultMapBySql(String sql, Map<String, Object> params) {
		SQLQuery q = getCurrentSession().createSQLQuery(sql);
		if (params != null && !params.isEmpty()) {
			for (String key : params.keySet()) {
				q.setParameter(key, params.get(key));
			}
		}
		return q.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
	}
	public List<Map<String, Object>> getResultMapBySql(String sql, Map<String, Object> params, int page, int rows) {
		SQLQuery q = getCurrentSession().createSQLQuery(sql);
		if (params != null && !params.isEmpty()) {
			for (String key : params.keySet()) {
				q.setParameter(key, params.get(key));
			}
		}
		// 这种的不能使用 setCacheable(withCache),会报错。
		return q.setFirstResult((page - 1) * rows)//
				.setMaxResults(rows)//
				.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP)//
				.list();
	}

使用二级缓存也会有很多不便的地方:

public void updateRole(SystemRole role) {
        //update(role); // 不能这样更新,cache是read-only模式
        String hql = "update SystemRole set " +
"roleName=:roleName,roleDesc=:roleDesc,updateDate=:updateDate " +
                " where uuid=:uuid";
        Map<String,Object> params = new HashMap<>();
        params.put("roleName",role.getRoleName());
        params.put("roleDesc",role.getRoleDesc());
        params.put("updateDate",role.getUpdateDate());
        params.put("uuid",role.getUuid());
        executeHQL(hql,params);
    }
不能直接调用update方法,更新对象,要采用执行sql或者hql语句方式,直接操作数据库。经测试,直接操作数据库的更新,缓存也会失效,也会更新的。

第二个就是使用sql语句查询的时候,如果使用cache为true的情况,不能返回List<Map>类型,必须指定成对象。当然setcache为false,顺利执行。 那么如果是true,代码应这样写。

@Override
    public List<DtoRoleMenu> getRoleHasAndNotHasMenus(String roleId) {
        String sql="select m.uuid as id,  " +
                "m.pId as pId, " +
                "m.name as name, " +
                "m.resUrl as resUrl, " +
                "m.type as type, " +
                "srm.sysRoleId as roleId " +
                "from system_menu m  " +
                "left join system_role_menu srm  " +
                "on m.uuid = srm.sysMenuId " +
                "and srm.sysRoleId =:roleId ";
        return  getCurrentSession()
                .createSQLQuery(sql)
                .addScalar("id", StringType.INSTANCE)
                .addScalar("pId", StringType.INSTANCE)
                .addScalar("name", StringType.INSTANCE)
                .addScalar("resUrl", StringType.INSTANCE)
                .addScalar("type", StringType.INSTANCE)
                .addScalar("roleId", StringType.INSTANCE)
                .setParameter("roleId",roleId)
.setResultTransformer(Transformers.aliasToBean(DtoRoleMenu.class))
                .setCacheable(false).list();
    }

贴上项目运行效果图吧。



项目运行

因为项目已经集成了 tomcat插件了。所以我们配置一下就行了,不需要额外的tomcat包了


点击OK之后,你会看到右侧就会出现你新建的东西。然后点击那两个绿色的按钮任意一个运行。


然后就可以运行了。

本项目做了一些初始化工作,所以,后台的管理员 用户名 root,密码 123456。


本项目下载地址:下载地址

如果你使用IDEA 直接打开,可能需要配置一下,因为 你的F盘可能没有maven软件,而且系统自带的maven肯定会下载jar包到你的c盘。所以最好配置一下。

还有就是 源码处,有一个无关痛痒的小错误,源码位置


我为了证明 能不能使用 cache 返回 List<Map>,测试的结果是不能使用 cache为true,否则报错。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值