Commit 7eba9641 authored by zhengjie's avatar zhengjie
Browse files

去除实时控制台功能,查询方式修改成注解方式

parent e6c23f81
package me.zhengjie.aop.limit;
package me.zhengjie.annotation;
import me.zhengjie.aspect.LimitType;
......
......@@ -6,23 +6,32 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @描述 : 为生成{@link javax.persistence.criteria.Predicate }提供的注解
* @作者 : Dong ZhaoYang
* @日期 : 2017/08/07
* @时间 : 16:25
* @author jie
* @date 2019-6-4 13:52:30
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PredicateInfo {
public @interface Query {
/** Dong ZhaoYang 2017/8/7 基本对象的属性名 */
String propName() default "";
/** Dong ZhaoYang 2017/8/7 查询方式 */
QueryType queryType() default QueryType.BASIC;
Type type() default Type.EQUAL;
enum QueryType {
/** Dong ZhaoYang 2017/8/7 基本 */
BASIC
/**
* 连接查询的属性名,如User类中的dept
* @return
*/
String joinName() default "";
/**
* 默认左连接
* @return
*/
Join join() default Join.LEFT;
enum Type {
EQUAL
/** Dong ZhaoYang 2017/8/7 大于等于 */
, GREATER_THAN
/** Dong ZhaoYang 2017/8/7 小于等于 */
......@@ -35,6 +44,19 @@ public @interface PredicateInfo {
, RIGHT_LIKE
/** Dong ZhaoYang 2017/8/7 小于 */
, LESS_THAN_NQ
//** jie 2019/6/4 包含 */
, IN
}
/**
* @author jie
* 适用于简单连接查询,复杂的请自定义该注解,或者使用sql查询
*/
enum Join {
/** jie 2019-6-4 13:18:30 左连接 */
LEFT
/** jie 2019-6-4 13:18:30 右连接 */
, RIGHT
}
}
......
package me.zhengjie.aspect;
import com.google.common.collect.ImmutableList;
import me.zhengjie.aop.limit.Limit;
import me.zhengjie.annotation.Limit;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.utils.RequestHolder;
import me.zhengjie.utils.StringUtils;
......@@ -28,7 +28,7 @@ public class LimitAspect {
private static final Logger logger = LoggerFactory.getLogger(LimitAspect.class);
@Pointcut("@annotation(me.zhengjie.aop.limit.Limit)")
@Pointcut("@annotation(me.zhengjie.annotation.Limit)")
public void pointcut() {
}
......
......@@ -121,7 +121,6 @@ public class RedisConfig extends CachingConfigurerSupport {
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
// 由于参数可能不同, hashCode肯定不一样, 缓存的key也需要不一样
sb.append(JSON.toJSONString(obj).hashCode());
}
return sb.toString();
......
package me.zhengjie.utils;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import me.zhengjie.annotation.PredicateInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
/**
* @描述 : JavaBean 帮助
* @作者 : Dong ZhaoYang
* @日期 : 2016/12/01
* @时间 : 09:54
*/
@SuppressWarnings("unused")
public class BeanHelp {
private final static ObjectMapper objectMapper = new ObjectMapper();
private static final Logger logger = LoggerFactory.getLogger(BeanHelp.class);
static {
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
/**
* @param <C> 泛型
* @param object 对象
* @return 属性集合
* @描述 : 获取对象的JSON属性Map对象集合
* @作者 : Dong ZhaoYang
* @日期 : 2017/02/24
* @时间 : 11:12
*/
@SuppressWarnings("unchecked")
public static <C> Map<String, C> getBeanJSONPropertyMap(Object object, Class<C> clazz) {
Map<String, C> result = new LinkedHashMap<>();
try {
JavaType javaType = objectMapper.getTypeFactory()
.constructParametrizedType(Map.class, Map.class, String.class, clazz);
result = objectMapper.readValue(objectMapper.writeValueAsString(object), javaType);
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
return result;
}
/**
* @param <C> 泛型
* @param propName 属性名
* @param object 对象
* @param clazz 返回类型
* @return 对象的属性名
* @描述 : 获取请求对象的JSON属性的Map集合
* @作者 : Dong ZhaoYang
* @日期 : 2017/03/20
* @时间 : 12:47
*/
@SuppressWarnings("unchecked")
private static <C> Map<String, C> getBeanJSONPropertyMap(String propName, Object object, Class<C> clazz) {
Map<String, C> result = new LinkedHashMap<>();
try {
Class<?> oClass = object.getClass();
Field[] fields = oClass.getDeclaredFields();
fieldLoop:
for (Field field : fields) {
String name = field.getName();
JsonIgnore ignore = oClass.getDeclaredField(name).getAnnotation(JsonIgnore.class);
if (ignore != null) {
continue;
}
JsonProperty property = oClass.getDeclaredField(name).getAnnotation(JsonProperty.class);
if (property != null) {
name = property.value();
}
name = propName == null ? name : propName + "." + name;
field.setAccessible(true);
Object prop = field.get(object);
if (prop == null) {
continue;
}
if (PropertyType.isBasicClazz(field.getType()) || prop instanceof Class
|| prop instanceof Collection) {
result.put(name, (C) prop);
} else if (prop instanceof Enum) {
Method[] methods = prop.getClass().getDeclaredMethods();
for (Method method : methods) {
JsonValue jsonValue = method.getAnnotation(JsonValue.class);
if (jsonValue != null) {
Object enumVal = method.invoke(prop);
result.putAll(getBeanJSONPropertyMap(name, enumVal, clazz));
continue fieldLoop;
}
}
} else {
result.putAll(getBeanJSONPropertyMap(name, prop, clazz));
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return result;
}
/**
* @param <T> 泛型
* @param json json字符串
* @param parentClass 最外层的父类
* @param childrenClasses 属性类
* @return 反序列化后的对象
* @描述 : 从JSON中获取对象
* @作者 : Dong ZhaoYang
* @日期 : 2017/02/24
* @时间 : 11:45
*/
public static <T> T getBeanFromJson(String json,
Class<?> parentClass, Class<?>... childrenClasses) {
JavaType javaType = objectMapper.getTypeFactory()
.constructParametrizedType(parentClass, parentClass, childrenClasses);
T o = null;
try {
o = objectMapper.readValue(json, javaType);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return o;
}
/**
* @param clazz 需要实例化的字节码对象
* @param <T> 对象类型
* @return 对象实例
* @描述 : 获取clazz的初始化对象,所有支持的属性 {@link PropertyType}将设为
* 对应的非null默认值
* @作者 : Dong ZhaoYang
* @日期 : 2017/3/6
* @时间 : 15:07
*/
public static <T> T getNoEmptyPropertyInstance(Class<T> clazz) {
T instance = null;
try {
instance = clazz.newInstance();
PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(clazz).getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
Method writeMethod = propertyDescriptor.getWriteMethod();
if (writeMethod != null) {
writeMethod.invoke(instance,
PropertyType.fromClazz(propertyDescriptor.getPropertyType()).getDefaultValue());
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return instance;
}
/**
* @param origin 原始对象数据
* @param update 更新对象数据
* @param <T> 对象类型
* @return 待更新的对象
* @描述 : 如果update的属性不为空,则更新对象origin的属性
* @作者 : Dong ZhaoYang
* @日期 : 2017/8/7
* @时间 : 15:48
*/
@SuppressWarnings("unchecked")
public static <T> T updateEntityExceptEmptyProps(T origin, T update) {
T instance = null;
try {
Class<T> clazz = (Class<T>) origin.getClass();
instance = clazz.newInstance();
PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(clazz).getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
Method readMethod = propertyDescriptor.getReadMethod();
Method writeMethod = propertyDescriptor.getWriteMethod();
if (readMethod != null && writeMethod != null) {
Object originProperty = readMethod.invoke(origin);
Object updateProperty = readMethod.invoke(update);
writeMethod.invoke(instance, NullHelp.isNull(updateProperty) ? originProperty : updateProperty);
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return instance;
}
/**
* @描述 : 转换为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()]));
}
try {
List<Field> fields = getAllFields(query.getClass(), new ArrayList<>());
for (Field field : fields) {
boolean accessible = field.isAccessible();
field.setAccessible(true);
PredicateInfo predicateInfo = field.getAnnotation(PredicateInfo.class);
if (predicateInfo != null) {
String propName = predicateInfo.propName();
String attributeName = isBlank(propName) ? field.getName() : propName;
Class<?> fieldType = field.getType();
Object val = field.get(query);
if (NullHelp.isNull(val)) {
continue;
}
switch (predicateInfo.queryType()) {
case BASIC:
list.add(cb.equal(root.get(attributeName).as(fieldType), val));
break;
case GREATER_THAN:
list.add(cb.greaterThanOrEqualTo(root.get(attributeName)
.as((Class<? extends Comparable>) fieldType), (Comparable) val));
break;
case LESS_THAN:
list.add(cb.lessThanOrEqualTo(root.get(attributeName)
.as((Class<? extends Comparable>) fieldType), (Comparable) val));
break;
case LESS_THAN_NQ:
list.add(cb.lessThan(root.get(attributeName)
.as((Class<? extends Comparable>) fieldType), (Comparable) val));
break;
case INNER_LIKE:
list.add(cb.like(root.get(attributeName)
.as(String.class), "%" + val.toString() + "%"));
break;
case LEFT_LIKE:
list.add(cb.like(root.get(attributeName)
.as(String.class), "%" + val.toString()));
break;
case RIGHT_LIKE:
list.add(cb.like(root.get(attributeName)
.as(String.class), val.toString() + "%"));
break;
}
}
field.setAccessible(accessible);
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return cb.and(list.toArray(new Predicate[list.size()]));
}
private static List<Field> getAllFields(Class clazz, List<Field> fields) {
if (clazz != null) {
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
getAllFields(clazz.getSuperclass(), fields);
}
return fields;
}
/**
* @param propName 属性名
* @param object 目标实例对象
* @param <T> 对象类型
* @return 属性值
* @描述 : 获取object对象的propName的属性值
* @作者 : Dong ZhaoYang
* @日期 : 2017/3/6
* @时间 : 15:08
*/
public static <T> Object getProperty(String propName, T object) {
Object result = null;
try {
Method readMethod = new PropertyDescriptor(propName, object.getClass()).getReadMethod();
if (readMethod != null) {
result = readMethod.invoke(object);
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return result;
}
/**
* @描述 : check 属性是否为空,有一个为空则返回false
* @作者 : lww
* @日期 : 2017/3/23
* @时间 : 16:14
*/
public static <T> boolean checkProperties(T object) {
T instance = null;
try {
PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(object.getClass()).getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
Method readMethod = propertyDescriptor.getReadMethod();
Object result = readMethod.invoke(object);
if (result == null) {
return false;
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return true;
}
/**
* @param object 目标实例对象
* @param <T> 对象类型
* @param <C> 属性类型
* @return 属性值
* @描述 : 获取object对象的propertyClazz的属性值
* @作者 : Dong ZhaoYang
* @日期 : 2017/3/6
* @时间 : 15:08
*/
@SuppressWarnings("unchecked")
public static <T, C> C getProperty(T object, Class<C> propertyClazz) {
C result = null;
try {
PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(object.getClass()).getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
if (propertyDescriptor.getPropertyType().equals(propertyClazz)) {
Method readMethod = propertyDescriptor.getReadMethod();
if (readMethod != null) {
result = (C) readMethod.invoke(object);
}
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return result;
}
/**
* @param clazz 拥有将获取属性的类
* @param propertyClazz 属性的类
* @return 属性的名称
* @描述 : 获取属性名
* @作者 : Dong ZhaoYang
* @日期 : 2017/03/14
* @时间 : 13:33
*/
public static String getPropertyName(Class clazz, Class propertyClazz) {
String result = null;
try {
PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(clazz).getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
if (propertyDescriptor.getPropertyType().equals(propertyClazz)) {
result = propertyDescriptor.getName();
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return result;
}
/**
* @描述 : Bean属性的字节码类型及其对应的默认值
* @作者 : Dong ZhaoYang
* @日期 : 2017/3/6
* @时间 : 15:08
*/
public enum PropertyType {
BOX_BOOLEAN(Boolean.class, Boolean.FALSE),
BOX_BYTE(Byte.class, 0),
BOX_SHORT(Short.class, 0),
BOX_CHARACTER(Character.class, '\u0000'),
BOX_INTEGER(Integer.class, 0),
BOX_LONG(Long.class, 0L),
BOX_FLOAT(Float.class, 0.00F),
BOX_DOUBLE(Double.class, 0.00D),
STRING(String.class, ""),
BIG_DECIMAL(BigDecimal.class, BigDecimal.ZERO),
BIG_INTEGER(BigInteger.class, BigInteger.ZERO),
DATE(Date.class, new Date()),
NULL(PropertyType.class, null);
private Class clazz;
private Object defaultValue;
PropertyType(Class clazz, Object defaultValue) {
this.clazz = clazz;
this.defaultValue = defaultValue;
}
public static boolean isBoxPrimitive(Class clazz) {
switch (clazz.getName()) {
case "java.lang.Boolean":
case "java.lang.Byte":
case "java.lang.Short":
case "java.lang.Character":
case "java.lang.Integer":
case "java.lang.Long":
case "java.lang.Float":
case "java.lang.Double":
case "java.lang.String":
return true;
default:
return false;
}
}
public static boolean isBasicClazz(Class clazz) {
switch (clazz.getName()) {
case "java.lang.Boolean":
case "java.lang.Byte":
case "java.lang.Short":
case "java.lang.Character":
case "java.lang.Integer":
case "java.lang.Long":
case "java.lang.Float":
case "java.lang.Double":
case "java.lang.String":
case "java.math.BigDecimal":
case "java.math.BigInteger":
case "java.util.Date":
return true;
default:
return false;
}
}
public static PropertyType fromClazz(Class clazz) {
switch (clazz.getName()) {
case "java.lang.Boolean":
return BOX_BOOLEAN;
case "java.lang.Byte":
return BOX_BYTE;
case "java.lang.Short":
return BOX_SHORT;
case "java.lang.Character":
return BOX_CHARACTER;
case "java.lang.Integer":
return BOX_INTEGER;
case "java.lang.Long":
return BOX_LONG;
case "java.lang.Float":
return BOX_FLOAT;
case "java.lang.Double":
return BOX_DOUBLE;
case "java.lang.String":
return STRING;
case "java.math.BigDecimal":
return BIG_DECIMAL;
case "java.math.BigInteger":
return BIG_INTEGER;
case "java.util.Date":
return DATE;
default:
return NULL;
}
}
public Class getClazz() {
return clazz;
}
public Object getDefaultValue() {
return defaultValue;
}
@Override
public String toString() {
return "PropertyType{" +
"clazz=" + clazz +
", defaultValue=" + defaultValue +
"} " + super.toString();
}
}
public static List<Field> getParentField(Class pc) {
List<Field> list = null;
while (pc != null) {
if (list == null) {
list = new ArrayList<>();
}
list.addAll(Arrays.asList(pc.getDeclaredFields()));
pc = pc.getSuperclass();
}
return list;
}
public static List<Field> getParentField(Object o) {
List<Field> list = null;
Class pc = o.getClass();
return BeanHelp.getParentField(pc);
}
public 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) {
return false;
}
}
return true;
}
}
package me.zhengjie.utils;
import java.util.Collection;
/**
* @描述 : 用于空对象处理
* @作者 : Dong ZhaoYang
* @日期 : 2017/01/19
* @时间 : 09:52
*/
public class NullHelp {
public static boolean isNull(Object obj) {
return obj == null ||
(obj instanceof String && isNullStr((String) obj)) ||
(obj instanceof Collection && ((Collection) obj).isEmpty());
}
public static boolean isNullStr(String str) {
str = str.trim();
return str.isEmpty()/* || str.equalsIgnoreCase("null")
|| str.equalsIgnoreCase("undefined")*/;
}
public static void check(Object... obj) throws Exception {
if (obj == null) {
throw new RuntimeException("数组参数不能为空");
}
for (int i = 0; i < obj.length; i++) {
Object o = obj[i];
if (o == null) {
throw new RuntimeException("obj[" + i + "]不能为空");
}
}
}
}
package me.zhengjie.utils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.annotation.Query;
import javax.persistence.criteria.*;
import java.lang.reflect.Field;
import java.util.*;
/**
* @author jie
* @date 2019-6-4 14:59:48
*/
@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()]));
}
try {
List<Field> fields = getAllFields(query.getClass(), new ArrayList<>());
for (Field field : fields) {
boolean accessible = field.isAccessible();
field.setAccessible(true);
Query q = field.getAnnotation(Query.class);
if (q != null) {
String propName = q.propName();
String joinName = q.joinName();
String attributeName = isBlank(propName) ? field.getName() : propName;
Class<?> fieldType = field.getType();
Object val = field.get(query);
if (ObjectUtil.isNull(val)) {
continue;
}
Join join = null;
if (ObjectUtil.isNotEmpty(joinName)) {
switch (q.join()) {
case LEFT:
join = root.join(joinName, JoinType.LEFT);
break;
case RIGHT:
join = root.join(joinName, JoinType.RIGHT);
break;
}
}
switch (q.type()) {
case EQUAL:
list.add(cb.equal(getExpression(attributeName,join,root)
.as((Class<? extends Comparable>) fieldType),val));
break;
case GREATER_THAN:
list.add(cb.greaterThanOrEqualTo(getExpression(attributeName,join,root)
.as((Class<? extends Comparable>) fieldType), (Comparable) val));
break;
case LESS_THAN:
list.add(cb.lessThanOrEqualTo(getExpression(attributeName,join,root)
.as((Class<? extends Comparable>) fieldType), (Comparable) val));
break;
case LESS_THAN_NQ:
list.add(cb.lessThan(getExpression(attributeName,join,root)
.as((Class<? extends Comparable>) fieldType), (Comparable) val));
break;
case INNER_LIKE:
list.add(cb.like(getExpression(attributeName,join,root)
.as(String.class), "%" + val.toString() + "%"));
break;
case LEFT_LIKE:
list.add(cb.like(getExpression(attributeName,join,root)
.as(String.class), "%" + val.toString()));
break;
case RIGHT_LIKE:
list.add(cb.like(getExpression(attributeName,join,root)
.as(String.class), val.toString() + "%"));
case IN:
if (CollUtil.isNotEmpty((Collection<Long>)val)) {
list.add(getExpression(attributeName,join,root).in((Collection<Long>) val));
}
break;
}
}
field.setAccessible(accessible);
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return cb.and(list.toArray(new Predicate[list.size()]));
}
private static <T, R> Expression<T> getExpression(String attributeName, Join join, Root<R> root) {
if (ObjectUtil.isNotEmpty(join)) {
return join.get(attributeName);
} else return root.get(attributeName);
}
public 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) {
return false;
}
}
return true;
}
private static List<Field> getAllFields(Class clazz, List<Field> fields) {
if (clazz != null) {
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
getAllFields(clazz.getSuperclass(), fields);
}
return fields;
}
}
package me.zhengjie.rest;
import me.zhengjie.domain.Log;
import me.zhengjie.service.LogService;
import me.zhengjie.service.query.LogQueryService;
import me.zhengjie.service.dto.LogQueryCriteria;
import me.zhengjie.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
......@@ -22,31 +21,28 @@ import org.springframework.web.bind.annotation.RestController;
@RequestMapping("api")
public class LogController {
@Autowired
private LogQueryService logQueryService;
@Autowired
private LogService logService;
@GetMapping(value = "/logs")
@PreAuthorize("hasAnyRole('ADMIN')")
public ResponseEntity getLogs(Log log, Pageable pageable){
log.setLogType("INFO");
return new ResponseEntity(logQueryService.queryAll(log,pageable), HttpStatus.OK);
public ResponseEntity getLogs(LogQueryCriteria criteria, Pageable pageable){
criteria.setLogType("INFO");
return new ResponseEntity(logService.queryAll(criteria,pageable), HttpStatus.OK);
}
@GetMapping(value = "/logs/user")
public ResponseEntity getUserLogs(Log log, Pageable pageable){
log.setLogType("INFO");
log.setUsername(SecurityUtils.getUsername());
return new ResponseEntity(logQueryService.queryAllByUser(log,pageable), HttpStatus.OK);
public ResponseEntity getUserLogs(LogQueryCriteria criteria, Pageable pageable){
criteria.setLogType("INFO");
criteria.setUsername(SecurityUtils.getUsername());
return new ResponseEntity(logService.queryAllByUser(criteria,pageable), HttpStatus.OK);
}
@GetMapping(value = "/logs/error")
@PreAuthorize("hasAnyRole('ADMIN')")
public ResponseEntity getErrorLogs(Log log, Pageable pageable){
log.setLogType("ERROR");
return new ResponseEntity(logQueryService.queryAll(log,pageable), HttpStatus.OK);
public ResponseEntity getErrorLogs(LogQueryCriteria criteria, Pageable pageable){
criteria.setLogType("ERROR");
return new ResponseEntity(logService.queryAll(criteria,pageable), HttpStatus.OK);
}
@GetMapping(value = "/logs/error/{id}")
......
package me.zhengjie.service;
import me.zhengjie.domain.Log;
import me.zhengjie.service.dto.LogQueryCriteria;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Async;
import javax.servlet.http.HttpServletRequest;
/**
* @author 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
*/
Object queryAllByUser(LogQueryCriteria criteria, Pageable pageable);
/**
* 新增日志
* @param joinPoint
......
package me.zhengjie.service.dto;
import lombok.Data;
import me.zhengjie.annotation.Query;
/**
* 日志查询类
* @author jie
* @date 2019-6-4 09:23:07
*/
@Data
public class LogQueryCriteria {
@Query(type = Query.Type.INNER_LIKE)
private String username;
@Query
private String logType;
}
......@@ -5,9 +5,16 @@ import cn.hutool.json.JSONObject;
import me.zhengjie.domain.Log;
import me.zhengjie.repository.LogRepository;
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.PageUtil;
import me.zhengjie.utils.QueryHelp;
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;
......@@ -24,8 +31,29 @@ public class LogServiceImpl implements LogService {
@Autowired
private LogRepository logRepository;
@Autowired
private LogErrorMapper logErrorMapper;
@Autowired
private LogSmallMapper logSmallMapper;
private final String LOGINPATH = "login";
@Override
public Object queryAll(LogQueryCriteria criteria, Pageable pageable){
Page<Log> page = logRepository.findAll(((root, criteriaQuery, cb) -> QueryHelp.getPredicate(root, criteria, cb)),pageable);
if (criteria.getLogType().equals("ERROR")) {
return PageUtil.toPage(page.map(logErrorMapper::toDto));
}
return page;
}
@Override
public Object queryAllByUser(LogQueryCriteria criteria, Pageable pageable) {
Page<Log> page = logRepository.findAll(((root, criteriaQuery, cb) -> QueryHelp.getPredicate(root, criteria, cb)),pageable);
return PageUtil.toPage(page.map(logSmallMapper::toDto));
}
@Override
@Transactional(rollbackFor = Exception.class)
public void save(String username, String ip, ProceedingJoinPoint joinPoint, Log log){
......
package me.zhengjie.service.query;
import me.zhengjie.domain.Log;
import me.zhengjie.repository.LogRepository;
import me.zhengjie.service.mapper.LogErrorMapper;
import me.zhengjie.service.mapper.LogSmallMapper;
import me.zhengjie.utils.PageUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author jie
* @date 2018-11-24
*/
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class LogQueryService {
@Autowired
private LogRepository logRepository;
@Autowired
private LogErrorMapper logErrorMapper;
@Autowired
private LogSmallMapper logSmallMapper;
public Object queryAll(Log log, Pageable pageable){
Page<Log> page = logRepository.findAll(new Spec(log),pageable);
if (log.getLogType().equals("ERROR")) {
return PageUtil.toPage(page.map(logErrorMapper::toDto));
}
return page;
}
public Object queryAllByUser(Log log, Pageable pageable) {
Page<Log> page = logRepository.findAll(new Spec(log),pageable);
return PageUtil.toPage(page.map(logSmallMapper::toDto));
}
class Spec implements Specification<Log> {
private Log log;
public Spec(Log log){
this.log = log;
}
@Override
public Predicate toPredicate(Root<Log> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
List<Predicate> list = new ArrayList<Predicate>();
if(!ObjectUtils.isEmpty(log.getUsername())){
list.add(cb.like(root.get("username").as(String.class),"%"+log.getUsername()+"%"));
}
if (!ObjectUtils.isEmpty(log.getLogType())) {
list.add(cb.equal(root.get("logType").as(String.class), log.getLogType()));
}
Predicate[] p = new Predicate[list.size()];
return cb.and(list.toArray(p));
}
}
}
......@@ -42,12 +42,6 @@
<version>${jjwt.version}</version>
</dependency>
<!--websocket-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
......
......@@ -6,7 +6,6 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
/**
* @author jie
......@@ -15,7 +14,6 @@ import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBr
@EnableAsync
@SpringBootApplication
@EnableTransactionManagement
@EnableWebSocketMessageBroker
public class AppRun {
public static void main(String[] args) {
......
package me.zhengjie.modules.monitor.config;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.IThrowableProxy;
import ch.qos.logback.core.filter.Filter;
import ch.qos.logback.core.spi.FilterReply;
import me.zhengjie.modules.monitor.domain.LogMessage;
import java.text.DateFormat;
import java.util.Date;
/**
* 定义Logfilter拦截输出日志
* @author jie
* @reference https://cloud.tencent.com/developer/article/1096792
* @date 2018-12-24
*/
public class LogFilter extends Filter<ILoggingEvent>{
@Override
public FilterReply decide(ILoggingEvent event) {
LogMessage loggerMessage = new LogMessage(
event.getFormattedMessage(),
DateFormat.getDateTimeInstance().format(new Date(event.getTimeStamp())),
event.getThreadName(),
event.getLoggerName(),
event.getLevel().levelStr
);
LoggerQueue.getInstance().push(loggerMessage);
return FilterReply.ACCEPT;
}
}
\ No newline at end of file
package me.zhengjie.modules.monitor.config;
import me.zhengjie.modules.monitor.domain.LogMessage;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
/**
* 创建一个阻塞队列,作为日志系统输出的日志的一个临时载体
* @author https://cloud.tencent.com/developer/article/1096792
* @date 2018-12-24
*/
public class LoggerQueue {
/**
* 队列大小
*/
public static final int QUEUE_MAX_SIZE = 10000;
private static LoggerQueue alarmMessageQueue = new LoggerQueue();
/**
* 阻塞队列
*/
private BlockingQueue blockingQueue = new LinkedBlockingQueue<>(QUEUE_MAX_SIZE);
private LoggerQueue() {
}
public static LoggerQueue getInstance() {
return alarmMessageQueue;
}
/**
* 消息入队
* @param log
* @return
*/
public boolean push(LogMessage log) {
return this.blockingQueue.add(log);
}
/**
* 消息出队
*
* @return
*/
public LogMessage poll() {
LogMessage result = null;
try {
result = (LogMessage) this.blockingQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
return result;
}
}
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;
/**
* 初始化站点统计
* @author jie
*/
@Component
public class VisitsInitialization implements ApplicationRunner {
@Autowired
private VisitsService visitsService;
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("--------------- 初始化站点统计,如果存在今日统计则跳过 ---------------");
visitsService.save();
System.out.println("--------------- 初始化站点统计完成 ---------------");
}
}
package me.zhengjie.modules.monitor.config;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.modules.monitor.domain.LogMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
import javax.annotation.PostConstruct;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 配置WebSocket消息代理端点,即stomp服务端
* @author jie
* @reference https://cloud.tencent.com/developer/article/1096792
* @date 2018-12-24
*/
@Slf4j
@Configuration
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Autowired
private SimpMessagingTemplate messagingTemplate;
private ExecutorService executorService = Executors.newSingleThreadExecutor();
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/websocket")
.setAllowedOrigins("*")
.withSockJS();
}
/**
* 推送日志到/topic/pullLogger
*/
@PostConstruct
public void pushLogger(){
Runnable runnable=new Runnable() {
@Override
public void run() {
while (true) {
try {
LogMessage log = LoggerQueue.getInstance().poll();
if(log!=null){
// 格式化异常堆栈信息
if("ERROR".equals(log.getLevel()) && "me.zhengjie.common.exception.handler.GlobalExceptionHandler".equals(log.getClassName())){
log.setBody("<pre>"+log.getBody()+"</pre>");
}
if(log.getClassName().equals("jdbc.resultsettable")){
log.setBody("<br><pre>"+log.getBody()+"</pre>");
}
if(messagingTemplate!=null){
messagingTemplate.convertAndSend("/topic/logMsg",log);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
executorService.submit(runnable);
}
}
\ No newline at end of file
package me.zhengjie.modules.monitor.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* @author https://cloud.tencent.com/developer/article/1096792
* @date 2018-12-24
*/
@Data
@AllArgsConstructor
public class LogMessage {
private String body;
private String timestamp;
private String threadName;
private String className;
private String level;
}
package me.zhengjie.modules.monitor.rest;
import me.zhengjie.aop.limit.Limit;
import me.zhengjie.annotation.Limit;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment