spring+hibernate+shiro+Ehcache 项目分享
来源:互联网 发布:爱伦坡 乌鸦 知乎 编辑:程序博客网 时间:2024/06/10 05:53
这篇文章,我将 把一个 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 loglog4j.appender.CONSOLE=org.apache.log4j.ConsoleAppenderlog4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayoutlog4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %l - %m%nlog4j.appender.CONSOLE.Target=System.out#all loglog4j.appender.DAILY_ALL=org.apache.log4j.DailyRollingFileAppenderlog4j.appender.DAILY_ALL.layout=org.apache.log4j.PatternLayoutlog4j.appender.DAILY_ALL.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %l - %m%nlog4j.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=truehibernate.format_sql=truehibernate.dialect=org.hibernate.dialect.MySQLDialectdriverClassName=com.mysql.jdbc.Driverjdbc_url=jdbc\:mysql\://localhost\:3306/dadmin?useUnicode\=true&characterEncoding\=UTF-8jdbc_username=rootjdbc_password=123456hibernate.hbm2ddl.auto=updatehibernate.query.substitutions=true 1, false 0hibernate.default_batch_fetch_size=16hibernate.max_fetch_depth=2hibernate.generate_statistics=falsehibernate.enable_lazy_load_no_trans=trueinitialSize=3maxActive=50minIdle=1maxWait=60000validationQuery=SELECT 1testOnBorrow=falsetestOnReturn=falsetestWhileIdle=truetimeBetweenEvictionRunsMillis=60000minEvictableIdleTimeMillis=25200000removeAbandoned=falseremoveAbandonedTimeout=1800logAbandoned=truefilters=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)
@Overridepublic 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,否则报错。
为了记录这篇博客,我tm真用了整整一下午时间啊。 因为这csdn的编辑器,实在是没习惯用啊。重复了好几遍已经做好的操作。哎,终于写完了。
- spring+hibernate+shiro+Ehcache 项目分享
- IntelliJ IDEA Spring Boot(6) 集成Hibernate+Shiro+Ehcache
- Spring mvc+shiro+ehcache整合
- spring+hibernate整合ehcache
- Spring+Hibernate+EHcache配置
- Spring+Hibernate+EHcache配置
- SpringMVC+Spring+Hibernate+EHCache
- spring + hibernate +ehcache配置
- Spring + hibernate + ehcache
- IntelliJ IDEA Spring Boot(7) 集成Hibernate+Shiro+Ehcache(2)
- Spring+SpringMVC+Hibernate+JPA+SpringData+Ehcache+C3p0+MySQL项目搭建
- spring boot集成shiro与缓存ehcache
- spring+springmvc+mybatis+shiro+ehcache集成demo
- Maven配置Spring+Hibernate Shiro权限控制项目
- springmvc 整合shiro ehcache 项目源码
- Spring + JPA + Hibernate + Tomcat + EHCache
- jpa +hibernate+spring +ehcache config
- 9.Spring + Hibernate + ehcache(二级缓存
- Solr性能调优。
- java常用类库---日期操作类(2)
- DrawerLayout实现侧滑菜单效果
- Linux下的tar压缩解压缩命令详解
- sssm
- spring+hibernate+shiro+Ehcache 项目分享
- 类和对象1-this指针
- 上传预览图片
- C语言实验——一元二次方程Ⅰ
- VerticalTabLayout的使用
- Dynamic Programing -- Leetcode problem 338. Counting Bits
- 算法(十)贪心算法
- 生成随机数
- 剑指offer 42 和为S的连续正整数序列