日志切面

本文详细介绍了一个基于Spring AOP的日志管理系统,该系统能够自动记录业务操作日志,包括请求参数、响应结果、异常信息等,并通过异步方式保存到数据库。同时,系统还具备错误捕获和处理能力,确保应用程序的稳定运行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

import com.alibaba.fastjson.JSON;
import com.google.common.base.Strings;
import com.ziku.mall.entity.MallSysLogWithBLOBs;
import com.ziku.mall.enums.ErrorCodeEnum;
import com.ziku.mall.exception.BizException;
import com.ziku.mall.interceptor.UncheckAuth;
import com.ziku.mall.model.user.UserResult;
import com.ziku.mall.util.ProjectUtil;
import com.ziku.mall.util.SpringContextUtil;
import com.ziku.msb.common.base.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description:
 * @Author: wangxuqiang
 * @Date: Created in 2018/9/27
 * @Version: 1.0
 */
@Aspect
@Slf4j
@Component
public class LogAspect {

    @Autowired
    private LogService logService;

    @Pointcut("execution(* com.ziku.mall.service..*.*Impl.add*(..)) ||" +
            "execution(* com.ziku.mall.service..*.*Impl.insert*(..)) ||" +
            "execution(* com.ziku.mall.service..*.*Impl.save*(..))")
    public void saveCell() {}

    @Pointcut("execution(* com.ziku.mall.service..*.*Impl.update*(..)) &&" +
            "!execution(* com.ziku.mall.service..*.*Impl.updateOrder(..)) ||" +
            "execution(* com.ziku.mall.service..*.*Impl.edit*(..)) ||" +
            "execution(* com.ziku.mall.service..*.*Impl.send*(..)) ||" +
            "execution(* com.ziku.mall.service..*.*Impl.pay*(..))")
    public void updateCell() {}

    @Pointcut("execution(* com.ziku.mall.service..*.*Impl.delete*(..)) ||" +
            "execution(* com.ziku.mall.service..*.*Impl.cancel*(..)) &&" +
            "!execution(* com.ziku.mall.service..*.*Impl.cancelCoupon(..))")
    public void deleteCell() {}

    @Around("saveCell()")
    public Object saveLog(final ProceedingJoinPoint joinPoint) throws Throwable {
        return doLog(joinPoint);
    }

    @Around("updateCell()")
    public Object updateLog(final ProceedingJoinPoint joinPoint) throws Throwable {
        return doLog(joinPoint);
    }

    @Around("deleteCell()")
    public Object deleteLog(final ProceedingJoinPoint joinPoint) throws Throwable {
        return doLog(joinPoint);
    }


    private Object doLog(final ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        MallSysLogWithBLOBs sysLog=new MallSysLogWithBLOBs();
        String errorStr="";
        try {
            sysLog.setGmtCreate(new Date());
            sysLog.setIp(getIP(request));
            sysLog.setMethod(getMethod(joinPoint));
            sysLog.setParams(getParams(joinPoint));
            sysLog.setResponseResult("SUCCESS");
            sysLog.setOperation(getOperation(request));
            sysLog.setUserId(getUserId(request,joinPoint));
        } catch (Exception e) {
            if (log.isErrorEnabled()) {
                log.error("[小程序]日志信息转换异常:{}",ExceptionUtils.getStackTrace(e));
            }
            errorStr=errorMsg(e);
            sysLog.setResponseResult(errorStr);
        }

        StopWatch sw = new StopWatch(System.currentTimeMillis()+""+Math.random());
        sw.start();
        Object object=null;
        try {
            object=joinPoint.proceed();
        } catch (Throwable throwable) {
            if (log.isErrorEnabled()) {
                log.error("[小程序]日志方法执行异常:{}",ExceptionUtils.getStackTrace(throwable));
            }
            errorStr=errorStr+" --- "+errorMsg(throwable);
            sysLog.setResponseResult(errorStr);
            if (throwable instanceof BizException) {
                sw.stop();
                sysLog.setResponseTime(sw.getTotalTimeMillis());
                sysLog.setResponseResult(errorStr);
                logService.asyncSaveSysLog(sysLog);
                throw throwable;
            }
        }
        sw.stop();

        sysLog.setResponseTime(sw.getTotalTimeMillis());

        logService.asyncSaveSysLog(sysLog);

        return object;
    }

    private String getIP(HttpServletRequest request){
        return ProjectUtil.getRemoteHost(request);
    }

    private String getOperation(HttpServletRequest request) {
        String url=request.getRequestURL().toString();
        return String.format("[小程序]请求路径:%s;HTTP_METHOD:%s",url,request.getMethod());
    }

    private String getMethod(ProceedingJoinPoint joinPoint) {
        return joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
    }

    private String getParams(final ProceedingJoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        String[] strings = methodSignature.getParameterNames();

        Map<Object,Object> map=new HashMap();
        String param = null;
        if(args!=null&& args.length>0 ){
            if (strings != null) {
                for (int i = 0; i < strings.length; i++) {
                    if (strings[i]!=null&&args[i]!=null) {
                        map.put(strings[i], args[i]);
                    }
                }
                param = JSON.toJSONString(map);
            } else {
                param = JSON.toJSONString(args);
            }
        }
        return param;
    }

    private String getUserId(HttpServletRequest request,ProceedingJoinPoint joinPoint){
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        // RequiresAuthentication 注解的方法需要用户登录认证
        Annotation an = methodSignature.getMethod().getAnnotation(UncheckAuth.class);

        UserResult member = getCacheUser(request.getHeader("token"));

        if (an == null) {
            if (member == null) {
                throw new BusinessException(ErrorCodeEnum.USER_TOKEN_EXPIRE.getErrorCode(),ErrorCodeEnum.USER_TOKEN_EXPIRE.getErrorMsg());
            }
        }

        return member != null ? String.valueOf(member.getUserId()) : null;
    }

    private UserResult getCacheUser(String token) {

        UserResult userInfo = null;

        if (Strings.isNullOrEmpty(token)) {

            return null;
        }

        StringRedisTemplate redisTemplate = (StringRedisTemplate) SpringContextUtil.getBean("stringRedisTemplate");

        String userId = redisTemplate.opsForValue().get("JWT_TOKEN:" + token);

        if (Strings.isNullOrEmpty(userId)) {

            return null;
        }
        String userJson = redisTemplate.opsForValue().get("USER-ID:" + userId);

        if (Strings.isNullOrEmpty(userJson)) {

            return null;
        }

        userInfo = JSON.parseObject(userJson, UserResult.class);

        return userInfo;

    }


    private String errorMsg(Exception e) {
        return String.format("转换异常信息:%s --- %s",e.toString(),e.getStackTrace()[0]);
    }

    private String errorMsg(Throwable e) {
        return String.format("执行方法异常信息:%s --- %s",e.toString(),e.getStackTrace()[0]);
    }
}

 

package com.ziku.mall.aspect;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @Description:
 * @Author: wangxuqiang
 * @Date: Created in 2018/12/18
 * @Version: 1.0
 */
@Aspect
@Slf4j
@Component
public class LogConsole {
    private static final String START_TIME = "request-start";

    /**
     * 切入点
     */
    @Pointcut("execution(public * com.ziku.mall.web.*Controller.*(..))")
    public void log() {

    }

    /**
     * 前置操作
     *
     * @param point 切入点
     */
    @Before("log()")
    public void beforeLog(JoinPoint point) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

        HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();

        log.info("【请求 URL】:{}\n【请求 IP】:{}\n【请求类名】:{},【请求方法名】:{}\n【请求参数】:{},", request.getRequestURL(),
                request.getRemoteAddr(),point.getSignature().getDeclaringTypeName(), point.getSignature().getName(),
                getParams(point));
        //log.info("【请求 IP】:{}", request.getRemoteAddr());
        //log.info("【请求类名】:{},【请求方法名】:{}", point.getSignature().getDeclaringTypeName(), point.getSignature().getName());
        //log.info("【请求参数】:{},", getParams(point));
        Long start = System.currentTimeMillis();
        request.setAttribute(START_TIME, start);
    }

    /**
     * 环绕操作
     *
     * @param point 切入点
     * @return 原方法返回值
     * @throws Throwable 异常信息
     */
    @Around("log()")
    public Object aroundLog(ProceedingJoinPoint point) throws Throwable {
        Object result = point.proceed();
        log.info("【返回值】:{}", JSON.toJSONString((result)));
        return result;
    }

    /**
     * 后置操作
     */
    @AfterReturning("log()")
    public void afterReturning() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();

        Long start = (Long) request.getAttribute(START_TIME);
        Long end = System.currentTimeMillis();
        log.info("【请求耗时】:{}毫秒", end - start);
    }

    private String getParams(final JoinPoint joinPoint) {
        String param = null;
        try {
            Object[] args = joinPoint.getArgs();
            Signature signature = joinPoint.getSignature();
            MethodSignature methodSignature = (MethodSignature) signature;
            String[] strings = methodSignature.getParameterNames();

            Map<Object,Object> map=new HashMap();
            param = null;
            if(args!=null&& args.length>0 ){
                if (strings != null) {
                    for (int i = 0; i < strings.length; i++) {
                        if (args[i] instanceof ServletRequest || args[i] instanceof ServletResponse || args[i] instanceof MultipartFile ||
                                args[i] instanceof BindingResult) {
                            //ServletRequest不能序列化,从入参里排除,否则报异常:java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
                            //ServletResponse不能序列化 从入参里排除,否则报异常:java.lang.IllegalStateException: getOutputStream() has already been called for this response
                            continue;
                        }
                        if (strings[i]!=null&&args[i]!=null) {
                            map.put(strings[i], args[i]);
                        }
                    }
                    param = JSON.toJSONString(map);
                } else {
                    param = JSON.toJSONString(args);
                }
            }
        } catch (Exception e) {
            log.info("参数无法序列化为JSON");
            return "参数无法序列化为JSON";
        }
        return param;
    }
}

 

package com.ziku.mall.aspect;

import com.ziku.mall.entity.MallSysLogWithBLOBs;
import com.ziku.mall.mapper.MallSysLogMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

/**
 * @Description:
 * @Author: wangxuqiang
 * @Date: Created in 2018/9/29
 * @Version: 1.0
 */
@Slf4j
@Component
public class LogService {

    @Autowired
    private MallSysLogMapper mallSysLogMapper;

    @Async
    public void asyncSaveSysLog(MallSysLogWithBLOBs sysLog) {
        try {
            mallSysLogMapper.insertSelective(sysLog);
        } catch (Exception e) {
            log.error("[小程序]日志保存失败:{}",e.getMessage());
        }
    }
}
在当今数字化教育蓬勃发展的背景下,校园网络作为教学与科研的关键基础设施,其重要性日益凸显。本文旨在探讨小型校园网络的规划与设计,以满足网络实验教学的需求,为相关专业师生提供一个高效、稳定且功能完备的网络实验环境,助力教学活动顺利开展,提升学生的实践能力和创新思维。 网络实验教学要求校园网络具备高度的灵活性与可扩展性。学生需在实验过程中模拟各种网络拓扑结构、配置不同网络设备参数,这就要求网络能够快速调整资源分配,适应多样化的实验场景。同时,为保证实验数据的准确性和实验过程的稳定性,网络的高可靠性与低延迟特性不可或缺。此外,考虑到校园内多用户同时接入的场景,网络还需具备良好的并发处理能力,确保每位用户都能流畅地进行实验操作。 采用层次化结构构建小型校园网络,分为核心层、汇聚层与接入层。核心层选用高性能交换机,负责高速数据转发与关键路由决策,保障网络主干的稳定运行;汇聚层连接不同教学区域,实现数据的汇聚与初步处理,通过划分虚拟局域网(VLAN)对不同专业或班级的实验流量进行隔离,避免相互干扰;接入层则直接连接学生终端设备,提供充足的接入端口,满足大量用户同时接入的需求,并通过端口安全策略限制非法设备接入,保障网络安全。 在设备选型上,核心层交换机需具备高吞吐量、低延迟以及丰富的路由协议支持能力,以满足复杂网络流量的转发需求;汇聚层交换机则注重VLAN划分与管理功能,以及对链路聚合的支持,提升网络的可靠性和带宽利用率;接入层交换机则需具备高密度端口、灵活的端口配置以及完善的用户认证功能。配置方面,通过静态路由与动态路由协议相结合的方式,确保网络路径的最优选择;在汇聚层与接入层设备上启用VLAN Trunk技术,实现不同VLAN间的数据交换;同时,利用网络管理软件对设备进行集中监控与管理,实时掌握网络运行状态,及时发现并解决潜在问题。 网络安全是校园网络规划的关键环节。在接入层设置严
管理后台HTML页面是Web开发中一种常见的实践,主要用于构建企业或组织内部的管理界面,具备数据监控、用户管理、内容编辑等功能。本文将探讨一套美观易用的二级菜单目录设计,帮助开发者创建高效且直观的后台管理系统。 HTML5:作为超文本标记语言的最新版本,HTML5增强了网页的互动性和可访问性,提供了更多语义元素,如<header>、<nav>、<section>、<article>等,有助于清晰地定义网页结构。在管理后台中,HTML5可用于构建页面布局,划分功能区域,并集成多媒体内容,如图像、音频和视频。 界面设计:良好的管理后台界面应具备清晰的导航、一致的布局和易于理解的图标。二级菜单目录设计能够有效组织信息,主菜单涵盖大类功能,次级菜单则提供更具体的操作选项,通过展开和折叠实现层次感,降低用户认知负担。 CSS:CSS是用于控制网页外观和布局的语言,可对HTML元素进行样式设置,包括颜色、字体、布局等。在管理后台中,CSS能够实现响应式设计,使页面在不同设备上具有良好的显示效果。借助CSS预处理器(如Sass或Less),可以编写更高效、模块化的样式代码,便于维护。 文件结构: guanli.html:可能是管理页面的主入口,包含后台的主要功能和布局。 xitong.html:可能是系统设置或配置页面,用于管理员调整系统参数。 denglu.html:登录页面,通常包含用户名和密码输入框、登录按钮,以及注册或忘记密码的链接。 image文件夹:存放页面使用的图片资源,如图标、背景图等。 css文件夹:包含后台系统的样式文件,如全局样式表style.css或按模块划分的样式文件。 响应式设计:在移动设备普及的背景下,管理后台需要支持多种屏幕尺寸。通过媒体查询(Media Queries)和流式布局(Fluid Grids),可以确保后台在桌面、平板和手机上都能良好展示。
标题Python基于Hadoop的租房数据分析系统的设计与实现AI更换标题第1章引言介绍租房数据分析的重要性,以及Hadoop和Python在数据分析领域的应用优势。1.1研究背景与意义分析租房市场的现状,说明数据分析在租房市场中的重要作用。1.2国内外研究现状概述Hadoop和Python在数据分析领域的应用现状及发展趋势。1.3论文研究内容与方法阐述论文的研究目标、主要研究内容和所采用的技术方法。第2章相关技术理论详细介绍Hadoop和Python的相关技术理论。2.1Hadoop技术概述解释Hadoop的基本概念、核心组件及其工作原理。2.2Python技术概述阐述Python在数据处理和分析方面的优势及相关库函数。2.3Hadoop与Python的结合应用讨论Hadoop与Python在数据处理和分析中的结合方式及优势。第3章租房数据分析系统设计详细描述基于Hadoop的租房数据分析系统的设计思路和实现方案。3.1系统架构设计给出系统的整体架构设计,包括数据采集、存储、处理和分析等模块。3.2数据采集与预处理介绍数据的来源、采集方式和预处理流程。3.3数据存储与管理阐述数据在Hadoop平台上的存储和管理方式。第4章租房数据分析系统实现详细介绍租房数据分析系统的实现过程,包括关键代码和算法。4.1数据分析算法实现给出数据分析算法的具体实现步骤和关键代码。4.2系统界面设计与实现介绍系统界面的设计思路和实现方法,包括前端和后端的交互方式。4.3系统测试与优化对系统进行测试,发现并解决问题,同时对系统进行优化以提高性能。第5章实验结果与分析对租房数据分析系统进行实验验证,并对实验结果进行详细分析。5.1实验环境与数据集介绍实验所采用的环境和数据集,包括数据来源和规模等。5.2实验方法与步骤给出实验的具体方法和步骤,包括数据预处理、模型训练和测试等。5.3实验结果分析从多
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值