springMvc改造springboot2.0踩坑
1. 支持jsp
applicaiton.proerties添加配置
#指定视图解析路径前缀 spring.mvc.view.prefix=/WEB-INF/jsp/ #指定视图解析后缀 spring.mvc.view.suffix=.jsp
#jsp修改不需要重启
server.servlet.jsp.init-parameters.development=true
pom.xml
<dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.2</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <!--如果通过Application的方式启动,不可以加scope,如果通过springBoot:run的方式启动,需要加上--> <!--<scope>provided</scope>--> </dependency>
2.Redis配置
package com.xx.config; import com.xx.common.DefaultKeyGenerator; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.cache.RedisCacheWriter; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.lang.Nullable; import redis.clients.jedis.JedisPoolConfig; import java.time.Duration; @Configuration @EnableCaching public class RedisConfig extends CachingConfigurerSupport { @Value("${spring.redis.host}") private String host; @Value("${spring.redis.port}") private int port; /** * 配置RedisTemplate * 设置添加序列化器 * key 使用string序列化器 * value 使用Json序列化器 * 还有一种简答的设置方式,改变defaultSerializer对象的实现。 * @return */ @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { //StringRedisTemplate的构造方法中默认设置了stringSerializer RedisTemplate<String, Object> template = new RedisTemplate<>(); //set key serializer StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); template.setKeySerializer(stringRedisSerializer); template.setConnectionFactory(redisConnectionFactory); template.afterPropertiesSet(); return template; } @Bean public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory){ RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofHours(1)); // 设置缓存有效期一小时 return RedisCacheManager .builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory)) .cacheDefaults(redisCacheConfiguration).build(); } @Override public KeyGenerator keyGenerator() { return new DefaultKeyGenerator(); } }
3.上传文件配置
@Bean //bean的name必须是multipartResolver,否则会出现 xxRequestxx cannot be cast to org.springframework.web.multipart.MultipartHttpServletRequest问题,同时注意common-fileupload,common-io jar包不要缺失冲突 public CommonsMultipartResolver multipartResolver(){ CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(); commonsMultipartResolver.setMaxUploadSize(Long.valueOf(upload_maxSize)); commonsMultipartResolver.setDefaultEncoding("utf-8"); return commonsMultipartResolver; }
4.shiro配置
//放在WebConfig里面
@Bean
//@Primary相同类型bean,按type注入时优先注入
//shiroFilter放前面,否则其他的filter获取的request不是shiro代理对象,(在tokenFilter里,无法获取session的保存的值)
//DelegatingFilterProxy默认实例名为delegatingFilterProxy 的bean,可通过构造参数设置bean实例名
public FilterRegistrationBean<Filter> delegatingFilter(){
DelegatingFilterProxy shiroFilter = new DelegatingFilterProxy("shiroFilter");
shiroFilter.setTargetFilterLifecycle(true);
FilterRegistrationBean<Filter> delegatingFilter = new FilterRegistrationBean<>(shiroFilter);
return delegatingFilter;
}
配置shiroFilter
@Bean public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager")SecurityManager securityManager){
//SysFormAuthenticationFilter和sysLogoutFilter不可以交给spring管理,否则spring会将Filter的类,自动包装为FilterRegistrationBean变为过滤器
SysFormAuthenticationFilter sysFormAuthenticationFilter = new SysFormAuthenticationFilter();
SysLogoutFilter sysLogoutFilter = new SysLogoutFilter();
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager); Map map = new HashMap();
map.put("login",sysFormAuthenticationFilter);
map.put("logout",sysLogoutFilter);
shiroFilterFactoryBean.setFilters(map);
shiroFilterFactoryBean.setLoginUrl("/login.shtml");
shiroFilterFactoryBean.setFilterChainDefinitions("/login.shtml = login " + " /logout.shtml = logout " + " /auth/** = authc " + " /wap/auth/** = authc");
return shiroFilterFactoryBean;
}
5.国际化配置
properties里添加
#国际化文件路径
#basename为包名+配置文件名前缀 spring.messages.basename=i18n/messages spring.messages.use-code-as-default-message=true
同时需要注意的是,国际化配置里,必须有 包名/配置文件名前缀.properties作为默认配置,否则不会生效
6.序列化
原代码 public String toString() { return new GsonBuilder().serializeNulls().setDateFormat("yyyy-MM-dd HH:mm:ss:SSS").create().toJson(this); 之后报错Attempted to serialize java.lang.Class: java.lang.String. Forgot to register a type adapter? 改为 public String toString() { return new GsonBuilder() .registerTypeAdapterFactory(new ClassTypeAdapterFactory()) .registerTypeAdapter(Class.class, new ClassTypeAdapter()) .serializeNulls().setDateFormat("yyyy-MM-dd HH:mm:ss:SSS").create().toJson(this);
public class ClassTypeAdapter extends TypeAdapter<Class<?>> { @Override public void write(JsonWriter jsonWriter, Class<?> clazz) throws IOException { if(clazz == null){ jsonWriter.nullValue(); return; } jsonWriter.value(clazz.getName()); } @Override public Class<?> read(JsonReader jsonReader) throws IOException { if (jsonReader.peek() == JsonToken.NULL) { jsonReader.nextNull(); return null; } Class<?> clazz = null; try { clazz = Class.forName(jsonReader.nextString()); } catch (ClassNotFoundException exception) { throw new IOException(exception); } return clazz; } }
public class ClassTypeAdapterFactory implements TypeAdapterFactory { @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { if(!Class.class.isAssignableFrom(typeToken.getRawType())) { return null; } return (TypeAdapter<T>) new ClassTypeAdapter(); } }