jeecg-boot 2.0 模块开发版本发布

This commit is contained in:
zhangdaihao
2019-05-19 18:54:09 +08:00
parent 64fb100ea2
commit 4858af9f33
770 changed files with 85014 additions and 19508 deletions

View File

@ -0,0 +1,28 @@
package org.jeecg.config;
import org.jeecgframework.core.util.ApplicationContextUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author: Scott
* @Date: 2018/2/7
* @description: autopoi 配置类
*/
@Configuration
public class AutoPoiConfig {
/**
* excel注解字典参数支持(导入导出字典值,自动翻译)
* 举例: @Excel(name = "性别", width = 15, dicCode = "sex")
* 1、导出的时候会根据字典配置把值1,2翻译成男、女;
* 2、导入的时候会把男、女翻译成1,2存进数据库;
* @return
*/
@Bean
public ApplicationContextUtil applicationContextUtil() {
return new org.jeecgframework.core.util.ApplicationContextUtil();
}
}

View File

@ -0,0 +1,35 @@
package org.jeecg.config;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
/**
* 单数据源配置jeecg.datasource.open = false时生效
* @Author zhoujf
*
*/
@Configuration
@MapperScan(value={"org.jeecg.modules.**.mapper*"})
public class MybatisPlusConfig {
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
// /**
// * mybatis-plus SQL执行效率插件【生产环境可以关闭】
// */
// @Bean
// public PerformanceInterceptor performanceInterceptor() {
// return new PerformanceInterceptor();
// }
}

View File

@ -0,0 +1,101 @@
package org.jeecg.config;
import java.lang.reflect.Method;
import java.time.Duration;
import javax.annotation.Resource;
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.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping;
@Configuration
@EnableCaching // 开启缓存支持
public class RedisConfig extends CachingConfigurerSupport {
@Resource
private LettuceConnectionFactory lettuceConnectionFactory;
/**
* @description 自定义的缓存key的生成策略 若想使用这个key
* 只需要讲注解上keyGenerator的值设置为keyGenerator即可</br>
* @return 自定义策略生成的key
*/
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuffer sb = new StringBuffer();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
/**
* RedisTemplate配置
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
// 设置序列化
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, Visibility.ANY);
om.enableDefaultTyping(DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置redisTemplate
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
RedisSerializer<?> stringSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer);// key序列化
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// value序列化
redisTemplate.setHashKeySerializer(stringSerializer);// Hash key序列化
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);// Hash value序列化
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
/**
* 缓存配置管理器
*/
@Bean
public CacheManager cacheManager(LettuceConnectionFactory factory) {
// 以锁写入的方式创建RedisCacheWriter对象
RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(factory);
/**
* 设置CacheManager的Value序列化方式为JdkSerializationRedisSerializer,
* 但其实RedisCacheConfiguration默认就是使用 StringRedisSerializer序列化key
* JdkSerializationRedisSerializer序列化value, 所以以下注释代码就是默认实现,没必要写,直接注释掉
*/
// RedisSerializationContext.SerializationPair pair =
// RedisSerializationContext.SerializationPair.fromSerializer(new
// JdkSerializationRedisSerializer(this.getClass().getClassLoader()));
// RedisCacheConfiguration config =
// RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);
// 创建默认缓存配置对象
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1)); // 设置缓存有效期一小时;
RedisCacheManager cacheManager = new RedisCacheManager(writer, config);
return cacheManager;
}
}

View File

@ -0,0 +1,130 @@
package org.jeecg.config;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.Filter;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
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.jeecg.modules.shiro.authc.ShiroRealm;
import org.jeecg.modules.shiro.authc.aop.JwtFilter;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
/**
* @author: Scott
* @date: 2018/2/7
* @description: shiro 配置类
*/
@Configuration
public class ShiroConfig {
/**
* Filter Chain定义说明
*
* 1、一个URL可以配置多个Filter使用逗号分隔
* 2、当设置多个过滤器时全部验证通过才视为通过
* 3、部分过滤器可指定参数如permsroles
*/
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 拦截器
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
// 配置不会被拦截的链接 顺序判断
filterChainDefinitionMap.put("/sys/login", "anon"); //登录接口排除
filterChainDefinitionMap.put("/auth/2step-code", "anon");//登录验证码
filterChainDefinitionMap.put("/sys/common/view/**", "anon");//图片预览不限制token
filterChainDefinitionMap.put("/sys/common/download/**", "anon");//文件下载不限制token
filterChainDefinitionMap.put("/sys/common/pdf/**", "anon");//pdf预览
filterChainDefinitionMap.put("/generic/**", "anon");//pdf预览需要文件
filterChainDefinitionMap.put("/", "anon");
filterChainDefinitionMap.put("/doc.html", "anon");
filterChainDefinitionMap.put("/**/*.js", "anon");
filterChainDefinitionMap.put("/**/*.css", "anon");
filterChainDefinitionMap.put("/**/*.html", "anon");
filterChainDefinitionMap.put("/**/*.svg", "anon");
filterChainDefinitionMap.put("/**/*.jpg", "anon");
filterChainDefinitionMap.put("/**/*.png", "anon");
filterChainDefinitionMap.put("/**/*.ico", "anon");
filterChainDefinitionMap.put("/druid/**", "anon");
filterChainDefinitionMap.put("/swagger-ui.html", "anon");
filterChainDefinitionMap.put("/swagger**/**", "anon");
filterChainDefinitionMap.put("/webjars/**", "anon");
filterChainDefinitionMap.put("/v2/**", "anon");
//性能监控
filterChainDefinitionMap.put("/actuator/metrics/**", "anon");
filterChainDefinitionMap.put("/actuator/httptrace/**", "anon");
filterChainDefinitionMap.put("/actuator/redis/**", "anon");
// 添加自己的过滤器并且取名为jwt
Map<String, Filter> filterMap = new HashMap<String, Filter>(1);
filterMap.put("jwt", new JwtFilter());
shiroFilterFactoryBean.setFilters(filterMap);
// <!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边
filterChainDefinitionMap.put("/**", "jwt");
// 未授权界面返回JSON
shiroFilterFactoryBean.setUnauthorizedUrl("/sys/common/403");
shiroFilterFactoryBean.setLoginUrl("/sys/common/403");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean("securityManager")
public DefaultWebSecurityManager securityManager(ShiroRealm myRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
/*
* 关闭shiro自带的session详情见文档
* http://shiro.apache.org/session-management.html#SessionManagement-
* StatelessApplications%28Sessionless%29
*/
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
securityManager.setSubjectDAO(subjectDAO);
return securityManager;
}
/**
* 下面的代码是添加注解支持
* @return
*/
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
}

View File

@ -0,0 +1,101 @@
package org.jeecg.config;
import java.util.ArrayList;
import java.util.List;
import org.jeecg.modules.shiro.vo.DefContants;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrapUI;
import io.swagger.annotations.ApiOperation;
import springfox.documentation.service.Parameter;
import lombok.extern.slf4j.Slf4j;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* @Author scott
*/
@Slf4j
@Configuration
@EnableSwagger2
@EnableSwaggerBootstrapUI
public class Swagger2Config implements WebMvcConfigurer {
/**
*
* 显示swagger-ui.html文档展示页还必须注入swagger资源
*
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
/**
* swagger2的配置文件这里可以配置swagger2的一些基本的内容比如扫描的包等等
*
* @return Docket
*/
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
//此包路径下的类,才生成接口文档
.apis(RequestHandlerSelectors.basePackage("org.jeecg.modules"))
//加了ApiOperation注解的类才生成接口文档
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build()
.globalOperationParameters(setHeaderToken());
}
/**
* JWT token
* @return
*/
private List<Parameter> setHeaderToken() {
ParameterBuilder tokenPar = new ParameterBuilder();
List<Parameter> pars = new ArrayList<>();
tokenPar.name(DefContants.X_ACCESS_TOKEN).description("token").modelRef(new ModelRef("string")).parameterType("header").required(false).build();
pars.add(tokenPar.build());
return pars;
}
/**
* api文档的详细信息函数,注意这里的注解引用的是哪个
*
* @return
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
// //大标题
.title("Jeecg-Boot 后台服务API接口文档")
// 版本号
.version("1.0")
// .termsOfServiceUrl("NO terms of service")
// 描述
.description("restful 风格接口")
// 作者
// .contact(new Contact("scott", "http://jeecg.org", "jeecgos@163.com"))
// .license("The Apache License, Version 2.0")
// .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
.build();
}
}

View File

@ -0,0 +1,62 @@
package org.jeecg.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Spring Boot 2.0 解决跨域问题
*
* @Author qinfeng
*
*/
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Value("${jeecg.path.upload}")
private String upLoadPath;
@Value("${jeecg.path.webapp}")
private String webAppPath;
@Value("${spring.resource.static-locations}")
private String staticLocations;
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
final CorsConfiguration corsConfiguration = new CorsConfiguration();
/* 是否允许请求带有验证信息 */
corsConfiguration.setAllowCredentials(true);
/* 允许访问的客户端域名 */
corsConfiguration.addAllowedOrigin("*");
/* 允许服务端访问的客户端请求头 */
corsConfiguration.addAllowedHeader("*");
/* 允许访问的方法名,GET POST等 */
corsConfiguration.addAllowedMethod("*");
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
/**
* 静态资源的配置 - 使得可以从磁盘中读取 Html、图片、视频、音频等
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations("file:" + upLoadPath + "//", "file:" + webAppPath + "//")
.addResourceLocations(staticLocations.split(","));
}
/**
* 访问根路径默认跳转 index.html页面 (简化部署方案: 可以把前端打包直接放到项目的 webapp上面的配置
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index.html");
}
}

View File

@ -0,0 +1,164 @@
package org.jeecg.config.mybatis;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.Properties;
import org.apache.ibatis.binding.MapperMethod.ParamMap;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.system.entity.SysUser;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
/**
* mybatis拦截器自动注入创建人、创建时间、修改人、修改时间
* @Author scott
* @Date 2019-01-19
*
*/
@Slf4j
@Component
@Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
public class MybatisInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
String sqlId = mappedStatement.getId();
log.debug("------sqlId------" + sqlId);
SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
Object parameter = invocation.getArgs()[1];
log.debug("------sqlCommandType------" + sqlCommandType);
if (parameter == null) {
return invocation.proceed();
}
if (SqlCommandType.INSERT == sqlCommandType) {
Field[] fields = oConvertUtils.getAllFields(parameter);
for (Field field : fields) {
log.debug("------field.name------" + field.getName());
try {
// 获取登录用户信息
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
if ("createBy".equals(field.getName())) {
field.setAccessible(true);
Object local_createBy = field.get(parameter);
field.setAccessible(false);
if (local_createBy == null || local_createBy.equals("")) {
String createBy = "jeecg";
if (sysUser != null) {
// 登录账号
createBy = sysUser.getUsername();
}
if (oConvertUtils.isNotEmpty(createBy)) {
field.setAccessible(true);
field.set(parameter, createBy);
field.setAccessible(false);
}
}
}
// 注入创建时间
if ("createTime".equals(field.getName())) {
field.setAccessible(true);
Object local_createDate = field.get(parameter);
field.setAccessible(false);
if (local_createDate == null || local_createDate.equals("")) {
field.setAccessible(true);
field.set(parameter, new Date());
field.setAccessible(false);
}
}
//注入部门编码
if ("sysOrgCode".equals(field.getName())) {
field.setAccessible(true);
Object local_sysOrgCode = field.get(parameter);
field.setAccessible(false);
if (local_sysOrgCode == null || local_sysOrgCode.equals("")) {
String sysOrgCode = "";
// 获取登录用户信息
if (sysUser != null) {
// 登录账号
sysOrgCode = sysUser.getOrgCode();
}
if (oConvertUtils.isNotEmpty(sysOrgCode)) {
field.setAccessible(true);
field.set(parameter, sysOrgCode);
field.setAccessible(false);
}
}
}
} catch (Exception e) {
}
}
}
if (SqlCommandType.UPDATE == sqlCommandType) {
Field[] fields = null;
if (parameter instanceof ParamMap) {
ParamMap<?> p = (ParamMap<?>) parameter;
parameter = p.get("param1");
fields = oConvertUtils.getAllFields(parameter);
} else {
fields = oConvertUtils.getAllFields(parameter);
}
for (Field field : fields) {
log.debug("------field.name------" + field.getName());
try {
if ("updateBy".equals(field.getName())) {
field.setAccessible(true);
Object local_updateBy = field.get(parameter);
field.setAccessible(false);
if (local_updateBy == null || local_updateBy.equals("")) {
String updateBy = "jeecg";
// 获取登录用户信息
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
if (sysUser != null) {
// 登录账号
updateBy = sysUser.getUsername();
}
if (oConvertUtils.isNotEmpty(updateBy)) {
field.setAccessible(true);
field.set(parameter, updateBy);
field.setAccessible(false);
}
}
}
if ("updateTime".equals(field.getName())) {
field.setAccessible(true);
Object local_updateDate = field.get(parameter);
field.setAccessible(false);
if (local_updateDate == null || local_updateDate.equals("")) {
field.setAccessible(true);
field.set(parameter, new Date());
field.setAccessible(false);
}
}
} catch (Exception e) {
}
}
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// TODO Auto-generated method stub
}
}