搭建过程的自我记录过程,不是教程.
拾起写写停停的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构建
表示自己的代码是挺烂的啊,整个项目整理好了,有信心,再开源.工作之余写的东西,进展缓慢.
JDK8,包括配置环境变量(这个还需要说?)
Maven,类库的依赖管理,最终还是需要使用maven,从maven.apache.org上下载最新程序,并配置好环境变量
Gradle,从http://www.grale.org下载最新程序,并配置环境变量,配置好后就可以在命令行窗口中使用gradle命令了(配置方式无非是在环境变量中新建GRADLE_HOME,指向下载并解压出来的gradle目录,再将%GRADLE_HOME%\bin添加到path中)
eclipse,我使用的是sts(从spring.io下载),并添加了gradle插件(直接从market中安装就可以了),
可以直接使用eclipse的新建工程中,找到gradle的项目,使用simplejava类的工程
编辑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" }
添加springside4的源码(省事,并且可以修改内容,直接引用源码,直接从github.com上下载吧)
按maven web的项目结构,创建webapp目录
添加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>
添加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>
添加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>
添加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>
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>
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>
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; } } }
登陆时采用了rsa对密码进行了加密,从后台解密,源码来源于网络,我测试正常,代码见github.com/itwarcraft/rsa-demo