上一篇测试到shiro的自定义realm以及加密。操作起来还是有些复杂的。但是有了spring就不一样了。下面测试shiro与ssm框架的集成。首先先集成ssm框架,ssm框架搭建好之后再集成shiro。
1.新建maven项目导入依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.hzu</groupId>
<artifactId>ssmTemplateDemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<!-- 声明常量 -->
<properties>
<servlet.version>3.1.0</servlet.version>
<jsp.version>2.3.1</jsp.version>
<spring.version>4.3.24.RELEASE</spring.version>
<mybatis.version>3.5.1</mybatis.version>
<mybatis.spring.version>2.0.1</mybatis.spring.version>
<mysql.version>5.1.47</mysql.version>
<pagehelper.version>5.1.10</pagehelper.version>
<druid.version>1.1.19</druid.version>
<log4j.version>1.2.17</log4j.version>
<slf4j.version>1.7.26</slf4j.version>
<jackson.version>2.9.9</jackson.version>
<shiro.version>1.4.1</shiro.version>
</properties>
<dependencies>
<!--servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet.version}</version>
<scope>provided</scope>
</dependency>
<!-- javax.servlet.jsp -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>${jsp.version}</version>
<scope>provided</scope>
</dependency>
<!--spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!-- mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis.spring.version}</version>
</dependency>
<!-- mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- pagehelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>${pagehelper.version}</version>
</dependency>
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<!-- slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- 引入shiro的包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<!-- lombok插件 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.6</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
2.ssm的集成
1.application-dao.xml的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 引进db.properties -->
<context:property-placeholder location="classpath:db.properties" system-properties-mode="FALLBACK"/>
<!--声明数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driver}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${username}"></property>
<property name="password" value="${password}"></property>
<property name="maxActive" value="${maxActive}"></property>
<property name="initialSize" value="${initialSize}"></property>
<property name="maxWait" value="${maxWait}"></property>
<property name="minIdle" value="${minIdle}"></property>
<property name="filters" value="${filters}"></property>
</bean>
<!--
mybatis的全局配置文件的配置的两种使用方式
1.保留全局配置文件,在sqlSessionFactoryBean中指定全局配置文件路径
2.去掉全局配置文件,需要配置的内容配置在org.apache.ibatis.session.Configuration和sqlSessionFactoryBean中,需要两个一起互补
注意:configuration对象和全局配置文件不能一起使用,否则会报错
Error creating bean with name 'sqlsessionFactory' defined in class path resource [application-dao.xml]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Property 'configuration' and 'configLocation' can not specified with together
-->
<!--创建 mybatis的configuration对象,相当于mybatis的全局配置文件-->
<!--大部分可以直接配置在sqlSessionFactoryBean 里面 -->
<bean id="configuration" class="org.apache.ibatis.session.Configuration">
<!--配置日志 -->
<property name="logImpl" value="org.apache.ibatis.logging.stdout.StdOutImpl"></property>
<!-- 配置驼峰命名 -->
<!-- <property name="mapUnderscoreToCamelCase" value="true"></property> -->
</bean>
<!--创建sqlSessionFactory -->
<bean id="sqlsessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--数据源 -->
<property name="dataSource" ref="dataSource"></property>
<!-- 配置配置类 -->
<property name="configuration" ref="configuration"></property>
<!--配置全局配置文件 -->
<!-- <property name="configLocation" value="classpath:mybatis.xml"></property> -->
<!--别名配置 -->
<!-- <property name="typeAliasesPackage" value="xxx包名"></property> -->
<!--扫描mapper.xml传的是数组 -->
<property name="mapperLocations">
<array>
<value>classpath:mapper/*Mapper.xml</value>
<!--多级路径 -->
<!-- <value>classpath:mapper/*/*Mapper.xml</value> -->
</array>
</property>
<!--插件配置,传的也是数组 -->
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor"></bean>
</array>
</property>
</bean>
<!-- 扫描mapper接口,在springboot中用用注解@mapper或@MapperScan -->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.hzu.mapper"></property>
<!-- 配置扫描多个包 -->
<!-- <property name="basePackage">
<value>
包1
包2
</value>
</property> -->
<!-- 注入sqlsessionFactory,这里不写也是可以的,写的话这里的值注意要用value,不能用ref,我也不知道为啥 -->
<property name="sqlSessionFactoryBeanName" value="sqlsessionFactory"></property>
</bean>
</beans>
2.application-service.xml的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--扫描业务层实现类 -->
<context:component-scan base-package="cn.hzu.service.impl"></context:component-scan>
<!--1.配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- DI注解解析器 这个可以不写,因为上面使用了包扫描已经包含了-->
<!-- <context:annotation-config/> -->
<!-- 启动注解事务 -->
<!-- <tx:annotation-driven/> -->
<!-- 2,声明事务的传播特性 也就是通知 -->
<tx:advice id="advise" transaction-manager="transactionManager">
<tx:attributes>
<!-- 以add开头的方法名需要事务 -->
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="change*" propagation="REQUIRED"/>
<tx:method name="reset*" propagation="REQUIRED"/>
<tx:method name="get*" read-only="true"/>
<tx:method name="load*" read-only="true"/>
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 3进行AOP织入 -->
<aop:config>
<!-- 声明切面 可以配置多个-->
<aop:pointcut expression="execution(* cn.hzu.service.impl.*.*(..))" id="pc1"/>
<!-- 织入 -->
<aop:advisor advice-ref="advise" pointcut-ref="pc1"/>
<!-- <aop:advisor advice-ref="advise" pointcut-ref="pc2"/>
<aop:advisor advice-ref="advise" pointcut-ref="pc3"/> -->
</aop:config>
</beans>
3.applicationContext的.xml的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<import resource="classpath:application-dao.xml" />
<import resource="classpath:application-service.xml" />
</beans>
4.springmvc.xml的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!--扫描controller -->
<context:component-scan base-package="cn.hzu.controller"></context:component-scan>
<!-- 配置适配器和映射器,这个注解可以使用springMVC的高级功能 -->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/view/"></property>
<!-- 后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 配置文件上传 -->
<!-- 配置拦截器 -->
<!-- 配置静态资源放行-->
<mvc:default-servlet-handler/>
</beans>
5.log4j.properties的配置
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
6.db.properties的配置
#数据库4要素
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/ssm-shiro?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username=root
password=123456
#连接池信息
maxActive=20
initialSize=1
maxWait=60000
minIdle=1
filters=stat,log4j,wall
7.web.xml的配置
<?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">
<!-- 配置编码过滤器 开始 -->
<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>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<servlet-name>springmvc</servlet-name>
</filter-mapping>
<!-- 配置编码过滤器 结束 -->
<!-- 配置spring的监听器加载 applicationContext.xml开始 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</context-param>
<!-- 配置spring的监听器加载 applicationContext.xml结束 -->
<!-- 配置前端控制器开始 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 注入springmvc.xml -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:springmvc.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>
<!-- 配置前端控制器结束 -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- druid的监控页面配置开始 -->
<servlet>
<servlet-name>StatViewServlet</servlet-name>
<servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
<!-- 配置登陆名 -->
<init-param>
<param-name>loginUsername</param-name>
<param-value>root</param-value>
</init-param>
<!-- 配置密码 -->
<init-param>
<param-name>loginPassword</param-name>
<param-value>123456</param-value>
</init-param>
<!-- 设置白名单 -->
<init-param>
<param-name>allow</param-name>
<!-- <param-value>192.168.1.1,192.168.2.4</param-value>s -->
<param-value></param-value>
</init-param>
<!-- 设置黑名单 -->
<init-param>
<param-name>deny</param-name>
<param-value></param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>StatViewServlet</servlet-name>
<url-pattern>/druid/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>WebStatFilter</filter-name>
<filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
<!-- 注入过滤的样式文件 -->
<init-param>
<param-name>exclusions</param-name>
<param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*</param-value>
</init-param>
<init-param>
<param-name>profileEnable</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>principalCookieName</param-name>
<param-value>USER_COOKIE</param-value>
</init-param>
<init-param>
<param-name>principalSessionName</param-name>
<param-value>USER_SESSION</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>WebStatFilter</filter-name>
<servlet-name>StatViewServlet</servlet-name>
</filter-mapping>
<!-- druid的监控页面配置结束 -->
</web-app>
至此ssm框架集成结束。接下来集成shiro。
3.shiro的集成
1.修改web.xml
在web.xml加入如shiro集成的配置。注意这里的过滤器的名称要和等下shiro的配置文件的过滤器一样
<!-- 配置shiro的集成开始 -->
<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>
<init-param>
<!-- 这里面的shiroFilter必须和application-shiro.xml里面的
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean" >id 一样 -->
<param-name>targetBeanName</param-name>
<param-value>shiroFilter</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<servlet-name>springmvc</servlet-name>
</filter-mapping>
<!-- 配置shiro的集成结束 -->
2.shiro的配置文件
新建shiro.xml。以前配置的安全管理器,凭证匹配器以及自定义的realm在这里面配置。注意过滤器的名称要和web.xml里面写的名称一样。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 声明凭证匹配器 -->
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!-- 加密算法名称 -->
<property name="hashAlgorithmName" value="md5"></property>
<!-- 散列次数 -->
<property name="hashIterations" value="2"></property>
</bean>
<!-- 声明Realm -->
<bean id="userRealm" class="cn.hzu.realm.UserRealm">
<!--注入凭证匹配器 -->
<property name="credentialsMatcher" ref="credentialsMatcher"></property>
</bean>
<!-- 声明安全管理器 ,注意web环境要用这个DefaultWebSecurityManager -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- 注入realm -->
<property name="realm" ref="userRealm"></property>
</bean>
<!-- 配置shiro的过滤器,这里的id必须和web.xml里面的配置一样 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!--注入安全管理器 -->
<property name="securityManager" ref="securityManager"></property>
<!-- 未登录的跳转页面,默认是webapp/login.jsp -->
<property name="loginUrl" value="/index.jsp"></property>
<!--注入未授权的访问页面 -->
<property name="unauthorizedUrl" value="/unauthorized.jsp"></property>
<!--配置过滤器连 -->
<property name="filterChainDefinitions">
<value>
<!-- 放行index.jsp页面 -->
/index.jsp*=anon
<!--放行跳转到登录页面的路径 -->
/login/toLogin*=anon
<!--放行登录的请求 -->
/login/login*=anon
<!--设置登出路径 -->
/login/logout*=logout
<!-- 其他全部拦截 -->
/**=authc
</value>
</property>
</bean>
</beans>
3.把shiro.xml的配置文件加到applicationContext.xml的配置文件中
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<import resource="classpath:application-dao.xml" />
<import resource="classpath:application-service.xml" />
<import resource="classpath:shiro.xml" />
</beans>
至此shiro集成结束。下面进行测试。数据库准备权限的5张表。以及创建在shiro.xml配置的自定义Realm。
4.测试
1.数据库准备
用户表user
角色表role
用户与角色的关系表user_role
权限表permission
角色与权限的关系表role_permission
2.生成对应实体类
User
package cn.hzu.domain;
public class User {
private Integer userid;
private String username;
private String userpwd;
private String sex;
private String address;
public Integer getUserid() {
return userid;
}
public void setUserid(Integer userid) {
this.userid = userid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username == null ? null : username.trim();
}
public String getUserpwd() {
return userpwd;
}
public void setUserpwd(String userpwd) {
this.userpwd = userpwd == null ? null : userpwd.trim();
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex == null ? null : sex.trim();
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address == null ? null : address.trim();
}
}
Role
package cn.hzu.domain;
public class Role {
private Integer roleid;
private String rolename;
public Integer getRoleid() {
return roleid;
}
public void setRoleid(Integer roleid) {
this.roleid = roleid;
}
public String getRolename() {
return rolename;
}
public void setRolename(String rolename) {
this.rolename = rolename == null ? null : rolename.trim();
}
}
Permission
package cn.hzu.domain;
public class Permission {
private Integer perid;
private String pername;
private String percode;
public Integer getPerid() {
return perid;
}
public void setPerid(Integer perid) {
this.perid = perid;
}
public String getPername() {
return pername;
}
public void setPername(String pername) {
this.pername = pername == null ? null : pername.trim();
}
public String getPercode() {
return percode;
}
public void setPercode(String percode) {
this.percode = percode == null ? null : percode.trim();
}
}
3.生成对应的mapper接口
UserMapper
package cn.hzu.mapper;
import org.apache.ibatis.annotations.Param;
import cn.hzu.domain.User;
public interface UserMapper {
int deleteByPrimaryKey(Integer userid);
int insert(User record);
int insertSelective(User record);
User selectByPrimaryKey(Integer userid);
int updateByPrimaryKeySelective(User record);
int updateByPrimaryKey(User record);
//根据用户名查询用户对象
User queryUserByUserName(@Param("username")String username);
}
RoleMapper
package cn.hzu.mapper;
import java.util.List;
import cn.hzu.domain.Role;
public interface RoleMapper {
int deleteByPrimaryKey(Integer roleid);
int insert(Role record);
int insertSelective(Role record);
Role selectByPrimaryKey(Integer roleid);
int updateByPrimaryKeySelective(Role record);
int updateByPrimaryKey(Role record);
//根据用户id查询角色
List<Role> queryRolesByUserId(Integer userId);
}
PermissionMapper
package cn.hzu.mapper;
import java.util.List;
import cn.hzu.domain.Permission;
public interface PermissionMapper {
int deleteByPrimaryKey(Integer perid);
int insert(Permission record);
int insertSelective(Permission record);
Permission selectByPrimaryKey(Integer perid);
int updateByPrimaryKeySelective(Permission record);
int updateByPrimaryKey(Permission record);
//根据用户id查询权限
List<Permission> queryPermissionByUserId(Integer userId);
}
4.生成对应的service接口
UserService
package cn.hzu.service;
import cn.hzu.domain.User;
public interface UserService {
/*
* 根据用户名查询用户对象
*/
public User queryuserByUserName(String username);
}
RoleService
package cn.hzu.service;
import java.util.List;
public interface RoleService {
/*
* 根据用户ID查询角色
*/
public List<String> queryRoleByUserId(Integer userId );
}
PermissionService
package cn.hzu.service;
import java.util.List;
public interface PermissionService {
/*
* 根据用户ID查询权限
*
*/
public List<String> queryPermissionByUserId(Integer userId);
}
5.生成service的实现类
UserServiceImpl
package cn.hzu.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.hzu.domain.User;
import cn.hzu.mapper.UserMapper;
import cn.hzu.service.UserService;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
//根据用户名查询用户
@Override
public User queryuserByUserName(String username) {
return userMapper.queryUserByUserName(username);
}
}
RoleServiceImpl
package cn.hzu.service.impl;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.hzu.domain.Role;
import cn.hzu.mapper.RoleMapper;
import cn.hzu.service.RoleService;
@Service
public class RoleServiceImpl implements RoleService {
@Autowired
private RoleMapper roleMapper;
//根据用户id查询所有的角色
@Override
public List<String> queryRoleByUserId(Integer userId) {
List<Role> list=roleMapper.queryRolesByUserId(userId);
List<String> roles=new ArrayList<String>();
//循环取出角色名放入集合
for (Role role : list) {
roles.add(role.getRolename());
}
return roles;
}
}
PermissionServiceImpl
package cn.hzu.service.impl;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.hzu.domain.Permission;
import cn.hzu.mapper.PermissionMapper;
import cn.hzu.service.PermissionService;
@Service
public class PermissionServiceImpl implements PermissionService {
@Autowired
private PermissionMapper permissionMapper;
//根据用户id查询用户权限
@Override
public List<String> queryPermissionByUserId(Integer userId) {
List<Permission> list=permissionMapper.queryPermissionByUserId(userId);
List<String> permissions=new ArrayList<String>();
//循环取出所有的权限
for (Permission permission : list) {
permissions.add(permission.getPercode());
}
return permissions;
}
}
6.对应的对应的mapper.xml
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="cn.hzu.mapper.UserMapper" >
<resultMap id="BaseResultMap" type="cn.hzu.domain.User" >
<id column="userid" property="userid" jdbcType="INTEGER" />
<result column="username" property="username" jdbcType="VARCHAR" />
<result column="userpwd" property="userpwd" jdbcType="VARCHAR" />
<result column="sex" property="sex" jdbcType="VARCHAR" />
<result column="address" property="address" jdbcType="VARCHAR" />
</resultMap>
<sql id="Base_Column_List" >
userid, username, userpwd, sex, address
</sql>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
select
<include refid="Base_Column_List" />
from user
where userid = #{userid,jdbcType=INTEGER}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
delete from user
where userid = #{userid,jdbcType=INTEGER}
</delete>
<insert id="insert" parameterType="cn.hzu.domain.User" >
insert into User (userid, username, userpwd,
sex, address)
values (#{userid,jdbcType=INTEGER}, #{username,jdbcType=VARCHAR}, #{userpwd,jdbcType=VARCHAR},
#{sex,jdbcType=VARCHAR}, #{address,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="cn.hzu.domain.User" >
insert into user
<trim prefix="(" suffix=")" suffixOverrides="," >
<if test="userid != null" >
userid,
</if>
<if test="username != null" >
username,
</if>
<if test="userpwd != null" >
userpwd,
</if>
<if test="sex != null" >
sex,
</if>
<if test="address != null" >
address,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides="," >
<if test="userid != null" >
#{userid,jdbcType=INTEGER},
</if>
<if test="username != null" >
#{username,jdbcType=VARCHAR},
</if>
<if test="userpwd != null" >
#{userpwd,jdbcType=VARCHAR},
</if>
<if test="sex != null" >
#{sex,jdbcType=VARCHAR},
</if>
<if test="address != null" >
#{address,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="cn.hzu.domain.User" >
update user
<set >
<if test="username != null" >
username = #{username,jdbcType=VARCHAR},
</if>
<if test="userpwd != null" >
userpwd = #{userpwd,jdbcType=VARCHAR},
</if>
<if test="sex != null" >
sex = #{sex,jdbcType=VARCHAR},
</if>
<if test="address != null" >
address = #{address,jdbcType=VARCHAR},
</if>
</set>
where userid = #{userid,jdbcType=INTEGER}
</update>
<update id="updateByPrimaryKey" parameterType="cn.hzu.domain.User" >
update user
set username = #{username,jdbcType=VARCHAR},
userpwd = #{userpwd,jdbcType=VARCHAR},
sex = #{sex,jdbcType=VARCHAR},
address = #{address,jdbcType=VARCHAR}
where userid = #{userid,jdbcType=INTEGER}
</update>
<!-- 根据用户名查询用户 -->
<select id="queryUserByUserName" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from user
where username=#{username}
</select>
</mapper>
RoleMapper.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="cn.hzu.mapper.RoleMapper" >
<resultMap id="BaseResultMap" type="cn.hzu.domain.Role" >
<id column="roleid" property="roleid" jdbcType="INTEGER" />
<result column="rolename" property="rolename" jdbcType="VARCHAR" />
</resultMap>
<sql id="Base_Column_List" >
roleid, rolename
</sql>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
select
<include refid="Base_Column_List" />
from role
where roleid = #{roleid,jdbcType=INTEGER}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
delete from role
where roleid = #{roleid,jdbcType=INTEGER}
</delete>
<insert id="insert" parameterType="cn.hzu.domain.Role" >
insert into role (roleid, rolename)
values (#{roleid,jdbcType=INTEGER}, #{rolename,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="cn.hzu.domain.Role" >
insert into role
<trim prefix="(" suffix=")" suffixOverrides="," >
<if test="roleid != null" >
roleid,
</if>
<if test="rolename != null" >
rolename,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides="," >
<if test="roleid != null" >
#{roleid,jdbcType=INTEGER},
</if>
<if test="rolename != null" >
#{rolename,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="cn.hzu.domain.Role" >
update role
<set >
<if test="rolename != null" >
rolename = #{rolename,jdbcType=VARCHAR},
</if>
</set>
where roleid = #{roleid,jdbcType=INTEGER}
</update>
<update id="updateByPrimaryKey" parameterType="cn.hzu.domain.Role" >
update role
set rolename = #{rolename,jdbcType=VARCHAR}
where roleid = #{roleid,jdbcType=INTEGER}
</update>
<!-- 根据用户名查询角色 -->
<select id="queryRolesByUserId" resultMap="BaseResultMap" >
select t1.* from role t1 inner join user_role t2 on(t1.roleid=t2.roleid)
where t2.userid=#{value}
</select>
</mapper>
PermissionMapper.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="cn.hzu.mapper.PermissionMapper" >
<resultMap id="BaseResultMap" type="cn.hzu.domain.Permission" >
<id column="perid" property="perid" jdbcType="INTEGER" />
<result column="pername" property="pername" jdbcType="VARCHAR" />
<result column="percode" property="percode" jdbcType="VARCHAR" />
</resultMap>
<sql id="Base_Column_List" >
perid, pername, percode
</sql>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
select
<include refid="Base_Column_List" />
from permission
where perid = #{perid,jdbcType=INTEGER}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
delete from permission
where perid = #{perid,jdbcType=INTEGER}
</delete>
<insert id="insert" parameterType="cn.hzu.domain.Permission" >
insert into permission (perid, pername, percode
)
values (#{perid,jdbcType=INTEGER}, #{pername,jdbcType=VARCHAR}, #{percode,jdbcType=VARCHAR}
)
</insert>
<insert id="insertSelective" parameterType="cn.hzu.domain.Permission" >
insert into permission
<trim prefix="(" suffix=")" suffixOverrides="," >
<if test="perid != null" >
perid,
</if>
<if test="pername != null" >
pername,
</if>
<if test="percode != null" >
percode,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides="," >
<if test="perid != null" >
#{perid,jdbcType=INTEGER},
</if>
<if test="pername != null" >
#{pername,jdbcType=VARCHAR},
</if>
<if test="percode != null" >
#{percode,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="cn.hzu.domain.Permission" >
update permission
<set >
<if test="pername != null" >
pername = #{pername,jdbcType=VARCHAR},
</if>
<if test="percode != null" >
percode = #{percode,jdbcType=VARCHAR},
</if>
</set>
where perid = #{perid,jdbcType=INTEGER}
</update>
<update id="updateByPrimaryKey" parameterType="cn.hzu.domain.Permission" >
update permission
set pername = #{pername,jdbcType=VARCHAR},
percode = #{percode,jdbcType=VARCHAR}
where perid = #{perid,jdbcType=INTEGER}
</update>
<!-- 根据用户ID查询权限 -->
<select id="queryPermissionByUserId" resultMap="BaseResultMap">
select distinct t1.* from permission t1 inner join role_permission
t2 inner join user_role t3
on(t1.perid=t2.perid and t2.roleid=t3.roleid)
where t3.userid=#{value}
</select>
</mapper>
7.创建ActivierUser类
这个在上一篇使用过了,就是用户,权限,角色的集合类。用于Realm的授权操作
package cn.hzu.utils;
import java.util.List;
import cn.hzu.domain.User;
/*
* 用户角色权限信息类
*
*/
public class ActivierUser {
private User user;
private List<String> roles;
private List<String> permissions;
public ActivierUser() {
}
public ActivierUser(User user, List<String> roles, List<String> permissions) {
super();
this.user = user;
this.roles = roles;
this.permissions = permissions;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List<String> getRoles() {
return roles;
}
public void setRoles(List<String> roles) {
this.roles = roles;
}
public List<String> getPermissions() {
return permissions;
}
public void setPermissions(List<String> permissions) {
this.permissions = permissions;
}
}
8.创建自定义realm
这个类的写法在上一篇也已经使用过,还分析了为啥要这样写。这个自定义realm在前面的shiro.xml文件中配置了。
UserRealm
package cn.hzu.realm;
import java.util.List;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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.springframework.beans.factory.annotation.Autowired;
import cn.hzu.domain.User;
import cn.hzu.service.PermissionService;
import cn.hzu.service.RoleService;
import cn.hzu.service.UserService;
import cn.hzu.utils.ActivierUser;
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Autowired
private RoleService roleService;
@Autowired
private PermissionService permissionService;
@Override
public String getName() {
return this.getClass().getSimpleName();
}
/*
* 认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//拿到登录的用户名
String username = token.getPrincipal().toString();
//根据用户名查询用户
User user=userService.queryuserByUserName(username);
//如果不为空则进行角色和权限的查询
if (null!=user) {
//查询角色
List<String> roles=roleService.queryRoleByUserId(user.getUserid());
//查询权限
List<String> permissions=permissionService.queryPermissionByUserId(user.getUserid());
//构造ActiveUser
ActivierUser activierUser=new ActivierUser();
activierUser.setUser(user);
activierUser.setPermissions(permissions);
activierUser.setRoles(roles);
//创建盐
ByteSource credentialsSalt=ByteSource.Util.bytes(user.getUsername()+user.getAddress());
//返回给认证器进行认证
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(activierUser, user.getUserpwd(), credentialsSalt,this.getName());
return info;
}else {
return null;
}
}
/*
* 授权
*
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
ActivierUser activierUser = (ActivierUser) principals.getPrimaryPrincipal();
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
List<String> roles = activierUser.getRoles();
List<String> permissions = activierUser.getPermissions();
if(null!=roles&&roles.size()>0) {
info.addRoles(roles);
}
if(null!=permissions&&permissions.size()>0) {
info.addStringPermissions(permissions);
}
return info;
}
}
8.创建登录控制器
LoginController
package cn.hzu.controller;
import javax.servlet.http.HttpSession;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import cn.hzu.utils.ActivierUser;
/**
* 类名称:LoginController
* 类描述: 用户登录控制器
* 创建人:wu
* 创建时间:2020年6月5日 上午10:40:15
*/
@Controller
@RequestMapping("/login")
public class LoginController {
/*
* 跳转到登录页面
*/
@RequestMapping("/toLogin")
public String toLogin(){
return "login";
}
/*
* 登录验证
*/
@RequestMapping("/login")
public String login(String username,String pwd,HttpSession session){
//得到主题对象
Subject subject = SecurityUtils.getSubject();
//构造token
UsernamePasswordToken token=new UsernamePasswordToken(username,pwd);
try {
subject.login(token);
//登录成功之后把角色和权限信息放入session
ActivierUser activierUser=(ActivierUser) subject.getPrincipal();
session.setAttribute("user",activierUser.getUser());
//重定向到用户界面
return "redirect:/user/toUserManager";
} catch (AuthenticationException e) {
e.printStackTrace();
return "redirect:/index.jsp";
}
}
}
9.创建用户控制器
UserController
package cn.hzu.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/user")
public class UserController {
/**
* 跳转到用户管理的页面
*/
@RequestMapping("/toUserManager")
public String toUserManager() {
return "list";
}
@RequestMapping("/query")
@ResponseBody
public Map<String,Object> query(){
Map<String,Object> map=new HashMap<>();
map.put("msg", "query");
return map;
}
@RequestMapping("/add")
@ResponseBody
public Map<String,Object> add(){
Map<String,Object> map=new HashMap<>();
map.put("msg", "add");
return map;
}
@RequestMapping("/update")
@ResponseBody
public Map<String,Object> update(){
Map<String,Object> map=new HashMap<>();
map.put("msg", "update");
return map;
}
@RequestMapping("/delete")
@ResponseBody
public Map<String,Object> delete(){
Map<String,Object> map=new HashMap<>();
map.put("msg", "delete");
return map;
}
@RequestMapping("/export")
@ResponseBody
public Map<String,Object> export(){
Map<String,Object> map=new HashMap<>();
map.put("msg", "export");
return map;
}
}
10.相关的页面
index.jsp。也就是默认的页面,在这个页面跳转到登录页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>Insert title here</title>
</head>
<body>
<jsp:forward page="login/toLogin"></jsp:forward>
</body>
</html>
登录页面login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>Insert title here</title>
</head>
<body>
<h2 align="center">用户登陆</h2>
<form action="${pageContext.request.contextPath}/login/login" method="post">
<table width="30%" align="center" border="1" cellpadding="2" cellspacing="2">
<tr>
<td align="right">用户名:</td>
<td>
<input type="text" name="username" >
</td>
</tr>
<tr>
<td align="right">密码:</td>
<td>
<input type="password" name="pwd" >
</td>
</tr>
<tr>
<td align="center" colspan="2">
<input type="submit" value="登陆">
</td>
</tr>
</table>
</form>
</body>
</html>
list页面
每一个都要具有对应的权限才能看到。
<%@ 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>Insert title here</title>
</head>
<body>
<shiro:hasPermission name="user:query">
<h1><a href="user/query">查询用户</a></h1>
</shiro:hasPermission>
<shiro:hasPermission name="user:add">
<h1><a href="user/add.action">添加用户</a></h1>
</shiro:hasPermission>
<shiro:hasPermission name="user:update">
<h1><a href="user/update">修改用户</a></h1>
</shiro:hasPermission>
<shiro:hasPermission name="user:delete">
<h1><a href="user/delete">删除用户</a></h1>
</shiro:hasPermission>
<shiro:hasPermission name="user:export">
<h1><a href="user/export">导出用户</a></h1>
</shiro:hasPermission>
</body>
</html>
11.启动项目测试
从数据库表中可以看出lisi具有用户查询,用户添加,用户修改三个权限。zhangsan具有用户查询,用户添加,用户修改,用户删除四个权限。
1.用lisi登录
2.用zahngsan登录
12.最终的项目结构
总结:shiro集成ssm主要是配置shiro的配置文件和使用自定义realm以及jsp的标签完成权限控制的,当然如果不是使用的jsp页面,也可以使用thymeleaf的标签完成。下一篇将测试使用注解的方式来完成,不在使用页面。当有权限时才能调用相应的方法。返回相应的jason数据。没有权限或没登录也返回相应的jason数据,实现前后端分离。