目前项目的技术栈:springmvc +shiro+mybatis+mysql+jsp
由于考虑到子系统越来越多后期将项目重构为spirngcloud分布式架构以及缩短运维部署工作量 第一阶段先将系统重构为spirngboot2.1.4-RELEASE单体架构
jdk版本不变:1.8
step1:将原来的pom文件整理重构为springboot依赖的
4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.4.RELEASE com kdlcsoft 3.0 jar kdlcsoft http://www.example.com 2.5.0 1.8 6.0.0 true org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-starter-aop org.springframework.boot spring-boot-starter-cache org.apache.tomcat.embed tomcat-embed-jasper javax.servlet.jsp javax.servlet.jsp-api 2.3.1 javax.servlet javax.servlet-api 3.0.1 javax.servlet jstl 1.2 com.aliyun aliyun-java-sdk-core 4.1.0 org.apache apache-ant-zip 2.3 system ${basedir}/lib/apache-ant-zip-2.3.jar org.bouncycastle bcprov-jdk15on 1.57 commons-fileupload commons-fileupload 1.3.1 commons-httpclient commons-httpclient 3.1-alpha1 com.vdurmont emoji-java 5.1.0 net.sf.ezmorph ezmorph 1.0.6 com.alibaba fastjson 1.2.70 org.freemarker freemarker 2.3.23 com.auth0 java-jwt 2.2.0 javax.inject javax.inject 1 io.jsonwebtoken jjwt 0.7.0 io.jsonwebtoken jjwt 0.7.0 sources jexcelapi jxl 2.6 javax.mail 1.4.7 org.mybatis mybatis 3.2.8 org.mybatis mybatis-spring 1.2.2 mysql mysql-connector-java 5.1.26 com.nimbusds nimbus-jose-jwt 4.10 com.belerweb pinyin4j 2.5.0 dom4j dom4j 1.6.1 org.apache.poi poi 3.10-FINAL org.apache.poi poi-ooxml 3.10-FINAL org.apache.poi poi-ooxml-schemas 3.10-FINAL com.deepoove poi-tl 1.3.1 org.apache.shiro shiro-core 1.2.3 org.apache.shiro shiro-ehcache 1.2.3 org.apache.shiro shiro-spring 1.2.3 org.apache.shiro shiro-web 1.2.3 org.fusesource sigar 1.6.4 org.slf4j slf4j-api 1.7.16 io.springfox springfox-core ${springfox.version} io.springfox springfox-schema ${springfox.version} io.springfox springfox-spi ${springfox.version} io.springfox springfox-spring-web ${springfox.version} io.springfox springfox-swagger2 ${springfox.version} io.springfox springfox-swagger-common ${springfox.version} io.springfox springfox-swagger-ui ${springfox.version} stax stax-api 1.0.1 io.swagger swagger-annotations 1.6.0 io.swagger swagger-models 1.6.0 com.blingblingbang ueditor 1.1.2 com.github.binarywang weixin-java-cp 1.3.4 com.thoughtworks.xstream xstream 1.4.9 com.jfinal enjoy 4.9.21 org.activiti activiti-spring-boot-starter-basic ${activiti.version} de.odysseus.juel juel-spi org.activiti activiti-spring-boot-starter-actuator ${activiti.version} org.activiti activiti-explorer 5.22.0 org.slf4j slf4j-log4j12 org.apache.xmlgraphics batik-codec 1.7 org.springframework.boot spring-boot-starter-amqp org.springframework.amqp spring-rabbit-test test org.springframework spring-test junit junit org.springframework.boot spring-boot-test org.springframework.boot spring-boot-maven-plugin 1.4.2.RELEASE true com.kdlc.KdlcSoftApplication repackage src/main/webapp META-INF/resources/ **/** src/main/resources **/**
这里需要注意的三点:
1) spring的maven plugin 选择用1.4.2-release的版本 不然后期打包为jar部署的jsp前端页面404
如果plugin爆红就先加入依赖中下载 然后去掉即可 idea中maven配置去掉workoffline复选框。
2) springboot自动配置类中解析静态资源的路径为 classpath下面的public static resources meta-inf/resources 等文件夹 所以我们的webapp中内容打包的时候需要打包到上述目录下 我这里打包到了META-INF/resources下
3)springboot中的quatz和shiro-quatz冲突 ,所以我这边去掉了shiro-quatz依赖 具体的schedulor用的啥看shiro配置里面
1.将ssm的classpath下面的配置shiro.properties spirngmvc.properties mybatis.properties application.properties 文件全部删除,换成用@configuration
DataSourceConfig:
@Configuration public class DataSourceConfig { @Value("${mybatis.mapper-locations}") public String mapperPath; @Value("${mybatis.typeAliasesPackage}") public String entityPackage; @Value("${spring.datasource.driver-class-name}") public String jdbcDriver; @Value("${spring.datasource.url}") public String jdbcUrl; @Value("${spring.datasource.username}") public String jdbcUserName; @Value("${spring.datasource.password}") public String jdbcPassword; @Bean(name = "dataSource") public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName(jdbcDriver); dataSource.setUrl(jdbcUrl); dataSource.setUsername(jdbcUserName); dataSource.setPassword(jdbcPassword); return dataSource; } }
shiro:
@Configuration public class ShiroConfig { @Bean public LifecycleBeanPostProcessor createLiftBean() { LifecycleBeanPostProcessor lifecycleBeanPostProcessor =new LifecycleBeanPostProcessor(); return lifecycleBeanPostProcessor; } @Bean(name = "sessionIdGenerator") public JavaUuidSessionIdGenerator sessionIdGenerator() { return new JavaUuidSessionIdGenerator(); } @Bean @ConditionalOnMissingBean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator(); defaultAAP.setProxyTargetClass(true); return defaultAAP; } @Bean(name = "hashedCredentialsMatcher") public RetryLimitHashedCredentialsMatcher hashedCredentialsMatcher( @Qualifier("cacheManager") SpringCacheManagerWrapper cacheManager) { RetryLimitHashedCredentialsMatcher matcher= new RetryLimitHashedCredentialsMatcher(cacheManager); matcher.setHashAlgorithmName("md5"); matcher.setHashIterations(2); matcher.setStoredCredentialsHexEncoded(true); return matcher; } //将自己的验证方式加入容器 @Bean(name = "userRealm") public MyRealm myShiroRealm(@Qualifier("hashedCredentialsMatcher") RetryLimitHashedCredentialsMatcher hashedCredentialsMatcher) { MyRealm customRealm = new MyRealm(); customRealm.setCredentialsMatcher(hashedCredentialsMatcher); customRealm.setAuthenticationCachingEnabled(false); return customRealm; } @Bean(name = "sessionDAO") public EnterpriseCacheSessionDAO sessionDAO() { EnterpriseCacheSessionDAO sessionDAO =new EnterpriseCacheSessionDAO(); sessionDAO.setActiveSessionsCacheName("shiro-activeSessionCache"); sessionDAO.setSessionIdGenerator(sessionIdGenerator()); return sessionDAO; } // 缓存配置 @Bean(name = "cacheManager") public SpringCacheManagerWrapper cacheManager(@Qualifier("springCacheManager") EhCacheCacheManager ehCacheCacheManager) { SpringCacheManagerWrapper cacheManager=new SpringCacheManagerWrapper(); cacheManager.setCacheManager(ehCacheCacheManager); return cacheManager; } // 缓存配置 @Bean(name = "springCacheManager") public EhCacheCacheManager springCacheManager( @Qualifier("ehcacheManager") EhCacheManagerFactoryBean ehcacheManager) { EhCacheCacheManager ehCacheCacheManager =new EhCacheCacheManager(); ehCacheCacheManager.setCacheManager(ehcacheManager.getObject()); ehCacheCacheManager.setTransactionAware(true); return ehCacheCacheManager; } @Bean(name = "ehcacheManager") public EhCacheManagerFactoryBean ehcacheManager() { EhCacheManagerFactoryBean ehcacheManager =new EhCacheManagerFactoryBean(); ehcacheManager.setConfigLocation(new ClassPathResource("ehcache.xml")); return ehcacheManager; } //权限管理,配置主要是Realm的管理认证 @Bean(name = "securityManager") public DefaultWebSecurityManager securityManager(@Qualifier("userRealm") MyRealm myShiroRealm, @Qualifier("cacheManager") SpringCacheManagerWrapper cacheManager ) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myShiroRealm); securityManager.setCacheManager(cacheManager); return securityManager; } //将自己的验证方式加入容器 @Bean(name = "kickoutSessionControlFilter") public KickoutSessionControlFilter kickFilter( @Qualifier("cacheManager") SpringCacheManagerWrapper cacheManager, @Qualifier("sessionManager") DefaultWebSessionManager sessionManager ){ KickoutSessionControlFilter kickoutSessionControlFilter = new KickoutSessionControlFilter(); kickoutSessionControlFilter.setCacheManager(cacheManager); kickoutSessionControlFilter.setSessionManager(sessionManager); kickoutSessionControlFilter.setKickoutAfter(false); kickoutSessionControlFilter.setMaxSession(1); kickoutSessionControlFilter.setKickoutUrl("/admin/login.html"); return kickoutSessionControlFilter; } @Bean(name = "sysUserFilter") public SysUserFilter sysUserFilter(){ return new SysUserFilter(); } //Filter工厂,设置对应的过滤条件和跳转条件 @Bean public ShiroFilterFactoryBean shiroFilter( @Qualifier("securityManager") DefaultWebSecurityManager securityManager, @Qualifier("kickoutSessionControlFilter") KickoutSessionControlFilter kickoutSessionControlFilter, @Qualifier("chainDefinitionSectionMetaSource") ChainDefinitionSectionMetaSource chainDefinitionSectionMetaSource ) throws Exception{ ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 必须设置 SecurityManager shiroFilterFactoryBean.setSecurityManager(securityManager); // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面 shiroFilterFactoryBean.setLoginUrl("/admin/login.html"); // 登录成功后要跳转的链接 shiroFilterFactoryBean.setSuccessUrl("/admin/index.html"); //未授权界面; /*shiroFilterFactoryBean.setUnauthorizedUrl("/noPermission");*/ //拦截器. Mapfilters = new HashMap (); filters.put("sysUser",sysUserFilter()); filters.put("kickout",kickoutSessionControlFilter); //Map filterChainDefinitionMap = new LinkedHashMap<>(); Map filterChainDefinitionMap = chainDefinitionSectionMetaSource.getObject(); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); shiroFilterFactoryBean.setFilters(filters); return shiroFilterFactoryBean; } @Bean(name = "chainDefinitionSectionMetaSource") public ChainDefinitionSectionMetaSource createMetaSource() { ChainDefinitionSectionMetaSource metaSource =new ChainDefinitionSectionMetaSource(); metaSource.setFilterChainDefinitions("\n" + " \t\t/static/** = anon\n" + " \t\t/modules/** = anon\n" + " \t\t/fonts/** = anon\n" + " \t\t/404/** = anon\n" + " \t\t/error.jsp = anon\n" + " \t\t/js/** = anon\n" + " \t\t/swagger-ui.html = anon\n" + " \t\t/webjars/springfox-swagger-ui/** = anon\n" + " \t\t/v2/api-docs = anon\n" + " \t\t/swagger-resources = anon"); return metaSource; } /* @Bean(name = "sessionValidationScheduler") public QuartzSessionValidationScheduler sessionValidationScheduler() { QuartzSessionValidationScheduler scheduler=new QuartzSessionValidationScheduler();//使用内存缓存 scheduler.setSessionValidationInterval(1800000); return scheduler; }*/ @Bean(name = "sessionValidationScheduler") public ExecutorServiceSessionValidationScheduler sessionValidationScheduler() { ExecutorServiceSessionValidationScheduler scheduler=new ExecutorServiceSessionValidationScheduler();//使用内存缓存 scheduler.setInterval(1800000); return scheduler; } @Bean(name = "sessionManager") public DefaultWebSessionManager sessionManager(@Qualifier("sessionDAO") EnterpriseCacheSessionDAO sessionDAO, @Qualifier("sessionValidationScheduler") ExecutorServiceSessionValidationScheduler sessionValidationScheduler ) { DefaultWebSessionManager sessionManager=new DefaultWebSessionManager();//使用内存缓存 sessionManager.setGlobalSessionTimeout(259200000); sessionManager.setDeleteInvalidSessions(true); sessionManager.setSessionValidationSchedulerEnabled(true); sessionManager.setSessionValidationScheduler(sessionValidationScheduler); sessionManager.setSessionDAO(sessionDAO); return sessionManager; } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") DefaultWebSecurityManager securityManager ) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } }
SqlSessionConfig:
@Configuration public class SqlSessionConfig { @Value("${mybatis.mapper-locations}") private String mapperPath; @Value("${mybatis.typeAliasesPackage}") private String entityPackage; @Bean public PagePlugin createPagePlugin() { PagePlugin pagePlugin =new PagePlugin(); Properties properties =new Properties(); properties.put("dialect","mysql"); properties.put("pageSqlId",".*query.*"); pagePlugin.setProperties(properties); return pagePlugin; } @Bean public MyExceptionHandler createExceptionHandler() { MyExceptionHandler myExceptionHandler = new MyExceptionHandler(); return myExceptionHandler; } /* @Bean public MapperScannerConfigurer createMapperConfig() { MapperScannerConfigurer mapperScannerConfigurer =new MapperScannerConfigurer(); mapperScannerConfigurer.setBasePackage("mappings.mapper"); return mapperScannerConfigurer; }*/ @Bean(name="transactionManager") public DataSourceTransactionManager createManger(@Qualifier("dataSource") DataSource dataSource) { DataSourceTransactionManager dataManager=new DataSourceTransactionManager(); dataManager.setDataSource(dataSource); return dataManager; } @Bean(name="manageCache") public ManageCache manageCache() { ManageCache manageCache =new ManageCache(); return manageCache; } @Bean(name="frontCache") public FrontCache frontCache() { FrontCache frontCache =new FrontCache(); return frontCache; } @Bean public SqlSessionFactoryBean createSqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws IOException { SqlSessionFactoryBean sqlSessionFactoryBean = null; try { // 实例SessionFactory sqlSessionFactoryBean = new SqlSessionFactoryBean(); // 配置数据源 sqlSessionFactoryBean.setDataSource(dataSource); // 扫描mapper PathMatchingResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); // 能加载多个,所以可以配置通配符(如:classpath*:mapper/**/*.xml) /* String packageSearchPath = PathMatchingResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX+mapperPath;*/ sqlSessionFactoryBean.setMapperLocations(resourcePatternResolver.getResources(mapperPath)); // 配置mybatis的config文件(我目前用不上) // sqlSessionFactoryBean.setConfigLocation("mybatis-config.xml"); sqlSessionFactoryBean.setTypeAliasesPackage(entityPackage); Interceptor [] array = {createPagePlugin()}; sqlSessionFactoryBean.setPlugins(array); } catch (Exception e) { e.printStackTrace(); } return sqlSessionFactoryBean; } }
WebAppConfig:
@Slf4j @Configuration @EnableWebMvc public class WebAppConfig implements WebMvcConfigurer { private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/","classpath:/public/"}; // "classpath:/modules/", @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/modules/admin/workflow/**") .addResourceLocations("/modules/admin/workflow/"); registry.addResourceHandler("/upload/**") .addResourceLocations("/classpath:/META-INF/resources/upload/"); registry.addResourceHandler("/wap/**") .addResourceLocations("/classpath:/META-INF/resources/wap/"); registry.addResourceHandler("/static/**") .addResourceLocations("classpath:/META-INF/resources/static/"); registry.addResourceHandler("/swagger-ui.html") .addResourceLocations("classpath:/META-INF/resources/"); registry.addResourceHandler("/webjars/") .addResourceLocations("classpath:/META-INF/resources/webjars/"); if (!registry.hasMappingForPattern("/**")) { registry.addResourceHandler("/**").addResourceLocations( CLASSPATH_RESOURCE_LOCATIONS); } } @Bean public InternalResourceViewResolver setupViewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setViewClass(org.springframework.web.servlet.view.JstlView.class); resolver.setPrefix("/"); resolver.setSuffix(".jsp"); return resolver; } @Bean public RequestMappingHandlerMapping createRequestMapping() { RequestMappingHandlerMapping requestMapping = new RequestMappingHandlerMapping(); return requestMapping; } @Override public void extendMessageConverters(List> converters) { StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(); List mediaTypeList = new ArrayList(); mediaTypeList.add(new MediaType("text", "html", Charset.forName("Utf-8"))); mediaTypeList.add(new MediaType("text", "json", Charset.forName("Utf-8"))); mediaTypeList.add(new MediaType("application", "json", Charset.forName("Utf-8"))); stringConverter.setSupportedMediaTypes(mediaTypeList); MappingJackson2HttpMessageConverter jackConverter = new MappingJackson2HttpMessageConverter(); jackConverter.setSupportedMediaTypes(mediaTypeList); converters.add(stringConverter); converters.add(jackConverter); } @Bean public RequestMappingHandlerAdapter createAdapter() { RequestMappingHandlerAdapter requestMappingHandlerAdapter = new RequestMappingHandlerAdapter(); List > converters = new ArrayList<>(); extendMessageConverters(converters); requestMappingHandlerAdapter.setMessageConverters(converters); return requestMappingHandlerAdapter; } @Bean(name = "multipartResolver") public MultipartResolver multipartResolver() { CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(); multipartResolver.setDefaultEncoding("utf-8"); multipartResolver.setMaxUploadSize(10485760000L); multipartResolver.setMaxInMemorySize(40960); return multipartResolver; } @Bean public AuthorizationAttributeSourceAdvisor createAdvidor(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; } @Override public void addInterceptors(InterceptorRegistry registry) { List patherList = new ArrayList (); patherList.add("/admin/login.html"); registry.addInterceptor(new ManageInterceptor()) .addPathPatterns("/admin/**") .excludePathPatterns(patherList); } @Bean public ServletRegistrationBean dispatcherRegistration1(DispatcherServlet dispatcherServlet) { ServletRegistrationBean servletBean = new ServletRegistrationBean(dispatcherServlet, "/kdlcsoft/activitiService/*"); servletBean.setLoadOnStartup(1); servletBean.setName("activitiDispatcher"); return servletBean; } /* @Bean public ServletRegistrationBean dispatcherRegistration(DispatcherServlet dispatcherServlet) { ServletRegistrationBean servletBean = new ServletRegistrationBean(dispatcherServlet, "*.html"); servletBean.setLoadOnStartup(2); servletBean.setName("defaultDispatcher"); return servletBean; }*/ @Bean public RequestContextListener requestContextListenerBean() { return new RequestContextListener(); } /* @Bean public ContextLoaderListener contextLoaderListenerBean() { return new ContextLoaderListener(); }*/ /* @Bean(name = "shiroFilter") public DelegatingFilterProxy shiroFilter() { return new DelegatingFilterProxy(); } @Bean public FilterRegistrationBean delegatingFilterProxy(){ FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); DelegatingFilterProxy proxy = new DelegatingFilterProxy(); proxy.setTargetFilterLifecycle(true); proxy.setTargetBeanName("shiroFilter"); filterRegistrationBean.setFilter(proxy); Collection collection = new ArrayList<>(); collection.add("/*"); filterRegistrationBean.setUrlPatterns(collection); return filterRegistrationBean; }*/ @Bean public SystemListener systemListenerBean() { return new SystemListener(); } @Bean public StdOutErrInitializer stdOutErrInitializerBean() { return new StdOutErrInitializer(); } }
根据自己项目的具体情况来配置addInterceptor拦截器以及addResoureHandler静态资源放行的资源