SpringMVC4+JPA(Hibernate4)+Spring-data-jpa+Shiro整合

搭建过程的自我记录过程,不是教程.


拾起写写停停的ERP系统,打算再次重头开始,要全部采用最新的框架来搭建,基于JDK8:

1. MVC采用SpringMVC4

2. ORM采用JPA(Hibernate实现)采用Hibernate-entitny4,搭配的使用Spring-data-jpa(1.7)

3. View还是用JSP

4. 权限当然是Shiro

5. 日志使用Logback 

6. 项目基于Gradle构建

表示自己的代码是挺烂的啊,整个项目整理好了,有信心,再开源.工作之余写的东西,进展缓慢.


那么正式开始搭建项目

一. 环境(先简单写,再完善)

  1. JDK8,包括配置环境变量(这个还需要说?)

  2. Maven,类库的依赖管理,最终还是需要使用maven,从maven.apache.org上下载最新程序,并配置好环境变量

  3. Gradle,从http://www.grale.org下载最新程序,并配置环境变量,配置好后就可以在命令行窗口中使用gradle命令了(配置方式无非是在环境变量中新建GRADLE_HOME,指向下载并解压出来的gradle目录,再将%GRADLE_HOME%\bin添加到path中)

  4. eclipse,我使用的是sts(从spring.io下载),并添加了gradle插件(直接从market中安装就可以了),

二. 建立工程

  1. 可以直接使用eclipse的新建工程中,找到gradle的项目,使用simplejava类的工程

  2. 编辑build.gradle,完整内容如下,配置完后,需要在build.gradle文件上右键,使用gradle菜单中的刷新命令,下载依赖文件

    apply plugin: 'maven'
    apply plugin: 'java'
    apply plugin: 'eclipse'
    apply plugin : 'war'
    apply plugin: 'jetty'
    
    sourceCompatibility = 1.8
    version = '1.0'
    jar {
        manifest {
            attributes 'Implementation-Title': 'lite-erp', 'Implementation-Version': version
        }
    }
    
    repositories {
        mavenCentral()
    }
    
    configurations{
    //移除依赖
     	all*.exclude group:'commons-logging'
    }
    
    dependencies {
        compile (
        
        	//spring
        	'org.springframework:spring-webmvc:4.1.1.RELEASE',
            'org.springframework:spring-jdbc:4.1.1.RELEASE',
            'org.springframework:spring-orm:4.1.1.RELEASE',
            'org.springframework:spring-context-support:4.1.1.RELEASE',
        
        	//orm
            'org.hibernate:hibernate-entitymanager:4.3.6.Final',
            'org.hibernate:hibernate-validator:5.1.2.Final',
            'org.springframework.data:spring-data-jpa:1.7.0.RELEASE',
            'org.hibernate:hibernate-ehcache:4.3.6.Final',
            
            'mysql:mysql-connector-java:5.1.33',
            'com.alibaba:druid:1.0.9',
            
            //shiro
            'org.apache.shiro:shiro-spring:1.2.3',
            'org.apache.shiro:shiro-ehcache:1.2.3',
            'org.apache.shiro:shiro-web:1.2.3',
            'org.bouncycastle:bcprov-jdk16:1.46',
            
            
            //j2ee
            'javax.servlet:javax.servlet-api:3.1.0',
            'javax.servlet:jstl:1.2',
            'javax.servlet.jsp:jsp-api:2.2',
            
            
            //log
            'ch.qos.logback:logback-classic:1.1.2',
            'org.slf4j:jul-to-slf4j:1.7.7',
            
            
            //commons
            'net.sf.dozer:dozer:5.5.1',
            'commons-codec:commons-codec:1.9',
            'commons-io:commons-io:2.4',
            'com.google.guava:guava:18.0',
            'com.thoughtworks.xstream:xstream:1.4.7',
            'org.freemarker:freemarker:2.3.21',
            'joda-time:joda-time:2.5',
            'com.fasterxml.jackson.core:jackson-databind:2.4.3',
            'com.fasterxml.jackson.module:jackson-module-jaxb-annotations:2.4.3'
            
     	)
     	
     	
     	   
        compile group: 'commons-collections', name: 'commons-collections', version: '3.2'
        testCompile group: 'junit', name: 'junit', version: '4.+'
        testCompile 'org.springframework:spring-test:4.1.1.RELEASE'
    }test {
        systemProperties 'property': 'value'
    }
    
    tasks.withType(Compile) {
         options.encoding = "UTF-8"
    }
  3. 添加springside4的源码(省事,并且可以修改内容,直接引用源码,直接从github.com上下载吧)

  4. 按maven web的项目结构,创建webapp目录

  5. 添加web.xml文件,内容基本来源于springside4中的showcase项目,内容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    	id="WebApp_ID" version="3.1">
    	<display-name>lite-erp</display-name>
    	
    	<context-param>
    		<param-name>contextConfigLocation</param-name>
    		<param-value>
    			classpath:spring-core.xml,
    			classpath:spring-shiro.xml
    		</param-value>
    	</context-param>
    
    	<listener>
    		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    	</listener>
    
    	<filter>
    		<filter-name>encodingFilter</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>encodingFilter</filter-name>
    		<url-pattern>/*</url-pattern>
    	</filter-mapping>
    
    	<filter>
    		<filter-name>openEntityManagerInViewFilter</filter-name>
    		<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
    	</filter>
    	<filter-mapping>
    		<filter-name>openEntityManagerInViewFilter</filter-name>
    		<url-pattern>/*</url-pattern>
    	</filter-mapping>
    
    	<filter>
    		<filter-name>shiroFilter</filter-name>
    		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    		<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>
    
    	<servlet>
    		<servlet-name>springmvc</servlet-name>
    		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    		<init-param>
    			<param-name>contextConfigLocation</param-name>
    			<param-value>classpath:spring-mvc.xml</param-value>
    		</init-param>
    		<load-on-startup>1</load-on-startup>
    	</servlet>
    	<servlet-mapping>
    		<servlet-name>springmvc</servlet-name>
    		<url-pattern>/</url-pattern>
    	</servlet-mapping>
    
    	<session-config>
    		<session-timeout>20</session-timeout>
    	</session-config>
    
    	<error-page>
    		<exception-type>java.lang.Throwable</exception-type>
    		<location>/WEB-INF/views/error/500.jsp</location>
    	</error-page>
    	<error-page>
    		<error-code>500</error-code>
    		<location>/WEB-INF/views/error/500.jsp</location>
    	</error-page>
    	<error-page>
    		<error-code>404</error-code>
    		<location>/WEB-INF/views/error/404.jsp</location>
    	</error-page>
    </web-app>
  6. 添加spring-core.xml,在src/main/resources目录下(其中,从网上找了下加密properties的文件,将数据库密码做了加密处理,暂时可以先去掉,也可以从网上找一下)

    <?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:c="http://www.springframework.org/schema/c"
    xmlns:cache="http://www.springframework.org/schema/cache"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xmlns:lang="http://www.springframework.org/schema/lang"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:task="http://www.springframework.org/schema/task"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
    http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.1.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
    http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd
    http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.1.xsd
    http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
    http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-4.1.xsd
    http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd"
    default-lazy-init="true">
    
    
    <description>Spring公共配置 </description>
    <!-- 加密时候使用 --> 
            <bean id="propertyConfig" class="lite.erp.ext.spring.PropertyPlaceholderConfigurerExt"> 
                    <property name="locations"> 
                            <list> 
                                    <value>classpath:jdbc.properties</value> 
                            </list> 
                    </property> 
            </bean> 
    
    <!-- 使用annotation 自动注册bean, 并保证@Required、@Autowired的属性被注入 -->
    <context:component-scan base-package="lite">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    <context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
    </context:component-scan>
    
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
    init-method="init" destroy-method="close">
    <property name="url"
    value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
    <property name="filters" value="stat" />
    <property name="maxActive" value="20" />
    <property name="initialSize" value="2" />
    <property name="maxWait" value="30" />
    <property name="minIdle" value="4" />
    <property name="timeBetweenEvictionRunsMillis" value="60000" />
    <property name="minEvictableIdleTimeMillis" value="300000" />
    <property name="validationQuery" value="SELECT 'x'" />
    <property name="testWhileIdle" value="true" />
    <property name="testOnBorrow" value="false" />
    <property name="testOnReturn" value="false" />
    <property name="maxOpenPreparedStatements" value="20" />
    <property name="removeAbandoned" value="true" /> <!-- 打开removeAbandoned功能 -->
    <property name="removeAbandonedTimeout" value="1800" /> <!-- 1800秒,也就是30分钟 -->
    <property name="logAbandoned" value="true" /> <!-- 关闭abanded连接时输出错误日志 -->
    </bean>
    
    <!-- Jpa Entity Manager 配置 -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="dataSource" ref="dataSource"/>
    <property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter"/>
    <property name="packagesToScan" value="lite"/>
    <property name="jpaProperties">
    <props>
    <!-- 命名规则 My_NAME->MyName -->
    <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
    <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
    <prop key="hibernate.hbm2ddl.auto">update</prop>
    <prop key="hibernate.show_sql">true</prop>
    <prop key="hibernate.format_sql">true</prop>
    <prop key="hibernate.query.substitutions">true 1, false 0</prop>
    <prop key="hibernate.default_batch_fetch_size">16</prop>
    <prop key="hibernate.max_fetch_depth">2</prop>
    <prop key="hibernate.generate_statistics">true</prop>
    <prop key="hibernate.bytecode.use_reflection_optimizer">true</prop>
    <!-- <prop key="hibernate.current_session_context_class">thread</prop> -->
    <!-- <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop> -->
    <prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</prop>
    <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
    <prop key="cache.cache.use_query_cache">true</prop>
    <prop key="cache.cache.use_second_level_cache">true</prop>
    </props>
    </property>
    </bean>
    <bean id="hibernateJpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    <property name="databasePlatform">
    <bean factory-method="getDialect" class="org.springside.modules.persistence.Hibernates">
    <constructor-arg ref="dataSource"/>
    </bean>
    </property>
    </bean>
    
    <!-- Spring Data Jpa配置 -->
      <jpa:repositories base-package="lite"  transaction-manager-ref="transactionManager" entity-manager-factory-ref="entityManagerFactory"/>
       
    <!-- Jpa 事务配置 -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>
    
    <!-- 使用annotation定义事务 -->
    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
    
    <!-- JSR303 Validator定义 -->
      <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
    
    </beans>
  7. 添加spring-mvc.xml,主要支持jsp json两种输出格式,文件存放在src/main/resources目录下

    <?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:c="http://www.springframework.org/schema/c"
    xmlns:cache="http://www.springframework.org/schema/cache"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xmlns:lang="http://www.springframework.org/schema/lang"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:repository="http://www.springframework.org/schema/data/repository"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
    http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.1.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
    http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd
    http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.1.xsd
    http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
    http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-4.1.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
    http://www.springframework.org/schema/data/repository http://www.springframework.org/schema/data/repository/spring-repository-1.7.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd"
    default-lazy-init="true">
    
    <!-- 自动扫描且只扫描@Controller -->
    <context:component-scan base-package="lite"
    use-default-filters="false">
    <context:include-filter type="annotation"
    expression="org.springframework.stereotype.Controller" />
    <context:include-filter type="annotation"
    expression="org.springframework.web.bind.annotation.ControllerAdvice" />
    </context:component-scan>
    
    <mvc:resources location="/assets/" mapping="/assets/*/**" />
    
    <mvc:annotation-driven content-negotiation-manager="contentNegotiationManager">
    <mvc:message-converters register-defaults="true">
    <!-- 将StringHttpMessageConverter的默认编码设为UTF-8 -->
    <bean class="org.springframework.http.converter.StringHttpMessageConverter">
        <constructor-arg value="UTF-8" />
    </bean>
    <!-- 将Jackson2HttpMessageConverter的默认格式化输出设为true -->
    <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                    <property name="prettyPrint" value="true"/>
                </bean>
       </mvc:message-converters>
    </mvc:annotation-driven>
    
    <!-- REST中根据URL后缀自动判定Content-Type及相应的View -->
    <bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
       <property name="ignoreAcceptHeader" value="true" />
                <property name="defaultContentType" value="application/json" />
       <property name="mediaTypes" >
           <value>
               json=application/json
               xml=application/xml
           </value>
       </property>
    </bean>
    <!-- 定义JSP文件的位置 -->  
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/"/>
    <property name="suffix" value=".jsp"/>
    </bean>
    <!-- 容器默认的DefaultServletHandler处理 所有静态内容与无RequestMapping处理的URL-->
    <mvc:default-servlet-handler/>
    <!-- 定义无需Controller的url<->view直接映射 -->
    <mvc:view-controller path="/" view-name="index"/>
    <!-- 将Controller抛出的异常转到特定View, 保持SiteMesh的装饰效果 -->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">  
    <property name="exceptionMappings">  
    <props>
    <prop key="org.apache.shiro.authz.UnauthorizedException">error/403</prop>
    <prop key="java.lang.Throwable">error/500</prop>
                </props>  
    </property>  
        </bean> 
        
    <!-- 支持 Shiro对Controller的方法级AOP安全控制  begin-->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
    <property name="proxyTargetClass" value="true" />
    </bean>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
         <property name="securityManager" ref="securityManager"/>
    </bean>
    <!-- end -->
    </beans>
  8. 添加spring-shiro.xml,文件位于src/main/resources目录下

    <?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:c="http://www.springframework.org/schema/c"
    xmlns:cache="http://www.springframework.org/schema/cache"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xmlns:lang="http://www.springframework.org/schema/lang"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:repository="http://www.springframework.org/schema/data/repository"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
    http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.1.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
    http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd
    http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.1.xsd
    http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
    http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-4.1.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
    http://www.springframework.org/schema/data/repository http://www.springframework.org/schema/data/repository/spring-repository-1.7.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd"
    default-lazy-init="true">
    
    <description>Shiro安全配置</description>
    
    <!-- Shiro's main business-tier object for web-enabled applications -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="realm" ref="shiroDbRealm" />
    <property name="cacheManager" ref="shiroEhcacheManager" />
    </bean>
    
    <!-- 項目自定义的Realm, 所有accountService依赖的dao都需要用depends-on声明 -->
    <bean id="shiroDbRealm" class="lite.erp.security.shiro.ShiroDbRealm">
    <property name="userService" ref="userService"/>
    </bean>
    <!-- Shiro Filter -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager" />
    <property name="loginUrl" value="/login" />
    <property name="successUrl" value="/index" />
    <property name="filterChainDefinitions">
    <value>
    /login = authc
    /logout = logout
    /assets/** = anon
    /register/** = anon
    /api/keypair = anon
    /admin/** = roles[admin]
    /** = user
    </value>
    </property>
    </bean>
    <!-- 用户授权信息Cache, 采用EhCache -->
    <bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
    <property name="cacheManagerConfigFile" value="classpath:ehcache/ehcache-shiro.xml"/>
    </bean>
    <!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
    </beans>
  9. ehcache配置,包含ehcache.xml与ehcache/ehcache-shiro.xml,按目录结构存放在src/main/resources中

    ehcache.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <ehcache>
    	<diskStore path="java.io.tmpdir" />
    	<!--缓存可以存储的总记录量 -->
    	<!--缓存是否永远不销毁 -->
    	<!--当缓存中的数据达到最大值时,是否把缓存数据写入磁盘 -->
    	<!--当缓存闲置时间超过该值,则缓存自动销毁 -->
    	<!--缓存创建之后,到达该缓存自动销毁 -->
    	<defaultCache maxElementsInMemory="5"
    		eternal="false"
    		overflowToDisk="true"
    		timeToIdleSeconds="15"
    		timeToLiveSeconds="120"
    		/>
    </ehcache>

    src/main/resources/ehcache目录下有ehcache-shiro.xml文件

    <ehcache updateCheck="false" name="shiroCache">
    
       <defaultCache
                maxElementsInMemory="10000"
                eternal="false"
                timeToIdleSeconds="120"
                timeToLiveSeconds="120"
                overflowToDisk="false"
                diskPersistent="false"
                diskExpiryThreadIntervalSeconds="120"
                />
    </ehcache>
  10. logback配置logback.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
    	<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
    		<encoder>
    			<pattern>%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    		</encoder>
    	</appender>
    
    	<appender name="rollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
    		<file>d:/logs/quickstart.log</file>
    		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    			<fileNamePattern>d:/logs/quickstart.%d{yyyy-MM-dd}.log</fileNamePattern>
    		</rollingPolicy>
    		<encoder>
    			<pattern>%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    		</encoder>
    	</appender>
    
    	<!-- project default level -->
    	<logger name="lite" level="INFO" />
    	 <!-- 下面配置一些第三方包的日志过滤级别,用于避免刷屏 -->  
      
        <logger name="org.hibernate" level="INFO" />  
        <logger name="org.springframework" level="INFO" />  
        <logger name="com.opensymphony" level="INFO" />  
        <logger name="org.apache" level="INFO" />  
      
        <!-- show parameters for hibernate sql 专为 Hibernate 定制 -->  
        <logger name="org.hibernate.type" level="TRACE" />
        <logger name="org.hibernate.type.descriptor.sql.BasicBinder"  
            level="TRACE" />  
        <logger name="org.hibernate.type.descriptor.sql.BasicExtractor"  
            level="DEBUG" />  
        <logger name="org.hibernate.SQL" level="DEBUG" />  
        <logger name="org.hibernate.engine.QueryParameters" level="DEBUG" />  
        <logger name="org.hibernate.engine.query.HQLQueryPlan" level="DEBUG" /> 
    
    	<!--log4jdbc -->
    	<logger name="jdbc.sqltiming" level="INFO"/>
    
    	<root level="WARN">
    		<appender-ref ref="console" />
    		<appender-ref ref="rollingFile" />
    	</root>
    </configuration>
  11. shirodbrealm代码

    package lite.erp.security.shiro;
    
    import java.io.Serializable;
    import java.math.BigInteger;
    import java.net.URLDecoder;
    import java.security.KeyPair;
    import java.security.interfaces.RSAPrivateKey;
    
    import javax.annotation.PostConstruct;
    
    import lite.erp.security.consts.RbacConsts;
    import lite.erp.security.crypto.RSAUtil;
    import lite.erp.security.entity.User;
    import lite.erp.security.service.IUserService;
    
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.AccountException;
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.AuthenticationInfo;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authc.LockedAccountException;
    import org.apache.shiro.authc.SimpleAuthenticationInfo;
    import org.apache.shiro.authc.UnknownAccountException;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
    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.apache.shiro.util.ByteSource;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springside.modules.utils.Encodes;
    
    import com.google.common.base.Objects;
    
    public class ShiroDbRealm extends AuthorizingRealm {
    
    	private Logger logger = LoggerFactory.getLogger(ShiroDbRealm.class);
    	
    	protected IUserService userService;
    
    	/**
    	 * 认证回调函数,登录时调用.
    	 */
    	@Override
    	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
    		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
    		try {
    			String pwd = decryptPwd(token.getPassword());
    			token.setPassword(pwd.toCharArray());
    		} catch (Exception e) {
    			throw new AccountException("解密密码失败");
    		}
    		User user = userService.findUserByName(token.getUsername());
    		SecurityUtils.getSubject().getSession().removeAttribute("errmsg");
    		if (user == null) {
    			SecurityUtils.getSubject().getSession().setAttribute("errmsg", "未找到用户!");
    			throw new UnknownAccountException();// 没有找到账号
    		}
    
    		if (Boolean.TRUE.equals(user.isLocked())) {
    			SecurityUtils.getSubject().getSession().setAttribute("errmsg", "账号锁定!");
    			throw new LockedAccountException(); // 帐号锁定
    		}
    		byte[] salt = Encodes.decodeHex(user.getSalt());
    		ShiroUser shiroUser = new ShiroUser(user.getId(), user.getName(), user.getName());
    		SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(shiroUser,
    				user.getPassword(), ByteSource.Util.bytes(salt), getName());
    		SecurityUtils.getSubject().getSession().setAttribute(RbacConsts.CURRENT_USER_SESSION_NAME, user);
    		return info;
    	}
    	
    	
    	private String decryptPwd(char[] pwds) throws Exception{
    		String pwd1 = new String(pwds);
    		String pwd = null;
    		KeyPair key = (KeyPair)SecurityUtils.getSubject().getSession().getAttribute("key");
    		RSAPrivateKey rsap = (RSAPrivateKey) key.getPrivate();
    		byte[] en_result = new BigInteger(pwd1, 16).toByteArray();
    		byte[] bs = RSAUtil.decrypt(rsap,en_result);
    		String de_orig = new String(bs);
    		StringBuffer sb = new StringBuffer();
    		sb.append(de_orig);
    		String uri_orig = sb.reverse().toString().trim();
    		//接收的数据做过编码处理,所以要还原
    		pwd =URLDecoder.decode(uri_orig,"UTF-8");//
    		return pwd;
    	}
    
    	/**
    	 * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
    	 */
    	@Override
    	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    		ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
    		User user = userService.findUserByName(shiroUser.loginName);
    		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    		info.addRoles(user.getRolesName());
    		//info.setRoles(this.getUserService().findRolesByUsername(username));
    //		info.setStringPermissions(this.getUserService().findPermissionsByUsername(username));
    
    		return info;
    	}
    
    	/**
    	 * 设定Password校验的Hash算法与迭代次数.
    	 */
    	@PostConstruct
    	public void initCredentialsMatcher() {
    		HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(IUserService.HASH_ALGORITHM);
    		matcher.setHashIterations(IUserService.HASH_INTERATIONS);
    
    		setCredentialsMatcher(matcher);
    	}
    
    	
    	public IUserService getUserService() {
    		return userService;
    	}
    	
    	public void setUserService(IUserService userService) {
    		this.userService = userService;
    	}
    	
    	
    	/**
    	 * 自定义Authentication对象,使得Subject除了携带用户的登录名外还可以携带更多信息.
    	 */
    	public static class ShiroUser implements Serializable {
    		private static final long serialVersionUID = -1373760761780840081L;
    		public Long id;
    		public String loginName;
    		public String name;
    
    		public ShiroUser(Long id, String loginName, String name) {
    			this.id = id;
    			this.loginName = loginName;
    			this.name = name;
    		}
    
    		public String getName() {
    			return name;
    		}
    
    		/**
    		 * 本函数输出将作为默认的<shiro:principal/>输出.
    		 */
    		@Override
    		public String toString() {
    			return loginName;
    		}
    
    		/**
    		 * 重载hashCode,只计算loginName;
    		 */
    		@Override
    		public int hashCode() {
    			return Objects.hashCode(loginName);
    		}
    
    		/**
    		 * 重载equals,只计算loginName;
    		 */
    		@Override
    		public boolean equals(Object obj) {
    			if (this == obj) {
    				return true;
    			}
    			if (obj == null) {
    				return false;
    			}
    			if (getClass() != obj.getClass()) {
    				return false;
    			}
    			ShiroUser other = (ShiroUser) obj;
    			if (loginName == null) {
    				if (other.loginName != null) {
    					return false;
    				}
    			} else if (!loginName.equals(other.loginName)) {
    				return false;
    			}
    			return true;
    		}
    	}
    }
  12. 登陆时采用了rsa对密码进行了加密,从后台解密,源码来源于网络,我测试正常,代码见github.com/itwarcraft/rsa-demo




你可能感兴趣的:(SpringMVC4+JPA(Hibernate4)+Spring-data-jpa+Shiro整合)