項目結構圖:
一、先新建一個maven項目,配置pom.xml
- <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/maven-v4_0_0.xsd”>
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.test</groupId>
- <artifactId>Test</artifactId>
- <packaging>war</packaging>
- <version>0.0.1</version>
- <name>Test</name>
- <url>http://maven.apache.org</url>
- <properties>
- <maven.compiler.source>1.8</maven.compiler.source>
- <maven.compiler.target>1.8</maven.compiler.target>
- </properties>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>3.8.1</version>
- <scope>test</scope>
- </dependency>
- <!–1、 spring相關包 –>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-aop</artifactId>
- <version>4.3.2.RELEASE</version>
- </dependency>
- <!– 要使用spring的aop,要麼引入aspectj,要麼cglib –>
- <dependency>
- <groupId>org.aspectj</groupId>
- <artifactId>aspectjweaver</artifactId>
- <version>1.6.11</version>
- <type>jar</type>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>cglib</groupId>
- <artifactId>cglib</artifactId>
- <version>3.2.4</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-beans</artifactId>
- <version>4.3.2.RELEASE</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-webmvc</artifactId>
- <version>4.3.2.RELEASE</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-jdbc</artifactId>
- <version>4.3.2.RELEASE</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-web</artifactId>
- <version>4.3.2.RELEASE</version>
- </dependency>
- <!– 事務相關spring包 –>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-tx</artifactId>
- <version>4.3.2.RELEASE</version>
- </dependency>
-
- <!–2、 數據庫相關包 –>
- <!– 導入dbcp的jar包,用來在applicationContext.xml中配置數據庫 –>
- <dependency>
- <groupId>commons-dbcp</groupId>
- <artifactId>commons-dbcp</artifactId>
- <version>1.4</version>
- </dependency>
- <!– 導入Mysql數據庫鏈接jar包 –>
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <!– Maven中driverClassName爲com.mysql.jdbc.Driver時不可使用6.0.3版本 –>
- <version>5.1.18</version>
- </dependency>
- <!– mybatis相關包 –>
- <dependency>
- <groupId>org.mybatis</groupId>
- <artifactId>mybatis</artifactId>
- <version>3.4.2</version>
- </dependency>
- <!– mybatis/spring包 –>
- <dependency>
- <groupId>org.mybatis</groupId>
- <artifactId>mybatis-spring</artifactId>
- <version>1.3.0</version>
- </dependency>
- <!– Ehcache實現,用於參考 –>
- <dependency>
- <groupId>org.mybatis</groupId>
- <artifactId>mybatis-ehcache</artifactId>
- <version>1.0.0</version>
- </dependency>
-
- <!– 3、日誌文件管理包 –>
- <!– log start –>
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.17</version>
- </dependency>
- <!– 格式化對象,方便輸出日誌 –>
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>fastjson</artifactId>
- <version>1.1.41</version>
- </dependency>
- <!– 簡單日誌門面 –>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- <version>1.7.7</version>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.7.7</version>
- </dependency>
- <!– log end –>
-
- <!–4、 使用jackson處理對象與JSON之間相互轉換 –>
- <dependency>
- <groupId>org.codehaus.jackson</groupId>
- <artifactId>jackson-mapper-asl</artifactId>
- <version>1.9.13</version>
- </dependency>
- <!– 5、上傳組件包 –>
- <!– 需要與commons-io配合使用 –>
- <dependency>
- <groupId>commons-fileupload</groupId>
- <artifactId>commons-fileupload</artifactId>
- <version>1.3.1</version>
- </dependency>
- <!– 開發IO流功能的工具類庫 –>
- <dependency>
- <groupId>commons-io</groupId>
- <artifactId>commons-io</artifactId>
- <version>2.4</version>
- </dependency>
- <!–6、 用來處理常用的編碼方法的工具類包 –>
- <dependency>
- <groupId>commons-codec</groupId>
- <artifactId>commons-codec</artifactId>
- <version>1.9</version>
- </dependency>
- <!– 7、支持servlet的jar包(HttpServletRequest、HttpServletResponse) –>
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>javax.servlet-api</artifactId>
- <version>3.1.0</version>
- </dependency>
- <!–8、shiro相關包 –>
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-core</artifactId>
- <version>1.3.2</version>
- </dependency>
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-web</artifactId>
- <version>1.3.2</version>
- </dependency>
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-ehcache</artifactId>
- <version>1.3.2</version>
- </dependency>
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-spring</artifactId>
- <version>1.3.2</version>
- </dependency>
- <!– shiro整合util方法需要 –>
- <dependency>
- <groupId>com.google.collections</groupId>
- <artifactId>google-collections</artifactId>
- <version>1.0</version>
- </dependency>
- <!– https://mvnrepository.com/artifact/com.google.guava/guava –>
- <dependency>
- <groupId>com.google.guava</groupId>
- <artifactId>guava</artifactId>
- <version>19.0</version>
- </dependency>
- <!– 9、lombok 包–>
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <version>1.16.16</version>
- </dependency>
- <!– 10、編譯jsp –>
- <dependency>
- <groupId>javax.servlet.jsp</groupId>
- <artifactId>jsp-api</artifactId>
- <version>2.2</version>
- </dependency>
- <!– 11、JSTL標籤類 –>
- <dependency>
- <groupId>jstl</groupId>
- <artifactId>jstl</artifactId>
- <version>1.2</version>
- </dependency>
-
- <!– https://mvnrepository.com/artifact/javax.mail/mail –>
- <dependency>
- <groupId>com.fasterxml.jackson.core</groupId>
- <artifactId>jackson-core</artifactId>
- <version>2.8.3</version>
- </dependency>
- <!– https://mvnrepository.com/artifact/org.codehaus.jackson/jackson-core-asl –>
- <dependency>
- <groupId>org.codehaus.jackson</groupId>
- <artifactId>jackson-core-asl</artifactId>
- <version>1.9.13</version>
- </dependency>
- <!– https://mvnrepository.com/artifact/org.codehaus.jackson/jackson-mapper-asl –>
- <dependency>
- <groupId>com.fasterxml.jackson.core</groupId>
- <artifactId>jackson-databind</artifactId>
- <version>2.8.3</version>
- </dependency>
- <!– https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations –>
- <dependency>
- <groupId>com.fasterxml.jackson.core</groupId>
- <artifactId>jackson-annotations</artifactId>
- <version>2.8.3</version>
- </dependency>
-
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-quartz</artifactId>
- <version>1.2.2</version>
- </dependency>
- <!– https://mvnrepository.com/artifact/org.springframework/spring-context-support –>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-context-support</artifactId>
- <version>3.2.8.RELEASE</version>
- </dependency>
- <dependency>
- <groupId>net.sf.ehcache</groupId>
- <artifactId>ehcache-core</artifactId>
- <version>2.6.11</version>
- </dependency>
- <dependency>
- <groupId>commons-collections</groupId>
- <artifactId>commons-collections</artifactId>
- <version>3.2.1</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-test</artifactId>
- <version> 3.2.4.RELEASE </version>
- <scope>provided</scope>
- </dependency>
- </dependencies>
- <build>
- <finalName>Test</finalName>
- <pluginManagement>
- <plugins>
- <!– 逆向工程生成po類以及mapper –>
- <plugin>
- <groupId>org.mybatis.generator</groupId>
- <artifactId>mybatis-generator-maven-plugin</artifactId>
- <version>1.3.2</version>
- <configuration>
- <configurationFile>src/main/resources/generator.xml</configurationFile>
- <verbose>true</verbose>
- <overwrite>true</overwrite>
- </configuration>
- <executions>
- <execution>
- <id>Generate MyBatis Artifacts</id>
- <goals>
- <goal>generate</goal>
- </goals>
- </execution>
- </executions>
- <dependencies>
- <dependency>
- <groupId>org.mybatis.generator</groupId>
- <artifactId>mybatis-generator-core</artifactId>
- <version>1.3.2</version>
- </dependency>
- </dependencies>
- </plugin>
- <!– 運用maven指令進行test –>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <version>2.19.1</version>
- <configuration>
- <skipTests>true</skipTests>
- </configuration>
- </plugin>
- <!– 默認加載本項目下的resource –>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-resources-plugin</artifactId>
- <version>3.0.1</version>
- <configuration>
- <encoding>UTF-8</encoding>
- </configuration>
- </plugin>
- <!– 運行maven指令運行tomcat –>
- <plugin>
- <groupId>org.apache.tomcat.maven</groupId>
- <artifactId>tomcat7-maven-plugin</artifactId>
- <version>2.2</version>
- </plugin>
- </plugins>
- </pluginManagement>
- <!– 掃描的resource目錄 –>
- <resources>
- <resource>
- <directory>src/main/resources</directory>
- <includes>
- <include>**/*</include>
- </includes>
- <filtering>true</filtering>
- </resource>
- </resources>
- </build>
- <!– 根據不同環境配置 –>
- <profiles>
- <profile>
- <id>dev</id>
- <activation>
- <activeByDefault>true</activeByDefault>
- </activation>
- <properties>
- <!– 數據庫 –>
- <ipPort>192.168.*.*:3306/dev_test</ipPort>
- </properties>
- <build>
- <!– 過濾的配置文件 –>
- <filters>
- <filter>src/main/resources/jdbc.properties</filter>
- <filter>src/main/resources/log4j.properties</filter>
- </filters>
- </build>
- </profile>
-
- <profile>
- <id>test</id>
- <properties>
- <!– 數據庫 –>
- <ipPort>192.168.*.*:3306/creditloan_ph</ipPort>
- </properties>
- <build>
- <filters>
- <filter>src/main/resources/jdbc.properties</filter>
- <filter>src/main/resources/log4j.properties</filter>
- </filters>
- </build>
- </profile>
- <profile>
- <id>product</id>
- <properties>
- <!– 數據庫 –>
- <ipPort>192.168.*.*:3306/creditloan_ph</ipPort>
- </properties>
- <build>
- <filters>
- <filter>src/main/resources/jdbc.properties</filter>
- <filter>src/main/resources/log4j.properties</filter>
- </filters>
- </build>
- </profile>
-
- </profiles>
- </project>
附:generator.xml
- <?xml version=“1.0” encoding=“UTF-8”?>
- <!DOCTYPE generatorConfiguration PUBLIC “-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN” “http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd”>
- <generatorConfiguration>
- <!– 數據庫驅動包位置 –>
- <classPathEntry
- location=“E:\apache-maven-3.3.9\repo\mysql\mysql-connector-java\5.1.18\mysql-connector-java-5.1.18.jar” />
- <context id=“Tables” targetRuntime=“MyBatis3”>
- <commentGenerator>
- <!– 是否去除自動生成的註釋 true:是 : false:否 –>
- <property name=“suppressAllComments” value=“true” />
- </commentGenerator>
- <!– 數據庫鏈接URL、用戶名、密碼 –>
- <jdbcConnection driverClass=“com.mysql.jdbc.Driver”
- connectionURL=“jdbc:mysql://192.168.*.*:3306/dev_test” userId=“用戶名”
- password=“密碼”>
- <!–<jdbcConnection driverClass=”oracle.jdbc.driver.OracleDriver” connectionURL=”jdbc:oracle:thin:@localhost:1521:orcl”
- userId=”msa” password=”msa”> –>
- </jdbcConnection>
- <javaTypeResolver>
- <!– 默認false,把JDBC DECIMAL 和 NUMERIC 類型解析爲 Integer, 爲 true時把JDBC DECIMAL和NUMERIC類型解析爲java.math.BigDecimal –>
- <property name=“forceBigDecimals” value=“true” />
- </javaTypeResolver>
- <!– 生成實體類的包名和位置,這裏配置將生成的實體類放在com.loan.entity這個包下 –>
- <javaModelGenerator targetPackage=“com.loan.entity”
- targetProject=“.\src\main\java\”>
- <!– enableSubPackages:是否讓schema作爲包的後綴 –>
- <property name=“enableSubPackages” value=“true” />
- <!– 從數據庫返回的值被清理前後的空格 –>
- <property name=“trimStrings” value=“true” />
- </javaModelGenerator>
- <!– 生成的SQL映射文件包名和位置,這裏配置將生成的SQL映射文件放在com.loan.dao.xml這個包下 –>
- <sqlMapGenerator targetPackage=“com.loan.dao.xml”
- targetProject=“.\src\main\java\”>
- <!– enableSubPackages:是否讓schema作爲包的後綴 –>
- <property name=“enableSubPackages” value=“true” />
- </sqlMapGenerator>
- <!– 生成DAO的包名和位置,這裏配置將生成的dao類放在com.loan.dao.mapper這個包下 –>
- <javaClientGenerator type=“XMLMAPPER”
- targetPackage=“com.loan.dao.mapper” targetProject=“.\src\main\java\”>
- <!– enableSubPackages:是否讓schema作爲包的後綴 –>
- <property name=“enableSubPackages” value=“true” />
- </javaClientGenerator>
- <!– 要生成那些表(更改tableName和domainObjectName就可以) –>
- <table tableName=“sys_user_role” domainObjectName=“UserRole”
- enableCountByExample=“false” enableUpdateByExample=“false”
- enableDeleteByExample=“false” enableSelectByExample=“false”
- selectByExampleQueryId=“false” />
- </context>
- </generatorConfiguration>
二、先把ssm的基本配置貼上來,就不詳細贅述了:
1、application-context.xml(spring管理的相關配置)
- <?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:context="http://www.springframework.org/schema/context"
- xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/mvc
- http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
-
- <!-- 第一步:【1.整合dao】 將Mybatis和Spring進行整合MyBatis和Spring整合,通過Spring管理mapper接口。使用mapper的掃描器自動掃描mapper接口在Spring中進行註冊。 -->
- <!-- 需要配置:a、數據源 b、SqlSessionFactory c、mapper掃描器 -->
- <!-- 1、數據源定義 -->
- <!-- (1)加載jdbc.properties、redis.properties文件中的內容 -->
- <bean id="propertyConfigurer"
- class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
- <property name="locations">
- <list>
- <value>classpath:jdbc.properties</value>
- <!-- <value>classpath:redis.properties</value> -->
- </list>
- </property>
- </bean>
- <!-- (2)mysql數據源配置 -->
- <!-- a、數據源 -->
- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
- destroy-method="close">
- <property name="driverClassName" value="${connection.driverClassName}"</span> /></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="36"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"url"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"${connection.url}" />
- <property name="username" value="${connection.username}"</span> /></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="38"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"${connection.password}" />
- <property name="maxActive" value="${connection.maxActive}"</span> /></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="40"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"maxIdle"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"${connection.maxIdle}" />
- <property name="minIdle" value="${connection.minIdle}"</span> /></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="42"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"removeAbandoned"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"${connection.removeAbandoned}" />
- <property name="removeAbandonedTimeout" value="${connection.removeAbandonedTimeout}"</span> /></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="44"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"logAbandoned"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"${connection.logAbandoned}" />
- <property name="defaultAutoCommit" value="${connection.defaultAutoCommit}"</span> /></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="46"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"defaultReadOnly"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"${connection.defaultReadOnly}" />
- <property name="validationQuery" value="${connection.validationQuery}"</span> /></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="48"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"testOnBorrow"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"${connection.testOnBorrow}" />
- </bean>
- <!-- b、sqlSessionFactory:創建sqlSessionFactory,同時指定數據源 -->
- <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
- <property name="dataSource" ref="dataSource"></property>
- <property name="configLocation" value="classpath:mybatis-config.xml" />
- <!-- 自動掃描mapper目錄, 省掉mybatis-config.xml裏的手工配置 -->
- <property name="mapperLocations">
- <list>
- <value>classpath:com/loan/dao/xml/*.xml</value>
- </list>
- </property>
- </bean>
- <!-- c、mapper掃描器:通過掃描的模式,掃描目錄在com/loan/mapper目錄下 -->
- <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
- <property name="basePackage" value="com.loan.dao.mapper" />
- <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
- </bean>
- <!-- 第二步:通過Spring管理Service接口。使用配置方式將Service接口配置在Spring配置文件中。實現事務控制。 -->
- <!-- (事務管理) -->
- <bean id="transactionManager"
- class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource"></property>
- </bean>
- <!-- 使用annotation定義數據庫事務,這樣可以在類或方法中直接使用@Transactional註解來聲明事務 -->
- <tx:annotation-driven transaction-manager="transactionManager" />
- <tx:advice id="txAdvice" transaction-manager="transactionManager">
- <tx:attributes>
- <tx:method name="save*" propagation="REQUIRED" />
- <tx:method name="update*" propagation="REQUIRED" />
- <tx:method name="delete*" propagation="REQUIRED" />
- <tx:method name="load*" propagation="SUPPORTS" read-only="true" />
- <tx:method name="find*" propagation="SUPPORTS" read-only="true" />
- <tx:method name="search*" propagation="SUPPORTS" read-only="true" />
- <tx:method name="approve" propagation="REQUIRED" />
- <tx:method name="undo" propagation="REQUIRED" />
- <tx:method name="*" propagation="SUPPORTS" read-only="true" />
- </tx:attributes>
- </tx:advice>
- <aop:config>
- <aop:pointcut id="serviceMethod"
- expression="execution(* com.loan.service..*.*(..))" />
- <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod" />
- </aop:config>
- <!-- spring管理:自動搜索註解路徑 在xml配置了這個標籤後,spring可以自動去掃描base-pack下面或者子包下面的Java文件,如果掃描到有@Component @Controller@Service等這些註解的類,則把這些類註冊爲bean-->
- <context:component-scan base-package="com.loan"></context:component-scan>
- </beans>
附:
a、jdbc.properties
connection.driverClassName=com.mysql.jdbc.Driver connection.url=jdbc:mysql://192.168.*.*:3306/dev_test?useUnicode=true&characterEncoding=UTF-8 connection.username=user connection.password=pwd connection.initialSize=0 connection.maxActive=100 connection.maxIdle=30 connection.minIdle=5 connection.maxWait=5000 connection.removeAbandoned=true connection.removeAbandonedTimeout=3000 connection.logAbandoned=false connection.defaultAutoCommit=true connection.defaultReadOnly=false connection.validationQuery=SELECT 1 connection.testOnBorrow=true
b、mybatis-config.xml
- <?xml version=“1.0” encoding=“UTF-8”?>
- <!DOCTYPE configuration PUBLIC “-//mybatis.org//DTD Config 3.0//EN” “http://mybatis.org/dtd/mybatis-3-config.dtd”>
- <configuration>
- <!–整合Spring的時候 只有 settings typeAliases mapper 三個屬性有用, 其餘的要在spring總配置文件中會覆蓋 –>
- <settings>
- <!– 全局映射器,是否啓用緩存 –>
- <setting name=“cacheEnabled” value=“true” />
- <!– 查詢時,關閉關聯對象即時加載以提高性能 –>
- <!– 設置關聯對象加載的形態,此處爲按需加載字段(加載字段由SQL指 定),不會加載關聯表的所有字段,以提高性能 –>
- <setting name=“aggressiveLazyLoading” value=“false” />
- <!– 對於未知的SQL查詢,允許返回不同的結果集以達到通用的效果 –>
- <setting name=“multipleResultSetsEnabled” value=“true” />
- <!– 允許使用列標籤代替列名 –>
- <setting name=“useColumnLabel” value=“true” />
- <!– 允許使用自定義的主鍵值(比如由程序生成的UUID 32位編碼作爲鍵值),數據表的PK生成策略將被覆蓋 –>
- <setting name=“useGeneratedKeys” value=“true” />
- <!– 給予被嵌套的resultMap以字段-屬性的映射支持 –>
- <setting name=“autoMappingBehavior” value=“FULL” />
- <!– 對於批量更新操作緩存SQL以提高性能 –>
- <!– <setting name=”defaultExecutorType” value=”BATCH” /> –>
- <!– 數據庫超過25000秒仍未響應則超時 –>
- <setting name=“defaultStatementTimeout” value=“25000” />
- </settings>
- </configuration>
2、spring-mvc.xml(SpringMVC的相關配置)
- <?xml version=“1.0” encoding=“UTF-8”?>
- <beans xmlns=“http://www.springframework.org/schema/beans”
- xmlns:aop=“http://www.springframework.org/schema/aop” xmlns:context=“http://www.springframework.org/schema/context”
- xmlns:mvc=“http://www.springframework.org/schema/mvc” xmlns:tx=“http://www.springframework.org/schema/tx”
- xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
- xsi:schemaLocation=”http://www.springframework.org/schema/util
- http://www.springframework.org/schema/util/spring-util-3.2.xsd
- http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.2.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
- http://www.springframework.org/schema/jee
- http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
- http://www.springframework.org/schema/mvc
- http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop-3.2.xsd”>
- <!– 使用 mvc:annotation-driven代替註解映射器和註解適配器配置 mvc:annotation-driven默認加載很多的參數綁定方法,
- 比如json轉換解析器就默認加載了,如果使用mvc:annotation-driven不用配置上邊的RequestMappingHandlerMapping和RequestMappingHandlerAdapter
- 實際開發時使用mvc:annotation-driven –>
- <mvc:annotation-driven />
- <context:component-scan base-package=“com.loan” />
- <bean
- class=“org.springframework.web.servlet.view.InternalResourceViewResolver”>
- <property name=“prefix” value=“/WEB-INF/view/” />
- <property name=“suffix” value=“.jsp” />
- </bean>
- </beans>
4、log4j.properties
log4j.rootLogger=INFO, stdout, logfile log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.threshold=INFO log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d \u4FE1\u9500\u7F51\u7AD9\u540E\u53F0\u7BA1\u7406 –>%5p{%F:%L}-%m%n log4j.appender.logfile=org.apache.log4j.DailyRollingFileAppender log4j.appender.logfile.threshold=ERROR log4j.appender.logfile.File=${catalina.home}/logs/Test/Test log4j.appender.logfile.DatePattern=’-‘yyyy-MM-dd-HH-mm’.log’ log4j.appender.logfile.layout=org.apache.log4j.PatternLayout log4j.appender.logfile.layout.ConversionPattern=%d \u4FE1\u9500\u7F51\u7AD9\ –>%5p{%F:%L}-%m%n
5、web.xml
- <?xml version=“1.0” encoding=“UTF-8”?>
- <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”>
- <context-param>
- <param-name>webAppRootKey</param-name>
- <param-value>test</param-value>
- </context-param>
- <context-param>
- <param-name>log4jConfigLocation</param-name>
- <param-value>classpath:log4j.properties</param-value>
- </context-param>
- <listener>
- <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
- </listener>
- <filter>
- <filter-name>CharacterEncodingFilter</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>CharacterEncodingFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>
- classpath:application-context.xml
- classpath:spring-shiro.xml
- </param-value>
- </context-param>
- <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
- <servlet>
- <servlet-name>dispatcher</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>dispatcher</servlet-name>
- <url-pattern>/</url-pattern>
- </servlet-mapping>
- <session-config>
- <session-timeout>30</session-timeout>
- </session-config>
-
- </web-app>
至此,ssm基本配置完成
三、整合shiro
1、spring-shiro.xml
- <beans xmlns=“http://www.springframework.org/schema/beans”
- xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xmlns:p=“http://www.springframework.org/schema/p”
- xmlns:context=“http://www.springframework.org/schema/context”
- xmlns:util=“http://www.springframework.org/schema/util” xmlns:jee=“http://www.springframework.org/schema/jee”
- xmlns:tx=“http://www.springframework.org/schema/tx” xmlns:mvc=“http://www.springframework.org/schema/mvc”
- xmlns:aop=“http://www.springframework.org/schema/aop”
- xsi:schemaLocation=”
- http://www.springframework.org/schema/util
- http://www.springframework.org/schema/util/spring-util-3.0.xsd
- http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
- http://www.springframework.org/schema/jee
- http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
- http://www.springframework.org/schema/mvc
- http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop-3.0.xsd”
- default-lazy-init=“false”>
- <!– 緩存管理器使用Ehcache實現 –>
- <bean id=“cacheManager” class=“org.apache.shiro.cache.ehcache.EhCacheManager”>
- <property name=“cacheManagerConfigFile” value=“classpath:ehcache.xml” />
- </bean>
- <!– 憑證匹配器 –>
- <bean id=“credentialsMatcher” class=“com.loan.credentials.RetryLimitHashedCredentialsMatcher”>
- <constructor-arg ref=“cacheManager” />
- <property name=“hashAlgorithmName” value=“md5” />
- <property name=“hashIterations” value=“2” />
- <property name=“storedCredentialsHexEncoded” value=“true” />
- </bean>
- <!– Realm實現 –>
- <bean id=“userRealm” class=“com.loan.realm.UserRealm”>
- <!– <property name=”userService” ref=”userService” /> –>
- <property name=“credentialsMatcher” ref=“credentialsMatcher” />
- <property name=“cachingEnabled” value=“true” />
- <property name=“authenticationCachingEnabled” value=“true” />
- <property name=“authenticationCacheName” value=“authenticationCache” />
- <property name=“authorizationCachingEnabled” value=“true” />
- <property name=“authorizationCacheName” value=“authorizationCache” />
- </bean>
- <!– 會話ID 生成器 –>
- <bean id=“sessionIdGenerator”
- class=“org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator” />
- <!– 會話DAO –>
- <bean id=“sessionDAO”
- class=“org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO”>
- <property name=“activeSessionsCacheName” value=“shiro-activeSessionCache” />
- <property name=“sessionIdGenerator” ref=“sessionIdGenerator” />
- </bean>
- <!– 會話驗證調度器 sessionValidationInterval:設置調度時間間隔 –>
- <bean id=“sessionValidationScheduler”
- class=“org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler”>
- <property name=“sessionValidationInterval” value=“18000000” />
- <property name=“sessionManager” ref=“sessionManager” />
- </bean>
- <!– 會話Cookie 模板 –>
- <bean id=“sessionIdCookie” class=“org.apache.shiro.web.servlet.SimpleCookie”>
- <constructor-arg value=“sid” />
- <property name=“httpOnly” value=“true” />
- <property name=“maxAge” value=“1800” />
- </bean>
- <!– 記住密碼cookie –>
- <bean id=“rememberMeCookie” class=“org.apache.shiro.web.servlet.SimpleCookie”>
- <constructor-arg value=“rememberMe” />
- <property name=“httpOnly” value=“true” />
- <property name=“maxAge” value=“2592000” /><!– 30天 30*24*60*60 –>
- </bean>
- <!– rememberMe管理器,cipherKey是加密rememberMe Cookie的密鑰;默認AES算 –>
- <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>
- <!– 會話管理器 globalSessionTimeout:設置全局會話超時時間,默認30分鐘,即如果30分鐘內沒有訪問會話將過期 sessionValidationSchedulerEnabled:是否開啓會話驗證器,默認是開啓的 –>
- <bean id=“sessionManager”
- class=“org.apache.shiro.web.session.mgt.DefaultWebSessionManager”>
- <property name=“globalSessionTimeout” value=“18000000” />
- <property name=“deleteInvalidSessions” value=“true” />
- <property name=“sessionValidationSchedulerEnabled” value=“true” />
- <property name=“sessionValidationScheduler” ref=“sessionValidationScheduler” />
- <property name=“sessionDAO” ref=“sessionDAO” />
- <property name=“sessionIdCookieEnabled” value=“true” />
- <property name=“sessionIdCookie” ref=“sessionIdCookie” />
- <property name=“sessionListeners” ref=“sessionListener1” />
- </bean>
- <!– 監聽會話 –>
- <bean id=“sessionListener1” class=“com.loan.util.MySessionListener1”></bean>
- <!– 安全管理器 –>
- <bean id=“securityManager” class=“org.apache.shiro.web.mgt.DefaultWebSecurityManager”>
- <property name=“realm” ref=“userRealm” />
- <property name=“sessionManager” ref=“sessionManager” />
- <property name=“cacheManager” ref=“cacheManager” />
- <property name=“rememberMeManager” ref=“rememberMeManager” />
- </bean>
- <!– kickoutSessionControlFilter 用於控制併發登錄人數的 –>
- <bean id=“kickoutSessionControlFilter”
- class=“com.loan.util.KickoutSessionControlFilter”>
- <property name=“cacheManager” ref=“cacheManager” />
- <property name=“sessionManager” ref=“sessionManager” />
- <property name=“kickoutAfter” value=“false” />
- <property name=“maxSession” value=“2” />
- <property name=“kickoutUrl” value=“/login?kickout=1” />
- </bean>
- <!– 相當於調用SecurityUtils.setSecurityManager(securityManager) –>
- <bean
- class=“org.springframework.beans.factory.config.MethodInvokingFactoryBean”>
- <property name=“staticMethod”
- value=“org.apache.shiro.SecurityUtils.setSecurityManager” />
- <property name=“arguments” ref=“securityManager” />
- </bean>
- <!– Shiro 生命週期處理器 –>
- <bean id=“lifecycleBeanPostProcessor” class=“org.apache.shiro.spring.LifecycleBeanPostProcessor” />
- <bean id=“formAuthenticationFilter”
- class=“org.apache.shiro.web.filter.authc.FormAuthenticationFilter”>
- <property name=“usernameParam” value=“username” />
- <property name=“passwordParam” value=“password” />
- <property name=“rememberMeParam” value=“rememberMe” />
- <property name=“loginUrl” value=“/login” />
- </bean>
- <!– Shiro 的Web過濾器 –>
- <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=“unauthorizedUrl” value=“/unauthorized” />
- <property name=“filters”>
- <util:map>
- <entry key=“authc” value-ref=“formAuthenticationFilter” />
- <entry key=“kickout” value-ref=“kickoutSessionControlFilter”/>
- </util:map>
- </property>
- <property name=“filterChainDefinitions”>
- <value>
- /static/** = anon
- /index = anon
- /unauthorized = anon
- /login =authc
- /logout = logout
- /admin/**=user,kickout
- </value>
- </property>
- </bean>
- <bean
- class=“org.springframework.web.servlet.handler.SimpleMappingExceptionResolver”>
- <property name=“exceptionMappings”>
- <props>
- <prop key=“org.apache.shiro.authz.UnauthorizedException”>
- /unauthorized
- </prop>
- <prop key=“org.apache.shiro.authz.UnauthenticatedException”>
- /login
- </prop>
- </props>
- </property>
- </bean>
- </beans>
附:
a、ehcache.xml
- <?xml version=“1.0” encoding=“UTF-8”?>
- <ehcache name=“es”>
-
- <diskStore path=“java.io.tmpdir”/>
-
- <!– 密碼輸入錯誤 鎖定1小時 –>
- <!– timeToIdleSeconds:設置對象在失效前的允許閒置時間(單位:秒) –>
- <!– timeToLiveSeconds:設置對象在失效前允許存活時間(單位:秒)。最大時間介於創建時間和失效時間之間。僅當eternal=false對象不是永久有效時使用,默認是0.,也就是對象存活時間無窮大。 –>
- <cache name=“passwordRetryCache”
- maxEntriesLocalHeap=“2000”
- eternal=“false”
- timeToIdleSeconds=“3600”
- timeToLiveSeconds=“0”
- overflowToDisk=“false”
- statistics=“true”>
- </cache>
- <!– 權限記錄緩存 鎖定1小時 –>
- <cache name=“authorizationCache”
- maxEntriesLocalHeap=“2000”
- eternal=“false”
- timeToIdleSeconds=“3600”
- timeToLiveSeconds=“0”
- overflowToDisk=“false”
- statistics=“true”>
- </cache>
- <!– 登錄認證記錄緩存 鎖定10分鐘 –>
- <cache name=“authenticationCache”
- maxEntriesLocalHeap=“2000”
- eternal=“false”
- timeToIdleSeconds=“3600”
- timeToLiveSeconds=“0”
- overflowToDisk=“false”
- statistics=“true”>
- </cache>
- <!– 會話次數緩存 –>
- <cache name=“shiro-activeSessionCache”
- maxEntriesLocalHeap=“10000”
- overflowToDisk=“false”
- eternal=“false”
- diskPersistent=“false”
- timeToLiveSeconds=“0”
- timeToIdleSeconds=“0”
- statistics=“true”/>
-
- </ehcache>
b、RetryLimitHashedCredentialsMatcher.java
- package com.loan.credentials;
-
- import java.util.concurrent.atomic.AtomicInteger;
-
- import javax.annotation.Resource;
-
- import org.apache.shiro.authc.AuthenticationInfo;
- import org.apache.shiro.authc.AuthenticationToken;
- import org.apache.shiro.authc.ExcessiveAttemptsException;
- import org.apache.shiro.authc.SaltedAuthenticationInfo;
- import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
- import org.apache.shiro.cache.Cache;
- import org.apache.shiro.cache.CacheManager;
- import org.apache.shiro.crypto.hash.SimpleHash;
- import org.apache.shiro.util.ByteSource;
-
-
- /**
- * <p>
- * User: Zhang Kaitao
- * <p>
- * Date: 14-1-28
- * <p>
- * Version: 1.0
- */
- public class RetryLimitHashedCredentialsMatcher extends
- HashedCredentialsMatcher {
- //AtomicInteger是一個提供原子操作的Integer類,通過線程安全的方式操作加減。
- private Cache<String, AtomicInteger> passwordRetryCache;
-
- public RetryLimitHashedCredentialsMatcher(CacheManager cacheManager) {
- passwordRetryCache = cacheManager.getCache(“passwordRetryCache”);
- }
- //控制密碼輸入錯誤次數
- @Override
- public boolean doCredentialsMatch(AuthenticationToken token,
- AuthenticationInfo info) {
- String username = (String) token.getPrincipal();
- // retry count + 1
- AtomicInteger retryCount = passwordRetryCache.get(username);
- System.out.println(“retryCount:”+retryCount);
- if (retryCount == null) {
- retryCount = new AtomicInteger(0);
- passwordRetryCache.put(username, retryCount);
- }
- if (retryCount.incrementAndGet() > 5) {
- // if retry count > 5 throw
- throw new ExcessiveAttemptsException();
- }
- boolean matches = super.doCredentialsMatch(token, info);
- if (matches) {
- // clear retry count
- passwordRetryCache.remove(username);
- }
-
- return matches;
- }
- }
c、UserRealm.java
- package com.loan.realm;
-
- import org.apache.log4j.Logger;
- import org.apache.shiro.authc.AuthenticationInfo;
- import org.apache.shiro.authc.AuthenticationToken;
- import org.apache.shiro.authc.SimpleAuthenticationInfo;
- import org.apache.shiro.authc.UsernamePasswordToken;
- 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 com.loan.entity.User;
- import com.loan.pojo.UserParams;
- import com.loan.service.ResourceService;
- import com.loan.service.RoleService;
- import com.loan.service.UserRoleService;
- import com.loan.service.UserService;
-
-
- /**
- * @ClassName: UserRealm
- * @Description: TODO(這裏用一句話描述這個類的作用)
- * @author jiayq
- * @date 2016年9月5日 上午10:09:51
- *
- */
- public class UserRealm extends AuthorizingRealm {
- private static final Logger logger = Logger.getLogger(UserRealm.class);
-
- @javax.annotation.Resource
- private UserRoleService userRoleService;
- @javax.annotation.Resource
- private ResourceService resourceService;
- @javax.annotation.Resource
- private UserService userService;
- @javax.annotation.Resource
- private RoleService roleService;
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(
- PrincipalCollection principals) {
- //直接調用getPrimaryPrincipal得到之前傳入的用戶名
- User user = (User) principals.getPrimaryPrincipal();
- logger.info("[用戶:" + user.getUsername() + "|權限授權]");
- SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
- //根據用戶名調用UserService接口獲取角色及權限信息
- authorizationInfo.setRoles(roleService
- .loadRoleIdByUsername(user.getUsername()));
- authorizationInfo.setStringPermissions(resourceService
- .loadPermissionsByUsername(user.getUsername()));
- logger.info("[用戶:" + user.getUsername() + "|權限授權完成]");
- return authorizationInfo;
- }
-
- @Override
- public AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
- // 獲取基於用戶名和密碼的令牌
- // 實際上這個authcToken是從LoginController裏面currentUser.login(token)傳過來的
- UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
- String username = (String) token.getPrincipal();
- System.out.println("pwd:"+token.getCredentials().toString());
- logger.info("[用戶:" + username + "|系統權限認證]");
- User u = new User();
- u.setUsername(username);
- if (userService.find(new UserParams(u)).size() > 0) {
- User sqluser = userService.find(new UserParams(u)).get(0);
- // 交給AuthenticatingRealm使用CredentialsMatcher進行密碼匹配,如果覺得人家的不好可以自定義實現
- System.out.println("Realm:"+ByteSource.Util.bytes(sqluser.getCredentialsSalt()));
- SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(sqluser, sqluser.getPassword(),
- ByteSource.Util.bytes(sqluser.getCredentialsSalt()), this.getName());// realm
- logger.info("[用戶:" + username + "|系統權限認證完成]");
- return authenticationInfo;
- }
- return null;
- }
- }
d、MySessionListener1(用戶測試會話過期時間)
- package com.loan.util;
- import java.util.Date;
-
- import org.apache.shiro.session.Session;
- import org.apache.shiro.session.SessionListener;
-
- public class MySessionListener1 implements SessionListener {
- @Override
- public void onStart(Session session) {//會話創建時觸發
- System.out.println("會話創建:" + session.getId()+"》》時間:"+session.getLastAccessTime());
- }
- @Override
- public void onExpiration(Session session) {//會話過期時觸發
- System.out.println("會話過期:" + session.getId()+"》》時間:"+new Date());
- }
- @Override
- public void onStop(Session session) {//退出/會話過期時觸發
- System.out.println("會話停止:" + session.getId()+"》》時間:"+session.getLastAccessTime());
- }
- }
e、KickoutSessionControlFilter.java
- package com.loan.util;
-
- import java.io.Serializable;
- import java.util.Deque;
- import java.util.LinkedList;
-
- import javax.servlet.ServletRequest;
- import javax.servlet.ServletResponse;
-
- import org.apache.shiro.cache.Cache;
- import org.apache.shiro.cache.CacheManager;
- import org.apache.shiro.session.Session;
- import org.apache.shiro.session.mgt.DefaultSessionKey;
- import org.apache.shiro.session.mgt.SessionManager;
- import org.apache.shiro.subject.Subject;
- import org.apache.shiro.web.filter.AccessControlFilter;
- import org.apache.shiro.web.util.WebUtils;
-
- import com.loan.entity.User;
-
- public class KickoutSessionControlFilter extends AccessControlFilter{
- private String kickoutUrl; //踢出後到的地址
- private boolean kickoutAfter; //踢出之前登錄的/之後登錄的用戶 默認踢出之前登錄的用戶
- private int maxSession; //同一個帳號最大會話數 默認1
- private SessionManager sessionManager;
- private Cache<String, Deque<Serializable>> cache;
-
- public void setKickoutUrl(String kickoutUrl) {
- this.kickoutUrl = kickoutUrl;
- }
-
- public void setKickoutAfter(boolean kickoutAfter) {
- this.kickoutAfter = kickoutAfter;
- }
-
- public void setMaxSession(int maxSession) {
- this.maxSession = maxSession;
- }
-
- public void setSessionManager(SessionManager sessionManager) {
- this.sessionManager = sessionManager;
- }
-
- public void setCacheManager(CacheManager cacheManager) {
- this.cache = cacheManager.getCache("shiro-activeSessionCache");
- }
- /**
- * 是否允許訪問,返回true表示允許
- */
- @Override
- protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
- return false;
- }
- /**
- * 表示訪問拒絕時是否自己處理,如果返回true表示自己不處理且繼續攔截器鏈執行,返回false表示自己已經處理了(比如重定向到另一個頁面)。
- */
- @Override
- protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
- Subject subject = getSubject(request, response);
- if(!subject.isAuthenticated() && !subject.isRemembered()) {
- //如果沒有登錄,直接進行之後的流程
- return true;
- }
-
- Session session = subject.getSession();
- String username = ((User)(subject.getPrincipal())).getUsername();
- Serializable sessionId = session.getId();
-
- // 初始化用戶的隊列放到緩存裏
- Deque<Serializable> deque = cache.get(username);
- if(deque == null) {
- deque = new LinkedList<Serializable>();
- cache.put(username, deque);
- }
-
- //如果隊列裏沒有此sessionId,且用戶沒有被踢出;放入隊列
- if(!deque.contains(sessionId) && session.getAttribute("kickout") == null) {
- deque.push(sessionId);
- }
- //如果隊列裏的sessionId數超出最大會話數,開始踢人
- while(deque.size() > maxSession) {
- Serializable kickoutSessionId = null;
- if(kickoutAfter) { //如果踢出後者
- kickoutSessionId=deque.getFirst();
- kickoutSessionId = deque.removeFirst();
- } else { //否則踢出前者
- kickoutSessionId = deque.removeLast();
- }
- try {
- Session kickoutSession = sessionManager.getSession(new DefaultSessionKey(kickoutSessionId));
- if(kickoutSession != null) {
- //設置會話的kickout屬性表示踢出了
- kickoutSession.setAttribute("kickout", true);
- }
- } catch (Exception e) {//ignore exception
- e.printStackTrace();
- }
- }
-
- //如果被踢出了,直接退出,重定向到踢出後的地址
- if (session.getAttribute("kickout") != null) {
- //會話被踢出了
- try {
- subject.logout();
- } catch (Exception e) {
- }
- WebUtils.issueRedirect(request, response, kickoutUrl);
- return false;
- }
- return true;
- }
- }
2、spring-mvc.xml中加入shiro註解配置
- <!– 配置用於開啓Shiro Spring AOP 權限註解的支持 –>
- <bean
- class=“org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator”
- depends-on=“lifecycleBeanPostProcessor” />
- <aop:config proxy-target-class=“true”></aop:config>
- <bean
- class=“org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor”>
- <property name=“securityManager” ref=“securityManager” />
- </bean>
- <mvc:resources mapping=“/static/**” location=“/static/” cache-period=“2592000”/>
3、web.xml中加入過濾器shiroFilter
- <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>
四、基本配置已經完成,接下來通過簡單的demo對邏輯進行梳理
1、登錄驗證邏輯
(1)建立sys_user數據庫表
(2)實體類User.java
- package com.loan.entity;
-
- import java.io.Serializable;
- import java.util.List;
-
- import lombok.Data;
- /**
- * @ClassName: User
- * @Description: TODO(這裏用一句話描述這個類的作用)
- * @author jiayq
- * @date 2016年9月5日 下午2:31:58
- *
- */
- @SuppressWarnings(“serial”)
- @Data
- public class User implements Serializable {
- private Long id;
- private String username;// 用戶名
- private String workNo;// 工作編號
- private String salt;// 鹽(密碼安全)
- private String password;// 密碼
- private Integer age;// 年齡
- private String state;// 狀態
- private Long orgId;
- private String pic;
- private String phone;
- private String address;
- private String email;
- private Integer percent;
- /**
- * @Title: getCredentialsSalt
- * @Description: salt = salt + username
- * @param @return 設定文件
- * @return String 返回類型
- * @author jiayq
- * @throws
- */
- public String getCredentialsSalt() {
- return username + salt;
- }
-
- }
(3)UserMapper.xml
- <?xml version=“1.0” encoding=“UTF-8”?>
- <!DOCTYPE mapper PUBLIC “-//mybatis.org//DTD Mapper 3.0//EN” “http://mybatis.org/dtd/mybatis-3-mapper.dtd”>
- <mapper namespace=“com.loan.dao.mapper.UserMapper”>
- <!–增加–>
- <insert id=“save” parameterType=“com.loan.entity.User” keyColumn=“id” useGeneratedKeys=“true” keyProperty=“id”>
- insert into sys_user(id,username,work_no,salt,password,age,state,org_id,pic,phone,address,email,percent) values (#{id},#{username},#{workNo},#{salt},#{password},#{age},#{state},#{orgId},#{pic},#{phone},#{address},#{email},#{percent})
- </insert>
- </mapper>
(4)UserMapper.java
- package com.loan.dao.mapper;
-
- import java.util.List;
-
- import com.loan.entity.User;
- import com.loan.pojo.UserParams;
-
-
- /**
- * @ClassName: UserMapper
- * @Description: TODO(這裏用一句話描述這個類的作用)
- * @author jiayq
- * @date 2016年9月29日 下午4:08:43
- *
- */
- public interface UserMapper {
- public void save(User user);
- }
(5)UserService.java
- package com.loan.service;
-
- import java.util.List;
-
- import com.loan.entity.User;
-
- /**
- * @ClassName: UserService
- * @Description: TODO(這裏用一句話描述這個類的作用)
- * @author jiayq
- * @date 2016年9月7日 上午10:09:32
- *
- */
- public interface UserService {
-
- public void save(User user);
-
- }
(6)UserServiceImpl.java
- package com.loan.service.impl;
-
- import java.util.List;
-
- import javax.annotation.Resource;
-
- import org.springframework.stereotype.Service;
-
- import com.loan.dao.mapper.UserMapper;
- import com.loan.dao.mapper.UserRoleMapper;
- import com.loan.entity.User;
- import com.loan.pojo.UserParams;
- import com.loan.service.UserService;
- import com.loan.util.EndecryptUtils;
- import com.loan.util.PasswordHelper;
- /**
- * @ClassName: UserServiceImpl
- * @Description: TODO(這裏用一句話描述這個類的作用)
- * @author jiayq
- * @date 2016年9月6日 上午9:24:49
- *
- */
- @Service("userService")
- public class UserServiceImpl implements UserService {
- @Resource
- private UserMapper userMapper;
- @Resource
- private UserRoleMapper userRoleMapper;
- @Override
- public void save(User user) {
- User u=new PasswordHelper().encryptPassword(user);
- userMapper.save(u);
-
- }
-
- }
(7)PasswordHelper.java
- package com.loan.util;
-
- import org.apache.shiro.authc.SimpleAuthenticationInfo;
- import org.apache.shiro.crypto.RandomNumberGenerator;
- import org.apache.shiro.crypto.SecureRandomNumberGenerator;
- import org.apache.shiro.crypto.hash.SimpleHash;
- import org.apache.shiro.util.ByteSource;
-
- import com.loan.entity.User;
-
- public class PasswordHelper {
- private RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();
- private String algorithmName = “md5”;
- private final int hashIterations = 2;
-
- public User encryptPassword(User user) {
- if(user.getSalt()==null||(“”).equals(user.getSalt())){
- user.setSalt(randomNumberGenerator.nextBytes().toHex());
- }
- String newPassword = new SimpleHash(algorithmName, user.getPassword(),
- ByteSource.Util.bytes(user.getCredentialsSalt()), hashIterations).toHex();
- user.setPassword(newPassword);
- return user;
- }
- }
重點:
(8)新建用戶
- package com.loan.controller;
-
- import javax.annotation.Resource;
-
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.springframework.stereotype.Controller;
- import org.springframework.test.context.ContextConfiguration;
- import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
- import org.springframework.ui.Model;
- import org.springframework.web.bind.annotation.RequestMapping;
-
- import com.loan.entity.User;
- import com.loan.service.UserService;
-
- @Controller
- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration(“classpath:/application-context.xml”)
- @RequestMapping(“/test”)
- public class TestController {
- @Resource
- private UserService userService;
- @Test
- public void userCreate(){
- User user=new User();
- user.setAge(20);
- user.setPassword(“123”);
- user.setUsername(“shiroUser”);
- userService.save(user);
- }
- }
右鍵run as JUnit test
(9)簡單login.jsp頁面進行登錄
- <%@ page contentType="text/html;charset=UTF-8" language="java"%>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta charset="utf-8" />
- <meta http-equiv="X-UA-Compatible" content="IE=edge" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <title>登錄</title>
- <!-- Javascript -->
- <script src="${pageContext.request.contextPath}/static/jquery-1.7.2.js"</span>></span><span class="undefined"></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span>></span><span class="javascript"></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="12"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-comment">//登錄</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="13"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">login</span>(<span class="hljs-params"></span>) </span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="14"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-keyword">if</span> ($(<span class="hljs-string">"#userName"</span>).val() == <span class="hljs-literal">null</span> || $(<span class="hljs-string">"#userName"</span>).val() == <span class="hljs-string">''</span>) {</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="15"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> alert(<span class="hljs-string">"請輸入用戶名!"</span>);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="16"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> ($(<span class="hljs-string">"#pwd"</span>).val() == <span class="hljs-literal">null</span> || $(<span class="hljs-string">"#pwd"</span>).val() == <span class="hljs-string">""</span>) {</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="17"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> alert(<span class="hljs-string">"密碼不能爲空!"</span>);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="18"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> } <span class="hljs-keyword">else</span> {</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="19"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"form"</span>).submit();</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="20"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> }</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="21"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="22"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> }</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="23"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-comment">//keydowm登錄</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="24"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">keydown_login</span>(<span class="hljs-params"></span>) </span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="25"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-built_in">document</span>.onkeydown = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">e</span>)</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="26"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-keyword">var</span> theEvent = <span class="hljs-built_in">window</span>.event || e;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="27"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-keyword">var</span> code = theEvent.keyCode || theEvent.which;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="28"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-keyword">if</span> (code == <span class="hljs-number">13</span> && (<span class="hljs-literal">null</span> != $(<span class="hljs-string">"#pwd"</span>).val())) {</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="29"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> theEvent.returnValue = <span class="hljs-literal">false</span>;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="30"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> theEvent.cancel = <span class="hljs-literal">true</span>;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="31"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"form"</span>).submit();</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="32"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> }</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="33"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> }</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="34"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> }</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="35"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"></<span class="hljs-name">script</span>></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="36"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"></<span class="hljs-name">head</span>></span> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="37"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">body</span>></span> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="38"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag"><<span class="hljs-name">form</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"form"</span> <span class="hljs-attr">action</span>=<span class="hljs-string">"${pageContext.request.contextPath}/loginTest">
- <div class="form-group">
- <label>Username</label>
- <input type="text" name="username" id="userName" />
- <label style="color: red; font-size: 14px; float: right; margin-right: 35px;">${message}</label>
- </div>
- <div class="form-group">
- <label >Password</label>
- <input type="password" name="password" id="pwd" />
- </div>
- <div class="checkbox">
- <label><input type="checkbox" name="rememberMe"/> RemeberMe</label>
- </div>
- <button type="button" class="btn" onclick="login()">Sign in!</button>
- </form>
- </body>
- </html>
(10)LoginController.java
- package com.loan.controller;
-
-
- import javax.annotation.Resource;
- import javax.servlet.http.HttpServletRequest;
-
- import org.apache.shiro.SecurityUtils;
- import org.apache.shiro.authc.AuthenticationException;
- import org.apache.shiro.authc.ExcessiveAttemptsException;
- import org.apache.shiro.authc.IncorrectCredentialsException;
- import org.apache.shiro.authc.UnknownAccountException;
- import org.apache.shiro.authc.UsernamePasswordToken;
- import org.apache.shiro.subject.Subject;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import org.springframework.web.bind.annotation.ResponseBody;
-
- import com.loan.entity.User;
- import com.loan.service.UserService;
- /**
- * @ClassName: LoginController
- * @Description: TODO(登錄controller)
- * @author jiayq
- * @date 2016年9月5日 下午5:06:33
- *
- */
- @Controller
- @RequestMapping("/")
- public class LoginController {
- @Resource
- private UserService userService;
- /**
- * @Title: loginView
- * @Description: TODO(轉向登錄界面)
- * @param @return 設定文件
- * @return String 返回類型
- * @throws
- */
- @RequestMapping(value = "/login")
- public String loginView(){
- return "login";
- }
-
- /**
- * @Title: login1
- * @Description: TODO(shiro+EndecryptUtils進行認證)
- * @param @param request
- * @param @param model
- * @param @param username
- * @param @param password
- * @param @return 設定文件
- * @return String 返回類型
- * @throws
- */
- @RequestMapping(value = "/loginTest")
- public String login(HttpServletRequest request, Model model, String username, String password,boolean rememberMe) {
- System.out.println("rememberMe:"+rememberMe);
- //將form中的用戶名密碼傳入Realm 的doGetAuthenticationInfo
- UsernamePasswordToken token = new UsernamePasswordToken(username, password.toCharArray());
- token.setRememberMe(rememberMe);
- Subject currentUser = SecurityUtils.getSubject();
- String error = "";
- try {
- currentUser.login(token);
- } catch (UnknownAccountException ex) {// 用戶名沒有找到
- error = "您輸入的用戶名不存在!";
- } catch (IncorrectCredentialsException ex) {// 用戶名密碼不匹配
- error = "用戶名密碼不匹配 !";
- }
- catch(ExcessiveAttemptsException e){
- error="密碼錯誤次數已超五次,賬號鎖定1小時!";
- }
- catch (AuthenticationException ex) {// 其他的登錄錯誤
- ex.printStackTrace();
- error = "其他的登錄錯誤 !";
- }
- // 驗證是否成功登錄的方法
- if (currentUser.isAuthenticated()) {
- return "redirect:/admin/index";
- } else {
- model.addAttribute("message", error);
- currentUser.logout();
- return "login";
- }
-
- }
-
-
- }
結果:
重點邏輯:
五、密碼輸入錯誤賬號鎖定功能
六、併發登錄人數控制
七、記住密碼
spring-shiro.xml中相關配置:
jsp:
LoginController.java
八、shiro的權限授權
- package com.loan.entity;
-
- import java.io.Serializable;
- import java.util.List;
-
- import lombok.Data;
- /**
- * @ClassName: User
- * @Description: TODO(這裏用一句話描述這個類的作用)
- * @author jiayq
- * @date 2016年9月5日 下午2:31:58
- *
- */
- @SuppressWarnings(“serial”)
- @Data
- public class User implements Serializable {
- private Long id;
- private String username;// 用戶名
- private String workNo;// 工作編號
- private String salt;// 鹽(密碼安全)
- private String password;// 密碼
- private Integer age;// 年齡
- private String state;// 狀態
- private Long orgId;
- private String pic;
- private String phone;
- private String address;
- private String email;
- private Integer percent;
- /**
- * @Title: getCredentialsSalt
- * @Description: salt = salt + username
- * @param @return 設定文件
- * @return String 返回類型
- * @author jiayq
- * @throws
- */
- public String getCredentialsSalt() {
- return username + salt;
- }
-
- }
- package com.loan.entity;
-
- import java.io.Serializable;
-
- import lombok.Data;
- /**
- * @ClassName: UserRole
- * @Description: TODO(這裏用一句話描述這個類的作用)
- * @author jiayq
- * @date 2016年9月20日 上午10:17:50
- *
- */
- @SuppressWarnings(“serial”)
- @Data
- public class UserRole implements Serializable {
- private Long id;
- private Long roleId;//角色id
- private Long userId;//用戶id
-
- }
- package com.loan.entity;
-
- import java.io.Serializable;
-
- import lombok.Data;
- /**
- * @ClassName: Role
- * @Description: TODO(這裏用一句話描述這個類的作用)
- * @author jiayq
- * @date 2016年9月20日 上午10:15:29
- *
- */
- @SuppressWarnings(“serial”)
- @Data
- public class Role implements Serializable{
- private Long id;
- private String name;//名稱
- private String description;//描述
- private String state;//狀態
- private String code;//編碼
- private Long pid ;//父id
- private String remark;//備註
- //關聯資源列表
- private String resources;
-
-
- }
- package com.loan.entity;
-
- import java.io.Serializable;
- import java.util.ArrayList;
- import java.util.List;
-
- import lombok.Data;
- /**
- * @ClassName: Resource
- * @Description: TODO(這裏用一句話描述這個類的作用)
- * @author jiayq
- * @date 2016年9月19日 下午4:57:11
- *
- */
- @SuppressWarnings(“serial”)
- @Data
- public class Resource implements Serializable{
- private Long id;
- private String name;//名稱
- //private ResourceType type = ResourceType.menu;//資源類型
- private String type;
- private Integer leaf;//0表示是葉子節點
- private Long priority;//順序
- private Long pid;//父id
- private String permission;//權限
- private String status;//狀態
- private String url;//路徑
- private String outUrl;//站外路徑
- private String pic;
- //關聯的角色列表
- private List<Role> roles;
- private List<Resource> children = new ArrayList<Resource>();
- }
- package com.loan.entity;
-
- import java.io.Serializable;
-
- import lombok.Data;
-
- /**
- * @ClassName: RoleResource
- * @Description: TODO(這裏用一句話描述這個類的作用)
- * @author jiayq
- * @date 2016年9月20日 上午10:16:57
- *
- */
- @Data
- public class RoleResource implements Serializable{
- private Long id;
- private Long roleId;//角色id
- private Long resourceId;//資源id
-
- }
2、新建角色Role爲角色分配資源Resource(權限)
- @Test
- public void resourceCreate(){
- //建立三個資源
- for(int i=1;i<4;i++){
- com.loan.entity.Resource resource=new com.loan.entity.Resource();
- resource.setName(“resourceTest_”+i);
- resource.setPermission(“test:permission_”+i);
- resourceService.save(resource);
- }
- }
(2)新建role
- @Test
- public void roleCreate(){
- Role role=new Role();
- role.setName("testRole");
- roleService.save(role);
- for(int i=143;i<146;i++){
- RoleResource roleResource=new RoleResource();
- roleResource.setRoleId(role.getId());
- roleResource.setResourceId((long)i);
- roleResourceService.save(roleResource);
- }
- }
(3)新建user
- @Test
- public void UserCreate(){
- User user=new User();
- user.setAge(20);
- user.setPassword("123");
- user.setUsername("shiroUser1");
- userService.save(user);
- UserRole ur=new UserRole();
- ur.setRoleId((long)25);
- ur.setUserId(user.getId());
- userRoleService.save(ur);
- }
至此,所以關係邏輯建立。
3、UserRealm權限授權
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(
- PrincipalCollection principals) {
- //直接調用getPrimaryPrincipal得到之前傳入的用戶名
- User user = (User) principals.getPrimaryPrincipal();
- logger.info("[用戶:" + user.getUsername() + "|權限授權]");
- SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
- //根據用戶名調用UserService接口獲取角色及權限信息
- authorizationInfo.setRoles(roleService
- .loadRoleIdByUsername(user.getUsername()));
- authorizationInfo.setStringPermissions(resourceService
- .loadPermissionsByUsername(user.getUsername()));
- logger.info("[用戶:" + user.getUsername() + "|權限授權完成]");
- return authorizationInfo;
- }
roleMapper.xml
- <select id="loadRoleIdByUsername" parameterType="java.lang.String" resultMap="Role_resultMap">
- select sr.* from sys_role sr,sys_user su,sys_user_role sur WHERE su.username=#{username} and su.id=sur.user_id and sr.id=sur.role_id
- </select>
resourceMapper.xml
- <select id="loadPermissionByUsername" parameterType="java.lang.String" resultMap="Resource_resultMap">
- SELECT sres.* from sys_user su,sys_user_role sur,sys_role sr,sys_role_resource srr,sys_resource sres WHERE su.username=#{name} and su.id=sur.user_id and sr.id=sur.role_id AND srr.role_id=sr.id and srr.resource_id=sres.id
- </select>
3、通過jsp/註釋測試
(1)jsp
- <%@ page language="java" contentType="text/html; charset=utf-8"
- pageEncoding="utf-8"%>
- <%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <title>test</title>
- <script src="${pageContext.request.contextPath}/static/jquery-1.7.2.js"</span>></span><span class="undefined"></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span>></span><span class="javascript"></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">logout</span>(<span class="hljs-params"></span>)</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="12"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> $.post(<span class="hljs-string">'${pageContext.request.contextPath}/logout'</span>,<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="13"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> location.reload();</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="14"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> });</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="15"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="16"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-tag"></<span class="hljs-name">script</span>></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="17"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-tag"></<span class="hljs-name">head</span>></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="18"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-tag"><<span class="hljs-name">body</span>></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="19"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-tag"><<span class="hljs-name">shiro:guest</span>></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="20"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">歡迎遊客訪問,<span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"${pageContext.request.contextPath}/login">登錄</a>
- </shiro:guest>
- <shiro:user>
- 歡迎<shiro:principal property="username"/>登錄,<a href="javascript:logout();">退出</a>
- </shiro:user>
- <br/>
- <shiro:authenticated>
- 用戶[<shiro:principal property="username"/>]已身份驗證通過
- </shiro:authenticated>
- <br/>
- <shiro:hasRole name="testRole">
- 用戶[<shiro:principal property="username"/>]擁有testRole角色<br/>
- </shiro:hasRole>
- <br/>
- <shiro:hasPermission name="test:permission_1">
- 用戶[<shiro:principal property="username"/>]擁有權限test:permission_1<br/>
- </shiro:hasPermission>
- </body>
- </html>
登錄結果:
(2)通過註解控制方法的訪問:
- @RequiresPermissions("test:permission_1")
- @RequestMapping("/testAnnotation")
- public String testAnnotation(){
- return "/index";
- }
-
- @RequiresPermissions("test:nopermission")
- @RequestMapping("/testAnnotation1")
- public String testAnnotation1(){
- return "index";
- }
測試結果:
終於完了!!!
源代碼下載:http://download.csdn.net/download/dreamer_8399/9959021