package me.zhengjie.common.aop.log; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author jie * @date 2018-11-24 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Log { String description() default ""; }
package me.zhengjie.common.aop.log; import lombok.extern.slf4j.Slf4j; import me.zhengjie.common.exception.BadRequestException; import me.zhengjie.monitor.domain.Logging; import me.zhengjie.monitor.service.LoggingService; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; 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 java.io.PrintWriter; import java.io.StringWriter; /** * @author jie * @date 2018-11-24 */ @Component @Aspect @Slf4j public class LogAspect { @Autowired private LoggingService loggingService; private long currentTime = 0L; /** * 配置切入点 */ @Pointcut("@annotation(me.zhengjie.common.aop.log.Log)") public void logPointcut() { // 该方法无方法体,主要为了让同类中其他方法使用此切入点 } /** * 配置环绕通知,使用在方法logPointcut()上注册的切入点 * * @param joinPoint join point for advice */ @Around("logPointcut()") public Object logAround(ProceedingJoinPoint joinPoint){ Object result = null; currentTime = System.currentTimeMillis(); try { result = joinPoint.proceed(); } catch (Throwable e) { throw new BadRequestException(e.getMessage()); } Logging logging = new Logging("INFO",System.currentTimeMillis() - currentTime); loggingService.save(joinPoint, logging); return result; } /** * 配置异常通知 * * @param joinPoint join point for advice * @param e exception */ @AfterThrowing(pointcut = "logPointcut()", throwing = "e") public void logAfterThrowing(JoinPoint joinPoint, Throwable e) { Logging logging = new Logging("ERROR",System.currentTimeMillis() - currentTime); logging.setExceptionDetail(e.getMessage()); loggingService.save((ProceedingJoinPoint)joinPoint, logging); } }
package me.zhengjie.monitor.service; import me.zhengjie.monitor.domain.Logging; import org.aspectj.lang.ProceedingJoinPoint; import org.springframework.scheduling.annotation.Async; /** * @author jie * @date 2018-11-24 */ public interface LoggingService { /** * 新增日志 * @param joinPoint * @param logging */ @Async void save(ProceedingJoinPoint joinPoint, Logging logging); }
package me.zhengjie.monitor.service.impl; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import me.zhengjie.common.utils.IpUtil; import me.zhengjie.common.utils.RequestHolder; import me.zhengjie.core.security.AuthorizationUser; import me.zhengjie.core.utils.JwtTokenUtil; import me.zhengjie.monitor.domain.Logging; import me.zhengjie.monitor.repository.LoggingRepository; import me.zhengjie.monitor.service.LoggingService; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; /** * @author jie * @date 2018-11-24 */ @Service @Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class) public class LoggingServiceImpl implements LoggingService { @Autowired private LoggingRepository loggingRepository; @Value("${jwt.header}") private String tokenHeader; @Autowired private JwtTokenUtil jwtTokenUtil; private final String LOGINPATH = "authenticationLogin"; @Override @Transactional(rollbackFor = Exception.class) public void save(ProceedingJoinPoint joinPoint, Logging logging){ // 获取request HttpServletRequest request = RequestHolder.getHttpServletRequest(); MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); me.zhengjie.common.aop.log.Log log = method.getAnnotation(me.zhengjie.common.aop.log.Log.class); // 描述 if (log != null) { logging.setDescription(log.description()); } // 方法路径 String methodName = joinPoint.getTarget().getClass().getName()+"."+signature.getName()+"()"; String params = "{"; //参数值 Object[] argValues = joinPoint.getArgs(); //参数名称 String[] argNames = ((MethodSignature)joinPoint.getSignature()).getParameterNames(); // 用户名 String username = ""; if(argValues != null){ for (int i = 0; i < argValues.length; i++) { params += " " + argNames[i] + ": " + argValues[i]; } } // 获取IP地址 logging.setRequestIp(IpUtil.getIP(request)); if(!LOGINPATH.equals(signature.getName())){ UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); username = userDetails.getUsername(); } else { AuthorizationUser user = JSONUtil.toBean(new JSONObject(argValues[0]),AuthorizationUser.class); username = user.getUsername(); } if (params.length() > 1000){ params = params.substring(0,999); } logging.setUsername(username); logging.setParams(params + " }"); loggingRepository.save(logging); } }
package me.zhengjie.monitor.domain; import lombok.Data; import lombok.NoArgsConstructor; import org.hibernate.annotations.CreationTimestamp; import javax.persistence.*; import java.sql.Timestamp; /** * @author jie * @date 2018-11-24 */ @Entity @Data @Table(name = "log") @NoArgsConstructor public class Logging { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; /** * 操作用户 */ private String username; /** * 描述 */ private String description; /** * 方法名 */ private String method; /** * 参数 */ @Column(length = 1500) private String params; /** * 日志类型 */ private String logType; /** * 请求ip */ private String requestIp; /** * 请求耗时 */ private Long time; /** * 异常详细 */ @Column(length = 1500) private String exceptionDetail; /** * 创建日期 */ @CreationTimestamp private Timestamp createTime; public Logging(String logType, Long time) { this.logType = logType; this.time = time; } }
package me.zhengjie.monitor.repository; import me.zhengjie.monitor.domain.Logging; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import java.util.List; /** * @author jie * @date 2018-11-24 */ @Repository public interface LoggingRepository extends JpaRepository<Logging,Long>, JpaSpecificationExecutor { /** * 获取一个时间段的IP记录 * @param date1 * @param date2 * @return */ @Query(value = "select count(*) FROM (select * FROM log where createTime between ?1 and ?2 GROUP BY requestIp) as s",nativeQuery = true) Long findIp(String date1, String date2); }
package me.zhengjie.monitor.service.query; import me.zhengjie.monitor.domain.Logging; import me.zhengjie.monitor.repository.LoggingRepository; 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; /** * @author jie * @date 2018-11-24 */ @Service @Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class) public class LoggingQueryService { @Autowired private LoggingRepository loggingRepository; public Page queryAll(Logging logging, Pageable pageable){ return loggingRepository.findAll(new Spec(logging),pageable); } public List queryAll(Logging logging){ return loggingRepository.findAll(new Spec(logging)); } class Spec implements Specification<Logging> { private Logging logging; public Spec(Logging logging){ this.logging = logging; } @Override public Predicate toPredicate(Root<Logging> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) { List<Predicate> list = new ArrayList<Predicate>(); if(!ObjectUtils.isEmpty(logging.getUsername())){ list.add(cb.like(root.get("username").as(String.class),"%"+logging.getUsername()+"%")); } if (!ObjectUtils.isEmpty(logging.getLogType())) { list.add(cb.equal(root.get("logType").as(String.class), logging.getLogType())); } Predicate[] p = new Predicate[list.size()]; return cb.and(list.toArray(p)); } } }