Merge branch '2.3dev'

pull/170/head
dqjdda 2019-11-01 19:42:29 +08:00
commit fd9fb2a600
227 changed files with 3427 additions and 3711 deletions

View File

@ -21,13 +21,12 @@ eladmin基于 Spring Boot 2.1.0 、 Jpa、 Spring Security、redis、Vue的前
| | 后端源码 | 前端源码 | | | 后端源码 | 前端源码 |
|--- |--- | --- | |--- |--- | --- |
| github | https://github.com/elunez/eladmin | https://github.com/elunez/eladmin-qd | | github | https://github.com/elunez/eladmin | https://github.com/elunez/eladmin-web |
| 码云 | https://gitee.com/elunez/eladmin | https://gitee.com/elunez/eladmin-qt | | 码云 | https://gitee.com/elunez/eladmin | https://gitee.com/elunez/eladmin-web |
#### 系统功能 #### 系统功能
- 用户管理提供用户的相关配置新增用户后默认密码为123456 - 用户管理提供用户的相关配置新增用户后默认密码为123456
- 角色管理:对权限与菜单进行分配,可根据部门设置角色的数据权限 - 角色管理:对权限与菜单进行分配,可根据部门设置角色的数据权限
- 权限管理:权限细化到接口,可以理解成按钮权限
- 菜单管理:已实现菜单动态路由,后端可配置化,支持多级菜单 - 菜单管理:已实现菜单动态路由,后端可配置化,支持多级菜单
- 部门管理:可配置系统组织架构,树形表格展示 - 部门管理:可配置系统组织架构,树形表格展示
- 岗位管理:配置各个部门的职位 - 岗位管理:配置各个部门的职位
@ -44,16 +43,19 @@ eladmin基于 Spring Boot 2.1.0 、 Jpa、 Spring Security、redis、Vue的前
- 支付宝支付:整合了支付宝支付并且提供了测试账号,可自行测试 - 支付宝支付:整合了支付宝支付并且提供了测试账号,可自行测试
#### 项目结构 #### 项目结构
项目采用分模块开发方式,将通用的配置放在公共模块,```system```模块为系统核心模块也是项目入口模块,```logging``` 模块为系统的日志模块,```tools``` 为第三方工具模块,包含了图床、邮件、七牛云、支付宝,```generator``` 为系统的代码生成模块 项目采用按功能分模块开发方式,将通用的配置放在公共模块,```system```模块为系统核心模块也是项目入口模块,```logging``` 模块为系统的日志模块,```tools``` 为第三方工具模块,包含了图床、邮件、七牛云、支付宝,```generator``` 为系统的代码生成模块
- eladmin-common 公共模块 - eladmin-common 公共模块
- exception 项目统一异常的处理 - annotation 为系统自定义注解
- mapper mapstruct的通用mapper - aspect 自定义注解的切面
- redis redis缓存相关配置 - base 提供了Entity、DTO基类和mapstruct的通用mapper
- swagger2 接口文档配置 - config 自定义权限实现、redis配置、swagger配置
- utils 系统通用工具类 - exception 项目统一异常的处理
- utils 系统通用工具类
- eladmin-system 系统核心模块(系统启动入口) - eladmin-system 系统核心模块(系统启动入口)
- config 配置跨域与静态资源,与数据权限 - config 配置跨域与静态资源,与数据权限
- modules 系统相关模块(登录授权、定时任务等) - thread 线程池相关
- modules 系统相关模块(登录授权、系统监控、定时任务等)
- eladmin-logging 系统日志模块 - eladmin-logging 系统日志模块
- eladmin-tools 系统第三方工具模块 - eladmin-tools 系统第三方工具模块
- eladmin-generator 系统代码生成模块 - eladmin-generator 系统代码生成模块
@ -78,6 +80,6 @@ eladmin基于 Spring Boot 2.1.0 、 Jpa、 Spring Security、redis、Vue的前
</table> </table>
#### 项目捐赠 #### 项目捐赠
项目的发展离不开你的支持,请作者喝杯咖啡吧 ☕! [Donate](https://docs.auauz.net/#/jz) 项目的发展离不开你的支持,请作者喝杯咖啡吧ps辣条也行 ☕! [Donate](https://docs.auauz.net/#/jz)
#### 反馈交流 #### 反馈交流
- QQ交流群891137268 - QQ交流群891137268

View File

@ -5,11 +5,10 @@
<parent> <parent>
<artifactId>eladmin</artifactId> <artifactId>eladmin</artifactId>
<groupId>me.zhengjie</groupId> <groupId>me.zhengjie</groupId>
<version>2.2</version> <version>2.3</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>eladmin-common</artifactId> <artifactId>eladmin-common</artifactId>
<name>公共模块</name> <name>公共模块</name>
</project> </project>

View File

@ -0,0 +1,16 @@
package me.zhengjie.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author jacky
* 访
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnonymousAccess {
}

View File

@ -13,45 +13,42 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface Query { public @interface Query {
/** Dong ZhaoYang 2017/8/7 基本对象的属性名 */ // Dong ZhaoYang 2017/8/7 基本对象的属性名
String propName() default ""; String propName() default "";
/** Dong ZhaoYang 2017/8/7 查询方式 */ // Dong ZhaoYang 2017/8/7 查询方式
Type type() default Type.EQUAL; Type type() default Type.EQUAL;
/** /**
* Userdept * Userdept
* @return
*/ */
String joinName() default ""; String joinName() default "";
/** /**
* *
* @return
*/ */
Join join() default Join.LEFT; Join join() default Join.LEFT;
/** /**
* String, @Query(blurry = "email,username") * String, @Query(blurry = "email,username")
* @return
*/ */
String blurry() default ""; String blurry() default "";
enum Type { enum Type {
/** jie 2019/6/4 相等 */ // jie 2019/6/4 相等
EQUAL EQUAL
/** Dong ZhaoYang 2017/8/7 大于等于 */ // Dong ZhaoYang 2017/8/7 大于等于
, GREATER_THAN , GREATER_THAN
/** Dong ZhaoYang 2017/8/7 小于等于 */ // Dong ZhaoYang 2017/8/7 小于等于
, LESS_THAN , LESS_THAN
/** Dong ZhaoYang 2017/8/7 中模糊查询 */ // Dong ZhaoYang 2017/8/7 中模糊查询
, INNER_LIKE , INNER_LIKE
/** Dong ZhaoYang 2017/8/7 左模糊查询 */ // Dong ZhaoYang 2017/8/7 左模糊查询
, LEFT_LIKE , LEFT_LIKE
/** Dong ZhaoYang 2017/8/7 右模糊查询 */ // Dong ZhaoYang 2017/8/7 右模糊查询
, RIGHT_LIKE , RIGHT_LIKE
/** Dong ZhaoYang 2017/8/7 小于 */ // Dong ZhaoYang 2017/8/7 小于
, LESS_THAN_NQ , LESS_THAN_NQ
//** jie 2019/6/4 包含 */ // jie 2019/6/4 包含
, IN , IN
} }

View File

@ -12,7 +12,6 @@ import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature; import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript; import org.springframework.data.redis.core.script.RedisScript;
@ -23,10 +22,13 @@ import java.lang.reflect.Method;
@Aspect @Aspect
@Component @Component
public class LimitAspect { public class LimitAspect {
@Autowired
private RedisTemplate redisTemplate; private final RedisTemplate<Object,Object> redisTemplate;
private static final Logger logger = LoggerFactory.getLogger(LimitAspect.class); private static final Logger logger = LoggerFactory.getLogger(LimitAspect.class);
public LimitAspect(RedisTemplate<Object,Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Pointcut("@annotation(me.zhengjie.annotation.Limit)") @Pointcut("@annotation(me.zhengjie.annotation.Limit)")
public void pointcut() { public void pointcut() {
@ -41,20 +43,18 @@ public class LimitAspect {
LimitType limitType = limit.limitType(); LimitType limitType = limit.limitType();
String key = limit.key(); String key = limit.key();
if (StringUtils.isEmpty(key)) { if (StringUtils.isEmpty(key)) {
switch (limitType) { if (limitType == LimitType.IP) {
case IP: key = StringUtils.getIp(request);
key = StringUtils.getIP(request); } else {
break; key = signatureMethod.getName();
default:
key = signatureMethod.getName();
} }
} }
ImmutableList keys = ImmutableList.of(StringUtils.join(limit.prefix(), "_", key, "_", request.getRequestURI().replaceAll("/","_"))); ImmutableList<Object> keys = ImmutableList.of(StringUtils.join(limit.prefix(), "_", key, "_", request.getRequestURI().replaceAll("/","_")));
String luaScript = buildLuaScript(); String luaScript = buildLuaScript();
RedisScript<Number> redisScript = new DefaultRedisScript<>(luaScript, Number.class); RedisScript<Number> redisScript = new DefaultRedisScript<>(luaScript, Number.class);
Number count = (Number) redisTemplate.execute(redisScript, keys, limit.count(), limit.period()); Number count = redisTemplate.execute(redisScript, keys, limit.count(), limit.period());
if (null != count && count.intValue() <= limit.count()) { if (null != count && count.intValue() <= limit.count()) {
logger.info("第{}次访问key为 {},描述为 [{}] 的接口", count, keys, limit.name()); logger.info("第{}次访问key为 {},描述为 [{}] 的接口", count, keys, limit.name());
return joinPoint.proceed(); return joinPoint.proceed();

View File

@ -1,7 +1,12 @@
package me.zhengjie.aspect; package me.zhengjie.aspect;
/**
*
* @author /
*/
public enum LimitType { public enum LimitType {
// 默认
CUSTOMER, CUSTOMER,
// by ip addr // by ip addr
IP; IP;
} }

View File

@ -0,0 +1,21 @@
package me.zhengjie.base;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.sql.Timestamp;
/**
* @author Zheng Jie
* @Date 2019102420:48:53
*/
@Getter
@Setter
public class BaseDTO implements Serializable {
private Boolean isDelete;
private Timestamp createTime;
private Timestamp updateTime;
}

View File

@ -0,0 +1,50 @@
package me.zhengjie.base;
import lombok.*;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import java.io.Serializable;
import java.sql.Timestamp;
import java.lang.reflect.Field;
/**
* @author Zheng Jie
* @Date 2019102420:46:32
*/
@Getter
@Setter
@MappedSuperclass
public class BaseEntity implements Serializable {
// 删除标识
@Column(name = "is_delete", columnDefinition = "bit default 0")
private Boolean isDelete = false;
@Column(name = "create_time")
@CreationTimestamp
private Timestamp createTime;
@Column(name = "update_time")
@UpdateTimestamp
private Timestamp updateTime;
public @interface Update {}
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
Field[] fields = this.getClass().getDeclaredFields();
try {
for (Field f : fields) {
f.setAccessible(true);
builder.append(f.getName(), f.get(this)).append("\n");
}
} catch (Exception e) {
builder.append("toString builder encounter an error");
}
return builder.toString();
}
}

View File

@ -1,4 +1,4 @@
package me.zhengjie.mapper; package me.zhengjie.base;
import java.util.List; import java.util.List;
@ -6,33 +6,25 @@ import java.util.List;
* @author Zheng Jie * @author Zheng Jie
* @date 2018-11-23 * @date 2018-11-23
*/ */
public interface EntityMapper<D, E> { public interface BaseMapper<D, E> {
/** /**
* DTOEntity * DTOEntity
* @param dto
* @return
*/ */
E toEntity(D dto); E toEntity(D dto);
/** /**
* EntityDTO * EntityDTO
* @param entity
* @return
*/ */
D toDto(E entity); D toDto(E entity);
/** /**
* DTOEntity * DTOEntity
* @param dtoList
* @return
*/ */
List <E> toEntity(List<D> dtoList); List <E> toEntity(List<D> dtoList);
/** /**
* EntityDTO * EntityDTO
* @param entityList
* @return
*/ */
List <D> toDto(List<E> entityList); List <D> toDto(List<E> entityList);
} }

View File

@ -0,0 +1,25 @@
package me.zhengjie.config;
import me.zhengjie.utils.SecurityUtils;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@Service(value = "el")
public class ElPermissionConfig {
public Boolean check(String ...permissions){
// 如果是匿名访问的,就放行
String anonymous = "anonymous";
if(Arrays.asList(permissions).contains(anonymous)){
return true;
}
// 获取当前用户的所有权限
List<String> elPermissions = SecurityUtils.getUserDetails().getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
// 判断当前用户的所有权限是否包含接口上定义的权限
List<String> list = Arrays.stream(permissions).filter(elPermissions::contains).collect(Collectors.toList());
return elPermissions.contains("admin") || list.size() != 0;
}
}

View File

@ -1,8 +1,12 @@
package me.zhengjie.redis; package me.zhengjie.config;
import cn.hutool.core.lang.Assert;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig; import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.zhengjie.utils.StringUtils;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties; import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
@ -19,7 +23,12 @@ import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisOperations; import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.Duration; import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
/** /**
* @author Zheng Jie * @author Zheng Jie
@ -28,21 +37,19 @@ import java.time.Duration;
@Slf4j @Slf4j
@Configuration @Configuration
@EnableCaching @EnableCaching
// 自动配置
@ConditionalOnClass(RedisOperations.class) @ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class) @EnableConfigurationProperties(RedisProperties.class)
public class RedisConfig extends CachingConfigurerSupport { public class RedisConfig extends CachingConfigurerSupport {
/** /**
* redis 1 * redis 6
* @cacheable * @cacheable
* @return
*/ */
@Bean @Bean
public RedisCacheConfiguration redisCacheConfiguration(){ public RedisCacheConfiguration redisCacheConfiguration(){
FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class); FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig(); RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer)).entryTtl(Duration.ofDays(1)); configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer)).entryTtl(Duration.ofHours(6));
return configuration; return configuration;
} }
@ -51,21 +58,20 @@ public class RedisConfig extends CachingConfigurerSupport {
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>(); RedisTemplate<Object, Object> template = new RedisTemplate<>();
//序列化 //序列化
FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class); FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
// value值的序列化采用fastJsonRedisSerializer // value值的序列化采用fastJsonRedisSerializer
template.setValueSerializer(fastJsonRedisSerializer); template.setValueSerializer(fastJsonRedisSerializer);
template.setHashValueSerializer(fastJsonRedisSerializer); template.setHashValueSerializer(fastJsonRedisSerializer);
// 全局开启AutoType这里方便开发使用全局的方式
// 全局开启AutoType不建议使用 ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
// ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
// 建议使用这种方式,小范围指定白名单 // 建议使用这种方式,小范围指定白名单
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.domain"); // ParserConfig.getGlobalInstance().addAccept("me.zhengjie.domain");
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.system.service.dto"); // ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.system.service.dto");
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.service.dto"); // ParserConfig.getGlobalInstance().addAccept("me.zhengjie.service.dto");
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.system.domain"); // ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.system.domain");
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.quartz.domain"); // ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.quartz.domain");
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.monitor.domain"); // ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.monitor.domain");
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.security.security"); // ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.security.security");
// key的序列化采用StringRedisSerializer // key的序列化采用StringRedisSerializer
template.setKeySerializer(new StringRedisSerializer()); template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer());
@ -75,20 +81,27 @@ public class RedisConfig extends CachingConfigurerSupport {
/** /**
* key使 * key使
* 使 @Cacheable
* @return
*/ */
@Bean @Bean
@Override @Override
public KeyGenerator keyGenerator() { public KeyGenerator keyGenerator() {
return (target, method, params) -> { return (target, method, params) -> {
StringBuilder sb = new StringBuilder(); Map<String,Object> container = new HashMap<>();
sb.append(target.getClass().getName()); Class<?> targetClassClass = target.getClass();
sb.append(method.getName()); // 类地址
for (Object obj : params) { container.put("class",targetClassClass.toGenericString());
sb.append(JSON.toJSONString(obj).hashCode()); // 方法名称
container.put("methodName",method.getName());
// 包名称
container.put("package",targetClassClass.getPackage());
// 参数列表
for (int i = 0; i < params.length; i++) {
container.put(String.valueOf(i),params[i]);
} }
return sb.toString(); // 转为JSON字符串
String jsonString = JSON.toJSONString(container);
// 做SHA256 Hash计算得到一个SHA256摘要作为Key
return DigestUtils.sha256Hex(jsonString);
}; };
} }
@ -97,7 +110,7 @@ public class RedisConfig extends CachingConfigurerSupport {
public CacheErrorHandler errorHandler() { public CacheErrorHandler errorHandler() {
// 异常处理当Redis发生异常时打印日志但是程序正常走 // 异常处理当Redis发生异常时打印日志但是程序正常走
log.info("初始化 -> [{}]", "Redis CacheErrorHandler"); log.info("初始化 -> [{}]", "Redis CacheErrorHandler");
CacheErrorHandler cacheErrorHandler = new CacheErrorHandler() { return new CacheErrorHandler() {
@Override @Override
public void handleCacheGetError(RuntimeException e, Cache cache, Object key) { public void handleCacheGetError(RuntimeException e, Cache cache, Object key) {
log.error("Redis occur handleCacheGetErrorkey -> [{}]", key, e); log.error("Redis occur handleCacheGetErrorkey -> [{}]", key, e);
@ -118,7 +131,74 @@ public class RedisConfig extends CachingConfigurerSupport {
log.error("Redis occur handleCacheClearError", e); log.error("Redis occur handleCacheClearError", e);
} }
}; };
return cacheErrorHandler;
} }
} }
/**
* Value
*
* @author /
* @param <T>
*/
class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
private Class<T> clazz;
FastJsonRedisSerializer(Class<T> clazz) {
super();
this.clazz = clazz;
}
@Override
public byte[] serialize(T t) {
if (t == null) {
return new byte[0];
}
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(StandardCharsets.UTF_8);
}
@Override
public T deserialize(byte[] bytes) {
if (bytes == null || bytes.length <= 0) {
return null;
}
String str = new String(bytes, StandardCharsets.UTF_8);
return JSON.parseObject(str, clazz);
}
}
/**
*
*
* @author /
*/
class StringRedisSerializer implements RedisSerializer<Object> {
private final Charset charset;
StringRedisSerializer() {
this(StandardCharsets.UTF_8);
}
private StringRedisSerializer(Charset charset) {
Assert.notNull(charset, "Charset must not be null!");
this.charset = charset;
}
@Override
public String deserialize(byte[] bytes) {
return (bytes == null ? null : new String(bytes, charset));
}
@Override
public byte[] serialize(Object object) {
String string = JSON.toJSONString(object);
if (StringUtils.isBlank(string)) {
return null;
}
string = string.replace("\"", "");
return string.getBytes(charset);
}
}

View File

@ -1,12 +1,20 @@
package me.zhengjie.swagger2; package me.zhengjie.config;
import com.fasterxml.classmate.TypeResolver;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.data.domain.Pageable;
import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder; import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.PathSelectors;
import springfox.documentation.schema.AlternateTypeRule;
import springfox.documentation.schema.AlternateTypeRuleConvention;
import springfox.documentation.schema.ModelRef; import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo; import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Parameter; import springfox.documentation.service.Parameter;
@ -15,6 +23,8 @@ import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2; import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static com.google.common.collect.Lists.newArrayList;
import static springfox.documentation.schema.AlternateTypeRules.newRule;
/** /**
* api /swagger-ui.html * api /swagger-ui.html
@ -33,9 +43,10 @@ public class SwaggerConfig {
private Boolean enabled; private Boolean enabled;
@Bean @Bean
@SuppressWarnings("all")
public Docket createRestApi() { public Docket createRestApi() {
ParameterBuilder ticketPar = new ParameterBuilder(); ParameterBuilder ticketPar = new ParameterBuilder();
List<Parameter> pars = new ArrayList<Parameter>(); List<Parameter> pars = new ArrayList<>();
ticketPar.name(tokenHeader).description("token") ticketPar.name(tokenHeader).description("token")
.modelRef(new ModelRef("string")) .modelRef(new ModelRef("string"))
.parameterType("header") .parameterType("header")
@ -55,8 +66,43 @@ public class SwaggerConfig {
private ApiInfo apiInfo() { private ApiInfo apiInfo() {
return new ApiInfoBuilder() return new ApiInfoBuilder()
.title("eladmin 接口文档") .title("eladmin 接口文档")
.version("2.1") .version("2.3")
.build(); .build();
} }
} }
/**
* Pageableswagger
*/
@Configuration
class SwaggerDataConfig {
@Bean
public AlternateTypeRuleConvention pageableConvention(final TypeResolver resolver) {
return new AlternateTypeRuleConvention() {
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
@Override
public List<AlternateTypeRule> rules() {
return newArrayList(newRule(resolver.resolve(Pageable.class), resolver.resolve(Page.class)));
}
};
}
@ApiModel
@Data
private static class Page {
@ApiModelProperty("页码 (0..N)")
private Integer page;
@ApiModelProperty("每页显示的数目")
private Integer size;
@ApiModelProperty("以下列格式排序标准property[,asc | desc]。 默认排序顺序为升序。 支持多种排序条件id,asc")
private List<String> sort;
}
}

View File

@ -2,7 +2,6 @@ package me.zhengjie.exception;
import lombok.Getter; import lombok.Getter;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import static org.springframework.http.HttpStatus.BAD_REQUEST; import static org.springframework.http.HttpStatus.BAD_REQUEST;
/** /**

View File

@ -2,33 +2,18 @@ package me.zhengjie.exception;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.IntStream;
/** /**
* @author Zheng Jie * @author Zheng Jie
* @date 2018-11-23 * @date 2018-11-23
*/ */
public class EntityExistException extends RuntimeException { public class EntityExistException extends RuntimeException {
public EntityExistException(Class clazz, Object... saveBodyParamsMap) { public EntityExistException(Class clazz, String field, String val) {
super(EntityExistException.generateMessage(clazz.getSimpleName(), toMap(String.class, String.class, saveBodyParamsMap))); super(EntityExistException.generateMessage(clazz.getSimpleName(), field, val));
} }
private static String generateMessage(String entity, Map<String, String> saveBodyParams) { private static String generateMessage(String entity, String field, String val) {
return StringUtils.capitalize(entity) + return StringUtils.capitalize(entity)
" 已存在 " + + " with " + field + " "+ val + " existed";
saveBodyParams;
}
private static <K, V> Map<K, V> toMap(
Class<K> keyType, Class<V> valueType, Object... entries) {
if (entries.length % 2 == 1)
throw new IllegalArgumentException("Invalid entries");
return IntStream.range(0, entries.length / 2).map(i -> i * 2)
.collect(HashMap::new,
(m, i) -> m.put(keyType.cast(entries[i]), valueType.cast(entries[i + 1])),
Map::putAll);
} }
} }

View File

@ -2,34 +2,18 @@ package me.zhengjie.exception;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.IntStream;
/** /**
* @author Zheng Jie * @author Zheng Jie
* @date 2018-11-23 * @date 2018-11-23
*/ */
public class EntityNotFoundException extends RuntimeException { public class EntityNotFoundException extends RuntimeException {
public EntityNotFoundException(Class clazz, Object... searchParamsMap) { public EntityNotFoundException(Class clazz, String field, String val) {
super(EntityNotFoundException.generateMessage(clazz.getSimpleName(), toMap(String.class, String.class, searchParamsMap))); super(EntityNotFoundException.generateMessage(clazz.getSimpleName(), field, val));
} }
private static String generateMessage(String entity, Map<String, String> searchParams) { private static String generateMessage(String entity, String field, String val) {
return StringUtils.capitalize(entity) + return StringUtils.capitalize(entity)
" 不存在 " + + " with " + field + " "+ val + " does not exist";
searchParams;
} }
private static <K, V> Map<K, V> toMap(
Class<K> keyType, Class<V> valueType, Object... entries) {
if (entries.length % 2 == 1)
throw new IllegalArgumentException("Invalid entries");
return IntStream.range(0, entries.length / 2).map(i -> i * 2)
.collect(HashMap::new,
(m, i) -> m.put(keyType.cast(entries[i]), valueType.cast(entries[i + 1])),
Map::putAll);
}
} }

View File

@ -12,7 +12,7 @@ import java.time.LocalDateTime;
@Data @Data
class ApiError { class ApiError {
private Integer status; private Integer status = 400;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime timestamp; private LocalDateTime timestamp;
private String message; private String message;
@ -21,10 +21,17 @@ class ApiError {
timestamp = LocalDateTime.now(); timestamp = LocalDateTime.now();
} }
public ApiError(Integer status,String message) { public static ApiError error(String message){
this(); ApiError apiError = new ApiError();
this.status = status; apiError.setMessage(message);
this.message = message; return apiError;
}
public static ApiError error(Integer status, String message){
ApiError apiError = new ApiError();
apiError.setStatus(status);
apiError.setMessage(message);
return apiError;
} }
} }

View File

@ -11,6 +11,7 @@ import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.Objects;
import static org.springframework.http.HttpStatus.*; import static org.springframework.http.HttpStatus.*;
/** /**
@ -23,91 +24,73 @@ public class GlobalExceptionHandler {
/** /**
* *
* @param e
* @return
*/ */
@ExceptionHandler(Throwable.class) @ExceptionHandler(Throwable.class)
public ResponseEntity handleException(Throwable e){ public ResponseEntity handleException(Throwable e){
// 打印堆栈信息 // 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e)); log.error(ThrowableUtil.getStackTrace(e));
ApiError apiError = new ApiError(BAD_REQUEST.value(),e.getMessage()); return buildResponseEntity(ApiError.error(e.getMessage()));
return buildResponseEntity(apiError);
} }
/** /**
* 访AccessDeniedException * 访AccessDeniedException
* @param e
* @return
*/ */
@ExceptionHandler(AccessDeniedException.class) @ExceptionHandler(AccessDeniedException.class)
public ResponseEntity handleAccessDeniedException(AccessDeniedException e){ public ResponseEntity handleAccessDeniedException(AccessDeniedException e){
// 打印堆栈信息 // 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e)); log.error(ThrowableUtil.getStackTrace(e));
ApiError apiError = new ApiError(FORBIDDEN.value(),e.getMessage()); return buildResponseEntity(ApiError.error(FORBIDDEN.value(),e.getMessage()));
return buildResponseEntity(apiError);
} }
/** /**
* *
* @param e
* @return
*/ */
@ExceptionHandler(value = BadRequestException.class) @ExceptionHandler(value = BadRequestException.class)
public ResponseEntity<ApiError> badRequestException(BadRequestException e) { public ResponseEntity<ApiError> badRequestException(BadRequestException e) {
// 打印堆栈信息 // 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e)); log.error(ThrowableUtil.getStackTrace(e));
ApiError apiError = new ApiError(e.getStatus(),e.getMessage()); return buildResponseEntity(ApiError.error(e.getStatus(),e.getMessage()));
return buildResponseEntity(apiError);
} }
/** /**
* EntityExist * EntityExist
* @param e
* @return
*/ */
@ExceptionHandler(value = EntityExistException.class) @ExceptionHandler(value = EntityExistException.class)
public ResponseEntity<ApiError> entityExistException(EntityExistException e) { public ResponseEntity<ApiError> entityExistException(EntityExistException e) {
// 打印堆栈信息 // 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e)); log.error(ThrowableUtil.getStackTrace(e));
ApiError apiError = new ApiError(BAD_REQUEST.value(),e.getMessage()); return buildResponseEntity(ApiError.error(e.getMessage()));
return buildResponseEntity(apiError);
} }
/** /**
* EntityNotFound * EntityNotFound
* @param e
* @return
*/ */
@ExceptionHandler(value = EntityNotFoundException.class) @ExceptionHandler(value = EntityNotFoundException.class)
public ResponseEntity<ApiError> entityNotFoundException(EntityNotFoundException e) { public ResponseEntity<ApiError> entityNotFoundException(EntityNotFoundException e) {
// 打印堆栈信息 // 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e)); log.error(ThrowableUtil.getStackTrace(e));
ApiError apiError = new ApiError(NOT_FOUND.value(),e.getMessage()); return buildResponseEntity(ApiError.error(NOT_FOUND.value(),e.getMessage()));
return buildResponseEntity(apiError);
} }
/** /**
* *
* @param e
* @returns
*/ */
@ExceptionHandler(MethodArgumentNotValidException.class) @ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiError> handleMethodArgumentNotValidException(MethodArgumentNotValidException e){ public ResponseEntity<ApiError> handleMethodArgumentNotValidException(MethodArgumentNotValidException e){
// 打印堆栈信息 // 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e)); log.error(ThrowableUtil.getStackTrace(e));
String[] str = e.getBindingResult().getAllErrors().get(0).getCodes()[1].split("\\."); String[] str = Objects.requireNonNull(e.getBindingResult().getAllErrors().get(0).getCodes())[1].split("\\.");
StringBuffer msg = new StringBuffer(str[1]+":"); String message = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
msg.append(e.getBindingResult().getAllErrors().get(0).getDefaultMessage()); if("不能为空".equals(message)){
ApiError apiError = new ApiError(BAD_REQUEST.value(),msg.toString()); message = str[1] + ":" + message;
return buildResponseEntity(apiError); }
return buildResponseEntity(ApiError.error(message));
} }
/** /**
* *
* @param apiError
* @return
*/ */
private ResponseEntity<ApiError> buildResponseEntity(ApiError apiError) { private ResponseEntity<ApiError> buildResponseEntity(ApiError apiError) {
return new ResponseEntity(apiError, HttpStatus.valueOf(apiError.getStatus())); return new ResponseEntity<>(apiError, HttpStatus.valueOf(apiError.getStatus()));
} }
} }

View File

@ -1,44 +0,0 @@
package me.zhengjie.redis;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import java.nio.charset.Charset;
/**
* Value
*
* @author /
* @param <T>
*/
public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private Class<T> clazz;
public FastJsonRedisSerializer(Class<T> clazz) {
super();
this.clazz = clazz;
}
@Override
public byte[] serialize(T t) throws SerializationException {
if (t == null) {
return new byte[0];
}
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
}
@Override
public T deserialize(byte[] bytes) throws SerializationException {
if (bytes == null || bytes.length <= 0) {
return null;
}
String str = new String(bytes, DEFAULT_CHARSET);
return (T) JSON.parseObject(str, clazz);
}
}

View File

@ -1,45 +0,0 @@
package me.zhengjie.redis;
import cn.hutool.core.lang.Assert;
import com.alibaba.fastjson.JSON;
import org.springframework.data.redis.serializer.RedisSerializer;
import java.nio.charset.Charset;
/**
*
*
* @author /
*/
public class StringRedisSerializer implements RedisSerializer<Object> {
private final Charset charset;
private final String target = "\"";
private final String replacement = "";
public StringRedisSerializer() {
this(Charset.forName("UTF8"));
}
public StringRedisSerializer(Charset charset) {
Assert.notNull(charset, "Charset must not be null!");
this.charset = charset;
}
@Override
public String deserialize(byte[] bytes) {
return (bytes == null ? null : new String(bytes, charset));
}
@Override
public byte[] serialize(Object object) {
String string = JSON.toJSONString(object);
if (string == null) {
return null;
}
string = string.replace(target, replacement);
return string.getBytes(charset);
}
}

View File

@ -1 +0,0 @@
package me.zhengjie.swagger2; import com.fasterxml.classmate.TypeResolver; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.data.domain.Pageable; import springfox.documentation.schema.AlternateTypeRule; import springfox.documentation.schema.AlternateTypeRuleConvention; import java.util.List; import static com.google.common.collect.Lists.newArrayList; import static springfox.documentation.schema.AlternateTypeRules.newRule; /** * 将Pageable转换展示在swagger中 */ @Configuration public class SwaggerDataConfig { @Bean public AlternateTypeRuleConvention pageableConvention(final TypeResolver resolver) { return new AlternateTypeRuleConvention() { @Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE; } @Override public List<AlternateTypeRule> rules() { return newArrayList(newRule(resolver.resolve(Pageable.class), resolver.resolve(Page.class))); } }; } @ApiModel static class Page { @ApiModelProperty("页码 (0..N)") private Integer page; @ApiModelProperty("每页显示的数目") private Integer size; @ApiModelProperty("以下列格式排序标准property[,asc | desc]。 默认排序顺序为升序。 支持多种排序条件id,asc") private List<String> sort; public Integer getPage() { return page; } public void setPage(Integer page) { this.page = page; } public Integer getSize() { return size; } public void setSize(Integer size) { this.size = size; } public List<String> getSort() { return sort; } public void setSort(List<String> sort) { this.sort = sort; } } }

View File

@ -14,7 +14,7 @@ public class ElAdminConstant {
/** /**
* IP * IP
*/ */
public static final String REGION = "内网IP|内网IP"; static final String REGION = "内网IP|内网IP";
/** /**
* *

View File

@ -6,6 +6,7 @@ import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory; import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec; import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.IvParameterSpec;
import java.nio.charset.StandardCharsets;
/** /**
* *
@ -18,32 +19,29 @@ public class EncryptUtils {
/** /**
* *
* @param source
* @return
* @throws Exception
*/ */
public static String desEncrypt(String source) throws Exception { public static String desEncrypt(String source) throws Exception {
if (source == null || source.length() == 0){ if (source == null || source.length() == 0){
return null; return null;
} }
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
DESKeySpec desKeySpec = new DESKeySpec(strKey.getBytes("UTF-8")); DESKeySpec desKeySpec = new DESKeySpec(strKey.getBytes(StandardCharsets.UTF_8));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(desKeySpec); SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
IvParameterSpec iv = new IvParameterSpec(strParam.getBytes("UTF-8")); IvParameterSpec iv = new IvParameterSpec(strParam.getBytes(StandardCharsets.UTF_8));
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv); cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
return byte2hex( return byte2hex(
cipher.doFinal(source.getBytes("UTF-8"))).toUpperCase(); cipher.doFinal(source.getBytes(StandardCharsets.UTF_8))).toUpperCase();
} }
public static String byte2hex(byte[] inStr) { private static String byte2hex(byte[] inStr) {
String stmp; String stmp;
StringBuffer out = new StringBuffer(inStr.length * 2); StringBuilder out = new StringBuilder(inStr.length * 2);
for (int n = 0; n < inStr.length; n++) { for (byte b : inStr) {
stmp = Integer.toHexString(inStr[n] & 0xFF); stmp = Integer.toHexString(b & 0xFF);
if (stmp.length() == 1) { if (stmp.length() == 1) {
// 如果是0至F的单位字符串则添加0 // 如果是0至F的单位字符串则添加0
out.append("0" + stmp); out.append("0").append(stmp);
} else { } else {
out.append(stmp); out.append(stmp);
} }
@ -51,8 +49,7 @@ public class EncryptUtils {
return out.toString(); return out.toString();
} }
private static byte[] hex2byte(byte[] b) {
public static byte[] hex2byte(byte[] b) {
if ((b.length % 2) != 0){ if ((b.length % 2) != 0){
throw new IllegalArgumentException("长度不是偶数"); throw new IllegalArgumentException("长度不是偶数");
} }
@ -66,9 +63,6 @@ public class EncryptUtils {
/** /**
* *
* @param source
* @return
* @throws Exception
*/ */
public static String desDecrypt(String source) throws Exception { public static String desDecrypt(String source) throws Exception {
if (source == null || source.length() == 0){ if (source == null || source.length() == 0){
@ -76,10 +70,10 @@ public class EncryptUtils {
} }
byte[] src = hex2byte(source.getBytes()); byte[] src = hex2byte(source.getBytes());
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
DESKeySpec desKeySpec = new DESKeySpec(strKey.getBytes("UTF-8")); DESKeySpec desKeySpec = new DESKeySpec(strKey.getBytes(StandardCharsets.UTF_8));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(desKeySpec); SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
IvParameterSpec iv = new IvParameterSpec(strParam.getBytes("UTF-8")); IvParameterSpec iv = new IvParameterSpec(strParam.getBytes(StandardCharsets.UTF_8));
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv); cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
byte[] retByte = cipher.doFinal(src); byte[] retByte = cipher.doFinal(src);
return new String(retByte); return new String(retByte);
@ -87,8 +81,6 @@ public class EncryptUtils {
/** /**
* *
* @param password
* @return
*/ */
public static String encryptPassword(String password){ public static String encryptPassword(String password){
return DigestUtils.md5DigestAsHex(password.getBytes()); return DigestUtils.md5DigestAsHex(password.getBytes());

View File

@ -11,6 +11,7 @@ import javax.activation.MimetypesFileTypeMap;
import javax.servlet.ServletOutputStream; import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.*; import java.io.*;
import java.security.MessageDigest;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
@ -44,8 +45,6 @@ public class FileUtil extends cn.hutool.core.io.FileUtil {
/** /**
* MultipartFileFile * MultipartFileFile
* @param multipartFile
* @return
*/ */
public static File toFile(MultipartFile multipartFile){ public static File toFile(MultipartFile multipartFile){
// 获取文件名 // 获取文件名
@ -65,21 +64,7 @@ public class FileUtil extends cn.hutool.core.io.FileUtil {
} }
/** /**
* * .
* @param files
*/
public static void deleteFile(File... files) {
for (File file : files) {
if (file.exists()) {
file.delete();
}
}
}
/**
*
* @param filename
* @return
*/ */
public static String getExtensionName(String filename) { public static String getExtensionName(String filename) {
if ((filename != null) && (filename.length() > 0)) { if ((filename != null) && (filename.length() > 0)) {
@ -93,8 +78,6 @@ public class FileUtil extends cn.hutool.core.io.FileUtil {
/** /**
* Java * Java
* @param filename
* @return
*/ */
public static String getFileNameNoEx(String filename) { public static String getFileNameNoEx(String filename) {
if ((filename != null) && (filename.length() > 0)) { if ((filename != null) && (filename.length() > 0)) {
@ -108,11 +91,9 @@ public class FileUtil extends cn.hutool.core.io.FileUtil {
/** /**
* *
* @param size
* @return
*/ */
public static String getSize(long size){ public static String getSize(long size){
String resultSize = ""; String resultSize;
if (size / GB >= 1) { if (size / GB >= 1) {
//如果当前Byte的值大于等于1GB //如果当前Byte的值大于等于1GB
resultSize = DF.format(size / (float) GB) + "GB "; resultSize = DF.format(size / (float) GB) + "GB ";
@ -130,18 +111,14 @@ public class FileUtil extends cn.hutool.core.io.FileUtil {
/** /**
* inputStream File * inputStream File
* @param ins
* @param name
* @return
* @throws Exception
*/ */
public static File inputStreamToFile(InputStream ins, String name) throws Exception{ static File inputStreamToFile(InputStream ins, String name) throws Exception{
File file = new File(System.getProperty("java.io.tmpdir") + File.separator + name); File file = new File(System.getProperty("java.io.tmpdir") + File.separator + name);
if (file.exists()) { if (file.exists()) {
return file; return file;
} }
OutputStream os = new FileOutputStream(file); OutputStream os = new FileOutputStream(file);
int bytesRead = 0; int bytesRead;
byte[] buffer = new byte[8192]; byte[] buffer = new byte[8192];
while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) { while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead); os.write(buffer, 0, bytesRead);
@ -153,10 +130,6 @@ public class FileUtil extends cn.hutool.core.io.FileUtil {
/** /**
* *
*
* @param file
* @param filePath
* @return
*/ */
public static File upload(MultipartFile file, String filePath) { public static File upload(MultipartFile file, String filePath) {
Date date = new Date(); Date date = new Date();
@ -170,10 +143,10 @@ public class FileUtil extends cn.hutool.core.io.FileUtil {
File dest = new File(path); File dest = new File(path);
// 检测是否存在目录 // 检测是否存在目录
if (!dest.getParentFile().exists()) { if (!dest.getParentFile().exists()) {
dest.getParentFile().mkdirs();// 新建文件夹 dest.getParentFile().mkdirs();
} }
String d = dest.getPath(); // 文件写入
file.transferTo(dest);// 文件写入 file.transferTo(dest);
return dest; return dest;
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@ -183,20 +156,16 @@ public class FileUtil extends cn.hutool.core.io.FileUtil {
public static String fileToBase64(File file) throws Exception { public static String fileToBase64(File file) throws Exception {
FileInputStream inputFile = new FileInputStream(file); FileInputStream inputFile = new FileInputStream(file);
String base64 =null; String base64;
byte[] buffer = new byte[(int)file.length()]; byte[] buffer = new byte[(int)file.length()];
inputFile.read(buffer); inputFile.read(buffer);
inputFile.close(); inputFile.close();
base64=new Base64().encode(buffer); base64=Base64.encode(buffer);
String encoded = base64.replaceAll("[\\s*\t\n\r]", ""); return base64.replaceAll("[\\s*\t\n\r]", "");
return encoded;
} }
/** /**
* excel * excel
* @param list
* @return
* @throws Exception
*/ */
public static void downloadExcel(List<Map<String, Object>> list, HttpServletResponse response) throws IOException { public static void downloadExcel(List<Map<String, Object>> list, HttpServletResponse response) throws IOException {
String tempPath =System.getProperty("java.io.tmpdir") + IdUtil.fastSimpleUUID() + ".xlsx"; String tempPath =System.getProperty("java.io.tmpdir") + IdUtil.fastSimpleUUID() + ".xlsx";
@ -217,28 +186,91 @@ public class FileUtil extends cn.hutool.core.io.FileUtil {
} }
public static String getFileType(String type) { public static String getFileType(String type) {
String documents = "txt doc pdf ppt pps xlsx xls"; String documents = "txt doc pdf ppt pps xlsx xls docx";
String music = "mp3 wav wma mpa ram ra aac aif m4a"; String music = "mp3 wav wma mpa ram ra aac aif m4a";
String video = "avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg"; String video = "avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg";
String image = "bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg"; String image = "bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg";
if(image.indexOf(type) != -1){ if(image.contains(type)){
return "图片"; return "图片";
} else if(documents.indexOf(type) != -1){ } else if(documents.contains(type)){
return "文档"; return "文档";
} else if(music.indexOf(type) != -1){ } else if(music.contains(type)){
return "音乐"; return "音乐";
} else if(video.indexOf(type) != -1){ } else if(video.contains(type)){
return "视频"; return "视频";
} else return "其他"; } else {
return "其他";
}
} }
public static String getFileTypeByMimeType(String type) { public static String getFileTypeByMimeType(String type) {
String mimeType = new MimetypesFileTypeMap().getContentType("." + type); String mimeType = new MimetypesFileTypeMap().getContentType("." + type);
return mimeType.split("\\/")[0]; return mimeType.split("/")[0];
} }
public static void checkSize(long maxSize, long size) { public static void checkSize(long maxSize, long size) {
if(size > (maxSize * 1024 * 1024)){ if(size > (maxSize * 1024 * 1024)){
throw new BadRequestException("文件超出规定大小"); throw new BadRequestException("文件超出规定大小");
} }
} }
/**
*
*/
public static boolean check(File file1, File file2) {
String img1Md5 = getMd5(file1);
String img2Md5 = getMd5(file2);
return img1Md5.equals(img2Md5);
}
/**
*
*/
public static boolean check(String file1Md5, String file2Md5) {
return file1Md5.equals(file2Md5);
}
private static byte[] getByte(File file) {
// 得到文件长度
byte[] b = new byte[(int) file.length()];
try {
InputStream in = new FileInputStream(file);
try {
in.read(b);
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
}
return b;
}
private static String getMd5(byte[] bytes) {
// 16进制字符
char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
try {
MessageDigest mdTemp = MessageDigest.getInstance("MD5");
mdTemp.update(bytes);
byte[] md = mdTemp.digest();
int j = md.length;
char[] str = new char[j * 2];
int k = 0;
// 移位 输出字符串
for (byte byte0 : md) {
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static String getMd5(File file) {
return getMd5(getByte(file));
}
} }

View File

@ -12,10 +12,6 @@ public class PageUtil extends cn.hutool.core.util.PageUtil {
/** /**
* List * List
* @param page
* @param size
* @param list
* @return
*/ */
public static List toPage(int page, int size , List list) { public static List toPage(int page, int size , List list) {
int fromIndex = page * size; int fromIndex = page * size;
@ -32,10 +28,8 @@ public class PageUtil extends cn.hutool.core.util.PageUtil {
/** /**
* Page redis * Page redis
* @param page
* @return
*/ */
public static Map toPage(Page page) { public static Map<String,Object> toPage(Page page) {
Map<String,Object> map = new LinkedHashMap<>(2); Map<String,Object> map = new LinkedHashMap<>(2);
map.put("content",page.getContent()); map.put("content",page.getContent());
map.put("totalElements",page.getTotalElements()); map.put("totalElements",page.getTotalElements());
@ -43,11 +37,9 @@ public class PageUtil extends cn.hutool.core.util.PageUtil {
} }
/** /**
* @param object *
* @param totalElements
* @return
*/ */
public static Map toPage(Object object, Object totalElements) { public static Map<String,Object> toPage(Object object, Object totalElements) {
Map<String,Object> map = new LinkedHashMap<>(2); Map<String,Object> map = new LinkedHashMap<>(2);
map.put("content",object); map.put("content",object);
map.put("totalElements",totalElements); map.put("totalElements",totalElements);

View File

@ -15,18 +15,12 @@ import java.util.*;
@Slf4j @Slf4j
public class QueryHelp { public class QueryHelp {
/**
* @ : Predicate
* @ : Dong ZhaoYang
* @ : 2017/8/7
* @ : 17:25
*/
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <R, Q> Predicate getPredicate(Root<R> root, Q query, CriteriaBuilder cb) { public static <R, Q> Predicate getPredicate(Root<R> root, Q query, CriteriaBuilder cb) {
List<Predicate> list = new ArrayList<>(); List<Predicate> list = new ArrayList<>();
if(query == null){ if(query == null){
return cb.and(list.toArray(new Predicate[list.size()])); return cb.and(list.toArray(new Predicate[0]));
} }
try { try {
List<Field> fields = getAllFields(query.getClass(), new ArrayList<>()); List<Field> fields = getAllFields(query.getClass(), new ArrayList<>());
@ -62,19 +56,20 @@ public class QueryHelp {
for (String name : joinNames) { for (String name : joinNames) {
switch (q.join()) { switch (q.join()) {
case LEFT: case LEFT:
if(ObjectUtil.isNotEmpty(join)){ if(ObjectUtil.isNotNull(join)){
join = join.join(name, JoinType.LEFT); join = join.join(name, JoinType.LEFT);
} else { } else {
join = root.join(name, JoinType.LEFT); join = root.join(name, JoinType.LEFT);
} }
break; break;
case RIGHT: case RIGHT:
if(ObjectUtil.isNotEmpty(join)){ if(ObjectUtil.isNotNull(join)){
join = join.join(name, JoinType.RIGHT); join = join.join(name, JoinType.RIGHT);
} else { } else {
join = root.join(name, JoinType.RIGHT); join = root.join(name, JoinType.RIGHT);
} }
break; break;
default: break;
} }
} }
} }
@ -111,6 +106,7 @@ public class QueryHelp {
list.add(getExpression(attributeName,join,root).in((Collection<Long>) val)); list.add(getExpression(attributeName,join,root).in((Collection<Long>) val));
} }
break; break;
default: break;
} }
} }
field.setAccessible(accessible); field.setAccessible(accessible);
@ -118,7 +114,8 @@ public class QueryHelp {
} catch (Exception e) { } catch (Exception e) {
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
} }
return cb.and(list.toArray(new Predicate[list.size()])); int size = list.size();
return cb.and(list.toArray(new Predicate[size]));
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -130,21 +127,19 @@ public class QueryHelp {
} }
} }
@SuppressWarnings("unchecked") private static boolean isBlank(final CharSequence cs) {
public static boolean isBlank(final CharSequence cs) {
int strLen; int strLen;
if (cs == null || (strLen = cs.length()) == 0) { if (cs == null || (strLen = cs.length()) == 0) {
return true; return true;
} }
for (int i = 0; i < strLen; i++) { for (int i = 0; i < strLen; i++) {
if (Character.isWhitespace(cs.charAt(i)) == false) { if (!Character.isWhitespace(cs.charAt(i))) {
return false; return false;
} }
} }
return true; return true;
} }
@SuppressWarnings("unchecked")
private static List<Field> getAllFields(Class clazz, List<Field> fields) { private static List<Field> getAllFields(Class clazz, List<Field> fields) {
if (clazz != null) { if (clazz != null) {
fields.addAll(Arrays.asList(clazz.getDeclaredFields())); fields.addAll(Arrays.asList(clazz.getDeclaredFields()));

View File

@ -3,6 +3,7 @@ package me.zhengjie.utils;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
/** /**
* HttpServletRequest * HttpServletRequest
@ -12,6 +13,6 @@ import javax.servlet.http.HttpServletRequest;
public class RequestHolder { public class RequestHolder {
public static HttpServletRequest getHttpServletRequest() { public static HttpServletRequest getHttpServletRequest() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
} }
} }

View File

@ -13,7 +13,7 @@ import org.springframework.security.core.userdetails.UserDetails;
public class SecurityUtils { public class SecurityUtils {
public static UserDetails getUserDetails() { public static UserDetails getUserDetails() {
UserDetails userDetails = null; UserDetails userDetails;
try { try {
userDetails = (UserDetails) org.springframework.security.core.context.SecurityContextHolder.getContext().getAuthentication().getPrincipal(); userDetails = (UserDetails) org.springframework.security.core.context.SecurityContextHolder.getContext().getAuthentication().getPrincipal();
} catch (Exception e) { } catch (Exception e) {
@ -28,8 +28,7 @@ public class SecurityUtils {
*/ */
public static String getUsername(){ public static String getUsername(){
Object obj = getUserDetails(); Object obj = getUserDetails();
JSONObject json = new JSONObject(obj); return new JSONObject(obj).get("username", String.class);
return json.get("username", String.class);
} }
/** /**
@ -38,7 +37,6 @@ public class SecurityUtils {
*/ */
public static Long getUserId(){ public static Long getUserId(){
Object obj = getUserDetails(); Object obj = getUserDetails();
JSONObject json = new JSONObject(obj); return new JSONObject(obj).get("id", Long.class);
return json.get("id", Long.class);
} }
} }

View File

@ -7,7 +7,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationContextAware;
/** /**
* @author * @author Jie
* @date 2019-01-07 * @date 2019-01-07
*/ */
@Slf4j @Slf4j
@ -15,17 +15,10 @@ public class SpringContextHolder implements ApplicationContextAware, DisposableB
private static ApplicationContext applicationContext = null; private static ApplicationContext applicationContext = null;
/**
* ApplicationContext.
*/
public static ApplicationContext getApplicationContext() {
assertContextInjected();
return applicationContext;
}
/** /**
* applicationContextBean, . * applicationContextBean, .
*/ */
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) { public static <T> T getBean(String name) {
assertContextInjected(); assertContextInjected();
return (T) applicationContext.getBean(name); return (T) applicationContext.getBean(name);
@ -52,14 +45,14 @@ public class SpringContextHolder implements ApplicationContextAware, DisposableB
/** /**
* SpringContextHolderApplicationContextNull. * SpringContextHolderApplicationContextNull.
*/ */
public static void clearHolder() { private static void clearHolder() {
log.debug("清除SpringContextHolder中的ApplicationContext:" log.debug("清除SpringContextHolder中的ApplicationContext:"
+ applicationContext); + applicationContext);
applicationContext = null; applicationContext = null;
} }
@Override @Override
public void destroy() throws Exception { public void destroy(){
SpringContextHolder.clearHolder(); SpringContextHolder.clearHolder();
} }

View File

@ -1,14 +1,16 @@
package me.zhengjie.utils; package me.zhengjie.utils;
import cn.hutool.core.io.resource.ClassPathResource; import cn.hutool.core.io.resource.ClassPathResource;
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.UserAgent;
import org.lionsoul.ip2region.DataBlock; import org.lionsoul.ip2region.DataBlock;
import org.lionsoul.ip2region.DbConfig; import org.lionsoul.ip2region.DbConfig;
import org.lionsoul.ip2region.DbSearcher; import org.lionsoul.ip2region.DbSearcher;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.io.File; import java.io.File;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
@ -18,25 +20,6 @@ import java.util.Date;
public class StringUtils extends org.apache.commons.lang3.StringUtils { public class StringUtils extends org.apache.commons.lang3.StringUtils {
private static final char SEPARATOR = '_'; private static final char SEPARATOR = '_';
private static final String CHARSET_NAME = "UTF-8";
/**
*
*
* @param str
* @param strs
* @return true
*/
public static boolean inString(String str, String... strs) {
if (str != null) {
for (String s : strs) {
if (str.equals(trim(s))) {
return true;
}
}
}
return false;
}
/** /**
* *
@ -92,7 +75,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* toCapitalizeCamelCase("hello_world") == "HelloWorld" * toCapitalizeCamelCase("hello_world") == "HelloWorld"
* toUnderScoreCase("helloWorld") = "hello_world" * toUnderScoreCase("helloWorld") = "hello_world"
*/ */
public static String toUnderScoreCase(String s) { static String toUnderScoreCase(String s) {
if (s == null) { if (s == null) {
return null; return null;
} }
@ -125,53 +108,45 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
/** /**
* ip * ip
* @param request
* @return
*/ */
public static String getIP(HttpServletRequest request) { public static String getIp(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for"); String ip = request.getHeader("x-forwarded-for");
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP"); ip = request.getHeader("Proxy-Client-IP");
} }
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP"); ip = request.getHeader("WL-Proxy-Client-IP");
} }
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr(); ip = request.getRemoteAddr();
} }
String[] ips = ip.split(","); if (ip.contains(",")) {
return "0:0:0:0:0:0:0:1".equals(ips[0])?"127.0.0.1":ips[0]; ip = ip.split(",")[0];
}
if ("127.0.0.1".equals(ip)) {
// 获取本机真正的ip地址
try {
ip = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
return ip;
} }
/** /**
* ip * ip
* @param ip
* @return
*/ */
public static String getCityInfo(String ip) { public static String getCityInfo(String ip) {
try { try {
String path = "ip2region/ip2region.db"; String path = "ip2region/ip2region.db";
String name = "ip2region.db"; String name = "ip2region.db";
int algorithm = DbSearcher.BTREE_ALGORITHM;
DbConfig config = new DbConfig(); DbConfig config = new DbConfig();
File file = FileUtil.inputStreamToFile(new ClassPathResource(path).getStream(), name); File file = FileUtil.inputStreamToFile(new ClassPathResource(path).getStream(), name);
DbSearcher searcher = new DbSearcher(config, file.getPath()); DbSearcher searcher = new DbSearcher(config, file.getPath());
Method method = null; Method method;
switch (algorithm) { method = searcher.getClass().getMethod("btreeSearch", String.class);
case DbSearcher.BTREE_ALGORITHM: DataBlock dataBlock;
method = searcher.getClass().getMethod("btreeSearch", String.class);
break;
case DbSearcher.BINARY_ALGORITHM:
method = searcher.getClass().getMethod("binarySearch", String.class);
break;
case DbSearcher.MEMORY_ALGORITYM:
method = searcher.getClass().getMethod("memorySearch", String.class);
break;
default:
method = searcher.getClass().getMethod("memorySearch", String.class);
break;
}
DataBlock dataBlock = null;
dataBlock = (DataBlock) method.invoke(searcher, ip); dataBlock = (DataBlock) method.invoke(searcher, ip);
String address = dataBlock.getRegion().replace("0|",""); String address = dataBlock.getRegion().replace("0|","");
if(address.charAt(address.length()-1) == '|'){ if(address.charAt(address.length()-1) == '|'){
@ -184,6 +159,12 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
return ""; return "";
} }
public static String getBrowser(HttpServletRequest request){
UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
Browser browser = userAgent.getBrowser();
return browser.getName();
}
/** /**
* *
*/ */

View File

@ -2,30 +2,23 @@ package me.zhengjie.utils;
import me.zhengjie.exception.BadRequestException; import me.zhengjie.exception.BadRequestException;
import org.hibernate.exception.ConstraintViolationException; import org.hibernate.exception.ConstraintViolationException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
/** /**
* * 2019-01-06
* @author Zheng Jie * @author Zheng Jie
* @date 2019-01-06
*/ */
public class ThrowableUtil { public class ThrowableUtil {
/** /**
* *
* @param throwable
* @return
*/ */
public static String getStackTrace(Throwable throwable){ public static String getStackTrace(Throwable throwable){
StringWriter sw = new StringWriter(); StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw); try (PrintWriter pw = new PrintWriter(sw)) {
try {
throwable.printStackTrace(pw); throwable.printStackTrace(pw);
return sw.toString(); return sw.toString();
} finally {
pw.close();
} }
} }
@ -34,9 +27,10 @@ public class ThrowableUtil {
while ((t != null) && !(t instanceof ConstraintViolationException)) { while ((t != null) && !(t instanceof ConstraintViolationException)) {
t = t.getCause(); t = t.getCause();
} }
if (t instanceof ConstraintViolationException) { if (t != null) {
throw new BadRequestException(msg); throw new BadRequestException(msg);
} }
assert false;
throw new BadRequestException("删除失败:" + t.getMessage()); throw new BadRequestException("删除失败:" + t.getMessage());
} }
} }

View File

@ -1,8 +1,6 @@
package me.zhengjie.utils; package me.zhengjie.utils;
import cn.hutool.json.JSONArray; import cn.hutool.json.JSONArray;
import lombok.var;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
@ -26,7 +24,7 @@ public class TranslatorUtil {
BufferedReader in = new BufferedReader( BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream())); new InputStreamReader(con.getInputStream()));
String inputLine; String inputLine;
StringBuffer response = new StringBuffer(); StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) { while ((inputLine = in.readLine()) != null) {
response.append(inputLine); response.append(inputLine);
@ -38,15 +36,12 @@ public class TranslatorUtil {
} }
} }
private static String parseResult(String inputJson) throws Exception { private static String parseResult(String inputJson){
JSONArray jsonArray = new JSONArray(inputJson); JSONArray jsonArray2 = (JSONArray) new JSONArray(inputJson).get(0);
JSONArray jsonArray2 = (JSONArray) jsonArray.get(0); StringBuilder result = new StringBuilder();
String result =""; for (Object o : jsonArray2) {
result.append(((JSONArray) o).get(0).toString());
for(var i = 0; i < jsonArray2.size(); i ++){
result += ((JSONArray) jsonArray2.get(i)).get(0).toString();
} }
return result; return result.toString();
} }
} }

View File

@ -1,7 +1,7 @@
package me.zhengjie.utils; package me.zhengjie.utils;
import cn.hutool.core.util.ObjectUtil;
import me.zhengjie.exception.BadRequestException; import me.zhengjie.exception.BadRequestException;
import java.util.Optional;
/** /**
* *
@ -12,27 +12,22 @@ public class ValidationUtil{
/** /**
* *
* @param optional
*/ */
public static void isNull(Optional optional, String entity,String parameter , Object value){ public static void isNull(Object obj, String entity, String parameter , Object value){
if(!optional.isPresent()){ if(ObjectUtil.isNull(obj)){
String msg = entity String msg = entity + " 不存在: "+ parameter +" is "+ value;
+ " 不存在 "
+"{ "+ parameter +":"+ value.toString() +" }";
throw new BadRequestException(msg); throw new BadRequestException(msg);
} }
} }
/** /**
* *
* @param string
* @return
*/ */
public static boolean isEmail(String string) { public static boolean isEmail(String string) {
if (string == null){ if (string == null){
return false; return false;
} }
String regEx1 = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$"; String regEx1 = "^([a-z0-9A-Z]+[-|.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
return string.matches(regEx1); return string.matches(regEx1);
} }
} }

View File

@ -11,12 +11,6 @@ import static org.junit.Assert.*;
public class StringUtilsTest { public class StringUtilsTest {
@Test
public void testInString() {
assertTrue(inString("?", "?"));
assertFalse(inString("?", new String[]{}));
}
@Test @Test
public void testToCamelCase() { public void testToCamelCase() {
assertNull(toCamelCase(null)); assertNull(toCamelCase(null));
@ -44,6 +38,6 @@ public class StringUtilsTest {
@Test @Test
public void testGetIP() { public void testGetIP() {
assertEquals("127.0.0.1", getIP(new MockHttpServletRequest())); assertEquals("127.0.0.1", getIp(new MockHttpServletRequest()));
} }
} }

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>eladmin</artifactId> <artifactId>eladmin</artifactId>
<groupId>me.zhengjie</groupId> <groupId>me.zhengjie</groupId>
<version>2.2</version> <version>2.3</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@ -20,7 +20,7 @@
<dependency> <dependency>
<groupId>me.zhengjie</groupId> <groupId>me.zhengjie</groupId>
<artifactId>eladmin-common</artifactId> <artifactId>eladmin-common</artifactId>
<version>2.2</version> <version>2.3</version>
</dependency> </dependency>
<!--模板引擎--> <!--模板引擎-->

View File

@ -16,26 +16,26 @@ public class GenConfig {
@Id @Id
private Long id; private Long id;
/** 包路径 **/ // 包路径
private String pack; private String pack;
/** 模块名 **/ // 模块名
@Column(name = "module_name") @Column(name = "module_name")
private String moduleName; private String moduleName;
/** 前端文件路径 **/ // 前端文件路径
private String path; private String path;
/** 前端文件路径 **/ // 前端文件路径
@Column(name = "api_path") @Column(name = "api_path")
private String apiPath; private String apiPath;
/** 作者 **/ // 作者
private String author; private String author;
/** 表前缀 **/ // 表前缀
private String prefix; private String prefix;
/** 是否覆盖 **/ // 是否覆盖
private Boolean cover; private Boolean cover;
} }

View File

@ -14,27 +14,27 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor @NoArgsConstructor
public class ColumnInfo { public class ColumnInfo {
/** 数据库字段名称 **/ // 数据库字段名称
private Object columnName; private Object columnName;
/** 允许空值 **/ // 允许空值
private Object isNullable; private Object isNullable;
/** 数据库字段类型 **/ // 数据库字段类型
private Object columnType; private Object columnType;
/** 数据库字段注释 **/ // 数据库字段注释
private Object columnComment; private Object columnComment;
/** 数据库字段键类型 **/ // 数据库字段键类型
private Object columnKey; private Object columnKey;
/** 额外的参数 **/ // 额外的参数
private Object extra; private Object extra;
/** 查询 1:模糊 2精确 **/ // 查询 1:模糊 2精确
private String columnQuery; private String columnQuery;
/** 是否在列表显示 **/ // 是否在列表显示
private String columnShow; private String columnShow;
} }

View File

@ -14,10 +14,10 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor @NoArgsConstructor
public class TableInfo { public class TableInfo {
/** 表名称 **/ // 表名称
private Object tableName; private Object tableName;
/** 创建日期 **/ // 创建日期
private Object createTime; private Object createTime;
// 数据库引擎 // 数据库引擎

View File

@ -1,8 +1,9 @@
package me.zhengjie.rest; package me.zhengjie.rest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import me.zhengjie.domain.GenConfig; import me.zhengjie.domain.GenConfig;
import me.zhengjie.service.GenConfigService; import me.zhengjie.service.GenConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -13,23 +14,25 @@ import org.springframework.web.bind.annotation.*;
* @date 2019-01-14 * @date 2019-01-14
*/ */
@RestController @RestController
@RequestMapping("api") @RequestMapping("/api/genConfig")
@Api(tags = "系统:代码生成器配置管理")
public class GenConfigController { public class GenConfigController {
@Autowired private final GenConfigService genConfigService;
private GenConfigService genConfigService;
/** public GenConfigController(GenConfigService genConfigService) {
* this.genConfigService = genConfigService;
* @return
*/
@GetMapping(value = "/genConfig")
public ResponseEntity get(){
return new ResponseEntity(genConfigService.find(), HttpStatus.OK);
} }
@PutMapping(value = "/genConfig") @ApiOperation("查询")
@GetMapping
public ResponseEntity get(){
return new ResponseEntity<>(genConfigService.find(), HttpStatus.OK);
}
@ApiOperation("修改")
@PutMapping
public ResponseEntity emailConfig(@Validated @RequestBody GenConfig genConfig){ public ResponseEntity emailConfig(@Validated @RequestBody GenConfig genConfig){
return new ResponseEntity(genConfigService.update(genConfig),HttpStatus.OK); return new ResponseEntity<>(genConfigService.update(genConfig),HttpStatus.OK);
} }
} }

View File

@ -1,11 +1,12 @@
package me.zhengjie.rest; package me.zhengjie.rest;
import cn.hutool.core.util.PageUtil; import cn.hutool.core.util.PageUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import me.zhengjie.domain.vo.ColumnInfo; import me.zhengjie.domain.vo.ColumnInfo;
import me.zhengjie.exception.BadRequestException; import me.zhengjie.exception.BadRequestException;
import me.zhengjie.service.GenConfigService; import me.zhengjie.service.GenConfigService;
import me.zhengjie.service.GeneratorService; import me.zhengjie.service.GeneratorService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@ -17,49 +18,39 @@ import java.util.List;
* @date 2019-01-02 * @date 2019-01-02
*/ */
@RestController @RestController
@RequestMapping("api") @RequestMapping("/api/generator")
@Api(tags = "系统:代码生成管理")
public class GeneratorController { public class GeneratorController {
@Autowired private final GeneratorService generatorService;
private GeneratorService generatorService;
@Autowired private final GenConfigService genConfigService;
private GenConfigService genConfigService;
@Value("${generator.enabled}") @Value("${generator.enabled}")
private Boolean generatorEnabled; private Boolean generatorEnabled;
/** public GeneratorController(GeneratorService generatorService, GenConfigService genConfigService) {
* this.generatorService = generatorService;
* @param name this.genConfigService = genConfigService;
* @param page }
* @param size
* @return @ApiOperation("查询数据库元数据")
*/ @GetMapping(value = "/tables")
@GetMapping(value = "/generator/tables")
public ResponseEntity getTables(@RequestParam(defaultValue = "") String name, public ResponseEntity getTables(@RequestParam(defaultValue = "") String name,
@RequestParam(defaultValue = "0")Integer page, @RequestParam(defaultValue = "0")Integer page,
@RequestParam(defaultValue = "10")Integer size){ @RequestParam(defaultValue = "10")Integer size){
int[] startEnd = PageUtil.transToStartEnd(page+1, size); int[] startEnd = PageUtil.transToStartEnd(page+1, size);
return new ResponseEntity(generatorService.getTables(name,startEnd), HttpStatus.OK); return new ResponseEntity<>(generatorService.getTables(name,startEnd), HttpStatus.OK);
} }
/** @ApiOperation("查询表内元数据")
* @GetMapping(value = "/columns")
* @param tableName
* @return
*/
@GetMapping(value = "/generator/columns")
public ResponseEntity getTables(@RequestParam String tableName){ public ResponseEntity getTables(@RequestParam String tableName){
return new ResponseEntity(generatorService.getColumns(tableName), HttpStatus.OK); return new ResponseEntity<>(generatorService.getColumns(tableName), HttpStatus.OK);
} }
/** @ApiOperation("生成代码")
* @PostMapping
* @param columnInfos
* @return
*/
@PostMapping(value = "/generator")
public ResponseEntity generator(@RequestBody List<ColumnInfo> columnInfos, @RequestParam String tableName){ public ResponseEntity generator(@RequestBody List<ColumnInfo> columnInfos, @RequestParam String tableName){
if(!generatorEnabled){ if(!generatorEnabled){
throw new BadRequestException("此环境不允许生成代码!"); throw new BadRequestException("此环境不允许生成代码!");

View File

@ -1,30 +1,14 @@
package me.zhengjie.service; package me.zhengjie.service;
import me.zhengjie.domain.GenConfig; import me.zhengjie.domain.GenConfig;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
/** /**
* @author Zheng Jie * @author Zheng Jie
* @date 2019-01-14 * @date 2019-01-14
*/ */
@CacheConfig(cacheNames = "genConfig")
public interface GenConfigService { public interface GenConfigService {
/**
* find
* @return
*/
@Cacheable(key = "'1'")
GenConfig find(); GenConfig find();
/**
* update
* @param genConfig
* @return
*/
@CacheEvict(allEntries = true)
GenConfig update(GenConfig genConfig); GenConfig update(GenConfig genConfig);
} }

View File

@ -12,24 +12,24 @@ public interface GeneratorService {
/** /**
* *
* @param name * @param name
* @param startEnd * @param startEnd
* @return * @return /
*/ */
Object getTables(String name, int[] startEnd); Object getTables(String name, int[] startEnd);
/** /**
* *
* @param name * @param name
* @return * @return /
*/ */
Object getColumns(String name); Object getColumns(String name);
/** /**
* *
* @param columnInfos * @param columnInfos
* @param genConfig * @param genConfig
* @param tableName * @param tableName
*/ */
void generator(List<ColumnInfo> columnInfos, GenConfig genConfig, String tableName); void generator(List<ColumnInfo> columnInfos, GenConfig genConfig, String tableName);
} }

View File

@ -3,9 +3,10 @@ package me.zhengjie.service.impl;
import me.zhengjie.domain.GenConfig; import me.zhengjie.domain.GenConfig;
import me.zhengjie.repository.GenConfigRepository; import me.zhengjie.repository.GenConfigRepository;
import me.zhengjie.service.GenConfigService; import me.zhengjie.service.GenConfigService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.io.File; import java.io.File;
import java.util.Optional; import java.util.Optional;
@ -14,35 +15,37 @@ import java.util.Optional;
* @date 2019-01-14 * @date 2019-01-14
*/ */
@Service @Service
@CacheConfig(cacheNames = "genConfig")
public class GenConfigServiceImpl implements GenConfigService { public class GenConfigServiceImpl implements GenConfigService {
@Autowired private final GenConfigRepository genConfigRepository;
private GenConfigRepository genConfigRepository;
@Override public GenConfigServiceImpl(GenConfigRepository genConfigRepository) {
public GenConfig find() { this.genConfigRepository = genConfigRepository;
Optional<GenConfig> genConfig = genConfigRepository.findById(1L);
if(genConfig.isPresent()){
return genConfig.get();
} else {
return new GenConfig();
}
} }
@Override @Override
@Cacheable(key = "'1'")
public GenConfig find() {
Optional<GenConfig> genConfig = genConfigRepository.findById(1L);
return genConfig.orElseGet(GenConfig::new);
}
@Override
@CacheEvict(allEntries = true)
public GenConfig update(GenConfig genConfig) { public GenConfig update(GenConfig genConfig) {
genConfig.setId(1L); genConfig.setId(1L);
// 自动设置Api路径注释掉前需要同步取消前端的注释 // 自动设置Api路径注释掉前需要同步取消前端的注释
String separator = File.separator; String separator = File.separator;
String[] paths = null; String[] paths;
if (separator.equals("\\")) { if (separator.equals("\\")) {
paths = genConfig.getPath().split("\\\\"); paths = genConfig.getPath().split("\\\\");
} else paths = genConfig.getPath().split(File.separator); } else paths = genConfig.getPath().split(File.separator);
StringBuffer api = new StringBuffer(); StringBuilder api = new StringBuilder();
for (int i = 0; i < paths.length; i++) { for (String path : paths) {
api.append(paths[i]); api.append(path);
api.append(separator); api.append(separator);
if(paths[i].equals("src")){ if (path.equals("src")) {
api.append("api"); api.append("api");
break; break;
} }

View File

@ -28,6 +28,7 @@ public class GeneratorServiceImpl implements GeneratorService {
private EntityManager em; private EntityManager em;
@Override @Override
@SuppressWarnings("all")
public Object getTables(String name, int[] startEnd) { public Object getTables(String name, int[] startEnd) {
// 使用预编译防止sql注入 // 使用预编译防止sql注入
String sql = "select table_name ,create_time , engine, table_collation, table_comment from information_schema.tables " + String sql = "select table_name ,create_time , engine, table_collation, table_comment from information_schema.tables " +
@ -37,10 +38,11 @@ public class GeneratorServiceImpl implements GeneratorService {
query.setFirstResult(startEnd[0]); query.setFirstResult(startEnd[0]);
query.setMaxResults(startEnd[1]-startEnd[0]); query.setMaxResults(startEnd[1]-startEnd[0]);
query.setParameter(1, StringUtils.isNotBlank(name) ? ("%" + name + "%") : "%%"); query.setParameter(1, StringUtils.isNotBlank(name) ? ("%" + name + "%") : "%%");
List<Object[]> result = query.getResultList(); List result = query.getResultList();
List<TableInfo> tableInfos = new ArrayList<>(); List<TableInfo> tableInfos = new ArrayList<>();
for (Object[] obj : result) { for (Object obj : result) {
tableInfos.add(new TableInfo(obj[0],obj[1],obj[2],obj[3], ObjectUtil.isNotEmpty(obj[4])? obj[4] : "-")); Object[] arr = (Object[]) obj;
tableInfos.add(new TableInfo(arr[0],arr[1],arr[2],arr[3], ObjectUtil.isNotEmpty(arr[4])? arr[4] : "-"));
} }
Query query1 = em.createNativeQuery("SELECT COUNT(*) from information_schema.tables where table_schema = (select database())"); Query query1 = em.createNativeQuery("SELECT COUNT(*) from information_schema.tables where table_schema = (select database())");
Object totalElements = query1.getSingleResult(); Object totalElements = query1.getSingleResult();
@ -48,16 +50,18 @@ public class GeneratorServiceImpl implements GeneratorService {
} }
@Override @Override
@SuppressWarnings("all")
public Object getColumns(String name) { public Object getColumns(String name) {
// 使用预编译防止sql注入 // 使用预编译防止sql注入
String sql = "select column_name, is_nullable, data_type, column_comment, column_key, extra from information_schema.columns " + String sql = "select column_name, is_nullable, data_type, column_comment, column_key, extra from information_schema.columns " +
"where table_name = ? and table_schema = (select database()) order by ordinal_position"; "where table_name = ? and table_schema = (select database()) order by ordinal_position";
Query query = em.createNativeQuery(sql); Query query = em.createNativeQuery(sql);
query.setParameter(1, StringUtils.isNotBlank(name) ? name : null); query.setParameter(1, StringUtils.isNotBlank(name) ? name : null);
List<Object[]> result = query.getResultList(); List result = query.getResultList();
List<ColumnInfo> columnInfos = new ArrayList<>(); List<ColumnInfo> columnInfos = new ArrayList<>();
for (Object[] obj : result) { for (Object obj : result) {
columnInfos.add(new ColumnInfo(obj[0],obj[1],obj[2],obj[3],obj[4],obj[5],null,"true")); Object[] arr = (Object[]) obj;
columnInfos.add(new ColumnInfo(arr[0],arr[1],arr[2],arr[3],arr[4],arr[5],null,"true"));
} }
return PageUtil.toPage(columnInfos,columnInfos.size()); return PageUtil.toPage(columnInfos,columnInfos.size());
} }

View File

@ -12,11 +12,12 @@ public class ColUtil {
/** /**
* mysqljava * mysqljava
* @param type * @param type
* @return * @return String
*/ */
public static String cloToJava(String type){ static String cloToJava(String type){
Configuration config = getConfig(); Configuration config = getConfig();
assert config != null;
return config.getString(type,"unknowType"); return config.getString(type,"unknowType");
} }

View File

@ -34,9 +34,9 @@ public class GenUtil {
/** /**
* *
* @return * @return List
*/ */
public static List<String> getAdminTemplateNames() { private static List<String> getAdminTemplateNames() {
List<String> templateNames = new ArrayList<>(); List<String> templateNames = new ArrayList<>();
templateNames.add("Entity"); templateNames.add("Entity");
templateNames.add("Dto"); templateNames.add("Dto");
@ -51,9 +51,9 @@ public class GenUtil {
/** /**
* *
* @return * @return List
*/ */
public static List<String> getFrontTemplateNames() { private static List<String> getFrontTemplateNames() {
List<String> templateNames = new ArrayList<>(); List<String> templateNames = new ArrayList<>();
templateNames.add("api"); templateNames.add("api");
templateNames.add("index"); templateNames.add("index");
@ -67,7 +67,7 @@ public class GenUtil {
* @param genConfig * @param genConfig
*/ */
public static void generatorCode(List<ColumnInfo> columnInfos, GenConfig genConfig, String tableName) throws IOException { public static void generatorCode(List<ColumnInfo> columnInfos, GenConfig genConfig, String tableName) throws IOException {
Map<String,Object> map = new HashMap(); Map<String,Object> map = new HashMap<>();
map.put("package",genConfig.getPack()); map.put("package",genConfig.getPack());
map.put("moduleName",genConfig.getModuleName()); map.put("moduleName",genConfig.getModuleName());
map.put("author",genConfig.getAuthor()); map.put("author",genConfig.getAuthor());
@ -85,6 +85,8 @@ public class GenUtil {
map.put("upperCaseClassName", className.toUpperCase()); map.put("upperCaseClassName", className.toUpperCase());
map.put("changeClassName", changeClassName); map.put("changeClassName", changeClassName);
map.put("hasTimestamp",false); map.put("hasTimestamp",false);
map.put("queryHasTimestamp",false);
map.put("queryHasBigDecimal",false);
map.put("hasBigDecimal",false); map.put("hasBigDecimal",false);
map.put("hasQuery",false); map.put("hasQuery",false);
map.put("auto",false); map.put("auto",false);
@ -92,7 +94,7 @@ public class GenUtil {
List<Map<String,Object>> columns = new ArrayList<>(); List<Map<String,Object>> columns = new ArrayList<>();
List<Map<String,Object>> queryColumns = new ArrayList<>(); List<Map<String,Object>> queryColumns = new ArrayList<>();
for (ColumnInfo column : columnInfos) { for (ColumnInfo column : columnInfos) {
Map<String,Object> listMap = new HashMap(); Map<String,Object> listMap = new HashMap<>();
listMap.put("columnComment",column.getColumnComment()); listMap.put("columnComment",column.getColumnComment());
listMap.put("columnKey",column.getColumnKey()); listMap.put("columnKey",column.getColumnKey());
@ -124,6 +126,12 @@ public class GenUtil {
if(!StringUtils.isBlank(column.getColumnQuery())){ if(!StringUtils.isBlank(column.getColumnQuery())){
listMap.put("columnQuery",column.getColumnQuery()); listMap.put("columnQuery",column.getColumnQuery());
map.put("hasQuery",true); map.put("hasQuery",true);
if(TIMESTAMP.equals(colType)){
map.put("queryHasTimestamp",true);
}
if(BIGDECIMAL.equals(colType)){
map.put("queryHasBigDecimal",true);
}
queryColumns.add(listMap); queryColumns.add(listMap);
} }
columns.add(listMap); columns.add(listMap);
@ -138,6 +146,7 @@ public class GenUtil {
Template template = engine.getTemplate("generator/admin/"+templateName+".ftl"); Template template = engine.getTemplate("generator/admin/"+templateName+".ftl");
String filePath = getAdminFilePath(templateName,genConfig,className); String filePath = getAdminFilePath(templateName,genConfig,className);
assert filePath != null;
File file = new File(filePath); File file = new File(filePath);
// 如果非覆盖生成 // 如果非覆盖生成
@ -154,6 +163,7 @@ public class GenUtil {
Template template = engine.getTemplate("generator/front/"+templateName+".ftl"); Template template = engine.getTemplate("generator/front/"+templateName+".ftl");
String filePath = getFrontFilePath(templateName,genConfig,map.get("changeClassName").toString()); String filePath = getFrontFilePath(templateName,genConfig,map.get("changeClassName").toString());
assert filePath != null;
File file = new File(filePath); File file = new File(filePath);
// 如果非覆盖生成 // 如果非覆盖生成
@ -168,7 +178,7 @@ public class GenUtil {
/** /**
* *
*/ */
public static String getAdminFilePath(String templateName, GenConfig genConfig, String className) { private static String getAdminFilePath(String templateName, GenConfig genConfig, String className) {
String projectPath = System.getProperty("user.dir") + File.separator + genConfig.getModuleName(); String projectPath = System.getProperty("user.dir") + File.separator + genConfig.getModuleName();
String packagePath = projectPath + File.separator + "src" +File.separator+ "main" + File.separator + "java" + File.separator; String packagePath = projectPath + File.separator + "src" +File.separator+ "main" + File.separator + "java" + File.separator;
if (!ObjectUtils.isEmpty(genConfig.getPack())) { if (!ObjectUtils.isEmpty(genConfig.getPack())) {
@ -213,7 +223,7 @@ public class GenUtil {
/** /**
* *
*/ */
public static String getFrontFilePath(String templateName, GenConfig genConfig, String apiName) { private static String getFrontFilePath(String templateName, GenConfig genConfig, String apiName) {
String path = genConfig.getPath(); String path = genConfig.getPath();
if ("api".equals(templateName)) { if ("api".equals(templateName)) {
@ -230,18 +240,17 @@ public class GenUtil {
return null; return null;
} }
public static void genFile(File file,Template template,Map<String,Object> map) throws IOException { private static void genFile(File file, Template template, Map<String, Object> map) throws IOException {
// 生成目标文件 // 生成目标文件
Writer writer = null; Writer writer = null;
try { try {
FileUtil.touch(file); FileUtil.touch(file);
writer = new FileWriter(file); writer = new FileWriter(file);
template.render(map, writer); template.render(map, writer);
} catch (TemplateException e) { } catch (TemplateException | IOException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} finally { } finally {
assert writer != null;
writer.close(); writer.close();
} }
} }

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>eladmin</artifactId> <artifactId>eladmin</artifactId>
<groupId>me.zhengjie</groupId> <groupId>me.zhengjie</groupId>
<version>2.2</version> <version>2.3</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@ -16,7 +16,7 @@
<dependency> <dependency>
<groupId>me.zhengjie</groupId> <groupId>me.zhengjie</groupId>
<artifactId>eladmin-common</artifactId> <artifactId>eladmin-common</artifactId>
<version>2.2</version> <version>2.3</version>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -2,7 +2,6 @@ package me.zhengjie.aspect;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.zhengjie.domain.Log; import me.zhengjie.domain.Log;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.service.LogService; import me.zhengjie.service.LogService;
import me.zhengjie.utils.RequestHolder; import me.zhengjie.utils.RequestHolder;
import me.zhengjie.utils.SecurityUtils; import me.zhengjie.utils.SecurityUtils;
@ -14,7 +13,6 @@ import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -28,11 +26,14 @@ import javax.servlet.http.HttpServletRequest;
@Slf4j @Slf4j
public class LogAspect { public class LogAspect {
@Autowired private final LogService logService;
private LogService logService;
private long currentTime = 0L; private long currentTime = 0L;
public LogAspect(LogService logService) {
this.logService = logService;
}
/** /**
* *
*/ */
@ -48,11 +49,12 @@ public class LogAspect {
*/ */
@Around("logPointcut()") @Around("logPointcut()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
Object result = null; Object result;
currentTime = System.currentTimeMillis(); currentTime = System.currentTimeMillis();
result = joinPoint.proceed(); result = joinPoint.proceed();
Log log = new Log("INFO",System.currentTimeMillis() - currentTime); Log log = new Log("INFO",System.currentTimeMillis() - currentTime);
logService.save(getUsername(), StringUtils.getIP(RequestHolder.getHttpServletRequest()),joinPoint, log); HttpServletRequest request = RequestHolder.getHttpServletRequest();
logService.save(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request),joinPoint, log);
return result; return result;
} }
@ -66,7 +68,8 @@ public class LogAspect {
public void logAfterThrowing(JoinPoint joinPoint, Throwable e) { public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
Log log = new Log("ERROR",System.currentTimeMillis() - currentTime); Log log = new Log("ERROR",System.currentTimeMillis() - currentTime);
log.setExceptionDetail(ThrowableUtil.getStackTrace(e).getBytes()); log.setExceptionDetail(ThrowableUtil.getStackTrace(e).getBytes());
logService.save(getUsername(), StringUtils.getIP(RequestHolder.getHttpServletRequest()), (ProceedingJoinPoint)joinPoint, log); HttpServletRequest request = RequestHolder.getHttpServletRequest();
logService.save(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request), (ProceedingJoinPoint)joinPoint, log);
} }
public String getUsername() { public String getUsername() {

View File

@ -21,56 +21,40 @@ public class Log implements Serializable {
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; private Long id;
/** // 操作用户
*
*/
private String username; private String username;
/** // 描述
*
*/
private String description; private String description;
/** // 方法名
*
*/
private String method; private String method;
/** // 参数
*
*/
@Column(columnDefinition = "text") @Column(columnDefinition = "text")
private String params; private String params;
/** // 日志类型
*
*/
@Column(name = "log_type") @Column(name = "log_type")
private String logType; private String logType;
/** // 请求ip
* ip
*/
@Column(name = "request_ip") @Column(name = "request_ip")
private String requestIp; private String requestIp;
@Column(name = "address") @Column(name = "address")
private String address; private String address;
/** private String browser;
*
*/ // 请求耗时
private Long time; private Long time;
/** // 异常详细
*
*/
@Column(name = "exception_detail", columnDefinition = "text") @Column(name = "exception_detail", columnDefinition = "text")
private byte[] exceptionDetail; private byte[] exceptionDetail;
/** // 创建日期
*
*/
@CreationTimestamp @CreationTimestamp
@Column(name = "create_time") @Column(name = "create_time")
private Timestamp createTime; private Timestamp createTime;

View File

@ -11,22 +11,14 @@ import org.springframework.stereotype.Repository;
* @date 2018-11-24 * @date 2018-11-24
*/ */
@Repository @Repository
public interface LogRepository extends JpaRepository<Log,Long>, JpaSpecificationExecutor { public interface LogRepository extends JpaRepository<Log,Long>, JpaSpecificationExecutor<Log> {
/** /**
* IP * IP
* @param date1
* @param date2
* @return
*/ */
@Query(value = "select count(*) FROM (select request_ip FROM log where create_time between ?1 and ?2 GROUP BY request_ip) as s",nativeQuery = true) @Query(value = "select count(*) FROM (select request_ip FROM log where create_time between ?1 and ?2 GROUP BY request_ip) as s",nativeQuery = true)
Long findIp(String date1, String date2); Long findIp(String date1, String date2);
/** @Query(value = "select l FROM Log l where l.id = ?1")
* findExceptionById Log findExceptionById(Long id);
* @param id
* @return
*/
@Query(value = "select exception_detail FROM log where id = ?1",nativeQuery = true)
String findExceptionById(Long id);
} }

View File

@ -1,9 +1,11 @@
package me.zhengjie.rest; package me.zhengjie.rest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import me.zhengjie.aop.log.Log;
import me.zhengjie.service.LogService; import me.zhengjie.service.LogService;
import me.zhengjie.service.dto.LogQueryCriteria; import me.zhengjie.service.dto.LogQueryCriteria;
import me.zhengjie.utils.SecurityUtils; import me.zhengjie.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@ -13,41 +15,60 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/** /**
* @author Zheng Jie * @author Zheng Jie
* @date 2018-11-24 * @date 2018-11-24
*/ */
@RestController @RestController
@RequestMapping("api") @RequestMapping("/api/logs")
@Api(tags = "监控:日志管理")
public class LogController { public class LogController {
@Autowired private final LogService logService;
private LogService logService;
@GetMapping(value = "/logs") public LogController(LogService logService) {
@PreAuthorize("hasAnyRole('ADMIN')") this.logService = logService;
public ResponseEntity getLogs(LogQueryCriteria criteria, Pageable pageable){
criteria.setLogType("INFO");
return new ResponseEntity(logService.queryAll(criteria,pageable), HttpStatus.OK);
} }
@GetMapping(value = "/logs/user") @Log("导出数据")
@ApiOperation("导出数据")
@GetMapping(value = "/download")
@PreAuthorize("@el.check()")
public void download(HttpServletResponse response, LogQueryCriteria criteria) throws IOException {
logService.download(logService.queryAll(criteria), response);
}
@GetMapping
@ApiOperation("日志查询")
@PreAuthorize("@el.check()")
public ResponseEntity getLogs(LogQueryCriteria criteria, Pageable pageable){
criteria.setLogType("INFO");
return new ResponseEntity<>(logService.queryAll(criteria,pageable), HttpStatus.OK);
}
@GetMapping(value = "/user")
@ApiOperation("用户日志查询")
public ResponseEntity getUserLogs(LogQueryCriteria criteria, Pageable pageable){ public ResponseEntity getUserLogs(LogQueryCriteria criteria, Pageable pageable){
criteria.setLogType("INFO"); criteria.setLogType("INFO");
criteria.setBlurry(SecurityUtils.getUsername()); criteria.setBlurry(SecurityUtils.getUsername());
return new ResponseEntity(logService.queryAllByUser(criteria,pageable), HttpStatus.OK); return new ResponseEntity<>(logService.queryAllByUser(criteria,pageable), HttpStatus.OK);
} }
@GetMapping(value = "/logs/error") @GetMapping(value = "/error")
@PreAuthorize("hasAnyRole('ADMIN')") @ApiOperation("错误日志查询")
@PreAuthorize("@el.check()")
public ResponseEntity getErrorLogs(LogQueryCriteria criteria, Pageable pageable){ public ResponseEntity getErrorLogs(LogQueryCriteria criteria, Pageable pageable){
criteria.setLogType("ERROR"); criteria.setLogType("ERROR");
return new ResponseEntity(logService.queryAll(criteria,pageable), HttpStatus.OK); return new ResponseEntity<>(logService.queryAll(criteria,pageable), HttpStatus.OK);
} }
@GetMapping(value = "/logs/error/{id}") @GetMapping(value = "/error/{id}")
@PreAuthorize("hasAnyRole('ADMIN')") @ApiOperation("日志异常详情查询")
@PreAuthorize("@el.check()")
public ResponseEntity getErrorLogs(@PathVariable Long id){ public ResponseEntity getErrorLogs(@PathVariable Long id){
return new ResponseEntity(logService.findByErrDetail(id), HttpStatus.OK); return new ResponseEntity<>(logService.findByErrDetail(id), HttpStatus.OK);
} }
} }

View File

@ -6,42 +6,31 @@ import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Async;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/** /**
* @author Zheng Jie * @author Zheng Jie
* @date 2018-11-24 * @date 2018-11-24
*/ */
public interface LogService { public interface LogService {
/**
* queryAll
* @param criteria
* @param pageable
* @return
*/
Object queryAll(LogQueryCriteria criteria, Pageable pageable); Object queryAll(LogQueryCriteria criteria, Pageable pageable);
/** List<Log> queryAll(LogQueryCriteria criteria);
* queryAllByUser
* @param criteria
* @param pageable
* @return
*/
Object queryAllByUser(LogQueryCriteria criteria, Pageable pageable); Object queryAllByUser(LogQueryCriteria criteria, Pageable pageable);
/**
*
* @param username
* @param ip
* @param joinPoint
* @param log
*/
@Async @Async
void save(String username, String ip, ProceedingJoinPoint joinPoint, Log log); void save(String username, String browser, String ip, ProceedingJoinPoint joinPoint, Log log);
/** /**
* *
* @param id * @param id ID
* @return * @return Object
*/ */
Object findByErrDetail(Long id); Object findByErrDetail(Long id);
void download(List<Log> queryAll, HttpServletResponse response) throws IOException;
} }

View File

@ -13,36 +13,26 @@ public class LogErrorDTO implements Serializable {
private Long id; private Long id;
/** // 操作用户
*
*/
private String username; private String username;
/** // 描述
*
*/
private String description; private String description;
/** // 方法名
*
*/
private String method; private String method;
/** // 参数
*
*/
private String params; private String params;
/** private String browser;
* ip
*/ // 请求ip
private String requestIp; private String requestIp;
private String address; private String address;
/** // 创建日期
*
*/
private Timestamp createTime; private Timestamp createTime;
} }

View File

@ -3,6 +3,8 @@ package me.zhengjie.service.dto;
import lombok.Data; import lombok.Data;
import me.zhengjie.annotation.Query; import me.zhengjie.annotation.Query;
import java.sql.Timestamp;
/** /**
* *
* @author Zheng Jie * @author Zheng Jie
@ -17,4 +19,10 @@ public class LogQueryCriteria {
@Query @Query
private String logType; private String logType;
@Query(type = Query.Type.GREATER_THAN,propName = "createTime")
private Timestamp startTime;
@Query(type = Query.Type.LESS_THAN,propName = "createTime")
private Timestamp endTime;
} }

View File

@ -1,7 +1,6 @@
package me.zhengjie.service.dto; package me.zhengjie.service.dto;
import lombok.Data; import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
import java.sql.Timestamp; import java.sql.Timestamp;
@ -12,25 +11,19 @@ import java.sql.Timestamp;
@Data @Data
public class LogSmallDTO implements Serializable { public class LogSmallDTO implements Serializable {
/** // 描述
*
*/
private String description; private String description;
/** // 请求ip
* ip
*/
private String requestIp; private String requestIp;
/** // 请求耗时
*
*/
private Long time; private Long time;
private String address; private String address;
/** private String browser;
*
*/ // 创建日期
private Timestamp createTime; private Timestamp createTime;
} }

View File

@ -1,6 +1,7 @@
package me.zhengjie.service.impl; package me.zhengjie.service.impl;
import cn.hutool.core.lang.Dict; import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import me.zhengjie.domain.Log; import me.zhengjie.domain.Log;
import me.zhengjie.repository.LogRepository; import me.zhengjie.repository.LogRepository;
@ -8,18 +9,25 @@ import me.zhengjie.service.LogService;
import me.zhengjie.service.dto.LogQueryCriteria; import me.zhengjie.service.dto.LogQueryCriteria;
import me.zhengjie.service.mapper.LogErrorMapper; import me.zhengjie.service.mapper.LogErrorMapper;
import me.zhengjie.service.mapper.LogSmallMapper; import me.zhengjie.service.mapper.LogSmallMapper;
import me.zhengjie.utils.FileUtil;
import me.zhengjie.utils.PageUtil; import me.zhengjie.utils.PageUtil;
import me.zhengjie.utils.QueryHelp; import me.zhengjie.utils.QueryHelp;
import me.zhengjie.utils.StringUtils; import me.zhengjie.utils.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature; import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/** /**
* @author Zheng Jie * @author Zheng Jie
@ -29,16 +37,17 @@ import java.lang.reflect.Method;
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class) @Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class LogServiceImpl implements LogService { public class LogServiceImpl implements LogService {
@Autowired private final LogRepository logRepository;
private LogRepository logRepository;
@Autowired private final LogErrorMapper logErrorMapper;
private LogErrorMapper logErrorMapper;
@Autowired private final LogSmallMapper logSmallMapper;
private LogSmallMapper logSmallMapper;
private final String LOGINPATH = "login"; public LogServiceImpl(LogRepository logRepository, LogErrorMapper logErrorMapper, LogSmallMapper logSmallMapper) {
this.logRepository = logRepository;
this.logErrorMapper = logErrorMapper;
this.logSmallMapper = logSmallMapper;
}
@Override @Override
public Object queryAll(LogQueryCriteria criteria, Pageable pageable){ public Object queryAll(LogQueryCriteria criteria, Pageable pageable){
@ -49,6 +58,11 @@ public class LogServiceImpl implements LogService {
return page; return page;
} }
@Override
public List<Log> queryAll(LogQueryCriteria criteria) {
return logRepository.findAll(((root, criteriaQuery, cb) -> QueryHelp.getPredicate(root, criteria, cb)));
}
@Override @Override
public Object queryAllByUser(LogQueryCriteria criteria, Pageable pageable) { public Object queryAllByUser(LogQueryCriteria criteria, Pageable pageable) {
Page<Log> page = logRepository.findAll(((root, criteriaQuery, cb) -> QueryHelp.getPredicate(root, criteria, cb)),pageable); Page<Log> page = logRepository.findAll(((root, criteriaQuery, cb) -> QueryHelp.getPredicate(root, criteria, cb)),pageable);
@ -57,38 +71,37 @@ public class LogServiceImpl implements LogService {
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void save(String username, String ip, ProceedingJoinPoint joinPoint, Log log){ public void save(String username, String browser, String ip, ProceedingJoinPoint joinPoint, Log log){
MethodSignature signature = (MethodSignature) joinPoint.getSignature(); MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod(); Method method = signature.getMethod();
me.zhengjie.aop.log.Log aopLog = method.getAnnotation(me.zhengjie.aop.log.Log.class); me.zhengjie.aop.log.Log aopLog = method.getAnnotation(me.zhengjie.aop.log.Log.class);
// 描述
if (log != null) {
log.setDescription(aopLog.value());
}
// 方法路径 // 方法路径
String methodName = joinPoint.getTarget().getClass().getName()+"."+signature.getName()+"()"; String methodName = joinPoint.getTarget().getClass().getName()+"."+signature.getName()+"()";
String params = "{"; StringBuilder params = new StringBuilder("{");
//参数值 //参数值
Object[] argValues = joinPoint.getArgs(); Object[] argValues = joinPoint.getArgs();
//参数名称 //参数名称
String[] argNames = ((MethodSignature)joinPoint.getSignature()).getParameterNames(); String[] argNames = ((MethodSignature)joinPoint.getSignature()).getParameterNames();
if(argValues != null){ if(argValues != null){
for (int i = 0; i < argValues.length; i++) { for (int i = 0; i < argValues.length; i++) {
params += " " + argNames[i] + ": " + argValues[i]; params.append(" ").append(argNames[i]).append(": ").append(argValues[i]);
} }
} }
// 描述
// 获取IP地址 if (log != null) {
log.setDescription(aopLog.value());
}
assert log != null;
log.setRequestIp(ip); log.setRequestIp(ip);
String LOGINPATH = "login";
if(LOGINPATH.equals(signature.getName())){ if(LOGINPATH.equals(signature.getName())){
try { try {
JSONObject jsonObject = new JSONObject(argValues[0]); assert argValues != null;
username = jsonObject.get("username").toString(); username = new JSONObject(argValues[0]).get("username").toString();
}catch (Exception e){ }catch (Exception e){
e.printStackTrace(); e.printStackTrace();
} }
@ -96,12 +109,32 @@ public class LogServiceImpl implements LogService {
log.setAddress(StringUtils.getCityInfo(log.getRequestIp())); log.setAddress(StringUtils.getCityInfo(log.getRequestIp()));
log.setMethod(methodName); log.setMethod(methodName);
log.setUsername(username); log.setUsername(username);
log.setParams(params + " }"); log.setParams(params.toString() + " }");
log.setBrowser(browser);
logRepository.save(log); logRepository.save(log);
} }
@Override @Override
public Object findByErrDetail(Long id) { public Object findByErrDetail(Long id) {
return Dict.create().set("exception",logRepository.findExceptionById(id)); byte[] details = logRepository.findExceptionById(id).getExceptionDetail();
return Dict.create().set("exception",new String(ObjectUtil.isNotNull(details) ? details : "".getBytes()));
}
@Override
public void download(List<Log> logs, HttpServletResponse response) throws IOException {
List<Map<String, Object>> list = new ArrayList<>();
for (Log log : logs) {
Map<String,Object> map = new LinkedHashMap<>();
map.put("用户名", log.getUsername());
map.put("IP", log.getRequestIp());
map.put("IP来源", log.getAddress());
map.put("描述", log.getDescription());
map.put("浏览器", log.getBrowser());
map.put("请求耗时/毫秒", log.getTime());
map.put("异常详情", new String(ObjectUtil.isNotNull(log.getExceptionDetail()) ? log.getExceptionDetail() : "".getBytes()));
map.put("创建日期", log.getCreateTime());
list.add(map);
}
FileUtil.downloadExcel(list, response);
} }
} }

View File

@ -1,7 +1,7 @@
package me.zhengjie.service.mapper; package me.zhengjie.service.mapper;
import me.zhengjie.base.BaseMapper;
import me.zhengjie.domain.Log; import me.zhengjie.domain.Log;
import me.zhengjie.mapper.EntityMapper;
import me.zhengjie.service.dto.LogErrorDTO; import me.zhengjie.service.dto.LogErrorDTO;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.ReportingPolicy; import org.mapstruct.ReportingPolicy;
@ -10,7 +10,7 @@ import org.mapstruct.ReportingPolicy;
* @author Zheng Jie * @author Zheng Jie
* @date 2019-5-22 * @date 2019-5-22
*/ */
@Mapper(componentModel = "spring",uses = {},unmappedTargetPolicy = ReportingPolicy.IGNORE) @Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface LogErrorMapper extends EntityMapper<LogErrorDTO, Log> { public interface LogErrorMapper extends BaseMapper<LogErrorDTO, Log> {
} }

View File

@ -1,7 +1,7 @@
package me.zhengjie.service.mapper; package me.zhengjie.service.mapper;
import me.zhengjie.base.BaseMapper;
import me.zhengjie.domain.Log; import me.zhengjie.domain.Log;
import me.zhengjie.mapper.EntityMapper;
import me.zhengjie.service.dto.LogSmallDTO; import me.zhengjie.service.dto.LogSmallDTO;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.ReportingPolicy; import org.mapstruct.ReportingPolicy;
@ -10,7 +10,7 @@ import org.mapstruct.ReportingPolicy;
* @author Zheng Jie * @author Zheng Jie
* @date 2019-5-22 * @date 2019-5-22
*/ */
@Mapper(componentModel = "spring",uses = {},unmappedTargetPolicy = ReportingPolicy.IGNORE) @Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface LogSmallMapper extends EntityMapper<LogSmallDTO, Log> { public interface LogSmallMapper extends BaseMapper<LogSmallDTO, Log> {
} }

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>eladmin</artifactId> <artifactId>eladmin</artifactId>
<groupId>me.zhengjie</groupId> <groupId>me.zhengjie</groupId>
<version>2.2</version> <version>2.3</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@ -20,7 +20,7 @@
<dependency> <dependency>
<groupId>me.zhengjie</groupId> <groupId>me.zhengjie</groupId>
<artifactId>eladmin-generator</artifactId> <artifactId>eladmin-generator</artifactId>
<version>2.2</version> <version>2.3</version>
<exclusions> <exclusions>
<exclusion> <exclusion>
<groupId>me.zhengjie</groupId> <groupId>me.zhengjie</groupId>
@ -32,7 +32,7 @@
<dependency> <dependency>
<groupId>me.zhengjie</groupId> <groupId>me.zhengjie</groupId>
<artifactId>eladmin-tools</artifactId> <artifactId>eladmin-tools</artifactId>
<version>2.2</version> <version>2.3</version>
</dependency> </dependency>
<!--jwt--> <!--jwt-->

View File

@ -25,14 +25,17 @@ public class DataScope {
private final String[] scopeType = {"全部","本级","自定义"}; private final String[] scopeType = {"全部","本级","自定义"};
@Autowired private final UserService userService;
private UserService userService;
@Autowired private final RoleService roleService;
private RoleService roleService;
@Autowired private final DeptService deptService;
private DeptService deptService;
public DataScope(UserService userService, RoleService roleService, DeptService deptService) {
this.userService = userService;
this.roleService = roleService;
this.deptService = deptService;
}
public Set<Long> getDeptIds() { public Set<Long> getDeptIds() {
@ -76,7 +79,7 @@ public class DataScope {
deptList.forEach(dept -> { deptList.forEach(dept -> {
if (dept!=null && dept.getEnabled()){ if (dept!=null && dept.getEnabled()){
List<Dept> depts = deptService.findByPid(dept.getId()); List<Dept> depts = deptService.findByPid(dept.getId());
if(deptList!=null && deptList.size()!=0){ if(deptList.size() != 0){
list.addAll(getDeptChildren(depts)); list.addAll(getDeptChildren(depts));
} }
list.add(dept.getId()); list.add(dept.getId());

View File

@ -0,0 +1,54 @@
package me.zhengjie.config.thread;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 线
* @author https://juejin.im/entry/5abb8f6951882555677e9da2
* @date 2019103115:06:18
*/
@Slf4j
@Configuration
public class AsyncTaskExecutePool implements AsyncConfigurer {
//注入配置类
private final AsyncTaskProperties config;
public AsyncTaskExecutePool(AsyncTaskProperties config) {
this.config = config;
}
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程池大小
executor.setCorePoolSize(config.getCorePoolSize());
//最大线程数
executor.setMaxPoolSize(config.getMaxPoolSize());
//队列容量
executor.setQueueCapacity(config.getQueueCapacity());
//活跃时间
executor.setKeepAliveSeconds(config.getKeepAliveSeconds());
//线程名字前缀
executor.setThreadNamePrefix("el-async-");
// setRejectedExecutionHandler当pool已经达到max size的时候如何处理新任务
// CallerRunsPolicy不在新线程中执行任务而是由调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (throwable, method, objects) -> {
log.error("===="+throwable.getMessage()+"====", throwable);
log.error("exception method:"+method.getName());
};
}
}

View File

@ -0,0 +1,24 @@
package me.zhengjie.config.thread;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 线
* @author https://juejin.im/entry/5abb8f6951882555677e9da2
* @date 2019103114:58:18
*/
@Data
@Component
@ConfigurationProperties(prefix = "task.pool")
public class AsyncTaskProperties {
private int corePoolSize;
private int maxPoolSize;
private int keepAliveSeconds;
private int queueCapacity;
}

View File

@ -0,0 +1,48 @@
package me.zhengjie.config.thread;
import org.springframework.stereotype.Component;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 线
* @author Zheng Jie
* @date 2019103117:49:55
*/
@Component
public class TheadFactoryName implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
public TheadFactoryName() {
this("el-pool");
}
private TheadFactoryName(String name){
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
//此时namePrefix就是 name + 第几个用这个工厂创建线程池的
this.namePrefix = name +
poolNumber.getAndIncrement();
}
@Override
public Thread newThread(Runnable r) {
//此时线程的名字 就是 namePrefix + -thread- + 这个线程池中第几个执行的线程
Thread t = new Thread(group, r,
namePrefix + "-thread-"+threadNumber.getAndIncrement(),
0);
if (t.isDaemon()) {
t.setDaemon(false);
}
if (t.getPriority() != Thread.NORM_PRIORITY) {
t.setPriority(Thread.NORM_PRIORITY);
}
return t;
}
}

View File

@ -0,0 +1,27 @@
package me.zhengjie.config.thread;
import me.zhengjie.utils.SpringContextHolder;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 线
* @author Zheng Jie
* @date 2019103118:16:47
*/
public class ThreadPoolExecutorUtil {
public static ThreadPoolExecutor getPoll(){
AsyncTaskProperties properties = SpringContextHolder.getBean(AsyncTaskProperties.class);
return new ThreadPoolExecutor(
properties.getCorePoolSize(),
properties.getMaxPoolSize(),
properties.getKeepAliveSeconds(),
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(properties.getQueueCapacity()),
new TheadFactoryName()
);
}
}

View File

@ -1,7 +1,6 @@
package me.zhengjie.modules.monitor.config; package me.zhengjie.modules.monitor.config;
import me.zhengjie.modules.monitor.service.VisitsService; import me.zhengjie.modules.monitor.service.VisitsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner; import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -13,11 +12,14 @@ import org.springframework.stereotype.Component;
@Component @Component
public class VisitsInitialization implements ApplicationRunner { public class VisitsInitialization implements ApplicationRunner {
@Autowired private final VisitsService visitsService;
private VisitsService visitsService;
public VisitsInitialization(VisitsService visitsService) {
this.visitsService = visitsService;
}
@Override @Override
public void run(ApplicationArguments args) throws Exception { public void run(ApplicationArguments args){
System.out.println("--------------- 初始化站点统计,如果存在今日统计则跳过 ---------------"); System.out.println("--------------- 初始化站点统计,如果存在今日统计则跳过 ---------------");
visitsService.save(); visitsService.save();
System.out.println("--------------- 初始化站点统计完成 ---------------"); System.out.println("--------------- 初始化站点统计完成 ---------------");

View File

@ -4,6 +4,7 @@ import lombok.Data;
import org.hibernate.annotations.CreationTimestamp; import org.hibernate.annotations.CreationTimestamp;
import javax.persistence.*; import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp; import java.sql.Timestamp;
/** /**
@ -15,7 +16,7 @@ import java.sql.Timestamp;
@Entity @Entity
@Data @Data
@Table(name = "visits") @Table(name = "visits")
public class Visits { public class Visits implements Serializable {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)

View File

@ -4,7 +4,6 @@ import me.zhengjie.modules.monitor.domain.Visits;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.util.List; import java.util.List;
/** /**
@ -16,18 +15,17 @@ public interface VisitsRepository extends JpaRepository<Visits,Long> {
/** /**
* findByDate * findByDate
* @param date * @param date
* @return * @return Visits
*/ */
Visits findByDate(String date); Visits findByDate(String date);
/** /**
* *
* @param date1 * @param date1 1
* @param date2 * @param date2 2
* @return * @return List
*/ */
@Query(value = "select * FROM visits where " + @Query(value = "select * FROM visits where create_time between ?1 and ?2",nativeQuery = true)
"create_time between ?1 and ?2",nativeQuery = true)
List<Visits> findAllVisits(String date1, String date2); List<Visits> findAllVisits(String date1, String date2);
} }

View File

@ -1,6 +1,10 @@
package me.zhengjie.modules.monitor.rest; package me.zhengjie.modules.monitor.rest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import me.zhengjie.annotation.AnonymousAccess;
import me.zhengjie.annotation.Limit; import me.zhengjie.annotation.Limit;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -12,15 +16,19 @@ import java.util.concurrent.atomic.AtomicInteger;
* *
*/ */
@RestController @RestController
@RequestMapping("api") @RequestMapping("/api/limit")
@Api(tags = "系统:限流测试管理")
public class LimitController { public class LimitController {
private static final AtomicInteger ATOMIC_INTEGER = new AtomicInteger(); private static final AtomicInteger ATOMIC_INTEGER = new AtomicInteger();
/** /**
* 60访 10redis limit_test * 60访 10redis limit_test
*/ */
@GetMapping
@PreAuthorize("@el.check('anonymous')")
@ApiOperation("测试")
@Limit(key = "test", period = 60, count = 10, name = "testLimit", prefix = "limit") @Limit(key = "test", period = 60, count = 10, name = "testLimit", prefix = "limit")
@GetMapping("/limit")
public int testLimit() { public int testLimit() {
return ATOMIC_INTEGER.incrementAndGet(); return ATOMIC_INTEGER.incrementAndGet();
} }

View File

@ -1,47 +1,65 @@
package me.zhengjie.modules.monitor.rest; package me.zhengjie.modules.monitor.rest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import me.zhengjie.aop.log.Log; import me.zhengjie.aop.log.Log;
import me.zhengjie.modules.monitor.domain.vo.RedisVo; import me.zhengjie.modules.monitor.domain.vo.RedisVo;
import me.zhengjie.modules.monitor.service.RedisService; import me.zhengjie.modules.monitor.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/** /**
* @author Zheng Jie * @author Zheng Jie
* @date 2018-12-10 * @date 2018-12-10
*/ */
@RestController @RestController
@RequestMapping("api") @RequestMapping("/api/redis")
@Api(tags = "系统Redis缓存管理")
public class RedisController { public class RedisController {
@Autowired private final RedisService redisService;
private RedisService redisService;
public RedisController(RedisService redisService) {
this.redisService = redisService;
}
@Log("查询Redis缓存") @Log("查询Redis缓存")
@GetMapping(value = "/redis") @GetMapping
@PreAuthorize("hasAnyRole('ADMIN','REDIS_ALL','REDIS_SELECT')") @ApiOperation("查询Redis缓存")
@PreAuthorize("@el.check('redis:list')")
public ResponseEntity getRedis(String key, Pageable pageable){ public ResponseEntity getRedis(String key, Pageable pageable){
return new ResponseEntity(redisService.findByKey(key,pageable), HttpStatus.OK); return new ResponseEntity<>(redisService.findByKey(key,pageable), HttpStatus.OK);
}
@Log("导出数据")
@ApiOperation("导出数据")
@GetMapping(value = "/download")
@PreAuthorize("@el.check('redis:list')")
public void download(HttpServletResponse response, String key) throws IOException {
redisService.download(redisService.findByKey(key), response);
} }
@Log("删除Redis缓存") @Log("删除Redis缓存")
@DeleteMapping(value = "/redis") @DeleteMapping
@PreAuthorize("hasAnyRole('ADMIN','REDIS_ALL','REDIS_DELETE')") @ApiOperation("删除Redis缓存")
@PreAuthorize("@el.check('redis:del')")
public ResponseEntity delete(@RequestBody RedisVo resources){ public ResponseEntity delete(@RequestBody RedisVo resources){
redisService.delete(resources.getKey()); redisService.delete(resources.getKey());
return new ResponseEntity(HttpStatus.OK); return new ResponseEntity(HttpStatus.OK);
} }
@Log("清空Redis缓存") @Log("清空Redis缓存")
@DeleteMapping(value = "/redis/all") @DeleteMapping(value = "/all")
@PreAuthorize("hasAnyRole('ADMIN','REDIS_ALL','REDIS_DELETE')") @ApiOperation("清空Redis缓存")
@PreAuthorize("@el.check('redis:del')")
public ResponseEntity deleteAll(){ public ResponseEntity deleteAll(){
redisService.flushdb(); redisService.deleteAll();
return new ResponseEntity(HttpStatus.OK); return new ResponseEntity(HttpStatus.OK);
} }
} }

View File

@ -1,8 +1,9 @@
package me.zhengjie.modules.monitor.rest; package me.zhengjie.modules.monitor.rest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import me.zhengjie.modules.monitor.service.VisitsService; import me.zhengjie.modules.monitor.service.VisitsService;
import me.zhengjie.utils.RequestHolder; import me.zhengjie.utils.RequestHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
@ -15,25 +16,32 @@ import org.springframework.web.bind.annotation.RestController;
* @date 2018-12-13 * @date 2018-12-13
*/ */
@RestController @RestController
@RequestMapping("api") @RequestMapping("/api/visits")
@Api(tags = "系统:访问记录管理")
public class VisitsController { public class VisitsController {
@Autowired private final VisitsService visitsService;
private VisitsService visitsService;
@PostMapping(value = "/visits") public VisitsController(VisitsService visitsService) {
this.visitsService = visitsService;
}
@PostMapping
@ApiOperation("创建访问记录")
public ResponseEntity create(){ public ResponseEntity create(){
visitsService.count(RequestHolder.getHttpServletRequest()); visitsService.count(RequestHolder.getHttpServletRequest());
return new ResponseEntity(HttpStatus.CREATED); return new ResponseEntity(HttpStatus.CREATED);
} }
@GetMapping(value = "/visits") @GetMapping
@ApiOperation("查询")
public ResponseEntity get(){ public ResponseEntity get(){
return new ResponseEntity(visitsService.get(),HttpStatus.OK); return new ResponseEntity<>(visitsService.get(),HttpStatus.OK);
} }
@GetMapping(value = "/visits/chartData") @GetMapping(value = "/chartData")
@ApiOperation("查询图表数据")
public ResponseEntity getChartData(){ public ResponseEntity getChartData(){
return new ResponseEntity(visitsService.getChartData(),HttpStatus.OK); return new ResponseEntity<>(visitsService.getChartData(),HttpStatus.OK);
} }
} }

View File

@ -4,6 +4,10 @@ import me.zhengjie.modules.monitor.domain.vo.RedisVo;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/** /**
* *
* @author Zheng Jie * @author Zheng Jie
@ -13,33 +17,47 @@ public interface RedisService {
/** /**
* findById * findById
* @param key * @param key
* @return * @return /
*/ */
Page findByKey(String key, Pageable pageable); Page findByKey(String key, Pageable pageable);
/**
* findById
* @param key
* @return /
*/
List<RedisVo> findByKey(String key);
/** /**
* *
* @param key * @param key
* @return * @return /
*/ */
String getCodeVal(String key); String getCodeVal(String key);
/** /**
* *
* @param key * @param key
* @param val * @param val
*/ */
void saveCode(String key, Object val); void saveCode(String key, Object val);
/** /**
* delete * delete
* @param key * @param key
*/ */
void delete(String key); void delete(String key);
/** /**
* *
*/ */
void flushdb(); void deleteAll();
/**
*
* @param redisVos /
* @param response /
*/
void download(List<RedisVo> redisVos, HttpServletResponse response) throws IOException;
} }

View File

@ -1,7 +1,6 @@
package me.zhengjie.modules.monitor.service; package me.zhengjie.modules.monitor.service;
import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Async;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
/** /**
@ -17,20 +16,20 @@ public interface VisitsService {
/** /**
* *
* @param request * @param request /
*/ */
@Async @Async
void count(HttpServletRequest request); void count(HttpServletRequest request);
/** /**
* *
* @return * @return /
*/ */
Object get(); Object get();
/** /**
* getChartData * getChartData
* @return * @return /
*/ */
Object getChartData(); Object getChartData();
} }

View File

@ -1,51 +1,71 @@
package me.zhengjie.modules.monitor.service.impl; package me.zhengjie.modules.monitor.service.impl;
import cn.hutool.core.util.ObjectUtil;
import me.zhengjie.modules.monitor.domain.vo.RedisVo; import me.zhengjie.modules.monitor.domain.vo.RedisVo;
import me.zhengjie.modules.monitor.service.RedisService; import me.zhengjie.modules.monitor.service.RedisService;
import me.zhengjie.utils.FileUtil;
import me.zhengjie.utils.PageUtil; import me.zhengjie.utils.PageUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List; import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/** /**
* @author Zheng Jie * @author Zheng Jie
* @date 2018-12-10 * @date 2018-12-10
*/ */
@Service @Service
@SuppressWarnings({"unchecked","all"})
public class RedisServiceImpl implements RedisService { public class RedisServiceImpl implements RedisService {
@Autowired private final RedisTemplate redisTemplate;
RedisTemplate redisTemplate;
@Value("${loginCode.expiration}") @Value("${loginCode.expiration}")
private Long expiration; private Long expiration;
@Value("${jwt.online}")
private String onlineKey;
@Value("${jwt.codeKey}")
private String codeKey;
public RedisServiceImpl(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Override @Override
public Page<RedisVo> findByKey(String key, Pageable pageable){ public Page<RedisVo> findByKey(String key, Pageable pageable){
List<RedisVo> redisVos = findByKey(key);
return new PageImpl<RedisVo>(
PageUtil.toPage(pageable.getPageNumber(),pageable.getPageSize(),redisVos),
pageable,
redisVos.size());
}
@Override
public List<RedisVo> findByKey(String key) {
List<RedisVo> redisVos = new ArrayList<>(); List<RedisVo> redisVos = new ArrayList<>();
if(!"*".equals(key)){ if(!"*".equals(key)){
key = "*" + key + "*"; key = "*" + key + "*";
} }
for (Object s : redisTemplate.keys(key)) { Set<String> keys = redisTemplate.keys(key);
for (String s : keys) {
// 过滤掉权限的缓存 // 过滤掉权限的缓存
if (s.toString().indexOf("role::loadPermissionByUser") != -1 || s.toString().indexOf("user::loadUserByUsername") != -1) { if (s.contains("role::loadPermissionByUser") || s.contains("user::loadUserByUsername") || s.contains(onlineKey) || s.contains(codeKey)) {
continue; continue;
} }
RedisVo redisVo = new RedisVo(s.toString(),redisTemplate.opsForValue().get(s.toString()).toString()); RedisVo redisVo = new RedisVo(s, Objects.requireNonNull(redisTemplate.opsForValue().get(s)).toString());
redisVos.add(redisVo); redisVos.add(redisVo);
} }
Page<RedisVo> page = new PageImpl<RedisVo>( return redisVos;
PageUtil.toPage(pageable.getPageNumber(),pageable.getPageSize(),redisVos),
pageable,
redisVos.size());
return page;
} }
@Override @Override
@ -54,15 +74,15 @@ public class RedisServiceImpl implements RedisService {
} }
@Override @Override
public void flushdb() { public void deleteAll() {
redisTemplate.getConnectionFactory().getConnection().flushDb(); Set<String> keys = redisTemplate.keys( "*");
redisTemplate.delete(keys.stream().filter(s -> !s.contains(onlineKey)).filter(s -> !s.contains(codeKey)).collect(Collectors.toList()));
} }
@Override @Override
public String getCodeVal(String key) { public String getCodeVal(String key) {
try { try {
String value = redisTemplate.opsForValue().get(key).toString(); return Objects.requireNonNull(redisTemplate.opsForValue().get(key)).toString();
return value;
}catch (Exception e){ }catch (Exception e){
return ""; return "";
} }
@ -73,4 +93,16 @@ public class RedisServiceImpl implements RedisService {
redisTemplate.opsForValue().set(key,val); redisTemplate.opsForValue().set(key,val);
redisTemplate.expire(key,expiration, TimeUnit.MINUTES); redisTemplate.expire(key,expiration, TimeUnit.MINUTES);
} }
@Override
public void download(List<RedisVo> redisVos, HttpServletResponse response) throws IOException {
List<Map<String, Object>> list = new ArrayList<>();
for (RedisVo redisVo : redisVos) {
Map<String,Object> map = new LinkedHashMap<>();
map.put("key", redisVo.getKey());
map.put("value", redisVo.getValue());
list.add(map);
}
FileUtil.downloadExcel(list, response);
}
} }

View File

@ -26,11 +26,14 @@ import java.util.stream.Collectors;
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class) @Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class VisitsServiceImpl implements VisitsService { public class VisitsServiceImpl implements VisitsService {
@Autowired private final VisitsRepository visitsRepository;
private VisitsRepository visitsRepository;
@Autowired private final LogRepository logRepository;
private LogRepository logRepository;
public VisitsServiceImpl(VisitsRepository visitsRepository, LogRepository logRepository) {
this.visitsRepository = visitsRepository;
this.logRepository = logRepository;
}
@Override @Override
public void save() { public void save() {
@ -58,7 +61,7 @@ public class VisitsServiceImpl implements VisitsService {
@Override @Override
public Object get() { public Object get() {
Map map = new HashMap(); Map<String,Object> map = new HashMap<>();
LocalDate localDate = LocalDate.now(); LocalDate localDate = LocalDate.now();
Visits visits = visitsRepository.findByDate(localDate.toString()); Visits visits = visitsRepository.findByDate(localDate.toString());
List<Visits> list = visitsRepository.findAllVisits(localDate.minusDays(6).toString(),localDate.plusDays(1).toString()); List<Visits> list = visitsRepository.findAllVisits(localDate.minusDays(6).toString(),localDate.plusDays(1).toString());
@ -77,7 +80,7 @@ public class VisitsServiceImpl implements VisitsService {
@Override @Override
public Object getChartData() { public Object getChartData() {
Map map = new HashMap(); Map<String,Object> map = new HashMap<>();
LocalDate localDate = LocalDate.now(); LocalDate localDate = LocalDate.now();
List<Visits> list = visitsRepository.findAllVisits(localDate.minusDays(6).toString(),localDate.plusDays(1).toString()); List<Visits> list = visitsRepository.findAllVisits(localDate.minusDays(6).toString(),localDate.plusDays(1).toString());
map.put("weekDays",list.stream().map(Visits::getWeekDay).collect(Collectors.toList())); map.put("weekDays",list.stream().map(Visits::getWeekDay).collect(Collectors.toList()));

View File

@ -3,7 +3,6 @@ package me.zhengjie.modules.quartz.config;
import me.zhengjie.modules.quartz.domain.QuartzJob; import me.zhengjie.modules.quartz.domain.QuartzJob;
import me.zhengjie.modules.quartz.repository.QuartzJobRepository; import me.zhengjie.modules.quartz.repository.QuartzJobRepository;
import me.zhengjie.modules.quartz.utils.QuartzManage; import me.zhengjie.modules.quartz.utils.QuartzManage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner; import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -17,24 +16,24 @@ import java.util.List;
@Component @Component
public class JobRunner implements ApplicationRunner { public class JobRunner implements ApplicationRunner {
@Autowired private final QuartzJobRepository quartzJobRepository;
private QuartzJobRepository quartzJobRepository;
@Autowired private final QuartzManage quartzManage;
private QuartzManage quartzManage;
public JobRunner(QuartzJobRepository quartzJobRepository, QuartzManage quartzManage) {
this.quartzJobRepository = quartzJobRepository;
this.quartzManage = quartzManage;
}
/** /**
* *
* @param applicationArguments * @param applicationArguments /
* @throws Exception
*/ */
@Override @Override
public void run(ApplicationArguments applicationArguments){ public void run(ApplicationArguments applicationArguments){
System.out.println("--------------------注入定时任务---------------------"); System.out.println("--------------------注入定时任务---------------------");
List<QuartzJob> quartzJobs = quartzJobRepository.findByIsPauseIsFalse(); List<QuartzJob> quartzJobs = quartzJobRepository.findByIsPauseIsFalse();
quartzJobs.forEach(quartzJob -> { quartzJobs.forEach(quartzManage::addJob);
quartzManage.addJob(quartzJob);
});
System.out.println("--------------------定时任务注入完成---------------------"); System.out.println("--------------------定时任务注入完成---------------------");
} }
} }

View File

@ -2,7 +2,6 @@ package me.zhengjie.modules.quartz.config;
import org.quartz.Scheduler; import org.quartz.Scheduler;
import org.quartz.spi.TriggerFiredBundle; import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -12,7 +11,7 @@ import org.springframework.stereotype.Component;
/** /**
* *
* @author * @author /
* @date 2019-01-07 * @date 2019-01-07
*/ */
@Configuration @Configuration
@ -22,10 +21,13 @@ public class QuartzConfig {
* JobSpring Beannull * JobSpring Beannull
*/ */
@Component("quartzJobFactory") @Component("quartzJobFactory")
public class QuartzJobFactory extends AdaptableJobFactory { public static class QuartzJobFactory extends AdaptableJobFactory {
@Autowired private final AutowireCapableBeanFactory capableBeanFactory;
private AutowireCapableBeanFactory capableBeanFactory;
public QuartzJobFactory(AutowireCapableBeanFactory capableBeanFactory) {
this.capableBeanFactory = capableBeanFactory;
}
@Override @Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
@ -39,9 +41,9 @@ public class QuartzConfig {
/** /**
* schedulerspring * schedulerspring
* @param quartzJobFactory * @param quartzJobFactory /
* @return * @return Scheduler
* @throws Exception * @throws Exception /
*/ */
@Bean(name = "scheduler") @Bean(name = "scheduler")
public Scheduler scheduler(QuartzJobFactory quartzJobFactory) throws Exception { public Scheduler scheduler(QuartzJobFactory quartzJobFactory) throws Exception {

View File

@ -1,8 +1,8 @@
package me.zhengjie.modules.quartz.domain; package me.zhengjie.modules.quartz.domain;
import lombok.Data; import lombok.Getter;
import org.hibernate.annotations.UpdateTimestamp; import lombok.Setter;
import org.hibernate.annotations.CreationTimestamp;
import javax.persistence.*; import javax.persistence.*;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
@ -13,10 +13,11 @@ import java.sql.Timestamp;
* @author Zheng Jie * @author Zheng Jie
* @date 2019-01-07 * @date 2019-01-07
*/ */
@Data @Getter
@Setter
@Entity @Entity
@Table(name = "quartz_job") @Table(name = "quartz_job")
public class QuartzJob implements Serializable { public class QuartzJob implements Serializable {
public static final String JOB_KEY = "JOB_KEY"; public static final String JOB_KEY = "JOB_KEY";
@ -25,58 +26,41 @@ public class QuartzJob implements Serializable {
@NotNull(groups = {Update.class}) @NotNull(groups = {Update.class})
private Long id; private Long id;
/** // 定时器名称
*
*/
@Column(name = "job_name") @Column(name = "job_name")
private String jobName; private String jobName;
/** // Bean名称
* Bean
*/
@Column(name = "bean_name") @Column(name = "bean_name")
@NotBlank @NotBlank
private String beanName; private String beanName;
/** // 方法名称
*
*/
@Column(name = "method_name") @Column(name = "method_name")
@NotBlank @NotBlank
private String methodName; private String methodName;
/** // 参数
*
*/
@Column(name = "params") @Column(name = "params")
private String params; private String params;
/** // cron表达式
* cron
*/
@Column(name = "cron_expression") @Column(name = "cron_expression")
@NotBlank @NotBlank
private String cronExpression; private String cronExpression;
/** // 状态
*
*/
@Column(name = "is_pause") @Column(name = "is_pause")
private Boolean isPause = false; private Boolean isPause = false;
/** // 备注
*
*/
@Column(name = "remark") @Column(name = "remark")
@NotBlank @NotBlank
private String remark; private String remark;
/** @Column(name = "create_time")
* @CreationTimestamp
*/ private Timestamp createTime;
@UpdateTimestamp
@Column(name = "update_time")
private Timestamp updateTime;
public interface Update{} public @interface Update {}
} }

View File

@ -20,56 +20,38 @@ public class QuartzLog implements Serializable {
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; private Long id;
/** // 任务名称
*
*/
@Column(name = "job_name") @Column(name = "job_name")
private String jobName; private String jobName;
/** // Bean名称
* Bean
*/
@Column(name = "baen_name") @Column(name = "baen_name")
private String beanName; private String beanName;
/** // 方法名称
*
*/
@Column(name = "method_name") @Column(name = "method_name")
private String methodName; private String methodName;
/** // 参数
*
*/
@Column(name = "params") @Column(name = "params")
private String params; private String params;
/** // cron表达式
* cron
*/
@Column(name = "cron_expression") @Column(name = "cron_expression")
private String cronExpression; private String cronExpression;
/** // 状态
*
*/
@Column(name = "is_success") @Column(name = "is_success")
private Boolean isSuccess; private Boolean isSuccess;
/** // 异常详细
*
*/
@Column(name = "exception_detail",columnDefinition = "text") @Column(name = "exception_detail",columnDefinition = "text")
private String exceptionDetail; private String exceptionDetail;
/** // 耗时(毫秒)
*
*/
private Long time; private Long time;
/** // 创建日期
*
*/
@CreationTimestamp @CreationTimestamp
@Column(name = "create_time") @Column(name = "create_time")
private Timestamp createTime; private Timestamp createTime;

View File

@ -9,11 +9,11 @@ import java.util.List;
* @author Zheng Jie * @author Zheng Jie
* @date 2019-01-07 * @date 2019-01-07
*/ */
public interface QuartzJobRepository extends JpaRepository<QuartzJob,Long>, JpaSpecificationExecutor { public interface QuartzJobRepository extends JpaRepository<QuartzJob,Long>, JpaSpecificationExecutor<QuartzJob> {
/** /**
* *
* @return * @return List
*/ */
List<QuartzJob> findByIsPauseIsFalse(); List<QuartzJob> findByIsPauseIsFalse();
} }

View File

@ -8,6 +8,6 @@ import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
* @author Zheng Jie * @author Zheng Jie
* @date 2019-01-07 * @date 2019-01-07
*/ */
public interface QuartzLogRepository extends JpaRepository<QuartzLog,Long>, JpaSpecificationExecutor { public interface QuartzLogRepository extends JpaRepository<QuartzLog,Long>, JpaSpecificationExecutor<QuartzLog> {
} }

View File

@ -1,12 +1,13 @@
package me.zhengjie.modules.quartz.rest; package me.zhengjie.modules.quartz.rest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.zhengjie.aop.log.Log; import me.zhengjie.aop.log.Log;
import me.zhengjie.exception.BadRequestException; import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.quartz.domain.QuartzJob; import me.zhengjie.modules.quartz.domain.QuartzJob;
import me.zhengjie.modules.quartz.service.QuartzJobService; import me.zhengjie.modules.quartz.service.QuartzJobService;
import me.zhengjie.modules.quartz.service.dto.JobQueryCriteria; import me.zhengjie.modules.quartz.service.dto.JobQueryCriteria;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@ -14,70 +15,100 @@ import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/** /**
* @author Zheng Jie * @author Zheng Jie
* @date 2019-01-07 * @date 2019-01-07
*/ */
@Slf4j @Slf4j
@RestController @RestController
@RequestMapping("/api") @Api(tags = "系统:定时任务管理")
@RequestMapping("/api/jobs")
public class QuartzJobController { public class QuartzJobController {
private static final String ENTITY_NAME = "quartzJob"; private static final String ENTITY_NAME = "quartzJob";
@Autowired private final QuartzJobService quartzJobService;
private QuartzJobService quartzJobService;
@Log("查询定时任务") public QuartzJobController(QuartzJobService quartzJobService) {
@GetMapping(value = "/jobs") this.quartzJobService = quartzJobService;
@PreAuthorize("hasAnyRole('ADMIN','JOB_ALL','JOB_SELECT')")
public ResponseEntity getJobs(JobQueryCriteria criteria, Pageable pageable){
return new ResponseEntity(quartzJobService.queryAll(criteria,pageable), HttpStatus.OK);
} }
@GetMapping(value = "/jobLogs") @Log("查询定时任务")
@PreAuthorize("hasAnyRole('ADMIN','JOB_ALL','JOB_SELECT')") @ApiOperation("查询定时任务")
@GetMapping
@PreAuthorize("@el.check('timing:list')")
public ResponseEntity getJobs(JobQueryCriteria criteria, Pageable pageable){
return new ResponseEntity<>(quartzJobService.queryAll(criteria,pageable), HttpStatus.OK);
}
@Log("导出任务数据")
@ApiOperation("导出任务数据")
@GetMapping(value = "/download")
@PreAuthorize("@el.check('timing:list')")
public void download(HttpServletResponse response, JobQueryCriteria criteria) throws IOException {
quartzJobService.download(quartzJobService.queryAll(criteria), response);
}
@Log("导出日志数据")
@ApiOperation("导出日志数据")
@GetMapping(value = "/download/log")
@PreAuthorize("@el.check('timing:list')")
public void downloadLog(HttpServletResponse response, JobQueryCriteria criteria) throws IOException {
quartzJobService.downloadLog(quartzJobService.queryAllLog(criteria), response);
}
@ApiOperation("查询任务执行日志")
@GetMapping(value = "/logs")
@PreAuthorize("@el.check('timing:list')")
public ResponseEntity getJobLogs(JobQueryCriteria criteria, Pageable pageable){ public ResponseEntity getJobLogs(JobQueryCriteria criteria, Pageable pageable){
return new ResponseEntity(quartzJobService.queryAllLog(criteria,pageable), HttpStatus.OK); return new ResponseEntity<>(quartzJobService.queryAllLog(criteria,pageable), HttpStatus.OK);
} }
@Log("新增定时任务") @Log("新增定时任务")
@PostMapping(value = "/jobs") @ApiOperation("新增定时任务")
@PreAuthorize("hasAnyRole('ADMIN','JOB_ALL','JOB_CREATE')") @PostMapping
@PreAuthorize("@el.check('timing:add')")
public ResponseEntity create(@Validated @RequestBody QuartzJob resources){ public ResponseEntity create(@Validated @RequestBody QuartzJob resources){
if (resources.getId() != null) { if (resources.getId() != null) {
throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID"); throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID");
} }
return new ResponseEntity(quartzJobService.create(resources),HttpStatus.CREATED); return new ResponseEntity<>(quartzJobService.create(resources),HttpStatus.CREATED);
} }
@Log("修改定时任务") @Log("修改定时任务")
@PutMapping(value = "/jobs") @ApiOperation("修改定时任务")
@PreAuthorize("hasAnyRole('ADMIN','JOB_ALL','JOB_EDIT')") @PutMapping
@PreAuthorize("@el.check('timing:edit')")
public ResponseEntity update(@Validated(QuartzJob.Update.class) @RequestBody QuartzJob resources){ public ResponseEntity update(@Validated(QuartzJob.Update.class) @RequestBody QuartzJob resources){
quartzJobService.update(resources); quartzJobService.update(resources);
return new ResponseEntity(HttpStatus.NO_CONTENT); return new ResponseEntity(HttpStatus.NO_CONTENT);
} }
@Log("更改定时任务状态") @Log("更改定时任务状态")
@PutMapping(value = "/jobs/{id}") @ApiOperation("更改定时任务状态")
@PreAuthorize("hasAnyRole('ADMIN','JOB_ALL','JOB_EDIT')") @PutMapping(value = "/{id}")
@PreAuthorize("@el.check('timing:edit')")
public ResponseEntity updateIsPause(@PathVariable Long id){ public ResponseEntity updateIsPause(@PathVariable Long id){
quartzJobService.updateIsPause(quartzJobService.findById(id)); quartzJobService.updateIsPause(quartzJobService.findById(id));
return new ResponseEntity(HttpStatus.NO_CONTENT); return new ResponseEntity(HttpStatus.NO_CONTENT);
} }
@Log("执行定时任务") @Log("执行定时任务")
@PutMapping(value = "/jobs/exec/{id}") @ApiOperation("执行定时任务")
@PreAuthorize("hasAnyRole('ADMIN','JOB_ALL','JOB_EDIT')") @PutMapping(value = "/exec/{id}")
@PreAuthorize("@el.check('timing:edit')")
public ResponseEntity execution(@PathVariable Long id){ public ResponseEntity execution(@PathVariable Long id){
quartzJobService.execution(quartzJobService.findById(id)); quartzJobService.execution(quartzJobService.findById(id));
return new ResponseEntity(HttpStatus.NO_CONTENT); return new ResponseEntity(HttpStatus.NO_CONTENT);
} }
@Log("删除定时任务") @Log("删除定时任务")
@DeleteMapping(value = "/jobs/{id}") @ApiOperation("删除定时任务")
@PreAuthorize("hasAnyRole('ADMIN','JOB_ALL','JOB_DELETE')") @DeleteMapping(value = "/{id}")
@PreAuthorize("@el.check('timing:del')")
public ResponseEntity delete(@PathVariable Long id){ public ResponseEntity delete(@PathVariable Long id){
quartzJobService.delete(quartzJobService.findById(id)); quartzJobService.delete(quartzJobService.findById(id));
return new ResponseEntity(HttpStatus.OK); return new ResponseEntity(HttpStatus.OK);

View File

@ -3,76 +3,47 @@ package me.zhengjie.modules.quartz.service;
import me.zhengjie.modules.quartz.domain.QuartzJob; import me.zhengjie.modules.quartz.domain.QuartzJob;
import me.zhengjie.modules.quartz.domain.QuartzLog; import me.zhengjie.modules.quartz.domain.QuartzLog;
import me.zhengjie.modules.quartz.service.dto.JobQueryCriteria; import me.zhengjie.modules.quartz.service.dto.JobQueryCriteria;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/** /**
* @author Zheng Jie * @author Zheng Jie
* @date 2019-01-07 * @date 2019-01-07
*/ */
@CacheConfig(cacheNames = "quartzJob")
public interface QuartzJobService { public interface QuartzJobService {
/**
* queryAll quartzJob
* @param criteria
* @param pageable
* @return
*/
@Cacheable
Object queryAll(JobQueryCriteria criteria, Pageable pageable); Object queryAll(JobQueryCriteria criteria, Pageable pageable);
/** List<QuartzJob> queryAll(JobQueryCriteria criteria);
* queryAll quartzLog
* @param criteria
* @param pageable
* @return
*/
Object queryAllLog(JobQueryCriteria criteria, Pageable pageable); Object queryAllLog(JobQueryCriteria criteria, Pageable pageable);
/** List<QuartzLog> queryAllLog(JobQueryCriteria criteria);
* create
* @param resources
* @return
*/
@CacheEvict(allEntries = true)
QuartzJob create(QuartzJob resources); QuartzJob create(QuartzJob resources);
/**
* update
* @param resources
* @return
*/
@CacheEvict(allEntries = true)
void update(QuartzJob resources); void update(QuartzJob resources);
/**
* del
* @param quartzJob
*/
@CacheEvict(allEntries = true)
void delete(QuartzJob quartzJob); void delete(QuartzJob quartzJob);
/**
* findById
* @param id
* @return
*/
@Cacheable(key = "#p0")
QuartzJob findById(Long id); QuartzJob findById(Long id);
/** /**
* *
* @param quartzJob * @param quartzJob /
*/ */
@CacheEvict(allEntries = true)
void updateIsPause(QuartzJob quartzJob); void updateIsPause(QuartzJob quartzJob);
/** /**
* *
* @param quartzJob * @param quartzJob /
*/ */
void execution(QuartzJob quartzJob); void execution(QuartzJob quartzJob);
void download(List<QuartzJob> queryAll, HttpServletResponse response) throws IOException;
void downloadLog(List<QuartzLog> queryAllLog, HttpServletResponse response) throws IOException;
} }

View File

@ -3,6 +3,8 @@ package me.zhengjie.modules.quartz.service.dto;
import lombok.Data; import lombok.Data;
import me.zhengjie.annotation.Query; import me.zhengjie.annotation.Query;
import java.sql.Timestamp;
/** /**
* @author Zheng Jie * @author Zheng Jie
* @date 2019-6-4 10:33:02 * @date 2019-6-4 10:33:02
@ -15,4 +17,10 @@ public class JobQueryCriteria {
@Query @Query
private Boolean isSuccess; private Boolean isSuccess;
@Query(type = Query.Type.GREATER_THAN,propName = "createTime")
private Timestamp startTime;
@Query(type = Query.Type.LESS_THAN,propName = "createTime")
private Timestamp endTime;
} }

View File

@ -2,40 +2,55 @@ package me.zhengjie.modules.quartz.service.impl;
import me.zhengjie.exception.BadRequestException; import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.quartz.domain.QuartzJob; import me.zhengjie.modules.quartz.domain.QuartzJob;
import me.zhengjie.modules.quartz.domain.QuartzLog;
import me.zhengjie.modules.quartz.repository.QuartzJobRepository; import me.zhengjie.modules.quartz.repository.QuartzJobRepository;
import me.zhengjie.modules.quartz.repository.QuartzLogRepository; import me.zhengjie.modules.quartz.repository.QuartzLogRepository;
import me.zhengjie.modules.quartz.service.QuartzJobService; import me.zhengjie.modules.quartz.service.QuartzJobService;
import me.zhengjie.modules.quartz.service.dto.JobQueryCriteria; import me.zhengjie.modules.quartz.service.dto.JobQueryCriteria;
import me.zhengjie.modules.quartz.utils.QuartzManage; import me.zhengjie.modules.quartz.utils.QuartzManage;
import me.zhengjie.utils.FileUtil;
import me.zhengjie.utils.PageUtil; import me.zhengjie.utils.PageUtil;
import me.zhengjie.utils.QueryHelp; import me.zhengjie.utils.QueryHelp;
import me.zhengjie.utils.ValidationUtil; import me.zhengjie.utils.ValidationUtil;
import org.quartz.CronExpression; import org.quartz.CronExpression;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/** /**
* @author Zheng Jie * @author Zheng Jie
* @date 2019-01-07 * @date 2019-01-07
*/ */
@Service(value = "quartzJobService") @Service(value = "quartzJobService")
@CacheConfig(cacheNames = "quartzJob")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class) @Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class QuartzJobServiceImpl implements QuartzJobService { public class QuartzJobServiceImpl implements QuartzJobService {
@Autowired private final QuartzJobRepository quartzJobRepository;
private QuartzJobRepository quartzJobRepository;
@Autowired private final QuartzLogRepository quartzLogRepository;
private QuartzLogRepository quartzLogRepository;
@Autowired private final QuartzManage quartzManage;
private QuartzManage quartzManage;
public QuartzJobServiceImpl(QuartzJobRepository quartzJobRepository, QuartzLogRepository quartzLogRepository, QuartzManage quartzManage) {
this.quartzJobRepository = quartzJobRepository;
this.quartzLogRepository = quartzLogRepository;
this.quartzManage = quartzManage;
}
@Override @Override
@Cacheable
public Object queryAll(JobQueryCriteria criteria, Pageable pageable){ public Object queryAll(JobQueryCriteria criteria, Pageable pageable){
return PageUtil.toPage(quartzJobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable)); return PageUtil.toPage(quartzJobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable));
} }
@ -46,13 +61,25 @@ public class QuartzJobServiceImpl implements QuartzJobService {
} }
@Override @Override
public QuartzJob findById(Long id) { public List<QuartzJob> queryAll(JobQueryCriteria criteria) {
Optional<QuartzJob> quartzJob = quartzJobRepository.findById(id); return quartzJobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder));
ValidationUtil.isNull(quartzJob,"QuartzJob","id",id);
return quartzJob.get();
} }
@Override @Override
public List<QuartzLog> queryAllLog(JobQueryCriteria criteria) {
return quartzLogRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder));
}
@Override
@Cacheable(key = "#p0")
public QuartzJob findById(Long id) {
QuartzJob quartzJob = quartzJobRepository.findById(id).orElseGet(QuartzJob::new);
ValidationUtil.isNull(quartzJob.getId(),"QuartzJob","id",id);
return quartzJob;
}
@Override
@CacheEvict(allEntries = true)
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public QuartzJob create(QuartzJob resources) { public QuartzJob create(QuartzJob resources) {
if (!CronExpression.isValidExpression(resources.getCronExpression())){ if (!CronExpression.isValidExpression(resources.getCronExpression())){
@ -64,6 +91,7 @@ public class QuartzJobServiceImpl implements QuartzJobService {
} }
@Override @Override
@CacheEvict(allEntries = true)
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void update(QuartzJob resources) { public void update(QuartzJob resources) {
if(resources.getId().equals(1L)){ if(resources.getId().equals(1L)){
@ -77,6 +105,7 @@ public class QuartzJobServiceImpl implements QuartzJobService {
} }
@Override @Override
@CacheEvict(allEntries = true)
public void updateIsPause(QuartzJob quartzJob) { public void updateIsPause(QuartzJob quartzJob) {
if(quartzJob.getId().equals(1L)){ if(quartzJob.getId().equals(1L)){
throw new BadRequestException("该任务不可操作"); throw new BadRequestException("该任务不可操作");
@ -100,6 +129,7 @@ public class QuartzJobServiceImpl implements QuartzJobService {
} }
@Override @Override
@CacheEvict(allEntries = true)
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void delete(QuartzJob quartzJob) { public void delete(QuartzJob quartzJob) {
if(quartzJob.getId().equals(1L)){ if(quartzJob.getId().equals(1L)){
@ -108,4 +138,41 @@ public class QuartzJobServiceImpl implements QuartzJobService {
quartzManage.deleteJob(quartzJob); quartzManage.deleteJob(quartzJob);
quartzJobRepository.delete(quartzJob); quartzJobRepository.delete(quartzJob);
} }
@Override
public void download(List<QuartzJob> quartzJobs, HttpServletResponse response) throws IOException {
List<Map<String, Object>> list = new ArrayList<>();
for (QuartzJob quartzJob : quartzJobs) {
Map<String,Object> map = new LinkedHashMap<>();
map.put("任务名称", quartzJob.getJobName());
map.put("Bean名称", quartzJob.getBeanName());
map.put("执行方法", quartzJob.getMethodName());
map.put("参数", quartzJob.getParams());
map.put("表达式", quartzJob.getCronExpression());
map.put("状态", quartzJob.getIsPause() ? "暂停中" : "运行中");
map.put("描述", quartzJob.getRemark());
map.put("创建日期", quartzJob.getCreateTime());
list.add(map);
}
FileUtil.downloadExcel(list, response);
}
@Override
public void downloadLog(List<QuartzLog> queryAllLog, HttpServletResponse response) throws IOException {
List<Map<String, Object>> list = new ArrayList<>();
for (QuartzLog quartzLog : queryAllLog) {
Map<String,Object> map = new LinkedHashMap<>();
map.put("任务名称", quartzLog.getJobName());
map.put("Bean名称", quartzLog.getBeanName());
map.put("执行方法", quartzLog.getMethodName());
map.put("参数", quartzLog.getParams());
map.put("表达式", quartzLog.getCronExpression());
map.put("异常详情", quartzLog.getExceptionDetail());
map.put("耗时/毫秒", quartzLog.getTime());
map.put("状态", quartzLog.getIsSuccess() ? "成功" : "失败");
map.put("创建日期", quartzLog.getCreateTime());
list.add(map);
}
FileUtil.downloadExcel(list, response);
}
} }

View File

@ -1,7 +1,6 @@
package me.zhengjie.modules.quartz.task; package me.zhengjie.modules.quartz.task;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.zhengjie.exception.BadRequestException;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**

View File

@ -1,7 +1,6 @@
package me.zhengjie.modules.quartz.task; package me.zhengjie.modules.quartz.task;
import me.zhengjie.modules.monitor.service.VisitsService; import me.zhengjie.modules.monitor.service.VisitsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
@ -11,8 +10,11 @@ import org.springframework.stereotype.Component;
@Component @Component
public class VisitsTask { public class VisitsTask {
@Autowired private final VisitsService visitsService;
private VisitsService visitsService;
public VisitsTask(VisitsService visitsService) {
this.visitsService = visitsService;
}
public void run(){ public void run(){
visitsService.save(); visitsService.save();

View File

@ -1,5 +1,7 @@
package me.zhengjie.modules.quartz.utils; package me.zhengjie.modules.quartz.utils;
import me.zhengjie.config.thread.TheadFactoryName;
import me.zhengjie.config.thread.ThreadPoolExecutorUtil;
import me.zhengjie.modules.quartz.domain.QuartzJob; import me.zhengjie.modules.quartz.domain.QuartzJob;
import me.zhengjie.modules.quartz.domain.QuartzLog; import me.zhengjie.modules.quartz.domain.QuartzLog;
import me.zhengjie.modules.quartz.repository.QuartzLogRepository; import me.zhengjie.modules.quartz.repository.QuartzLogRepository;
@ -11,13 +13,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.quartz.QuartzJobBean; import org.springframework.scheduling.quartz.QuartzJobBean;
import java.util.concurrent.ExecutorService; import java.util.concurrent.*;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/** /**
* https://gitee.com/renrenio/renren-security * https://gitee.com/renrenio/renren-security
* @author * @author /
* @date 2019-01-07 * @date 2019-01-07
*/ */
@Async @Async
@ -25,16 +25,16 @@ public class ExecutionJob extends QuartzJobBean {
private Logger logger = LoggerFactory.getLogger(this.getClass()); private Logger logger = LoggerFactory.getLogger(this.getClass());
// 建议自定义线程池实现方式,该处仅供参考 // 该处仅供参考
private ExecutorService executorService = Executors.newSingleThreadExecutor(); private final static ThreadPoolExecutor executor = ThreadPoolExecutorUtil.getPoll();
@Override @Override
@SuppressWarnings("unchecked")
protected void executeInternal(JobExecutionContext context) { protected void executeInternal(JobExecutionContext context) {
QuartzJob quartzJob = (QuartzJob) context.getMergedJobDataMap().get(QuartzJob.JOB_KEY); QuartzJob quartzJob = (QuartzJob) context.getMergedJobDataMap().get(QuartzJob.JOB_KEY);
// 获取spring bean // 获取spring bean
QuartzLogRepository quartzLogRepository = SpringContextHolder.getBean("quartzLogRepository"); QuartzLogRepository quartzLogRepository = SpringContextHolder.getBean(QuartzLogRepository.class);
QuartzJobService quartzJobService = SpringContextHolder.getBean("quartzJobService"); QuartzJobService quartzJobService = SpringContextHolder.getBean(QuartzJobService.class);
QuartzManage quartzManage = SpringContextHolder.getBean("quartzManage");
QuartzLog log = new QuartzLog(); QuartzLog log = new QuartzLog();
log.setJobName(quartzJob.getJobName()); log.setJobName(quartzJob.getJobName());
@ -48,7 +48,7 @@ public class ExecutionJob extends QuartzJobBean {
logger.info("任务准备执行,任务名称:{}", quartzJob.getJobName()); logger.info("任务准备执行,任务名称:{}", quartzJob.getJobName());
QuartzRunnable task = new QuartzRunnable(quartzJob.getBeanName(), quartzJob.getMethodName(), QuartzRunnable task = new QuartzRunnable(quartzJob.getBeanName(), quartzJob.getMethodName(),
quartzJob.getParams()); quartzJob.getParams());
Future<?> future = executorService.submit(task); Future<?> future = executor.submit(task);
future.get(); future.get();
long times = System.currentTimeMillis() - startTime; long times = System.currentTimeMillis() - startTime;
log.setTime(times); log.setTime(times);

View File

@ -56,8 +56,7 @@ public class QuartzManage {
/** /**
* job cron * job cron
* @param quartzJob * @param quartzJob /
* @throws SchedulerException
*/ */
public void updateJobCron(QuartzJob quartzJob){ public void updateJobCron(QuartzJob quartzJob){
try { try {
@ -88,8 +87,7 @@ public class QuartzManage {
/** /**
* job * job
* @param quartzJob * @param quartzJob /
* @throws SchedulerException
*/ */
public void deleteJob(QuartzJob quartzJob){ public void deleteJob(QuartzJob quartzJob){
try { try {
@ -104,8 +102,7 @@ public class QuartzManage {
/** /**
* job * job
* @param quartzJob * @param quartzJob /
* @throws SchedulerException
*/ */
public void resumeJob(QuartzJob quartzJob){ public void resumeJob(QuartzJob quartzJob){
try { try {
@ -124,8 +121,7 @@ public class QuartzManage {
/** /**
* job * job
* @param quartzJob * @param quartzJob /
* @throws SchedulerException
*/ */
public void runAJobNow(QuartzJob quartzJob){ public void runAJobNow(QuartzJob quartzJob){
try { try {
@ -146,8 +142,7 @@ public class QuartzManage {
/** /**
* job * job
* @param quartzJob * @param quartzJob /
* @throws SchedulerException
*/ */
public void pauseJob(QuartzJob quartzJob){ public void pauseJob(QuartzJob quartzJob){
try { try {

View File

@ -1,7 +1,6 @@
package me.zhengjie.modules.quartz.utils; package me.zhengjie.modules.quartz.utils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.utils.SpringContextHolder; import me.zhengjie.utils.SpringContextHolder;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
@ -10,7 +9,7 @@ import java.util.concurrent.Callable;
/** /**
* *
* @author * @author /
*/ */
@Slf4j @Slf4j
public class QuartzRunnable implements Callable { public class QuartzRunnable implements Callable {

View File

@ -1,13 +1,17 @@
package me.zhengjie.modules.security.config; package me.zhengjie.modules.security.config;
import me.zhengjie.annotation.AnonymousAccess;
import me.zhengjie.config.ElPermissionConfig;
import me.zhengjie.modules.security.security.JwtAuthenticationEntryPoint; import me.zhengjie.modules.security.security.JwtAuthenticationEntryPoint;
import me.zhengjie.modules.security.security.JwtAuthorizationTokenFilter; import me.zhengjie.modules.security.security.JwtAuthorizationTokenFilter;
import me.zhengjie.modules.security.service.JwtUserDetailsService; import me.zhengjie.modules.security.service.JwtUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
@ -19,29 +23,37 @@ import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@Configuration @Configuration
@EnableWebSecurity @EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) @EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter { public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired private final JwtAuthenticationEntryPoint unauthorizedHandler;
private JwtAuthenticationEntryPoint unauthorizedHandler;
@Autowired private final JwtUserDetailsService jwtUserDetailsService;
private JwtUserDetailsService jwtUserDetailsService;
/** private final ApplicationContext applicationContext;
* JWT
*/ // 自定义基于JWT的安全过滤器
@Autowired private final JwtAuthorizationTokenFilter authenticationTokenFilter;
JwtAuthorizationTokenFilter authenticationTokenFilter;
@Value("${jwt.header}") @Value("${jwt.header}")
private String tokenHeader; private String tokenHeader;
@Value("${jwt.auth.path}") public SecurityConfig(JwtAuthenticationEntryPoint unauthorizedHandler, JwtUserDetailsService jwtUserDetailsService, JwtAuthorizationTokenFilter authenticationTokenFilter, ApplicationContext applicationContext) {
private String loginPath; this.unauthorizedHandler = unauthorizedHandler;
this.jwtUserDetailsService = jwtUserDetailsService;
this.authenticationTokenFilter = authenticationTokenFilter;
this.applicationContext = applicationContext;
}
@Autowired @Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
@ -69,18 +81,26 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override @Override
protected void configure(HttpSecurity httpSecurity) throws Exception { protected void configure(HttpSecurity httpSecurity) throws Exception {
// 搜寻 匿名标记 url PreAuthorize("hasAnyRole('anonymous')") 和 PreAuthorize("@el.check('anonymous')") 和 AnonymousAccess
Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = applicationContext.getBean(RequestMappingHandlerMapping.class).getHandlerMethods();
Set<String> anonymousUrls = new HashSet<>();
for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) {
HandlerMethod handlerMethod = infoEntry.getValue();
AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class);
PreAuthorize preAuthorize = handlerMethod.getMethodAnnotation(PreAuthorize.class);
if (null != preAuthorize && preAuthorize.value().contains("anonymous")) {
anonymousUrls.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
} else if (null != anonymousAccess && null == preAuthorize) {
anonymousUrls.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
}
}
httpSecurity httpSecurity
// 禁用 CSRF // 禁用 CSRF
.csrf().disable() .csrf().disable()
// 授权异常 // 授权异常
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
// 不创建会话 // 不创建会话
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
// 过滤请求 // 过滤请求
.authorizeRequests() .authorizeRequests()
.antMatchers( .antMatchers(
@ -90,35 +110,24 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
"/**/*.css", "/**/*.css",
"/**/*.js" "/**/*.js"
).anonymous() ).anonymous()
.antMatchers( HttpMethod.POST,"/auth/"+loginPath).anonymous()
.antMatchers("/auth/vCode").anonymous()
// 支付宝回调
.antMatchers("/api/aliPay/return").anonymous()
.antMatchers("/api/aliPay/notify").anonymous()
// swagger start // swagger start
.antMatchers("/swagger-ui.html").anonymous() .antMatchers("/swagger-ui.html").permitAll()
.antMatchers("/swagger-resources/**").anonymous() .antMatchers("/swagger-resources/**").permitAll()
.antMatchers("/webjars/**").anonymous() .antMatchers("/webjars/**").permitAll()
.antMatchers("/*/api-docs").anonymous() .antMatchers("/*/api-docs").permitAll()
// swagger end // swagger end
// 接口限流测试
.antMatchers("/test/**").anonymous()
// 文件 // 文件
.antMatchers("/avatar/**").anonymous() .antMatchers("/avatar/**").permitAll()
.antMatchers("/file/**").anonymous() .antMatchers("/file/**").permitAll()
// 放行OPTIONS请求 // 放行OPTIONS请求
.antMatchers(HttpMethod.OPTIONS, "/**").anonymous() .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/druid/**").permitAll()
.antMatchers("/druid/**").anonymous() // 自定义匿名访问所有url放行 允许 匿名和带权限以及登录用户访问
.antMatchers(anonymousUrls.toArray(new String[0])).permitAll()
// 所有请求都需要认证 // 所有请求都需要认证
.anyRequest().authenticated() .anyRequest().authenticated()
// 防止iframe 造成跨域 // 防止iframe 造成跨域
.and().headers().frameOptions().disable(); .and().headers().frameOptions().disable();
httpSecurity httpSecurity
.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
} }

View File

@ -1,31 +1,32 @@
package me.zhengjie.modules.security.rest; package me.zhengjie.modules.security.rest;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import com.wf.captcha.ArithmeticCaptcha;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.zhengjie.annotation.AnonymousAccess;
import me.zhengjie.aop.log.Log; import me.zhengjie.aop.log.Log;
import me.zhengjie.exception.BadRequestException; import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.monitor.service.RedisService; import me.zhengjie.modules.monitor.service.RedisService;
import me.zhengjie.modules.security.security.AuthenticationInfo; import me.zhengjie.modules.security.security.AuthInfo;
import me.zhengjie.modules.security.security.AuthorizationUser; import me.zhengjie.modules.security.security.AuthUser;
import me.zhengjie.modules.security.security.ImgResult; import me.zhengjie.modules.security.security.ImgResult;
import me.zhengjie.modules.security.security.JwtUser; import me.zhengjie.modules.security.security.JwtUser;
import me.zhengjie.modules.security.utils.VerifyCodeUtils; import me.zhengjie.modules.security.service.OnlineUserService;
import me.zhengjie.utils.EncryptUtils; import me.zhengjie.utils.EncryptUtils;
import me.zhengjie.modules.security.utils.JwtTokenUtil; import me.zhengjie.modules.security.utils.JwtTokenUtil;
import me.zhengjie.utils.SecurityUtils; import me.zhengjie.utils.SecurityUtils;
import me.zhengjie.utils.StringUtils; import me.zhengjie.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AccountExpiredException; import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/** /**
* @author Zheng Jie * @author Zheng Jie
@ -34,30 +35,33 @@ import java.io.IOException;
*/ */
@Slf4j @Slf4j
@RestController @RestController
@RequestMapping("auth") @RequestMapping("/auth")
@Api(tags = "系统:系统授权接口")
public class AuthenticationController { public class AuthenticationController {
@Value("${jwt.header}") @Value("${jwt.codeKey}")
private String tokenHeader; private String codeKey;
@Autowired private final JwtTokenUtil jwtTokenUtil;
private JwtTokenUtil jwtTokenUtil;
@Autowired private final RedisService redisService;
private RedisService redisService;
@Autowired private final UserDetailsService userDetailsService;
@Qualifier("jwtUserDetailsService")
private UserDetailsService userDetailsService; private final OnlineUserService onlineUserService;
public AuthenticationController(JwtTokenUtil jwtTokenUtil, RedisService redisService, @Qualifier("jwtUserDetailsService") UserDetailsService userDetailsService, OnlineUserService onlineUserService) {
this.jwtTokenUtil = jwtTokenUtil;
this.redisService = redisService;
this.userDetailsService = userDetailsService;
this.onlineUserService = onlineUserService;
}
/**
*
* @param authorizationUser
* @return
*/
@Log("用户登录") @Log("用户登录")
@PostMapping(value = "${jwt.auth.path}") @ApiOperation("登录授权")
public ResponseEntity login(@Validated @RequestBody AuthorizationUser authorizationUser){ @AnonymousAccess
@PostMapping(value = "/login")
public ResponseEntity login(@Validated @RequestBody AuthUser authorizationUser, HttpServletRequest request){
// 查询验证码 // 查询验证码
String code = redisService.getCodeVal(authorizationUser.getUuid()); String code = redisService.getCodeVal(authorizationUser.getUuid());
@ -78,45 +82,41 @@ public class AuthenticationController {
if(!jwtUser.isEnabled()){ if(!jwtUser.isEnabled()){
throw new AccountExpiredException("账号已停用,请联系管理员"); throw new AccountExpiredException("账号已停用,请联系管理员");
} }
// 生成令牌 // 生成令牌
final String token = jwtTokenUtil.generateToken(jwtUser); final String token = jwtTokenUtil.generateToken(jwtUser);
// 保存在线信息
onlineUserService.save(jwtUser, token, request);
// 返回 token // 返回 token
return ResponseEntity.ok(new AuthenticationInfo(token,jwtUser)); return ResponseEntity.ok(new AuthInfo(token,jwtUser));
} }
/** @ApiOperation("获取用户信息")
* @GetMapping(value = "/info")
* @return
*/
@GetMapping(value = "${jwt.auth.account}")
public ResponseEntity getUserInfo(){ public ResponseEntity getUserInfo(){
JwtUser jwtUser = (JwtUser)userDetailsService.loadUserByUsername(SecurityUtils.getUsername()); JwtUser jwtUser = (JwtUser)userDetailsService.loadUserByUsername(SecurityUtils.getUsername());
return ResponseEntity.ok(jwtUser); return ResponseEntity.ok(jwtUser);
} }
/** @ApiOperation("获取验证码")
* @AnonymousAccess
*/ @GetMapping(value = "/code")
@GetMapping(value = "vCode") public ImgResult getCode(){
public ImgResult getCode(HttpServletResponse response) throws IOException { // 算术类型 https://gitee.com/whvse/EasyCaptcha
ArithmeticCaptcha captcha = new ArithmeticCaptcha(111, 36);
// 几位数运算,默认是两位
captcha.setLen(2);
// 获取运算的结果5
String result = captcha.text();
String uuid = codeKey + IdUtil.simpleUUID();
redisService.saveCode(uuid,result);
return new ImgResult(captcha.toBase64(),uuid);
}
//生成随机字串 @ApiOperation("退出登录")
String verifyCode = VerifyCodeUtils.generateVerifyCode(4); @AnonymousAccess
String uuid = IdUtil.simpleUUID(); @DeleteMapping(value = "/logout")
redisService.saveCode(uuid,verifyCode); public ResponseEntity logout(HttpServletRequest request){
// 生成图片 onlineUserService.logout(jwtTokenUtil.getToken(request));
int w = 111, h = 36; return new ResponseEntity(HttpStatus.OK);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
VerifyCodeUtils.outputImage(w, h, stream, verifyCode);
try {
return new ImgResult(Base64.encode(stream.toByteArray()),uuid);
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
stream.close();
}
} }
} }

View File

@ -0,0 +1,49 @@
package me.zhengjie.modules.security.rest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import me.zhengjie.aop.log.Log;
import me.zhengjie.modules.security.service.OnlineUserService;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@RestController
@RequestMapping("/auth/online")
@Api(tags = "系统:在线用户管理")
public class OnlineController {
private final OnlineUserService onlineUserService;
public OnlineController(OnlineUserService onlineUserService) {
this.onlineUserService = onlineUserService;
}
@ApiOperation("查询在线用户")
@GetMapping
@PreAuthorize("@el.check()")
public ResponseEntity getAll(String filter, Pageable pageable){
return new ResponseEntity<>(onlineUserService.getAll(filter, pageable),HttpStatus.OK);
}
@Log("导出数据")
@ApiOperation("导出数据")
@GetMapping(value = "/download")
@PreAuthorize("@el.check()")
public void download(HttpServletResponse response, String filter) throws IOException {
onlineUserService.download(onlineUserService.getAll(filter), response);
}
@ApiOperation("踢出用户")
@DeleteMapping(value = "/{key}")
@PreAuthorize("@el.check()")
public ResponseEntity delete(@PathVariable String key) throws Exception {
onlineUserService.kickOut(key);
return new ResponseEntity(HttpStatus.OK);
}
}

View File

@ -1,19 +1,19 @@
package me.zhengjie.modules.security.security; package me.zhengjie.modules.security.security;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import java.io.Serializable; import java.io.Serializable;
/** /**
* @author Zheng Jie * @author Zheng Jie
* @date 2018-11-23 * @date 2018-11-23
* token * token
*/ */
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public class AuthenticationInfo implements Serializable { public class AuthInfo implements Serializable {
private final String token; private final String token;
private final JwtUser user; private final JwtUser user;
} }

View File

@ -11,7 +11,7 @@ import javax.validation.constraints.NotBlank;
*/ */
@Getter @Getter
@Setter @Setter
public class AuthorizationUser { public class AuthUser {
@NotBlank @NotBlank
private String username; private String username;

View File

@ -18,9 +18,7 @@ public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Se
public void commence(HttpServletRequest request, public void commence(HttpServletRequest request,
HttpServletResponse response, HttpServletResponse response,
AuthenticationException authException) throws IOException { AuthenticationException authException) throws IOException {
/** // 当用户尝试访问安全的REST资源而不提供任何凭据时将调用此方法发送401 响应
* 访REST401
*/
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException==null?"Unauthorized":authException.getMessage()); response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException==null?"Unauthorized":authException.getMessage());
} }
} }

View File

@ -3,11 +3,12 @@ package me.zhengjie.modules.security.security;
import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.zhengjie.modules.security.utils.JwtTokenUtil; import me.zhengjie.modules.security.utils.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -22,38 +23,33 @@ import java.io.IOException;
@Component @Component
public class JwtAuthorizationTokenFilter extends OncePerRequestFilter { public class JwtAuthorizationTokenFilter extends OncePerRequestFilter {
@Value("${jwt.online}")
private String onlineKey;
private final UserDetailsService userDetailsService; private final UserDetailsService userDetailsService;
private final JwtTokenUtil jwtTokenUtil; private final JwtTokenUtil jwtTokenUtil;
private final String tokenHeader; private final RedisTemplate redisTemplate;
public JwtAuthorizationTokenFilter(@Qualifier("jwtUserDetailsService") UserDetailsService userDetailsService, JwtTokenUtil jwtTokenUtil, @Value("${jwt.header}") String tokenHeader) { public JwtAuthorizationTokenFilter(@Qualifier("jwtUserDetailsService") UserDetailsService userDetailsService, JwtTokenUtil jwtTokenUtil, RedisTemplate redisTemplate) {
this.userDetailsService = userDetailsService; this.userDetailsService = userDetailsService;
this.jwtTokenUtil = jwtTokenUtil; this.jwtTokenUtil = jwtTokenUtil;
this.tokenHeader = tokenHeader; this.redisTemplate = redisTemplate;
} }
@Override @Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
String authToken = jwtTokenUtil.getToken(request);
final String requestHeader = request.getHeader(this.tokenHeader); OnlineUser onlineUser = null;
try {
String username = null; onlineUser = (OnlineUser)redisTemplate.opsForValue().get(onlineKey + authToken);
String authToken = null; } catch (ExpiredJwtException e) {
if (requestHeader != null && requestHeader.startsWith("Bearer ")) { log.error(e.getMessage());
authToken = requestHeader.substring(7);
try {
username = jwtTokenUtil.getUsernameFromToken(authToken);
} catch (ExpiredJwtException e) {
log.error(e.getMessage());
}
} }
if (onlineUser != null && SecurityContextHolder.getContext().getAuthentication() == null) {
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
// It is not compelling necessary to load the use details from the database. You could also store the information // It is not compelling necessary to load the use details from the database. You could also store the information
// in the token and read it from it. It's up to you ;) // in the token and read it from it. It's up to you ;)
JwtUser userDetails = (JwtUser)this.userDetailsService.loadUserByUsername(username); JwtUser userDetails = (JwtUser)this.userDetailsService.loadUserByUsername(onlineUser.getUserName());
// For simple validation it is completely sufficient to just check the token integrity. You don't have to call // For simple validation it is completely sufficient to just check the token integrity. You don't have to call
// the database compellingly. Again it's up to you ;) // the database compellingly. Again it's up to you ;)
if (jwtTokenUtil.validateToken(authToken, userDetails)) { if (jwtTokenUtil.validateToken(authToken, userDetails)) {

View File

@ -0,0 +1,32 @@
package me.zhengjie.modules.security.security;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
/**
* @author Zheng Jie
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OnlineUser {
private String userName;
private String job;
private String browser;
private String ip;
private String address;
private String key;
private Date loginTime;
}

View File

@ -1,15 +1,17 @@
package me.zhengjie.modules.security.service; package me.zhengjie.modules.security.service;
import me.zhengjie.modules.system.domain.Menu;
import me.zhengjie.modules.system.domain.Role; import me.zhengjie.modules.system.domain.Role;
import me.zhengjie.modules.system.repository.RoleRepository; import me.zhengjie.modules.system.repository.RoleRepository;
import me.zhengjie.modules.system.service.dto.UserDTO; import me.zhengjie.modules.system.service.dto.UserDTO;
import org.springframework.beans.factory.annotation.Autowired; import me.zhengjie.utils.StringUtils;
import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -17,13 +19,16 @@ import java.util.stream.Collectors;
@CacheConfig(cacheNames = "role") @CacheConfig(cacheNames = "role")
public class JwtPermissionService { public class JwtPermissionService {
@Autowired private final RoleRepository roleRepository;
private RoleRepository roleRepository;
public JwtPermissionService(RoleRepository roleRepository) {
this.roleRepository = roleRepository;
}
/** /**
* key UserServiceImpl update * key UserServiceImpl update
* @param user * @param user
* @return * @return Collection
*/ */
@Cacheable(key = "'loadPermissionByUser:' + #p0.username") @Cacheable(key = "'loadPermissionByUser:' + #p0.username")
public Collection<GrantedAuthority> mapToGrantedAuthorities(UserDTO user) { public Collection<GrantedAuthority> mapToGrantedAuthorities(UserDTO user) {
@ -31,9 +36,13 @@ public class JwtPermissionService {
System.out.println("--------------------loadPermissionByUser:" + user.getUsername() + "---------------------"); System.out.println("--------------------loadPermissionByUser:" + user.getUsername() + "---------------------");
Set<Role> roles = roleRepository.findByUsers_Id(user.getId()); Set<Role> roles = roleRepository.findByUsers_Id(user.getId());
Set<String> permissions = roles.stream().filter(role -> StringUtils.isNotBlank(role.getPermission())).map(Role::getPermission).collect(Collectors.toSet());
return roles.stream().flatMap(role -> role.getPermissions().stream()) permissions.addAll(
.map(permission -> new SimpleGrantedAuthority(permission.getName())) roles.stream().flatMap(role -> role.getMenus().stream())
.filter(menu -> StringUtils.isNotBlank(menu.getPermission()))
.map(Menu::getPermission).collect(Collectors.toSet())
);
return permissions.stream().map(permission -> new SimpleGrantedAuthority(permission))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
} }

View File

@ -4,7 +4,6 @@ import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.security.security.JwtUser; import me.zhengjie.modules.security.security.JwtUser;
import me.zhengjie.modules.system.service.UserService; import me.zhengjie.modules.system.service.UserService;
import me.zhengjie.modules.system.service.dto.*; import me.zhengjie.modules.system.service.dto.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -20,11 +19,14 @@ import java.util.Optional;
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class) @Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class JwtUserDetailsService implements UserDetailsService { public class JwtUserDetailsService implements UserDetailsService {
@Autowired private final UserService userService;
private UserService userService;
@Autowired private final JwtPermissionService permissionService;
private JwtPermissionService permissionService;
public JwtUserDetailsService(UserService userService, JwtPermissionService permissionService) {
this.userService = userService;
this.permissionService = permissionService;
}
@Override @Override
public UserDetails loadUserByUsername(String username){ public UserDetails loadUserByUsername(String username){

View File

@ -0,0 +1,108 @@
package me.zhengjie.modules.security.service;
import me.zhengjie.modules.security.security.JwtUser;
import me.zhengjie.modules.security.security.OnlineUser;
import me.zhengjie.utils.EncryptUtils;
import me.zhengjie.utils.FileUtil;
import me.zhengjie.utils.PageUtil;
import me.zhengjie.utils.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* @author Zheng Jie
* @Date 2019102621:56:27
*/
@Service
@SuppressWarnings({"unchecked","all"})
public class OnlineUserService {
@Value("${jwt.expiration}")
private Long expiration;
@Value("${jwt.online}")
private String onlineKey;
private final RedisTemplate redisTemplate;
public OnlineUserService(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
public void save(JwtUser jwtUser, String token, HttpServletRequest request){
String job = jwtUser.getDept() + "/" + jwtUser.getJob();
String ip = StringUtils.getIp(request);
String browser = StringUtils.getBrowser(request);
String address = StringUtils.getCityInfo(ip);
OnlineUser onlineUser = null;
try {
onlineUser = new OnlineUser(jwtUser.getUsername(), job, browser , ip, address, EncryptUtils.desEncrypt(token), new Date());
} catch (Exception e) {
e.printStackTrace();
}
redisTemplate.opsForValue().set(onlineKey + token, onlineUser);
redisTemplate.expire(onlineKey + token,expiration, TimeUnit.MILLISECONDS);
}
public Page<OnlineUser> getAll(String filter, Pageable pageable){
List<OnlineUser> onlineUsers = getAll(filter);
return new PageImpl<OnlineUser>(
PageUtil.toPage(pageable.getPageNumber(),pageable.getPageSize(),onlineUsers),
pageable,
onlineUsers.size());
}
public List<OnlineUser> getAll(String filter){
List<String> keys = new ArrayList<>(redisTemplate.keys(onlineKey + "*"));
Collections.reverse(keys);
List<OnlineUser> onlineUsers = new ArrayList<>();
for (String key : keys) {
OnlineUser onlineUser = (OnlineUser) redisTemplate.opsForValue().get(key);
if(StringUtils.isNotBlank(filter)){
if(onlineUser.toString().contains(filter)){
onlineUsers.add(onlineUser);
}
} else {
onlineUsers.add(onlineUser);
}
}
Collections.sort(onlineUsers, (o1, o2) -> {
return o2.getLoginTime().compareTo(o1.getLoginTime());
});
return onlineUsers;
}
public void kickOut(String val) throws Exception {
String key = onlineKey + EncryptUtils.desDecrypt(val);
redisTemplate.delete(key);
}
public void logout(String token) {
String key = onlineKey + token;
redisTemplate.delete(key);
}
public void download(List<OnlineUser> all, HttpServletResponse response) throws IOException {
List<Map<String, Object>> list = new ArrayList<>();
for (OnlineUser user : all) {
Map<String,Object> map = new LinkedHashMap<>();
map.put("用户名", user.getUserName());
map.put("岗位", user.getJob());
map.put("登录IP", user.getIp());
map.put("登录地点", user.getAddress());
map.put("浏览器", user.getBrowser());
map.put("登录日期", user.getLoginTime());
list.add(map);
}
FileUtil.downloadExcel(list, response);
}
}

View File

@ -6,6 +6,8 @@ import me.zhengjie.modules.security.security.JwtUser;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
@ -31,15 +33,15 @@ public class JwtTokenUtil implements Serializable {
return getClaimFromToken(token, Claims::getSubject); return getClaimFromToken(token, Claims::getSubject);
} }
public Date getIssuedAtDateFromToken(String token) { private Date getIssuedAtDateFromToken(String token) {
return getClaimFromToken(token, Claims::getIssuedAt); return getClaimFromToken(token, Claims::getIssuedAt);
} }
public Date getExpirationDateFromToken(String token) { private Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token, Claims::getExpiration); return getClaimFromToken(token, Claims::getExpiration);
} }
public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) { private <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
final Claims claims = getAllClaimsFromToken(token); final Claims claims = getAllClaimsFromToken(token);
return claimsResolver.apply(claims); return claimsResolver.apply(claims);
} }
@ -103,6 +105,14 @@ public class JwtTokenUtil implements Serializable {
.compact(); .compact();
} }
public String getToken(HttpServletRequest request){
final String requestHeader = request.getHeader(tokenHeader);
if (requestHeader != null && requestHeader.startsWith("Bearer ")) {
return requestHeader.substring(7);
}
return null;
}
public Boolean validateToken(String token, UserDetails userDetails) { public Boolean validateToken(String token, UserDetails userDetails) {
JwtUser user = (JwtUser) userDetails; JwtUser user = (JwtUser) userDetails;
final Date created = getIssuedAtDateFromToken(token); final Date created = getIssuedAtDateFromToken(token);

Some files were not shown because too many files have changed in this diff Show More