springBoot学习 整合mvc,mybatis ,shiro 缓存使用redis (-)

  本人第一次写博客,其中有问题的地方希望大家指正。

     springboot基础安装就不说了,网上太多了。

先贴下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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>test2</groupId>
	<artifactId>test2</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>test2</name>
	<url>http://maven.apache.org</url>

	<!-- spring boot parent节点,引入这个之后,在下面和spring boot相关的就不需要引入版本了; -->
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.9.RELEASE</version>
	</parent>

	<properties>
		<!-- 指定一下jdk的版本 ,这里我们使用jdk 1.8 ,默认是1.6 -->
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>




	<dependencies>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter-redis</artifactId>
		    <version>1.2.8.RELEASE</version>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<optional>true</optional><!-- optional=true,依赖不会传递,该项目依赖devtools;之后依赖该项目的项目如果想要使用devtools,需要重新引入 -->
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<!-- servlet 依赖. -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
		</dependency>

		<!-- tomcat 的支持. -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-jasper</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.3.0</version>
		</dependency>

		<dependency>
    		<groupId>org.apache.shiro</groupId>
    		<artifactId>shiro-spring</artifactId>
    		<version>1.4.0</version>
		</dependency>

	<dependency>
		<groupId>org.apache.shiro</groupId>
		<artifactId>shiro-ehcache</artifactId>
		<version>1.2.3</version>
	</dependency>

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-cache</artifactId>
	</dependency>
	
	</dependencies>
	 <build>
        <plugins>
            <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                  <!--fork :  如果没有该项配置则devtools不会起作用,即应用不会restart -->
                <fork>true</fork>
            </configuration>
            </plugin>
        </plugins>
    </build>
</project>

1.整合mvc

在application.properties配置

##mvc配置spring.mvc.view.prefix=/WEB-INF/jsp/spring.mvc.view.suffix=.jspspring.mvc.static-path-pattern=/static/**spring.resources.static-locations=/WEB-INF/static/

资源目录结构是

因为本人习惯使用jsp,所以没有使用官方推荐的thymeleaf 感觉都是模板引擎技术为什么不用熟悉的,既然都使用

了jsp那目录结构也用webapp了。

2.整合mybatis

##mybatis.typeAliasesPackage=com.**.model  深坑  不能使用通配只好改成全名mybatis.mapperLocations=classpath:mybatis/mapper/**/*.xmlmybatis.configLocations=classpath:mybatis/mybatis-config.xml

这里有个问题就是在配置文件里配置别名,不能使用通配符不知道为什么。接下mybatis全局配置

<?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>
	<!-- 参数设置 -->
	  <!-- 设置运行参数 -->  
    <settings>  
        <!-- 全局映射器启用缓存 -->  
        <setting name="cacheEnabled" value="true" />  
        <!-- 查询时,关闭关联对象及时加载以提高性能 -->  
        <setting name="lazyLoadingEnabled" value="false" />  
        <!-- 设置关联对象加载的形态,此处为按需加载字段(加载字段由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="PARTIAL" />  
        <!-- 对于批量更新操作缓存SQL以提高性能 -->  
        <setting name="defaultExecutorType" value="REUSE" />  
        <!-- 数据库超过25000秒仍未响应则超时 -->  
        <setting name="defaultStatementTimeout" value="25000" />  
        <!-- 打印查询语句 -->  
       <!--  <setting name="logImpl" value="STDOUT_LOGGING" />  --> 
    </settings> 
</configuration>  



这里遇到了一个问题,这里关联对象延迟加载无效,找了好久都没有解决,大神看到了指导一下。

在springmvc我们一般通过映射接口注入到org.mybatis.spring.mapper.MapperScannerConfigurer类bean中basePackage属性

中。而springboot中只需要在启动上加一行注解就可以了

package com;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@EnableTransactionManagement 
@MapperScan("com.**.dao")
public class App {
	
	public static void main(String[] args) {
		SpringApplication.run(App.class, args);
	}
}

这样与mybatsi整合就完成了。

3.整合shiro

学习shiro推荐看这篇博文 , 感觉写的挺好的
http://jinnianshilongnian.iteye.com/blog/2018936/
刚开始整合shiro使用的是shiro官网上和springboot整合的例子。但是官网上的内容太少了,出了bug一直解决不了,所以还是使用shiro-spring的方式整合进去的。
官网例子 是http://shiro.apache.org/spring-boot.html
首先配置real,这个是最重要的实现。
package com.base.shiro;

import java.util.List;

import javax.annotation.Resource;

import org.apache.shiro.SecurityUtils;
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.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.context.annotation.Lazy;

import com.system.model.Role;
import com.system.model.User;
import com.system.service.UserService;
/**
 * shiro验证类
 * @author gl 
 * @time  2018-01-09
 */
public class SystemUserReal extends AuthorizingRealm  {
	
	//@lazy这个注解为了解决缓存问题  应为shiro的bean在rediscach之前注入  导致springboot会默认吧ehcache注入到cache  导致redis缓存配置无效的情况
	//好像通过改变注入顺序  advice实现  具体源码不懂  
	@Resource
	@Lazy
	private UserService userService;
	
	//权限认证
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
	     SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		  User user= (User) SecurityUtils.getSubject().getPrincipal();
		  User newUser=userService.queryByUserName(user.getUsername());
		  Role role=newUser.getRole();
		  if(role!=null){
			  List<com.system.model.Resource> resourceList=role.getList();
			  // 权限信息对象info,用来存放查出的用户的所有的角色(role)及权限(permission)
			  for (com.system.model.Resource resource : resourceList) {
				  info.addStringPermission(resource.getResourceUrl());
			}
		  }
	  
		return info;
	}
	
	//身份认证
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken token) throws AuthenticationException {
		//获取登录时的用户输入的账号密码
		UsernamePasswordToken upToken = (UsernamePasswordToken) token;
		//此处的username字段一定要命名为username  因为登录时自动调用sbuject的login()方法  此时token中username字段自动把前端提交数据用户名set进去
		//如果不相同则用户名取出来的是空的  不过可以自定义令牌(暂时不知道怎么搞  后续补上) 可以通过重写formAuthenticationFilter实现
		String username = (String)upToken.getPrincipal();
		String password=new String( upToken.getPassword());
		//根据用户名获取数据库中的用户信息
		User dUser=userService.queryByUserName(username);
		if(dUser.getPassword().equals(password)){//此处省略密码加密验证 可自定义密码验证类  再返回info时shiro框架会自动进行密码验证
			//设置用户信息session   shiro中的session
			 	Session session = SecurityUtils.getSubject().getSession();
		        session.setAttribute("userSession", dUser);
		        session.setAttribute("userSessionId", dUser.getId());
			return new SimpleAuthenticationInfo(dUser, password, dUser.getUsername());//此处应是真正用户名称 不是账号 此处省略 后续补上
		}
		return null;
	}

}



real中主要实现权限认证,和登录认证。
接下来是shiroconfig  
package com.base.config;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.Filter;

import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.util.StringUtils;

import com.base.shiro.MyFormAuthenticationFilter;
import com.base.shiro.SystemUserReal;
import com.system.dao.ResourceDao;
/**
 * 
 * @author gl
 *遇到的神坑  把@Configuration写成了@Configurable  结果配置无效  找了三天多才发现    我的天啊
 *
 */


@Configuration
public class ShiroConfig {

	
	@Resource
	private ResourceDao resourceDao;
	
	
	// 保证实现了Shiro内部lifecycle函数的bean执行 
	//在此重点说明这个方法,如果不设置为静态方法会导致bean对象无法注入进来,
	   @Bean(name = "lifecycleBeanPostProcessor")
	    public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
	        return new LifecycleBeanPostProcessor();
	    }
	  
	    @Bean(name="ehCacheManager")
	    public EhCacheManager ehCacheManager() {  
	        EhCacheManager em = new EhCacheManager();  
	        em.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");  
	        return em;  
	    } 
	   
	   
	  	@Bean(name="systemUserReal")
	    public  SystemUserReal systemUserReal(){  
	  		SystemUserReal realm = new SystemUserReal(); 
	  	   //启用缓存,默认false
	  		realm.setCachingEnabled(true);
	  	    //  启用身份验证缓存,即缓存AuthenticationInfo信息,默认false;
	  		realm.setAuthenticationCachingEnabled(true);
	  	    //  缓存AuthenticationInfo信息的缓存名称,即配置在ehcache.xml中的cache name
	  		realm.setAuthenticationCacheName("authenticationCache");
	  	    //  启用授权缓存,即缓存AuthorizationInfo信息,默认false;
	  		realm.setAuthorizationCachingEnabled(true);
	  	    //  缓存AuthorizationInfo信息的缓存名称;
	  		realm.setAuthorizationCacheName("authorizationCache");
	  		return realm;
	    }  
	  	
		@Bean(name="securityManager")
	    public SecurityManager  securityManager(@Qualifier("systemUserReal") SystemUserReal authRealm){
	        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
	        //设置realm
	        securityManager.setRealm(authRealm);
	        securityManager.setCacheManager(ehCacheManager());
	        return securityManager;
	    }
		
//	    @Bean(name="myFormAuthenticationFilter")
//	    public MyFormAuthenticationFilter myFormAuthenticationFilter(){
//	    	return new MyFormAuthenticationFilter();
//	    }
	    
		
	    @Bean(name="shirFilter")
	    public  ShiroFilterFactoryBean  shirFilter(@Qualifier("securityManager") SecurityManager securityManager){
	        System.out.println("**************shirFilter**************");
	        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
			shiroFilterFactoryBean.setSecurityManager(securityManager);
	        shiroFilterFactoryBean.setLoginUrl("/login");
	        // 登录成功后要跳转的链接
	        shiroFilterFactoryBean.setSuccessUrl("/index");
	        //未授权界面
	        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
	        Map<String, Filter> filtersMap = shiroFilterFactoryBean.getFilters();
	        //限制相同账号重复登录问题
	        filtersMap.put("authc",new MyFormAuthenticationFilter());
	      	shiroFilterFactoryBean.setFilters(filtersMap);
	      
	        //拦截器
	        Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();

	        //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
	        filterChainDefinitionMap.put("/logout", "logout");
	        filterChainDefinitionMap.put("/static/**","anon");
	        //<!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
	        //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
	        //自定义加载权限资源关系
	        List<com.system.model.Resource> resourcesList = resourceDao.queryAll();
	         for(com.system.model.Resource resource:resourcesList){
	            if (!StringUtils.isEmpty(resource.getResourceUrl())){
	                String permission = "perms[" + resource.getResourceUrl()+ "]";
	                filterChainDefinitionMap.put(resource.getResourceUrl(),permission);
	            }
	        }
	         filterChainDefinitionMap.put("/**", "authc");


	        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
	        return shiroFilterFactoryBean;
	    }
	   
	    
	    /**
	     *  开启shiro aop注解(RequiresRoles等)支持  Controller才能使用@RequiresPermissions
	     *  使用代理方式;所以需要开启代码支持;
	     * @param securityManager
	     * @return
	     */
	    @Bean
	    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager")SecurityManager securityManager){
	        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
	        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
	        return authorizationAttributeSourceAdvisor;
	    }
	    
	    
	    @Bean 
	    @DependsOn({"lifecycleBeanPostProcessor"})
		public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
			DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator(); 
			daap.setProxyTargetClass(true); 
			return daap; 
		} 
	   
	    
	    

//	    @Bean
//	    protected CacheManager cacheManager() {
//	        return new MemoryConstrainedCacheManager();
//	    }

}

以上就是shiro的整合,说下遇到问题。最大的坑就是把配置类注解敲错了,简直晕了。然后就是自定义表单拦截器的注入问题,

不知道为毛用bean注入的方式一直报错只好改成new对象的方式注入了。

4.缓存的使用

这里使用了两个缓存。一个是ehCache作为shiro的缓存,一个是使用redis作为系统缓存,主要缓存查询信息的。

整合ehcache:

首先添加ehcache-shiro.xml配置文件,放到resource目录下。

<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="es">
    <diskStore path="java.io.tmpdir"/>
    <!--
       name:缓存名称。
       maxElementsInMemory:缓存最大数目
       maxElementsOnDisk:硬盘最大缓存个数。 
       eternal:对象是否永久有效,一但设置了,timeout将不起作用。 
       overflowToDisk:是否保存到磁盘,当系统当机时
       timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
       timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
       diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false. 
       diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。 
       diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
       memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。 
       clearOnFlush:内存数量最大时是否清除。
       memoryStoreEvictionPolicy:
       Ehcache的三种清空策略;
          FIFO,first in first out,这个是大家最熟的,先进先出。
          LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
          LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
    -->
    <cache name="authorizationCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>

    <cache name="authenticationCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>

    <cache name="shiro-activeSessionCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>
</ehcache>



然后将ehcache注入bean中

    @Bean(name="ehCacheManager")
   public EhCacheManager ehCacheManager() {  
       EhCacheManager em = new EhCacheManager();  
       em.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");  
       return em;  
   } 

再将缓存注入到securityManager中。

@Bean(name="securityManager")
   public SecurityManager  securityManager(@Qualifier("systemUserReal") SystemUserReal authRealm){
       DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
       //设置realm
       securityManager.setRealm(authRealm);
       securityManager.setCacheManager(ehCacheManager());
       return securityManager;
   }

Shiro提供了CachingRealm,其实现了CacheManagerAware接口,提供了缓存的一些基础实现;另外AuthenticatingRealm及AuthorizingRealm分别提供了对AuthenticationInfo 和AuthorizationInfo信息的缓存。

接着整合redis:

package com.base.config;



import java.util.Arrays;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;



/**
 * @ClassName: RedisConfig
 * @Description: TODO
 * @author: gl
 * @date: 2018年1月17日 下午3:48:34
 */
@Configuration
@EnableCaching
public class RedisConfig {
	
	
	  @Bean(name="redisTemplate")
	    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
	        RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
	        template.setConnectionFactory(factory);
//	        template.setKeySerializer(new StringRedisSerializer());
//	        template.setValueSerializer(new RedisObjectSerializer());
	        return template;
	    }
	
	//将redis缓存设置到spring缓存机制中    后续可以通过注解启动缓存
    @Bean(name="cacheManager")
    public CacheManager cacheManager(@Qualifier("redisTemplate")RedisTemplate<Object, Object> redisTemplate) {
        String[] cacheNames = {"app_default", "users", "blogs", "goods", "configs", "info"};
        RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate, Arrays.asList(cacheNames));
        redisCacheManager.setDefaultExpiration(18000);
        return redisCacheManager;
    }
    
  
    

    

  
}

然后再想使用缓存的地方使用@Cacheable等等缓存注解就可以了。遇到的最大问题就是shiro缓存和redis缓存同时使用时redis缓存无效,后面在网上百度出来答案是加@lazy注解,调整注入bean的顺序解决的。

以上就是全部内容了,还有好多bug没有解决希望大神们指导一波。因为本人也是菜鸟,就没有什么源码讲解,主要是如何配置使用。写的时候参考了好多网上博客的内容,谢谢大神们的分享。

项目下载地址点击打开链接










  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本项目详细介绍请看:http://www.sojson.com/shiro (强烈推荐) Demo已经部署到线上,地址是http://shiro.itboy.net, 管理员帐号:admin,密码:sojson.com 如果密码错误,请用sojson。 PS:你可以注册自己的帐号,然后用管理员赋权限给你自己的帐号,但是,每20分钟会把数据初始化一次。建议自己下载源码,让Demo跑起来,然后跑的更快,有问题加群解决。 声明: 本人提供这个Shiro + SpringMvc + Mybatis + Redis 的Demo 本着学习的态度,如果有欠缺和不足的地方,给予指正,并且多多包涵。 “去其糟粕取其精华”。如果觉得写的好的地方就给个赞,写的不好的地方,也请多多包涵。 使用过程: 1.创建数据库。 创建语句 :tables.sql 2.插入初始化数据 插入初始化数据:init.data.sql 3.运行。 管理员帐号:admin 密码:sojson ps:定时任务的sql会把密码改变为sojson.com 新版本说明:http://www.sojson.com/blog/164.html 和 http://www.sojson.com/blog/165.html 主要解决是之前说的问题:Shiro 教程,关于最近反应的相关异常问题,解决方法合集。 项目在本页面的附件中提取。 一、Cache配置修改。 配置文件(spring-cache.xml )中已经修改为如下配置: <!-- redis 配置,也可以把配置挪到properties配置文件中,再读取 --> <!-- 这种 arguments 构造的方式,之前配置有缺点。 这里之前的配置有问题,因为参数类型不一致,有时候jar和环境的问题,导致参数根据index对应,会处理问题, 理论上加另一个 name,就可以解决,现在把name 和type都加上,更保险。 --> 二、登录获取上一个URL地址报错。 当没有获取到退出前的request ,为null 的时候会报错。在(UserLoginController.java )135行处有所修改。 /** * shiro 获取登录之前的地址 * 之前0.1版本这个没判断空。 */ SavedRequest savedRequest = WebUtils.getSavedRequest(request); String url = null ; if(null != savedRequest){ url = savedRequest.getRequestUrl(); } /** * 我们平常用的获取上一个请求的方式,在Session不一致的情况下是获取不到的 * String url = (String) request.getAttribute(WebUtils.FORWARD_REQUEST_URI_ATTRIBUTE); */ 三、删除了配置文件中的cookie写入域的问题。 在配置文件里(spring-shiro.xml )中的配置有所修改。 <!-- 会话Cookie模板 --> <!--cookie的name,我故意取名叫xxxxbaidu --> <!--cookie的有效时间 --> <!-- 配置存储Session Cookie的domain为 一级域名 --> 上面配置是去掉了 Session 的存储Key 的作用域,之前设置的.itboy.net ,是写到当前域名的 一级域名 下,这样就可以做到N 个 二级域名 下,三级、四级....下 Session 都是共享的。 <!-- 用户信息记住我功能的相关配置 --> <!-- 配置存储rememberMe Cookie的domain为 一级域名 --> <!-- 30天时间,记住我30天 --> 记住我登录的信息配置。和上面配置是一样的道理,可以在相同 一级域名 下的所有域名都可以获取到登录的信息。 四、简单实现了单个帐号只能在一处登录。 我们在其他的系统中可以看到,单个帐号只允许一人使用,在A处登录了,B处再登录,那A处就被踢出了。如下图所示。 但是此功能不是很完美,当A处被踢出后,再重新登录,这时候B处反应有点慢,具体我还没看,因为是之前加的功能,现在凌晨了,下次我有空再瞧瞧,同学你也可以看看,解决了和我说一声,我把功能修复。 五、修复功能(BUG) 1.修复权限添加功能BUG。 之前功能有问题,每当添加一个权限的时候,默认都给角色为“管理员”的角色默认添加当前新添加的权限。这样达到管理员的权限永远是最大的。由于代码有BUG ,导致所有权限删除了。现已修复。 2.修复项目只能部署到Root目录下的问题。 问题描述:之前项目只能部署到Root 下才能正常运行,目前已经修复,可以带项目路径进行访问了,之前只能这样访问,http://localhost:8080 而不能http://localhost:8080/shiro.demo/ 访问,目前是可以了。 解决方案:在 FreeMarkerViewExtend.java 33行处 增加了BasePath ,通过BasePath 来控制请求目录,在 Freemarker 中可以自由使用,而 JSP 中是直接在 JSP 中获取BasePath 使用。 解决后遗症:因为我们的权限是通过URL 来控制的,那么增加了项目的目录,导致权限不能正确的判断,再加上我们的项目名称(目录)可以自定义,导致更不好判断。 后遗症解决方案:PermissionFilter.java 50行处 解决了这个问题,详情请看代码和注释,其实就是replace 了一下。 HttpServletRequest httpRequest = ((HttpServletRequest)request); /** * 此处是改版后,为了兼容项目不需要部署到root下,也可以正常运行,但是权限没设置目前必须到root 的URI, * 原因:如果你把这个项目叫 ShiroDemo,那么路径就是 /ShiroDemo/xxxx.shtml ,那另外一个人使用,又叫Shiro_Demo,那么就要这么控制/Shiro_Demo/xxxx.shtml * 理解了吗? * 所以这里替换了一下,使用根目录开始的URI */ String uri = httpRequest.getRequestURI();//获取URI String basePath = httpRequest.getContextPath();//获取basePath if(null != uri && uri.startsWith(basePath)){ uri = uri.replace(basePath, ""); } 3.项目启动的时候报错,关于JNDI的错误提示。 其实也不是错,但是看着不舒服,所以还得解决这个问题。解决这个问题需要在web.xml 中的开始部位加入以下代码。 spring.profiles.active dev spring.profiles.default dev spring.liveBeansView.mbeanDomain dev 4.项目Maven打包问题。 打包的时候,不同版本的 Eclipse 还有IDEA 会有打包打不进去Mapper.xml 文件,这个时候要加如下代码(群里同学提供的)。 src/main/java **/*.properties **/*.xml false 在 标签内加入即可,如果还是不能解决,那么请你加群(改名后)说明你的问题,有人会回答你。 5.Tomcat7以上在访问JSP页面的时候,提示JSTL错误。 这个错误是因为Tomcat7 中没有 JSTL 的jar包,现在已经在项目pom.xml 中增加了如下 jar 的引入管理。 javax.servlet jstl 1.2 javax.servlet jsp-api 2.0 provided 如果还是不能解决问题,请在官方群(群号:259217951)内搜索“jstl” 如图下载依赖包。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值