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 |
| 码云 | https://gitee.com/elunez/eladmin | https://gitee.com/elunez/eladmin-qt |
| github | https://github.com/elunez/eladmin | https://github.com/elunez/eladmin-web |
| 码云 | https://gitee.com/elunez/eladmin | https://gitee.com/elunez/eladmin-web |
#### 系统功能
- 用户管理提供用户的相关配置新增用户后默认密码为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 公共模块
- exception 项目统一异常的处理
- mapper mapstruct的通用mapper
- redis redis缓存相关配置
- swagger2 接口文档配置
- utils 系统通用工具类
- annotation 为系统自定义注解
- aspect 自定义注解的切面
- base 提供了Entity、DTO基类和mapstruct的通用mapper
- config 自定义权限实现、redis配置、swagger配置
- exception 项目统一异常的处理
- utils 系统通用工具类
- eladmin-system 系统核心模块(系统启动入口)
- config 配置跨域与静态资源,与数据权限
- modules 系统相关模块(登录授权、定时任务等)
- config 配置跨域与静态资源,与数据权限
- thread 线程池相关
- modules 系统相关模块(登录授权、系统监控、定时任务等)
- eladmin-logging 系统日志模块
- eladmin-tools 系统第三方工具模块
- eladmin-generator 系统代码生成模块
@ -78,6 +80,6 @@ eladmin基于 Spring Boot 2.1.0 、 Jpa、 Spring Security、redis、Vue的前
</table>
#### 项目捐赠
项目的发展离不开你的支持,请作者喝杯咖啡吧 ☕! [Donate](https://docs.auauz.net/#/jz)
项目的发展离不开你的支持,请作者喝杯咖啡吧ps辣条也行 ☕! [Donate](https://docs.auauz.net/#/jz)
#### 反馈交流
- QQ交流群891137268

View File

@ -5,11 +5,10 @@
<parent>
<artifactId>eladmin</artifactId>
<groupId>me.zhengjie</groupId>
<version>2.2</version>
<version>2.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>eladmin-common</artifactId>
<name>公共模块</name>
</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)
public @interface Query {
/** Dong ZhaoYang 2017/8/7 基本对象的属性名 */
// Dong ZhaoYang 2017/8/7 基本对象的属性名
String propName() default "";
/** Dong ZhaoYang 2017/8/7 查询方式 */
// Dong ZhaoYang 2017/8/7 查询方式
Type type() default Type.EQUAL;
/**
* Userdept
* @return
*/
String joinName() default "";
/**
*
* @return
*/
Join join() default Join.LEFT;
/**
* String, @Query(blurry = "email,username")
* @return
*/
String blurry() default "";
enum Type {
/** jie 2019/6/4 相等 */
// jie 2019/6/4 相等
EQUAL
/** Dong ZhaoYang 2017/8/7 大于等于 */
// Dong ZhaoYang 2017/8/7 大于等于
, GREATER_THAN
/** Dong ZhaoYang 2017/8/7 小于等于 */
// Dong ZhaoYang 2017/8/7 小于等于
, LESS_THAN
/** Dong ZhaoYang 2017/8/7 中模糊查询 */
// Dong ZhaoYang 2017/8/7 中模糊查询
, INNER_LIKE
/** Dong ZhaoYang 2017/8/7 左模糊查询 */
// Dong ZhaoYang 2017/8/7 左模糊查询
, LEFT_LIKE
/** Dong ZhaoYang 2017/8/7 右模糊查询 */
// Dong ZhaoYang 2017/8/7 右模糊查询
, RIGHT_LIKE
/** Dong ZhaoYang 2017/8/7 小于 */
// Dong ZhaoYang 2017/8/7 小于
, LESS_THAN_NQ
//** jie 2019/6/4 包含 */
// jie 2019/6/4 包含
, IN
}

View File

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

View File

@ -1,7 +1,12 @@
package me.zhengjie.aspect;
/**
*
* @author /
*/
public enum LimitType {
// 默认
CUSTOMER,
// by ip addr
// by ip addr
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;
@ -6,33 +6,25 @@ import java.util.List;
* @author Zheng Jie
* @date 2018-11-23
*/
public interface EntityMapper<D, E> {
public interface BaseMapper<D, E> {
/**
* DTOEntity
* @param dto
* @return
*/
E toEntity(D dto);
/**
* EntityDTO
* @param entity
* @return
*/
D toDto(E entity);
/**
* DTOEntity
* @param dtoList
* @return
*/
List <E> toEntity(List<D> dtoList);
/**
* EntityDTO
* @param entityList
* @return
*/
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.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
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.ConditionalOnMissingBean;
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.RedisTemplate;
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.util.HashMap;
import java.util.Map;
/**
* @author Zheng Jie
@ -28,21 +37,19 @@ import java.time.Duration;
@Slf4j
@Configuration
@EnableCaching
// 自动配置
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
public class RedisConfig extends CachingConfigurerSupport {
/**
* redis 1
* redis 6
* @cacheable
* @return
*/
@Bean
public RedisCacheConfiguration redisCacheConfiguration(){
FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
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;
}
@ -51,21 +58,20 @@ public class RedisConfig extends CachingConfigurerSupport {
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
//序列化
FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);
FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
// value值的序列化采用fastJsonRedisSerializer
template.setValueSerializer(fastJsonRedisSerializer);
template.setHashValueSerializer(fastJsonRedisSerializer);
// 全局开启AutoType不建议使用
// ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
// 全局开启AutoType这里方便开发使用全局的方式
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
// 建议使用这种方式,小范围指定白名单
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.domain");
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.system.service.dto");
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.service.dto");
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.system.domain");
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.quartz.domain");
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.monitor.domain");
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.security.security");
// ParserConfig.getGlobalInstance().addAccept("me.zhengjie.domain");
// ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.system.service.dto");
// ParserConfig.getGlobalInstance().addAccept("me.zhengjie.service.dto");
// ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.system.domain");
// ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.quartz.domain");
// ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.monitor.domain");
// ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.security.security");
// key的序列化采用StringRedisSerializer
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
@ -75,20 +81,27 @@ public class RedisConfig extends CachingConfigurerSupport {
/**
* key使
* 使 @Cacheable
* @return
*/
@Bean
@Override
public KeyGenerator keyGenerator() {
return (target, method, params) -> {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(JSON.toJSONString(obj).hashCode());
Map<String,Object> container = new HashMap<>();
Class<?> targetClassClass = target.getClass();
// 类地址
container.put("class",targetClassClass.toGenericString());
// 方法名称
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() {
// 异常处理当Redis发生异常时打印日志但是程序正常走
log.info("初始化 -> [{}]", "Redis CacheErrorHandler");
CacheErrorHandler cacheErrorHandler = new CacheErrorHandler() {
return new CacheErrorHandler() {
@Override
public void handleCacheGetError(RuntimeException e, Cache cache, Object key) {
log.error("Redis occur handleCacheGetErrorkey -> [{}]", key, e);
@ -118,7 +131,74 @@ public class RedisConfig extends CachingConfigurerSupport {
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 io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
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.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.schema.AlternateTypeRule;
import springfox.documentation.schema.AlternateTypeRuleConvention;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Parameter;
@ -15,6 +23,8 @@ import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.List;
import static com.google.common.collect.Lists.newArrayList;
import static springfox.documentation.schema.AlternateTypeRules.newRule;
/**
* api /swagger-ui.html
@ -33,9 +43,10 @@ public class SwaggerConfig {
private Boolean enabled;
@Bean
@SuppressWarnings("all")
public Docket createRestApi() {
ParameterBuilder ticketPar = new ParameterBuilder();
List<Parameter> pars = new ArrayList<Parameter>();
List<Parameter> pars = new ArrayList<>();
ticketPar.name(tokenHeader).description("token")
.modelRef(new ModelRef("string"))
.parameterType("header")
@ -55,8 +66,43 @@ public class SwaggerConfig {
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("eladmin 接口文档")
.version("2.1")
.version("2.3")
.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 org.springframework.http.HttpStatus;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
/**

View File

@ -2,33 +2,18 @@ package me.zhengjie.exception;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.IntStream;
/**
* @author Zheng Jie
* @date 2018-11-23
*/
public class EntityExistException extends RuntimeException {
public EntityExistException(Class clazz, Object... saveBodyParamsMap) {
super(EntityExistException.generateMessage(clazz.getSimpleName(), toMap(String.class, String.class, saveBodyParamsMap)));
public EntityExistException(Class clazz, String field, String val) {
super(EntityExistException.generateMessage(clazz.getSimpleName(), field, val));
}
private static String generateMessage(String entity, Map<String, String> saveBodyParams) {
return StringUtils.capitalize(entity) +
" 已存在 " +
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);
private static String generateMessage(String entity, String field, String val) {
return StringUtils.capitalize(entity)
+ " with " + field + " "+ val + " existed";
}
}

View File

@ -2,34 +2,18 @@ package me.zhengjie.exception;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.IntStream;
/**
* @author Zheng Jie
* @date 2018-11-23
*/
public class EntityNotFoundException extends RuntimeException {
public EntityNotFoundException(Class clazz, Object... searchParamsMap) {
super(EntityNotFoundException.generateMessage(clazz.getSimpleName(), toMap(String.class, String.class, searchParamsMap)));
public EntityNotFoundException(Class clazz, String field, String val) {
super(EntityNotFoundException.generateMessage(clazz.getSimpleName(), field, val));
}
private static String generateMessage(String entity, Map<String, String> searchParams) {
return StringUtils.capitalize(entity) +
" 不存在 " +
searchParams;
private static String generateMessage(String entity, String field, String val) {
return StringUtils.capitalize(entity)
+ " with " + field + " "+ val + " does not exist";
}
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
class ApiError {
private Integer status;
private Integer status = 400;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime timestamp;
private String message;
@ -21,10 +21,17 @@ class ApiError {
timestamp = LocalDateTime.now();
}
public ApiError(Integer status,String message) {
this();
this.status = status;
this.message = message;
public static ApiError error(String message){
ApiError apiError = new ApiError();
apiError.setMessage(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.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.Objects;
import static org.springframework.http.HttpStatus.*;
/**
@ -23,91 +24,73 @@ public class GlobalExceptionHandler {
/**
*
* @param e
* @return
*/
@ExceptionHandler(Throwable.class)
public ResponseEntity handleException(Throwable e){
// 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e));
ApiError apiError = new ApiError(BAD_REQUEST.value(),e.getMessage());
return buildResponseEntity(apiError);
return buildResponseEntity(ApiError.error(e.getMessage()));
}
/**
* 访AccessDeniedException
* @param e
* @return
*/
@ExceptionHandler(AccessDeniedException.class)
public ResponseEntity handleAccessDeniedException(AccessDeniedException e){
// 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e));
ApiError apiError = new ApiError(FORBIDDEN.value(),e.getMessage());
return buildResponseEntity(apiError);
return buildResponseEntity(ApiError.error(FORBIDDEN.value(),e.getMessage()));
}
/**
*
* @param e
* @return
*/
@ExceptionHandler(value = BadRequestException.class)
public ResponseEntity<ApiError> badRequestException(BadRequestException e) {
// 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e));
ApiError apiError = new ApiError(e.getStatus(),e.getMessage());
return buildResponseEntity(apiError);
return buildResponseEntity(ApiError.error(e.getStatus(),e.getMessage()));
}
/**
* EntityExist
* @param e
* @return
*/
@ExceptionHandler(value = EntityExistException.class)
public ResponseEntity<ApiError> entityExistException(EntityExistException e) {
// 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e));
ApiError apiError = new ApiError(BAD_REQUEST.value(),e.getMessage());
return buildResponseEntity(apiError);
return buildResponseEntity(ApiError.error(e.getMessage()));
}
/**
* EntityNotFound
* @param e
* @return
*/
@ExceptionHandler(value = EntityNotFoundException.class)
public ResponseEntity<ApiError> entityNotFoundException(EntityNotFoundException e) {
// 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e));
ApiError apiError = new ApiError(NOT_FOUND.value(),e.getMessage());
return buildResponseEntity(apiError);
return buildResponseEntity(ApiError.error(NOT_FOUND.value(),e.getMessage()));
}
/**
*
* @param e
* @returns
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiError> handleMethodArgumentNotValidException(MethodArgumentNotValidException e){
// 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e));
String[] str = e.getBindingResult().getAllErrors().get(0).getCodes()[1].split("\\.");
StringBuffer msg = new StringBuffer(str[1]+":");
msg.append(e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
ApiError apiError = new ApiError(BAD_REQUEST.value(),msg.toString());
return buildResponseEntity(apiError);
String[] str = Objects.requireNonNull(e.getBindingResult().getAllErrors().get(0).getCodes())[1].split("\\.");
String message = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
if("不能为空".equals(message)){
message = str[1] + ":" + message;
}
return buildResponseEntity(ApiError.error(message));
}
/**
*
* @param apiError
* @return
*/
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
*/
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.spec.DESKeySpec;
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 {
if (source == null || source.length() == 0){
return null;
}
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");
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);
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;
StringBuffer out = new StringBuffer(inStr.length * 2);
for (int n = 0; n < inStr.length; n++) {
stmp = Integer.toHexString(inStr[n] & 0xFF);
StringBuilder out = new StringBuilder(inStr.length * 2);
for (byte b : inStr) {
stmp = Integer.toHexString(b & 0xFF);
if (stmp.length() == 1) {
// 如果是0至F的单位字符串则添加0
out.append("0" + stmp);
out.append("0").append(stmp);
} else {
out.append(stmp);
}
@ -51,8 +49,7 @@ public class EncryptUtils {
return out.toString();
}
public static byte[] hex2byte(byte[] b) {
private static byte[] hex2byte(byte[] b) {
if ((b.length % 2) != 0){
throw new IllegalArgumentException("长度不是偶数");
}
@ -66,9 +63,6 @@ public class EncryptUtils {
/**
*
* @param source
* @return
* @throws Exception
*/
public static String desDecrypt(String source) throws Exception {
if (source == null || source.length() == 0){
@ -76,10 +70,10 @@ public class EncryptUtils {
}
byte[] src = hex2byte(source.getBytes());
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");
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);
byte[] retByte = cipher.doFinal(src);
return new String(retByte);
@ -87,8 +81,6 @@ public class EncryptUtils {
/**
*
* @param password
* @return
*/
public static String encryptPassword(String password){
return DigestUtils.md5DigestAsHex(password.getBytes());

View File

@ -11,6 +11,7 @@ import javax.activation.MimetypesFileTypeMap;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.security.MessageDigest;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
@ -44,8 +45,6 @@ public class FileUtil extends cn.hutool.core.io.FileUtil {
/**
* MultipartFileFile
* @param multipartFile
* @return
*/
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) {
if ((filename != null) && (filename.length() > 0)) {
@ -93,8 +78,6 @@ public class FileUtil extends cn.hutool.core.io.FileUtil {
/**
* Java
* @param filename
* @return
*/
public static String getFileNameNoEx(String filename) {
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){
String resultSize = "";
String resultSize;
if (size / GB >= 1) {
//如果当前Byte的值大于等于1GB
resultSize = DF.format(size / (float) GB) + "GB ";
@ -130,18 +111,14 @@ public class FileUtil extends cn.hutool.core.io.FileUtil {
/**
* 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);
if (file.exists()) {
return file;
}
OutputStream os = new FileOutputStream(file);
int bytesRead = 0;
int bytesRead;
byte[] buffer = new byte[8192];
while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
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) {
Date date = new Date();
@ -170,10 +143,10 @@ public class FileUtil extends cn.hutool.core.io.FileUtil {
File dest = new File(path);
// 检测是否存在目录
if (!dest.getParentFile().exists()) {
dest.getParentFile().mkdirs();// 新建文件夹
dest.getParentFile().mkdirs();
}
String d = dest.getPath();
file.transferTo(dest);// 文件写入
// 文件写入
file.transferTo(dest);
return dest;
} catch (Exception e) {
e.printStackTrace();
@ -183,20 +156,16 @@ public class FileUtil extends cn.hutool.core.io.FileUtil {
public static String fileToBase64(File file) throws Exception {
FileInputStream inputFile = new FileInputStream(file);
String base64 =null;
String base64;
byte[] buffer = new byte[(int)file.length()];
inputFile.read(buffer);
inputFile.close();
base64=new Base64().encode(buffer);
String encoded = base64.replaceAll("[\\s*\t\n\r]", "");
return encoded;
base64=Base64.encode(buffer);
return base64.replaceAll("[\\s*\t\n\r]", "");
}
/**
* excel
* @param list
* @return
* @throws Exception
*/
public static void downloadExcel(List<Map<String, Object>> list, HttpServletResponse response) throws IOException {
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) {
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 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";
if(image.indexOf(type) != -1){
if(image.contains(type)){
return "图片";
} else if(documents.indexOf(type) != -1){
} else if(documents.contains(type)){
return "文档";
} else if(music.indexOf(type) != -1){
} else if(music.contains(type)){
return "音乐";
} else if(video.indexOf(type) != -1){
} else if(video.contains(type)){
return "视频";
} else return "其他";
} else {
return "其他";
}
}
public static String getFileTypeByMimeType(String type) {
String mimeType = new MimetypesFileTypeMap().getContentType("." + type);
return mimeType.split("\\/")[0];
return mimeType.split("/")[0];
}
public static void checkSize(long maxSize, long size) {
if(size > (maxSize * 1024 * 1024)){
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
* @param page
* @param size
* @param list
* @return
*/
public static List toPage(int page, int size , List list) {
int fromIndex = page * size;
@ -32,10 +28,8 @@ public class PageUtil extends cn.hutool.core.util.PageUtil {
/**
* 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.put("content",page.getContent());
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.put("content",object);
map.put("totalElements",totalElements);

View File

@ -15,18 +15,12 @@ import java.util.*;
@Slf4j
public class QueryHelp {
/**
* @ : Predicate
* @ : Dong ZhaoYang
* @ : 2017/8/7
* @ : 17:25
*/
@SuppressWarnings("unchecked")
public static <R, Q> Predicate getPredicate(Root<R> root, Q query, CriteriaBuilder cb) {
List<Predicate> list = new ArrayList<>();
if(query == null){
return cb.and(list.toArray(new Predicate[list.size()]));
return cb.and(list.toArray(new Predicate[0]));
}
try {
List<Field> fields = getAllFields(query.getClass(), new ArrayList<>());
@ -62,19 +56,20 @@ public class QueryHelp {
for (String name : joinNames) {
switch (q.join()) {
case LEFT:
if(ObjectUtil.isNotEmpty(join)){
if(ObjectUtil.isNotNull(join)){
join = join.join(name, JoinType.LEFT);
} else {
join = root.join(name, JoinType.LEFT);
}
break;
case RIGHT:
if(ObjectUtil.isNotEmpty(join)){
if(ObjectUtil.isNotNull(join)){
join = join.join(name, JoinType.RIGHT);
} else {
join = root.join(name, JoinType.RIGHT);
}
break;
default: break;
}
}
}
@ -111,6 +106,7 @@ public class QueryHelp {
list.add(getExpression(attributeName,join,root).in((Collection<Long>) val));
}
break;
default: break;
}
}
field.setAccessible(accessible);
@ -118,7 +114,8 @@ public class QueryHelp {
} catch (Exception 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")
@ -130,21 +127,19 @@ public class QueryHelp {
}
}
@SuppressWarnings("unchecked")
public static boolean isBlank(final CharSequence cs) {
private static boolean isBlank(final CharSequence cs) {
int strLen;
if (cs == null || (strLen = cs.length()) == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if (Character.isWhitespace(cs.charAt(i)) == false) {
if (!Character.isWhitespace(cs.charAt(i))) {
return false;
}
}
return true;
}
@SuppressWarnings("unchecked")
private static List<Field> getAllFields(Class clazz, List<Field> fields) {
if (clazz != null) {
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.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
/**
* HttpServletRequest
@ -12,6 +13,6 @@ import javax.servlet.http.HttpServletRequest;
public class RequestHolder {
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 static UserDetails getUserDetails() {
UserDetails userDetails = null;
UserDetails userDetails;
try {
userDetails = (UserDetails) org.springframework.security.core.context.SecurityContextHolder.getContext().getAuthentication().getPrincipal();
} catch (Exception e) {
@ -28,8 +28,7 @@ public class SecurityUtils {
*/
public static String getUsername(){
Object obj = getUserDetails();
JSONObject json = new JSONObject(obj);
return json.get("username", String.class);
return new JSONObject(obj).get("username", String.class);
}
/**
@ -38,7 +37,6 @@ public class SecurityUtils {
*/
public static Long getUserId(){
Object obj = getUserDetails();
JSONObject json = new JSONObject(obj);
return json.get("id", Long.class);
return new JSONObject(obj).get("id", Long.class);
}
}

View File

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

View File

@ -1,14 +1,16 @@
package me.zhengjie.utils;
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.DbConfig;
import org.lionsoul.ip2region.DbSearcher;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Calendar;
import java.util.Date;
@ -18,25 +20,6 @@ import java.util.Date;
public class StringUtils extends org.apache.commons.lang3.StringUtils {
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"
* toUnderScoreCase("helloWorld") = "hello_world"
*/
public static String toUnderScoreCase(String s) {
static String toUnderScoreCase(String s) {
if (s == null) {
return null;
}
@ -125,53 +108,45 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
/**
* ip
* @param request
* @return
*/
public static String getIP(HttpServletRequest request) {
public static String getIp(HttpServletRequest request) {
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");
}
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");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
String[] ips = ip.split(",");
return "0:0:0:0:0:0:0:1".equals(ips[0])?"127.0.0.1":ips[0];
if (ip.contains(",")) {
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
* @param ip
* @return
*/
public static String getCityInfo(String ip) {
try {
String path = "ip2region/ip2region.db";
String name = "ip2region.db";
int algorithm = DbSearcher.BTREE_ALGORITHM;
DbConfig config = new DbConfig();
File file = FileUtil.inputStreamToFile(new ClassPathResource(path).getStream(), name);
DbSearcher searcher = new DbSearcher(config, file.getPath());
Method method = null;
switch (algorithm) {
case DbSearcher.BTREE_ALGORITHM:
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;
Method method;
method = searcher.getClass().getMethod("btreeSearch", String.class);
DataBlock dataBlock;
dataBlock = (DataBlock) method.invoke(searcher, ip);
String address = dataBlock.getRegion().replace("0|","");
if(address.charAt(address.length()-1) == '|'){
@ -184,6 +159,12 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
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 org.hibernate.exception.ConstraintViolationException;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
*
* 2019-01-06
* @author Zheng Jie
* @date 2019-01-06
*/
public class ThrowableUtil {
/**
*
* @param throwable
* @return
*/
public static String getStackTrace(Throwable throwable){
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
try {
try (PrintWriter pw = new PrintWriter(sw)) {
throwable.printStackTrace(pw);
return sw.toString();
} finally {
pw.close();
}
}
@ -34,9 +27,10 @@ public class ThrowableUtil {
while ((t != null) && !(t instanceof ConstraintViolationException)) {
t = t.getCause();
}
if (t instanceof ConstraintViolationException) {
if (t != null) {
throw new BadRequestException(msg);
}
assert false;
throw new BadRequestException("删除失败:" + t.getMessage());
}
}

View File

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

View File

@ -1,7 +1,7 @@
package me.zhengjie.utils;
import cn.hutool.core.util.ObjectUtil;
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){
if(!optional.isPresent()){
String msg = entity
+ " 不存在 "
+"{ "+ parameter +":"+ value.toString() +" }";
public static void isNull(Object obj, String entity, String parameter , Object value){
if(ObjectUtil.isNull(obj)){
String msg = entity + " 不存在: "+ parameter +" is "+ value;
throw new BadRequestException(msg);
}
}
/**
*
* @param string
* @return
*/
public static boolean isEmail(String string) {
if (string == null){
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);
}
}

View File

@ -11,12 +11,6 @@ import static org.junit.Assert.*;
public class StringUtilsTest {
@Test
public void testInString() {
assertTrue(inString("?", "?"));
assertFalse(inString("?", new String[]{}));
}
@Test
public void testToCamelCase() {
assertNull(toCamelCase(null));
@ -44,6 +38,6 @@ public class StringUtilsTest {
@Test
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>
<artifactId>eladmin</artifactId>
<groupId>me.zhengjie</groupId>
<version>2.2</version>
<version>2.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -20,7 +20,7 @@
<dependency>
<groupId>me.zhengjie</groupId>
<artifactId>eladmin-common</artifactId>
<version>2.2</version>
<version>2.3</version>
</dependency>
<!--模板引擎-->

View File

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

View File

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

View File

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

View File

@ -1,8 +1,9 @@
package me.zhengjie.rest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import me.zhengjie.domain.GenConfig;
import me.zhengjie.service.GenConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
@ -13,23 +14,25 @@ import org.springframework.web.bind.annotation.*;
* @date 2019-01-14
*/
@RestController
@RequestMapping("api")
@RequestMapping("/api/genConfig")
@Api(tags = "系统:代码生成器配置管理")
public class GenConfigController {
@Autowired
private GenConfigService genConfigService;
private final GenConfigService genConfigService;
/**
*
* @return
*/
@GetMapping(value = "/genConfig")
public ResponseEntity get(){
return new ResponseEntity(genConfigService.find(), HttpStatus.OK);
public GenConfigController(GenConfigService genConfigService) {
this.genConfigService = genConfigService;
}
@PutMapping(value = "/genConfig")
@ApiOperation("查询")
@GetMapping
public ResponseEntity get(){
return new ResponseEntity<>(genConfigService.find(), HttpStatus.OK);
}
@ApiOperation("修改")
@PutMapping
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;
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.exception.BadRequestException;
import me.zhengjie.service.GenConfigService;
import me.zhengjie.service.GeneratorService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@ -17,49 +18,39 @@ import java.util.List;
* @date 2019-01-02
*/
@RestController
@RequestMapping("api")
@RequestMapping("/api/generator")
@Api(tags = "系统:代码生成管理")
public class GeneratorController {
@Autowired
private GeneratorService generatorService;
private final GeneratorService generatorService;
@Autowired
private GenConfigService genConfigService;
private final GenConfigService genConfigService;
@Value("${generator.enabled}")
private Boolean generatorEnabled;
/**
*
* @param name
* @param page
* @param size
* @return
*/
@GetMapping(value = "/generator/tables")
public GeneratorController(GeneratorService generatorService, GenConfigService genConfigService) {
this.generatorService = generatorService;
this.genConfigService = genConfigService;
}
@ApiOperation("查询数据库元数据")
@GetMapping(value = "/tables")
public ResponseEntity getTables(@RequestParam(defaultValue = "") String name,
@RequestParam(defaultValue = "0")Integer page,
@RequestParam(defaultValue = "10")Integer size){
@RequestParam(defaultValue = "0")Integer page,
@RequestParam(defaultValue = "10")Integer 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);
}
/**
*
* @param tableName
* @return
*/
@GetMapping(value = "/generator/columns")
@ApiOperation("查询表内元数据")
@GetMapping(value = "/columns")
public ResponseEntity getTables(@RequestParam String tableName){
return new ResponseEntity(generatorService.getColumns(tableName), HttpStatus.OK);
return new ResponseEntity<>(generatorService.getColumns(tableName), HttpStatus.OK);
}
/**
*
* @param columnInfos
* @return
*/
@PostMapping(value = "/generator")
@ApiOperation("生成代码")
@PostMapping
public ResponseEntity generator(@RequestBody List<ColumnInfo> columnInfos, @RequestParam String tableName){
if(!generatorEnabled){
throw new BadRequestException("此环境不允许生成代码!");

View File

@ -1,30 +1,14 @@
package me.zhengjie.service;
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
* @date 2019-01-14
*/
@CacheConfig(cacheNames = "genConfig")
public interface GenConfigService {
/**
* find
* @return
*/
@Cacheable(key = "'1'")
GenConfig find();
/**
* update
* @param genConfig
* @return
*/
@CacheEvict(allEntries = true)
GenConfig update(GenConfig genConfig);
}

View File

@ -12,24 +12,24 @@ public interface GeneratorService {
/**
*
* @param name
* @param startEnd
* @return
* @param name
* @param startEnd
* @return /
*/
Object getTables(String name, int[] startEnd);
/**
*
* @param name
* @return
* @param name
* @return /
*/
Object getColumns(String name);
/**
*
* @param columnInfos
* @param genConfig
* @param tableName
* @param columnInfos
* @param genConfig
* @param 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.repository.GenConfigRepository;
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 java.io.File;
import java.util.Optional;
@ -14,35 +15,37 @@ import java.util.Optional;
* @date 2019-01-14
*/
@Service
@CacheConfig(cacheNames = "genConfig")
public class GenConfigServiceImpl implements GenConfigService {
@Autowired
private GenConfigRepository genConfigRepository;
private final GenConfigRepository genConfigRepository;
@Override
public GenConfig find() {
Optional<GenConfig> genConfig = genConfigRepository.findById(1L);
if(genConfig.isPresent()){
return genConfig.get();
} else {
return new GenConfig();
}
public GenConfigServiceImpl(GenConfigRepository genConfigRepository) {
this.genConfigRepository = genConfigRepository;
}
@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) {
genConfig.setId(1L);
// 自动设置Api路径注释掉前需要同步取消前端的注释
String separator = File.separator;
String[] paths = null;
String[] paths;
if (separator.equals("\\")) {
paths = genConfig.getPath().split("\\\\");
} else paths = genConfig.getPath().split(File.separator);
StringBuffer api = new StringBuffer();
for (int i = 0; i < paths.length; i++) {
api.append(paths[i]);
StringBuilder api = new StringBuilder();
for (String path : paths) {
api.append(path);
api.append(separator);
if(paths[i].equals("src")){
if (path.equals("src")) {
api.append("api");
break;
}

View File

@ -28,6 +28,7 @@ public class GeneratorServiceImpl implements GeneratorService {
private EntityManager em;
@Override
@SuppressWarnings("all")
public Object getTables(String name, int[] startEnd) {
// 使用预编译防止sql注入
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.setMaxResults(startEnd[1]-startEnd[0]);
query.setParameter(1, StringUtils.isNotBlank(name) ? ("%" + name + "%") : "%%");
List<Object[]> result = query.getResultList();
List result = query.getResultList();
List<TableInfo> tableInfos = new ArrayList<>();
for (Object[] obj : result) {
tableInfos.add(new TableInfo(obj[0],obj[1],obj[2],obj[3], ObjectUtil.isNotEmpty(obj[4])? obj[4] : "-"));
for (Object obj : result) {
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())");
Object totalElements = query1.getSingleResult();
@ -48,16 +50,18 @@ public class GeneratorServiceImpl implements GeneratorService {
}
@Override
@SuppressWarnings("all")
public Object getColumns(String name) {
// 使用预编译防止sql注入
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";
Query query = em.createNativeQuery(sql);
query.setParameter(1, StringUtils.isNotBlank(name) ? name : null);
List<Object[]> result = query.getResultList();
List result = query.getResultList();
List<ColumnInfo> columnInfos = new ArrayList<>();
for (Object[] obj : result) {
columnInfos.add(new ColumnInfo(obj[0],obj[1],obj[2],obj[3],obj[4],obj[5],null,"true"));
for (Object obj : result) {
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());
}

View File

@ -12,11 +12,12 @@ public class ColUtil {
/**
* mysqljava
* @param type
* @return
* @param type
* @return String
*/
public static String cloToJava(String type){
static String cloToJava(String type){
Configuration config = getConfig();
assert config != null;
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<>();
templateNames.add("Entity");
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<>();
templateNames.add("api");
templateNames.add("index");
@ -67,7 +67,7 @@ public class GenUtil {
* @param genConfig
*/
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("moduleName",genConfig.getModuleName());
map.put("author",genConfig.getAuthor());
@ -85,6 +85,8 @@ public class GenUtil {
map.put("upperCaseClassName", className.toUpperCase());
map.put("changeClassName", changeClassName);
map.put("hasTimestamp",false);
map.put("queryHasTimestamp",false);
map.put("queryHasBigDecimal",false);
map.put("hasBigDecimal",false);
map.put("hasQuery",false);
map.put("auto",false);
@ -92,7 +94,7 @@ public class GenUtil {
List<Map<String,Object>> columns = new ArrayList<>();
List<Map<String,Object>> queryColumns = new ArrayList<>();
for (ColumnInfo column : columnInfos) {
Map<String,Object> listMap = new HashMap();
Map<String,Object> listMap = new HashMap<>();
listMap.put("columnComment",column.getColumnComment());
listMap.put("columnKey",column.getColumnKey());
@ -124,6 +126,12 @@ public class GenUtil {
if(!StringUtils.isBlank(column.getColumnQuery())){
listMap.put("columnQuery",column.getColumnQuery());
map.put("hasQuery",true);
if(TIMESTAMP.equals(colType)){
map.put("queryHasTimestamp",true);
}
if(BIGDECIMAL.equals(colType)){
map.put("queryHasBigDecimal",true);
}
queryColumns.add(listMap);
}
columns.add(listMap);
@ -138,6 +146,7 @@ public class GenUtil {
Template template = engine.getTemplate("generator/admin/"+templateName+".ftl");
String filePath = getAdminFilePath(templateName,genConfig,className);
assert filePath != null;
File file = new File(filePath);
// 如果非覆盖生成
@ -154,6 +163,7 @@ public class GenUtil {
Template template = engine.getTemplate("generator/front/"+templateName+".ftl");
String filePath = getFrontFilePath(templateName,genConfig,map.get("changeClassName").toString());
assert filePath != null;
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 packagePath = projectPath + File.separator + "src" +File.separator+ "main" + File.separator + "java" + File.separator;
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();
if ("api".equals(templateName)) {
@ -230,18 +240,17 @@ public class GenUtil {
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;
try {
FileUtil.touch(file);
writer = new FileWriter(file);
template.render(map, writer);
} catch (TemplateException e) {
throw new RuntimeException(e);
} catch (IOException e) {
} catch (TemplateException | IOException e) {
throw new RuntimeException(e);
} finally {
assert writer != null;
writer.close();
}
}

View File

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

View File

@ -2,7 +2,6 @@ package me.zhengjie.aspect;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.domain.Log;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.service.LogService;
import me.zhengjie.utils.RequestHolder;
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.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@ -28,11 +26,14 @@ import javax.servlet.http.HttpServletRequest;
@Slf4j
public class LogAspect {
@Autowired
private LogService logService;
private final LogService logService;
private long currentTime = 0L;
public LogAspect(LogService logService) {
this.logService = logService;
}
/**
*
*/
@ -48,11 +49,12 @@ public class LogAspect {
*/
@Around("logPointcut()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
Object result = null;
Object result;
currentTime = System.currentTimeMillis();
result = joinPoint.proceed();
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;
}
@ -66,7 +68,8 @@ public class LogAspect {
public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
Log log = new Log("ERROR",System.currentTimeMillis() - currentTime);
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() {

View File

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

View File

@ -11,22 +11,14 @@ import org.springframework.stereotype.Repository;
* @date 2018-11-24
*/
@Repository
public interface LogRepository extends JpaRepository<Log,Long>, JpaSpecificationExecutor {
public interface LogRepository extends JpaRepository<Log,Long>, JpaSpecificationExecutor<Log> {
/**
* 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)
Long findIp(String date1, String date2);
/**
* findExceptionById
* @param id
* @return
*/
@Query(value = "select exception_detail FROM log where id = ?1",nativeQuery = true)
String findExceptionById(Long id);
@Query(value = "select l FROM Log l where l.id = ?1")
Log findExceptionById(Long id);
}

View File

@ -1,9 +1,11 @@
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.dto.LogQueryCriteria;
import me.zhengjie.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
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.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author Zheng Jie
* @date 2018-11-24
*/
@RestController
@RequestMapping("api")
@RequestMapping("/api/logs")
@Api(tags = "监控:日志管理")
public class LogController {
@Autowired
private LogService logService;
private final LogService logService;
@GetMapping(value = "/logs")
@PreAuthorize("hasAnyRole('ADMIN')")
public ResponseEntity getLogs(LogQueryCriteria criteria, Pageable pageable){
criteria.setLogType("INFO");
return new ResponseEntity(logService.queryAll(criteria,pageable), HttpStatus.OK);
public LogController(LogService logService) {
this.logService = logService;
}
@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){
criteria.setLogType("INFO");
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")
@PreAuthorize("hasAnyRole('ADMIN')")
@GetMapping(value = "/error")
@ApiOperation("错误日志查询")
@PreAuthorize("@el.check()")
public ResponseEntity getErrorLogs(LogQueryCriteria criteria, Pageable pageable){
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}")
@PreAuthorize("hasAnyRole('ADMIN')")
@GetMapping(value = "/error/{id}")
@ApiOperation("日志异常详情查询")
@PreAuthorize("@el.check()")
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.scheduling.annotation.Async;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/**
* @author Zheng Jie
* @date 2018-11-24
*/
public interface LogService {
/**
* queryAll
* @param criteria
* @param pageable
* @return
*/
Object queryAll(LogQueryCriteria criteria, Pageable pageable);
/**
* queryAllByUser
* @param criteria
* @param pageable
* @return
*/
List<Log> queryAll(LogQueryCriteria criteria);
Object queryAllByUser(LogQueryCriteria criteria, Pageable pageable);
/**
*
* @param username
* @param ip
* @param joinPoint
* @param log
*/
@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
* @return
* @param id ID
* @return Object
*/
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 String username;
/**
*
*/
// 描述
private String description;
/**
*
*/
// 方法名
private String method;
/**
*
*/
// 参数
private String params;
/**
* ip
*/
private String browser;
// 请求ip
private String requestIp;
private String address;
/**
*
*/
// 创建日期
private Timestamp createTime;
}

View File

@ -3,6 +3,8 @@ package me.zhengjie.service.dto;
import lombok.Data;
import me.zhengjie.annotation.Query;
import java.sql.Timestamp;
/**
*
* @author Zheng Jie
@ -17,4 +19,10 @@ public class LogQueryCriteria {
@Query
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;
import lombok.Data;
import java.io.Serializable;
import java.sql.Timestamp;
@ -12,25 +11,19 @@ import java.sql.Timestamp;
@Data
public class LogSmallDTO implements Serializable {
/**
*
*/
// 描述
private String description;
/**
* ip
*/
// 请求ip
private String requestIp;
/**
*
*/
// 请求耗时
private Long time;
private String address;
/**
*
*/
private String browser;
// 创建日期
private Timestamp createTime;
}

View File

@ -1,6 +1,7 @@
package me.zhengjie.service.impl;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import me.zhengjie.domain.Log;
import me.zhengjie.repository.LogRepository;
@ -8,18 +9,25 @@ import me.zhengjie.service.LogService;
import me.zhengjie.service.dto.LogQueryCriteria;
import me.zhengjie.service.mapper.LogErrorMapper;
import me.zhengjie.service.mapper.LogSmallMapper;
import me.zhengjie.utils.FileUtil;
import me.zhengjie.utils.PageUtil;
import me.zhengjie.utils.QueryHelp;
import me.zhengjie.utils.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* @author Zheng Jie
@ -29,16 +37,17 @@ import java.lang.reflect.Method;
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class LogServiceImpl implements LogService {
@Autowired
private LogRepository logRepository;
private final LogRepository logRepository;
@Autowired
private LogErrorMapper logErrorMapper;
private final LogErrorMapper logErrorMapper;
@Autowired
private LogSmallMapper logSmallMapper;
private final 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
public Object queryAll(LogQueryCriteria criteria, Pageable pageable){
@ -49,6 +58,11 @@ public class LogServiceImpl implements LogService {
return page;
}
@Override
public List<Log> queryAll(LogQueryCriteria criteria) {
return logRepository.findAll(((root, criteriaQuery, cb) -> QueryHelp.getPredicate(root, criteria, cb)));
}
@Override
public Object queryAllByUser(LogQueryCriteria criteria, Pageable 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
@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();
Method method = signature.getMethod();
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 params = "{";
StringBuilder params = new StringBuilder("{");
//参数值
Object[] argValues = joinPoint.getArgs();
//参数名称
String[] argNames = ((MethodSignature)joinPoint.getSignature()).getParameterNames();
if(argValues != null){
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);
String LOGINPATH = "login";
if(LOGINPATH.equals(signature.getName())){
try {
JSONObject jsonObject = new JSONObject(argValues[0]);
username = jsonObject.get("username").toString();
assert argValues != null;
username = new JSONObject(argValues[0]).get("username").toString();
}catch (Exception e){
e.printStackTrace();
}
@ -96,12 +109,32 @@ public class LogServiceImpl implements LogService {
log.setAddress(StringUtils.getCityInfo(log.getRequestIp()));
log.setMethod(methodName);
log.setUsername(username);
log.setParams(params + " }");
log.setParams(params.toString() + " }");
log.setBrowser(browser);
logRepository.save(log);
}
@Override
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;
import me.zhengjie.base.BaseMapper;
import me.zhengjie.domain.Log;
import me.zhengjie.mapper.EntityMapper;
import me.zhengjie.service.dto.LogErrorDTO;
import org.mapstruct.Mapper;
import org.mapstruct.ReportingPolicy;
@ -10,7 +10,7 @@ import org.mapstruct.ReportingPolicy;
* @author Zheng Jie
* @date 2019-5-22
*/
@Mapper(componentModel = "spring",uses = {},unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface LogErrorMapper extends EntityMapper<LogErrorDTO, Log> {
@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface LogErrorMapper extends BaseMapper<LogErrorDTO, Log> {
}

View File

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

View File

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

View File

@ -25,14 +25,17 @@ public class DataScope {
private final String[] scopeType = {"全部","本级","自定义"};
@Autowired
private UserService userService;
private final UserService userService;
@Autowired
private RoleService roleService;
private final RoleService roleService;
@Autowired
private DeptService deptService;
private final DeptService deptService;
public DataScope(UserService userService, RoleService roleService, DeptService deptService) {
this.userService = userService;
this.roleService = roleService;
this.deptService = deptService;
}
public Set<Long> getDeptIds() {
@ -76,7 +79,7 @@ public class DataScope {
deptList.forEach(dept -> {
if (dept!=null && dept.getEnabled()){
List<Dept> depts = deptService.findByPid(dept.getId());
if(deptList!=null && deptList.size()!=0){
if(deptList.size() != 0){
list.addAll(getDeptChildren(depts));
}
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;
import me.zhengjie.modules.monitor.service.VisitsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@ -13,11 +12,14 @@ import org.springframework.stereotype.Component;
@Component
public class VisitsInitialization implements ApplicationRunner {
@Autowired
private VisitsService visitsService;
private final VisitsService visitsService;
public VisitsInitialization(VisitsService visitsService) {
this.visitsService = visitsService;
}
@Override
public void run(ApplicationArguments args) throws Exception {
public void run(ApplicationArguments args){
System.out.println("--------------- 初始化站点统计,如果存在今日统计则跳过 ---------------");
visitsService.save();
System.out.println("--------------- 初始化站点统计完成 ---------------");

View File

@ -4,6 +4,7 @@ import lombok.Data;
import org.hibernate.annotations.CreationTimestamp;
import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp;
/**
@ -15,7 +16,7 @@ import java.sql.Timestamp;
@Entity
@Data
@Table(name = "visits")
public class Visits {
public class Visits implements Serializable {
@Id
@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.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
@ -16,18 +15,17 @@ public interface VisitsRepository extends JpaRepository<Visits,Long> {
/**
* findByDate
* @param date
* @return
* @param date
* @return Visits
*/
Visits findByDate(String date);
/**
*
* @param date1
* @param date2
* @return
* @param date1 1
* @param date2 2
* @return List
*/
@Query(value = "select * FROM visits where " +
"create_time between ?1 and ?2",nativeQuery = true)
@Query(value = "select * FROM visits where create_time between ?1 and ?2",nativeQuery = true)
List<Visits> findAllVisits(String date1, String date2);
}

View File

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

View File

@ -1,47 +1,65 @@
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.modules.monitor.domain.vo.RedisVo;
import me.zhengjie.modules.monitor.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
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.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author Zheng Jie
* @date 2018-12-10
*/
@RestController
@RequestMapping("api")
@RequestMapping("/api/redis")
@Api(tags = "系统Redis缓存管理")
public class RedisController {
@Autowired
private RedisService redisService;
private final RedisService redisService;
public RedisController(RedisService redisService) {
this.redisService = redisService;
}
@Log("查询Redis缓存")
@GetMapping(value = "/redis")
@PreAuthorize("hasAnyRole('ADMIN','REDIS_ALL','REDIS_SELECT')")
@GetMapping
@ApiOperation("查询Redis缓存")
@PreAuthorize("@el.check('redis:list')")
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缓存")
@DeleteMapping(value = "/redis")
@PreAuthorize("hasAnyRole('ADMIN','REDIS_ALL','REDIS_DELETE')")
@DeleteMapping
@ApiOperation("删除Redis缓存")
@PreAuthorize("@el.check('redis:del')")
public ResponseEntity delete(@RequestBody RedisVo resources){
redisService.delete(resources.getKey());
return new ResponseEntity(HttpStatus.OK);
}
@Log("清空Redis缓存")
@DeleteMapping(value = "/redis/all")
@PreAuthorize("hasAnyRole('ADMIN','REDIS_ALL','REDIS_DELETE')")
@DeleteMapping(value = "/all")
@ApiOperation("清空Redis缓存")
@PreAuthorize("@el.check('redis:del')")
public ResponseEntity deleteAll(){
redisService.flushdb();
redisService.deleteAll();
return new ResponseEntity(HttpStatus.OK);
}
}

View File

@ -1,8 +1,9 @@
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.utils.RequestHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
@ -15,25 +16,32 @@ import org.springframework.web.bind.annotation.RestController;
* @date 2018-12-13
*/
@RestController
@RequestMapping("api")
@RequestMapping("/api/visits")
@Api(tags = "系统:访问记录管理")
public class VisitsController {
@Autowired
private VisitsService visitsService;
private final VisitsService visitsService;
@PostMapping(value = "/visits")
public VisitsController(VisitsService visitsService) {
this.visitsService = visitsService;
}
@PostMapping
@ApiOperation("创建访问记录")
public ResponseEntity create(){
visitsService.count(RequestHolder.getHttpServletRequest());
return new ResponseEntity(HttpStatus.CREATED);
}
@GetMapping(value = "/visits")
@GetMapping
@ApiOperation("查询")
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(){
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.Pageable;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/**
*
* @author Zheng Jie
@ -13,33 +17,47 @@ public interface RedisService {
/**
* findById
* @param key
* @return
* @param key
* @return /
*/
Page findByKey(String key, Pageable pageable);
/**
* findById
* @param key
* @return /
*/
List<RedisVo> findByKey(String key);
/**
*
* @param key
* @return
* @param key
* @return /
*/
String getCodeVal(String key);
/**
*
* @param key
* @param val
* @param key
* @param val
*/
void saveCode(String key, Object val);
/**
* delete
* @param key
* @param 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;
import org.springframework.scheduling.annotation.Async;
import javax.servlet.http.HttpServletRequest;
/**
@ -17,20 +16,20 @@ public interface VisitsService {
/**
*
* @param request
* @param request /
*/
@Async
void count(HttpServletRequest request);
/**
*
* @return
* @return /
*/
Object get();
/**
* getChartData
* @return
* @return /
*/
Object getChartData();
}

View File

@ -1,51 +1,71 @@
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.service.RedisService;
import me.zhengjie.utils.FileUtil;
import me.zhengjie.utils.PageUtil;
import org.springframework.beans.factory.annotation.Autowired;
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 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.stream.Collectors;
/**
* @author Zheng Jie
* @date 2018-12-10
*/
@Service
@SuppressWarnings({"unchecked","all"})
public class RedisServiceImpl implements RedisService {
@Autowired
RedisTemplate redisTemplate;
private final RedisTemplate redisTemplate;
@Value("${loginCode.expiration}")
private Long expiration;
@Value("${jwt.online}")
private String onlineKey;
@Value("${jwt.codeKey}")
private String codeKey;
public RedisServiceImpl(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Override
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<>();
if(!"*".equals(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;
}
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);
}
Page<RedisVo> page = new PageImpl<RedisVo>(
PageUtil.toPage(pageable.getPageNumber(),pageable.getPageSize(),redisVos),
pageable,
redisVos.size());
return page;
return redisVos;
}
@Override
@ -54,15 +74,15 @@ public class RedisServiceImpl implements RedisService {
}
@Override
public void flushdb() {
redisTemplate.getConnectionFactory().getConnection().flushDb();
public void deleteAll() {
Set<String> keys = redisTemplate.keys( "*");
redisTemplate.delete(keys.stream().filter(s -> !s.contains(onlineKey)).filter(s -> !s.contains(codeKey)).collect(Collectors.toList()));
}
@Override
public String getCodeVal(String key) {
try {
String value = redisTemplate.opsForValue().get(key).toString();
return value;
return Objects.requireNonNull(redisTemplate.opsForValue().get(key)).toString();
}catch (Exception e){
return "";
}
@ -73,4 +93,16 @@ public class RedisServiceImpl implements RedisService {
redisTemplate.opsForValue().set(key,val);
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)
public class VisitsServiceImpl implements VisitsService {
@Autowired
private VisitsRepository visitsRepository;
private final VisitsRepository visitsRepository;
@Autowired
private LogRepository logRepository;
private final LogRepository logRepository;
public VisitsServiceImpl(VisitsRepository visitsRepository, LogRepository logRepository) {
this.visitsRepository = visitsRepository;
this.logRepository = logRepository;
}
@Override
public void save() {
@ -58,7 +61,7 @@ public class VisitsServiceImpl implements VisitsService {
@Override
public Object get() {
Map map = new HashMap();
Map<String,Object> map = new HashMap<>();
LocalDate localDate = LocalDate.now();
Visits visits = visitsRepository.findByDate(localDate.toString());
List<Visits> list = visitsRepository.findAllVisits(localDate.minusDays(6).toString(),localDate.plusDays(1).toString());
@ -77,7 +80,7 @@ public class VisitsServiceImpl implements VisitsService {
@Override
public Object getChartData() {
Map map = new HashMap();
Map<String,Object> map = new HashMap<>();
LocalDate localDate = LocalDate.now();
List<Visits> list = visitsRepository.findAllVisits(localDate.minusDays(6).toString(),localDate.plusDays(1).toString());
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.repository.QuartzJobRepository;
import me.zhengjie.modules.quartz.utils.QuartzManage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@ -17,24 +16,24 @@ import java.util.List;
@Component
public class JobRunner implements ApplicationRunner {
@Autowired
private QuartzJobRepository quartzJobRepository;
private final QuartzJobRepository quartzJobRepository;
@Autowired
private QuartzManage quartzManage;
private final QuartzManage quartzManage;
public JobRunner(QuartzJobRepository quartzJobRepository, QuartzManage quartzManage) {
this.quartzJobRepository = quartzJobRepository;
this.quartzManage = quartzManage;
}
/**
*
* @param applicationArguments
* @throws Exception
* @param applicationArguments /
*/
@Override
public void run(ApplicationArguments applicationArguments){
System.out.println("--------------------注入定时任务---------------------");
List<QuartzJob> quartzJobs = quartzJobRepository.findByIsPauseIsFalse();
quartzJobs.forEach(quartzJob -> {
quartzManage.addJob(quartzJob);
});
quartzJobs.forEach(quartzManage::addJob);
System.out.println("--------------------定时任务注入完成---------------------");
}
}

View File

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

View File

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

View File

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

View File

@ -9,11 +9,11 @@ import java.util.List;
* @author Zheng Jie
* @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();
}

View File

@ -8,6 +8,6 @@ import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
* @author Zheng Jie
* @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;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.aop.log.Log;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.quartz.domain.QuartzJob;
import me.zhengjie.modules.quartz.service.QuartzJobService;
import me.zhengjie.modules.quartz.service.dto.JobQueryCriteria;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
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.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author Zheng Jie
* @date 2019-01-07
*/
@Slf4j
@RestController
@RequestMapping("/api")
@Api(tags = "系统:定时任务管理")
@RequestMapping("/api/jobs")
public class QuartzJobController {
private static final String ENTITY_NAME = "quartzJob";
@Autowired
private QuartzJobService quartzJobService;
private final QuartzJobService quartzJobService;
@Log("查询定时任务")
@GetMapping(value = "/jobs")
@PreAuthorize("hasAnyRole('ADMIN','JOB_ALL','JOB_SELECT')")
public ResponseEntity getJobs(JobQueryCriteria criteria, Pageable pageable){
return new ResponseEntity(quartzJobService.queryAll(criteria,pageable), HttpStatus.OK);
public QuartzJobController(QuartzJobService quartzJobService) {
this.quartzJobService = quartzJobService;
}
@GetMapping(value = "/jobLogs")
@PreAuthorize("hasAnyRole('ADMIN','JOB_ALL','JOB_SELECT')")
@Log("查询定时任务")
@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){
return new ResponseEntity(quartzJobService.queryAllLog(criteria,pageable), HttpStatus.OK);
return new ResponseEntity<>(quartzJobService.queryAllLog(criteria,pageable), HttpStatus.OK);
}
@Log("新增定时任务")
@PostMapping(value = "/jobs")
@PreAuthorize("hasAnyRole('ADMIN','JOB_ALL','JOB_CREATE')")
@ApiOperation("新增定时任务")
@PostMapping
@PreAuthorize("@el.check('timing:add')")
public ResponseEntity create(@Validated @RequestBody QuartzJob resources){
if (resources.getId() != null) {
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("修改定时任务")
@PutMapping(value = "/jobs")
@PreAuthorize("hasAnyRole('ADMIN','JOB_ALL','JOB_EDIT')")
@ApiOperation("修改定时任务")
@PutMapping
@PreAuthorize("@el.check('timing:edit')")
public ResponseEntity update(@Validated(QuartzJob.Update.class) @RequestBody QuartzJob resources){
quartzJobService.update(resources);
return new ResponseEntity(HttpStatus.NO_CONTENT);
}
@Log("更改定时任务状态")
@PutMapping(value = "/jobs/{id}")
@PreAuthorize("hasAnyRole('ADMIN','JOB_ALL','JOB_EDIT')")
@ApiOperation("更改定时任务状态")
@PutMapping(value = "/{id}")
@PreAuthorize("@el.check('timing:edit')")
public ResponseEntity updateIsPause(@PathVariable Long id){
quartzJobService.updateIsPause(quartzJobService.findById(id));
return new ResponseEntity(HttpStatus.NO_CONTENT);
}
@Log("执行定时任务")
@PutMapping(value = "/jobs/exec/{id}")
@PreAuthorize("hasAnyRole('ADMIN','JOB_ALL','JOB_EDIT')")
@ApiOperation("执行定时任务")
@PutMapping(value = "/exec/{id}")
@PreAuthorize("@el.check('timing:edit')")
public ResponseEntity execution(@PathVariable Long id){
quartzJobService.execution(quartzJobService.findById(id));
return new ResponseEntity(HttpStatus.NO_CONTENT);
}
@Log("删除定时任务")
@DeleteMapping(value = "/jobs/{id}")
@PreAuthorize("hasAnyRole('ADMIN','JOB_ALL','JOB_DELETE')")
@ApiOperation("删除定时任务")
@DeleteMapping(value = "/{id}")
@PreAuthorize("@el.check('timing:del')")
public ResponseEntity delete(@PathVariable Long id){
quartzJobService.delete(quartzJobService.findById(id));
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.QuartzLog;
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 javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/**
* @author Zheng Jie
* @date 2019-01-07
*/
@CacheConfig(cacheNames = "quartzJob")
public interface QuartzJobService {
/**
* queryAll quartzJob
* @param criteria
* @param pageable
* @return
*/
@Cacheable
Object queryAll(JobQueryCriteria criteria, Pageable pageable);
/**
* queryAll quartzLog
* @param criteria
* @param pageable
* @return
*/
List<QuartzJob> queryAll(JobQueryCriteria criteria);
Object queryAllLog(JobQueryCriteria criteria, Pageable pageable);
/**
* create
* @param resources
* @return
*/
@CacheEvict(allEntries = true)
List<QuartzLog> queryAllLog(JobQueryCriteria criteria);
QuartzJob create(QuartzJob resources);
/**
* update
* @param resources
* @return
*/
@CacheEvict(allEntries = true)
void update(QuartzJob resources);
/**
* del
* @param quartzJob
*/
@CacheEvict(allEntries = true)
void delete(QuartzJob quartzJob);
/**
* findById
* @param id
* @return
*/
@Cacheable(key = "#p0")
QuartzJob findById(Long id);
/**
*
* @param quartzJob
* @param quartzJob /
*/
@CacheEvict(allEntries = true)
void updateIsPause(QuartzJob quartzJob);
/**
*
* @param quartzJob
* @param 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 me.zhengjie.annotation.Query;
import java.sql.Timestamp;
/**
* @author Zheng Jie
* @date 2019-6-4 10:33:02
@ -15,4 +17,10 @@ public class JobQueryCriteria {
@Query
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.modules.quartz.domain.QuartzJob;
import me.zhengjie.modules.quartz.domain.QuartzLog;
import me.zhengjie.modules.quartz.repository.QuartzJobRepository;
import me.zhengjie.modules.quartz.repository.QuartzLogRepository;
import me.zhengjie.modules.quartz.service.QuartzJobService;
import me.zhengjie.modules.quartz.service.dto.JobQueryCriteria;
import me.zhengjie.modules.quartz.utils.QuartzManage;
import me.zhengjie.utils.FileUtil;
import me.zhengjie.utils.PageUtil;
import me.zhengjie.utils.QueryHelp;
import me.zhengjie.utils.ValidationUtil;
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.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
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
* @date 2019-01-07
*/
@Service(value = "quartzJobService")
@CacheConfig(cacheNames = "quartzJob")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class QuartzJobServiceImpl implements QuartzJobService {
@Autowired
private QuartzJobRepository quartzJobRepository;
private final QuartzJobRepository quartzJobRepository;
@Autowired
private QuartzLogRepository quartzLogRepository;
private final QuartzLogRepository quartzLogRepository;
@Autowired
private QuartzManage quartzManage;
private final QuartzManage quartzManage;
public QuartzJobServiceImpl(QuartzJobRepository quartzJobRepository, QuartzLogRepository quartzLogRepository, QuartzManage quartzManage) {
this.quartzJobRepository = quartzJobRepository;
this.quartzLogRepository = quartzLogRepository;
this.quartzManage = quartzManage;
}
@Override
@Cacheable
public Object queryAll(JobQueryCriteria criteria, Pageable 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
public QuartzJob findById(Long id) {
Optional<QuartzJob> quartzJob = quartzJobRepository.findById(id);
ValidationUtil.isNull(quartzJob,"QuartzJob","id",id);
return quartzJob.get();
public List<QuartzJob> queryAll(JobQueryCriteria criteria) {
return quartzJobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder));
}
@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)
public QuartzJob create(QuartzJob resources) {
if (!CronExpression.isValidExpression(resources.getCronExpression())){
@ -64,6 +91,7 @@ public class QuartzJobServiceImpl implements QuartzJobService {
}
@Override
@CacheEvict(allEntries = true)
@Transactional(rollbackFor = Exception.class)
public void update(QuartzJob resources) {
if(resources.getId().equals(1L)){
@ -77,6 +105,7 @@ public class QuartzJobServiceImpl implements QuartzJobService {
}
@Override
@CacheEvict(allEntries = true)
public void updateIsPause(QuartzJob quartzJob) {
if(quartzJob.getId().equals(1L)){
throw new BadRequestException("该任务不可操作");
@ -100,6 +129,7 @@ public class QuartzJobServiceImpl implements QuartzJobService {
}
@Override
@CacheEvict(allEntries = true)
@Transactional(rollbackFor = Exception.class)
public void delete(QuartzJob quartzJob) {
if(quartzJob.getId().equals(1L)){
@ -108,4 +138,41 @@ public class QuartzJobServiceImpl implements QuartzJobService {
quartzManage.deleteJob(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;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.exception.BadRequestException;
import org.springframework.stereotype.Component;
/**

View File

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

View File

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

View File

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

View File

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

View File

@ -1,13 +1,17 @@
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.JwtAuthorizationTokenFilter;
import me.zhengjie.modules.security.service.JwtUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.password.PasswordEncoder;
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
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
private final JwtAuthenticationEntryPoint unauthorizedHandler;
@Autowired
private JwtUserDetailsService jwtUserDetailsService;
private final JwtUserDetailsService jwtUserDetailsService;
/**
* JWT
*/
@Autowired
JwtAuthorizationTokenFilter authenticationTokenFilter;
private final ApplicationContext applicationContext;
// 自定义基于JWT的安全过滤器
private final JwtAuthorizationTokenFilter authenticationTokenFilter;
@Value("${jwt.header}")
private String tokenHeader;
@Value("${jwt.auth.path}")
private String loginPath;
public SecurityConfig(JwtAuthenticationEntryPoint unauthorizedHandler, JwtUserDetailsService jwtUserDetailsService, JwtAuthorizationTokenFilter authenticationTokenFilter, ApplicationContext applicationContext) {
this.unauthorizedHandler = unauthorizedHandler;
this.jwtUserDetailsService = jwtUserDetailsService;
this.authenticationTokenFilter = authenticationTokenFilter;
this.applicationContext = applicationContext;
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
@ -69,18 +81,26 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
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
// 禁用 CSRF
.csrf().disable()
// 授权异常
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
// 不创建会话
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
// 过滤请求
.authorizeRequests()
.antMatchers(
@ -90,35 +110,24 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
"/**/*.css",
"/**/*.js"
).anonymous()
.antMatchers( HttpMethod.POST,"/auth/"+loginPath).anonymous()
.antMatchers("/auth/vCode").anonymous()
// 支付宝回调
.antMatchers("/api/aliPay/return").anonymous()
.antMatchers("/api/aliPay/notify").anonymous()
// swagger start
.antMatchers("/swagger-ui.html").anonymous()
.antMatchers("/swagger-resources/**").anonymous()
.antMatchers("/webjars/**").anonymous()
.antMatchers("/*/api-docs").anonymous()
.antMatchers("/swagger-ui.html").permitAll()
.antMatchers("/swagger-resources/**").permitAll()
.antMatchers("/webjars/**").permitAll()
.antMatchers("/*/api-docs").permitAll()
// swagger end
// 接口限流测试
.antMatchers("/test/**").anonymous()
// 文件
.antMatchers("/avatar/**").anonymous()
.antMatchers("/file/**").anonymous()
.antMatchers("/avatar/**").permitAll()
.antMatchers("/file/**").permitAll()
// 放行OPTIONS请求
.antMatchers(HttpMethod.OPTIONS, "/**").anonymous()
.antMatchers("/druid/**").anonymous()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/druid/**").permitAll()
// 自定义匿名访问所有url放行 允许 匿名和带权限以及登录用户访问
.antMatchers(anonymousUrls.toArray(new String[0])).permitAll()
// 所有请求都需要认证
.anyRequest().authenticated()
// 防止iframe 造成跨域
.and().headers().frameOptions().disable();
httpSecurity
.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
}

View File

@ -1,31 +1,32 @@
package me.zhengjie.modules.security.rest;
import cn.hutool.core.codec.Base64;
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 me.zhengjie.annotation.AnonymousAccess;
import me.zhengjie.aop.log.Log;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.monitor.service.RedisService;
import me.zhengjie.modules.security.security.AuthenticationInfo;
import me.zhengjie.modules.security.security.AuthorizationUser;
import me.zhengjie.modules.security.security.AuthInfo;
import me.zhengjie.modules.security.security.AuthUser;
import me.zhengjie.modules.security.security.ImgResult;
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.modules.security.utils.JwtTokenUtil;
import me.zhengjie.utils.SecurityUtils;
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.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
/**
* @author Zheng Jie
@ -34,30 +35,33 @@ import java.io.IOException;
*/
@Slf4j
@RestController
@RequestMapping("auth")
@RequestMapping("/auth")
@Api(tags = "系统:系统授权接口")
public class AuthenticationController {
@Value("${jwt.header}")
private String tokenHeader;
@Value("${jwt.codeKey}")
private String codeKey;
@Autowired
private JwtTokenUtil jwtTokenUtil;
private final JwtTokenUtil jwtTokenUtil;
@Autowired
private RedisService redisService;
private final RedisService redisService;
@Autowired
@Qualifier("jwtUserDetailsService")
private UserDetailsService userDetailsService;
private final 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("用户登录")
@PostMapping(value = "${jwt.auth.path}")
public ResponseEntity login(@Validated @RequestBody AuthorizationUser authorizationUser){
@ApiOperation("登录授权")
@AnonymousAccess
@PostMapping(value = "/login")
public ResponseEntity login(@Validated @RequestBody AuthUser authorizationUser, HttpServletRequest request){
// 查询验证码
String code = redisService.getCodeVal(authorizationUser.getUuid());
@ -78,45 +82,41 @@ public class AuthenticationController {
if(!jwtUser.isEnabled()){
throw new AccountExpiredException("账号已停用,请联系管理员");
}
// 生成令牌
final String token = jwtTokenUtil.generateToken(jwtUser);
// 保存在线信息
onlineUserService.save(jwtUser, token, request);
// 返回 token
return ResponseEntity.ok(new AuthenticationInfo(token,jwtUser));
return ResponseEntity.ok(new AuthInfo(token,jwtUser));
}
/**
*
* @return
*/
@GetMapping(value = "${jwt.auth.account}")
@ApiOperation("获取用户信息")
@GetMapping(value = "/info")
public ResponseEntity getUserInfo(){
JwtUser jwtUser = (JwtUser)userDetailsService.loadUserByUsername(SecurityUtils.getUsername());
return ResponseEntity.ok(jwtUser);
}
/**
*
*/
@GetMapping(value = "vCode")
public ImgResult getCode(HttpServletResponse response) throws IOException {
@ApiOperation("获取验证码")
@AnonymousAccess
@GetMapping(value = "/code")
public ImgResult getCode(){
// 算术类型 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);
}
//生成随机字串
String verifyCode = VerifyCodeUtils.generateVerifyCode(4);
String uuid = IdUtil.simpleUUID();
redisService.saveCode(uuid,verifyCode);
// 生成图片
int w = 111, h = 36;
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();
}
@ApiOperation("退出登录")
@AnonymousAccess
@DeleteMapping(value = "/logout")
public ResponseEntity logout(HttpServletRequest request){
onlineUserService.logout(jwtTokenUtil.getToken(request));
return new ResponseEntity(HttpStatus.OK);
}
}

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;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.io.Serializable;
/**
* @author Zheng Jie
* @date 2018-11-23
* token
*/
@Getter
@AllArgsConstructor
public class AuthenticationInfo implements Serializable {
private final String token;
private final JwtUser user;
}
package me.zhengjie.modules.security.security;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.io.Serializable;
/**
* @author Zheng Jie
* @date 2018-11-23
* token
*/
@Getter
@AllArgsConstructor
public class AuthInfo implements Serializable {
private final String token;
private final JwtUser user;
}

View File

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

View File

@ -18,9 +18,7 @@ public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Se
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException {
/**
* 访REST401
*/
// 当用户尝试访问安全的REST资源而不提供任何凭据时将调用此方法发送401 响应
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 lombok.extern.slf4j.Slf4j;
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.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
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.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
@ -22,38 +23,33 @@ import java.io.IOException;
@Component
public class JwtAuthorizationTokenFilter extends OncePerRequestFilter {
@Value("${jwt.online}")
private String onlineKey;
private final UserDetailsService userDetailsService;
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.jwtTokenUtil = jwtTokenUtil;
this.tokenHeader = tokenHeader;
this.redisTemplate = redisTemplate;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
final String requestHeader = request.getHeader(this.tokenHeader);
String username = null;
String authToken = null;
if (requestHeader != null && requestHeader.startsWith("Bearer ")) {
authToken = requestHeader.substring(7);
try {
username = jwtTokenUtil.getUsernameFromToken(authToken);
} catch (ExpiredJwtException e) {
log.error(e.getMessage());
}
String authToken = jwtTokenUtil.getToken(request);
OnlineUser onlineUser = null;
try {
onlineUser = (OnlineUser)redisTemplate.opsForValue().get(onlineKey + authToken);
} catch (ExpiredJwtException e) {
log.error(e.getMessage());
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
if (onlineUser != null && SecurityContextHolder.getContext().getAuthentication() == null) {
// 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 ;)
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
// the database compellingly. Again it's up to you ;)
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;
import me.zhengjie.modules.system.domain.Menu;
import me.zhengjie.modules.system.domain.Role;
import me.zhengjie.modules.system.repository.RoleRepository;
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.Cacheable;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@ -17,13 +19,16 @@ import java.util.stream.Collectors;
@CacheConfig(cacheNames = "role")
public class JwtPermissionService {
@Autowired
private RoleRepository roleRepository;
private final RoleRepository roleRepository;
public JwtPermissionService(RoleRepository roleRepository) {
this.roleRepository = roleRepository;
}
/**
* key UserServiceImpl update
* @param user
* @return
* @param user
* @return Collection
*/
@Cacheable(key = "'loadPermissionByUser:' + #p0.username")
public Collection<GrantedAuthority> mapToGrantedAuthorities(UserDTO user) {
@ -31,9 +36,13 @@ public class JwtPermissionService {
System.out.println("--------------------loadPermissionByUser:" + user.getUsername() + "---------------------");
Set<Role> roles = roleRepository.findByUsers_Id(user.getId());
return roles.stream().flatMap(role -> role.getPermissions().stream())
.map(permission -> new SimpleGrantedAuthority(permission.getName()))
Set<String> permissions = roles.stream().filter(role -> StringUtils.isNotBlank(role.getPermission())).map(Role::getPermission).collect(Collectors.toSet());
permissions.addAll(
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());
}
}

View File

@ -4,7 +4,6 @@ import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.security.security.JwtUser;
import me.zhengjie.modules.system.service.UserService;
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.UserDetailsService;
import org.springframework.stereotype.Service;
@ -20,11 +19,14 @@ import java.util.Optional;
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class JwtUserDetailsService implements UserDetailsService {
@Autowired
private UserService userService;
private final UserService userService;
@Autowired
private JwtPermissionService permissionService;
private final JwtPermissionService permissionService;
public JwtUserDetailsService(UserService userService, JwtPermissionService permissionService) {
this.userService = userService;
this.permissionService = permissionService;
}
@Override
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.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
@ -31,15 +33,15 @@ public class JwtTokenUtil implements Serializable {
return getClaimFromToken(token, Claims::getSubject);
}
public Date getIssuedAtDateFromToken(String token) {
private Date getIssuedAtDateFromToken(String token) {
return getClaimFromToken(token, Claims::getIssuedAt);
}
public Date getExpirationDateFromToken(String token) {
private Date getExpirationDateFromToken(String token) {
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);
return claimsResolver.apply(claims);
}
@ -103,6 +105,14 @@ public class JwtTokenUtil implements Serializable {
.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) {
JwtUser user = (JwtUser) userDetails;
final Date created = getIssuedAtDateFromToken(token);

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