精华内容
下载资源
问答
  • java filter打印请求返回参数
  • 用户操作日志.zip

    2019-09-11 11:25:02
    java aop 用户操作日志 在每个action\controller 上加上注解 就可以了 例如 @Log(“添加用户”) 日志包含(请求时间,请求ip,请求类名 ,请求方法,请求参数,请求异常)
  • 前言:为了完整的记录外部接口请求记录,记录内容包括:请求参数,响应参数,请求耗时,请求IP地址,请求成功还是失败,请求方法名称,请求接口地址等重要信息。 1.引入maven <dependency> <groupId>...

    前言:为了完整的记录外部接口请求记录,记录内容包括:请求参数,响应参数,请求耗时,请求IP地址,请求成功还是失败,请求方法名称,请求接口地址等重要信息。

    1.引入maven

    <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-aop</artifactId>
         <version>1.4.1.RELEASE</version>
    </dependency>

    备注:此包是为了在aop中获取request对象而引入 

    2.日志记录model如下

    package com.tjair.log.model;
    
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import javax.persistence.Column;
    import javax.persistence.Id;
    import javax.persistence.Table;
    import java.util.Date;
    
    @Table(name = "t_tjapi_log")
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public class TjapiLog {
        @Id
        private Integer id;
    
        /**
         * 采购编码
         */
        @Column(name = "partnerId")
        private String partnerid;
    
        /**
         * 请求地址
         */
        private String url;
    
        /**
         * 接口描述
         */
        @Column(name = "api_name")
        private String apiName;
    
        /**
         * 请求时间
         */
        @Column(name = "create_time")
        private Date createTime;
    
        /**
         * 请求方式
         */
        private String method;
    
        /**
         * 请求参数
         */
        private String params;
    
        /**
         * 请求状态:1 成功 0 失败
         */
        private Integer status;
    
        /**
         * 请求IP
         */
        private String ip;
    
        /**
         * 请求来源地址
         */
        private String location;
    
        /**
         * 请求耗时
         */
        private Integer time;
    
        /**
         * 返回内容
         */
        private String response;
    }

    3.AOP切面如下

    package com.tjair.tjapi.config;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import com.tjair.common.log.TjapiLogVo;
    import com.tjair.common.util.IPUtil;
    import com.tjair.tjapi.feign.LogFeignService;
    import com.tjair.tjapi.util.HttpHelper;
    import io.swagger.annotations.ApiOperation;
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.ProceedingJoinPoint;
    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.context.annotation.Configuration;
    import org.springframework.web.context.request.RequestAttributes;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    import javax.servlet.http.HttpServletRequest;
    import java.io.IOException;
    import java.util.Date;
    import java.util.Objects;
    
    
    /**
     * @description 拦截所有控制器的返回,记录响应报文
     * @author unhejing
     * @date 2021-03-17 上午11:52:26
     */
    @Aspect
    @Configuration
    @Slf4j
    public class LogAspect {
    
        @Autowired
        private LogFeignService logFeignService;
    
        public LogAspect() {
        }
    
        @Pointcut("execution(public * com.tjair.tjapi.controller.*.*(..))")
        public void pointCutMethod() {
        }
    
        // 声明环绕通知
        @Around("pointCutMethod()")
        public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
            Long startTime = System.currentTimeMillis();
            ApiOperation apiOperation = ((MethodSignature)pjp.getSignature()).getMethod().getAnnotation(ApiOperation.class);
            // 获取request对象
            RequestAttributes ra = RequestContextHolder.getRequestAttributes();
            ServletRequestAttributes sra = (ServletRequestAttributes) ra;
            HttpServletRequest request = sra.getRequest();
            Object ret = pjp.proceed();
            Long endTime = System.currentTimeMillis();
            TjapiLogVo tjapiLogVo = getTjapiLogVo(request,Objects.nonNull(apiOperation) ? apiOperation.value() : "",endTime-startTime,JSON.toJSONString(ret));
            // 添加日志
            addLog(tjapiLogVo);
            log.info("响应数据耗时{}:响应数据{}",endTime-startTime,JSON.toJSONString(ret));
            return ret;
        }
    
        public void addLog(TjapiLogVo tjapiLogVo) {
            log.info("添加日志:{}",JSON.toJSONString(tjapiLogVo));
            Long startTime = System.currentTimeMillis();
            logFeignService.addTjapiLog(tjapiLogVo);
            Long endtime = System.currentTimeMillis();
            log.info("添加日志耗时:{}",endtime-startTime);
        }
    
    
        private TjapiLogVo getTjapiLogVo(HttpServletRequest request,String apiName,Long time,String response) throws IOException {
            TjapiLogVo tjapiLogVo = new TjapiLogVo();
            String jsonBody = HttpHelper.getBodyString(request);
            log.info("请求参数:{}",jsonBody);
            JSONObject reqObj = Objects.nonNull(JSON.parseObject(jsonBody)) ? JSON.parseObject(jsonBody) : new JSONObject();
            JSONObject resObj = Objects.nonNull(JSON.parseObject(response)) ? JSON.parseObject(response) : new JSONObject();
            //设置请求参数
            tjapiLogVo.setParams(jsonBody);
            tjapiLogVo.setPartnerid(Objects.nonNull(reqObj.getString("partnerId")) ? reqObj.getString("partnerId") : "-1");
            // 设置IP地址
            tjapiLogVo.setIp(IPUtil.getIpAddr(request));
            // 设置位置
            tjapiLogVo.setLocation(IPUtil.getCityInfo(tjapiLogVo.getIp()));
            //设置请求方法,GET,POST...
            tjapiLogVo.setMethod(request.getMethod());
            //设置请求路径
            tjapiLogVo.setUrl(request.getRequestURI());
            // 设置请求方法名称
            tjapiLogVo.setApiName(apiName);
            // 设置创建时间
            tjapiLogVo.setCreateTime(new Date());
            // 设置请求状态
            Integer code = Objects.nonNull(resObj.getInteger("code")) ? resObj.getInteger("code") : 1;
            tjapiLogVo.setStatus(code);
            // 设置接口消耗时间
            tjapiLogVo.setTime(time.intValue());
            // 设置响应内容
            tjapiLogVo.setResponse(response);
            return tjapiLogVo;
        }
    }

    4.测试接口

    package com.tjair.tjapi.controller;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import com.tjair.common.service.RedisUtils;
    import com.tjair.common.util.Result;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @author jingyujie
     * @create 2021-03-16 下午2:39
     **/
    @RestController
    @RequestMapping("/test")
    @Api(tags = "测试API控制器")
    public class TestController {
    
        @Autowired
        private RedisUtils redisUtils;
        
        @PostMapping("/apiTest")
        @ApiOperation("接口测试")
        public Result apiTest(@RequestBody JSONObject obj){
            return Result.returnSuccess("接口已联通,请求入参:"+ JSON.toJSONString(obj));
        }
    
    }
    

     

    5.请求结果如下

    备注说明:

    1.LogFeignService是添加日志的service

    2.IPUtil是获取IP和地址信息相关的工具类

    3.HttpHelper是解析request中的请求参数的工具类

    4.ApiOperation是获取接口的注解上面的接口描述

    5.partnerId是我请求参数里面必传的用户编码

    6.code是响应参数里面的状态码,用于判断接口是否请求成功

    末尾附上工具类:

    IPUtil.java

    类中的/ip2region.db这个是一个地址库,可直接百度下载即可。

    package com.tjair.common.util;
    
    import org.apache.commons.io.FileUtils;
    import org.lionsoul.ip2region.DataBlock;
    import org.lionsoul.ip2region.DbConfig;
    import org.lionsoul.ip2region.DbSearcher;
    import org.lionsoul.ip2region.Util;
    
    import javax.servlet.http.HttpServletRequest;
    import java.io.File;
    import java.lang.reflect.Method;
    
    /**
     * ip操作相关工具类
     * @author jingyujie
     * @create 2020-06-24 下午2:11
     **/
    
    public class IPUtil {
    
        public static String getCityInfo(String ip){
            try {
                //db
                String dbPath = IPUtil.class.getResource("/ip2region.db").getPath();
                System.out.println("路径:"+dbPath);
                File file = new File(dbPath);
                if (file.exists() == false) {
                    System.out.println("Error: Invalid ip2region.db file");
                    String tmpDir = System.getProperties().getProperty("java.io.tmpdir");
                    dbPath = tmpDir + "ip.db";
                    System.out.println(dbPath);
                    file = new File(dbPath);
                    FileUtils.copyInputStreamToFile(IPUtil.class.getClassLoader().getResourceAsStream("classpath:ip2region.db"), file);
                }
    
                //查询算法
                int algorithm = DbSearcher.BTREE_ALGORITHM; //B-tree
                //DbSearcher.BINARY_ALGORITHM //Binary
                //DbSearcher.MEMORY_ALGORITYM //Memory
                DbSearcher searcher = null;
                try {
                    DbConfig config = new DbConfig();
                    searcher = new DbSearcher(config, dbPath);
    
                    //define the method
                    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;
                    }
    
                    DataBlock dataBlock = null;
                    if (Util.isIpAddress(ip) == false) {
                        System.out.println("Error: Invalid ip address");
                    }
    
                    dataBlock = (DataBlock) method.invoke(searcher, ip);
    
                    return dataBlock.getRegion();
    
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (searcher != null) {
                        searcher.close();
                    }
                }
                return null;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        public static String getIpAddr(HttpServletRequest request) {
            String ip = request.getHeader("x-forwarded-for");
            System.out.println("x-forwarded-for ip: " + ip);
            if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
                // 多次反向代理后会有多个ip值,第一个ip才是真实ip
                if( ip.indexOf(",")!=-1 ){
                    ip = ip.split(",")[0];
                }
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
                System.out.println("Proxy-Client-IP ip: " + ip);
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
                System.out.println("WL-Proxy-Client-IP ip: " + ip);
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
                System.out.println("HTTP_CLIENT_IP ip: " + ip);
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
                System.out.println("HTTP_X_FORWARDED_FOR ip: " + ip);
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("X-Real-IP");
                System.out.println("X-Real-IP ip: " + ip);
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
                System.out.println("getRemoteAddr ip: " + ip);
            }
            System.out.println("获取客户端ip: " + ip);
            return ip;
        }
    }
    

     HttpHelper.java

    此方法要获取request body参数还需要HttpServletRequestWrapper 实现对request body的二次读取,具体实现请自行百度。

    package com.tjair.tjapi.util;
    
    import javax.servlet.http.HttpServletRequest;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.nio.charset.Charset;
    
    public class HttpHelper {
        public static String getBodyString(HttpServletRequest request) throws IOException {
            StringBuilder sb = new StringBuilder();
            InputStream inputStream = null;
            BufferedReader reader = null;
            try {
                inputStream = request.getInputStream();
                reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
                String line = "";
                while ((line = reader.readLine()) != null) {
                    sb.append(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return sb.toString();
        }
    }
    

     

     

    展开全文
  •  针对不同的action 方法中有修改删除的敏感操作的接口,需要记录对应的参数,ip地址,员工的id名称等信息,方便追责定位问题 分析:  1.使用注解将对应方法打上标记  2.每次调用完该方法的时候才开始记录日志  3....

    需求:

     针对不同的action 方法中有修改删除的敏感操作的接口,需要记录对应的参数,ip地址,员工的id名称等信息,方便追责定位问题

    分析:

      1.使用注解将对应方法打上标记

      2.每次调用完该方法的时候才开始记录日志

      3.需要记录用户请求的ip地址,参数,用户名称等等

    ①定义注解

    
    import java.lang.annotation.*;
    
    @Target({ ElementType.METHOD, ElementType.TYPE })
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface MethodLog {
    
    	//对标记接口的补充说明
    	String content() default ""; 
    
    	String operType() default "0";
    	
    	int operLevel() default 0; //操作等级
    }

    ②定义切面

     

    
    /**
     * 操作日志切面配置
     */
    @Aspect
    @Component("operateLogAspect")
    public class OperateLogAspect {
        private Logger logger = LoggerFactory.getLogger(getClass());
        
        //注入持久化该日志信息的service
        @Autowired
        private OperateService operateService;
        //注入根据request获取登录用户信息的service
        @Autowired
        private SysUserService sysUserService;
    
        @After(value = "execution (* com.web.controller..*.*(..))") //指定切点,使用after 让该切面在方法执行完成后切入
        public void after(JoinPoint point) throws Throwable {
            try {
                // 拦截的action方法上面的标记是否包含 MethodLog 的注解
                Map<String, Object> map = getMthodRemark(point);
                if (map.isEmpty()) {
                    // 没有MethodLog 注解标记 ,无此配置,直接返回
                    return;
                }
                //获取requestBody 参数信息,过滤掉 ServletRequest 和 ServletResponse 类型的参数
                Object object = Arrays.stream(point.getArgs()).filter(t ->!( t instanceof ServletRequest) && !( t instanceof ServletResponse) ).collect(Collectors.toList());
                //请求参数转成jsonString 
                String requestBody = JSONObject.toJSONString(object);
    
                HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
                if (null == request) {
                    logger.info("获取request失败.直接返回");
                    return;
                }
                //根据request获取用户ID
                Long userId = this.getSysUserId(request);
                if (userId == null) {
                    logger.error("未从request中获取到员工信息,直接返回");
                    return;
                }
               //获取用户数使用客户端信息
                String userAgent = request.getHeader("user-agent");
                //根据用户ID调用service获取用户信息 
                SystemUser myUser = sysUserService.queryOne(userId);
                //获取该方法的名称
                String requestMethod = request.getMethod();
                StringBuffer params = new StringBuffer();
                // action方法名称
                String actionName = point.getSignature().getName();
                String pms = requestBody;
               
                // 构建操作日志对象
                OperateLog log = new OperateLog();
                log.setUserId(Integer.parseInt("" + myUser.getUserId()));
                log.setUserName(myUser.getUserName());
                log.setOperContent(null == map.get("content") ? "" : map.get("content").toString());
                log.setOperLevel(null == map.get("operLevel") ? 0 : Integer.parseInt(map.get("operLevel").toString()));
                log.setOpParams(pms);
                log.setOperUserAgent(userAgent);
                log.setOpIp(getIpAdrress(request));
                log.setOpSysType(null == map.get("operType") ? 0 : Integer.parseInt(map.get("operType").toString()));
                log.setOperMethod(actionName);
                log.setOpDisplayMode("");
                operateLogService.insertOperateLog(log);
            }catch (JSONException je){
                logger.error("记录操作日志参数异常,json转型异常:{}", je.getMessage());
            } catch (Exception e) {
                logger.error("记录操作日志出错:{}", StackTraceLogUtil.getStackTraceAsString(e));
            }
            return;
        }
    
        /**
         * 计算两天是否同一天
         *
         * @param day1
         * @param day2
         * @return
         */
        public boolean isSameDay(Date day1, Date day2) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String ds1 = sdf.format(day1);
            String ds2 = sdf.format(day2);
            return ds1.equals(ds2) ? true : false;
        }
    
        /**
         * @param request
         * @return 当前登陆员工Id
         * @desc 获取当前登陆用户Id
         */
        protected Long getSysUserId(HttpServletRequest request) {
            Object object = request.getAttribute(CommonConstant.UID);
    
            if (object == null)
                object = request.getHeader(CommonConstant.UID);
            return Optional.ofNullable(object).isPresent() ? Long.valueOf(String.valueOf(object)) : null;
        }
    
        /**
         * 是否相差time
         *
         * @param d1
         * @param d2
         * @param time
         * @return
         */
        public boolean isDifferTime(Date d1, Date d2, int time) {
            if ((d2.getTime() - d1.getTime()) / 1000 / 60 > time)
                return true;
            else
                return false;
        }
    
        /**
         * 获取Ip地址
         * @param request
         * @return
         */
        private static String getIpAdrress(HttpServletRequest request) {
            String Xip = request.getHeader("X-Real-IP");
            String XFor = request.getHeader("X-Forwarded-For");
            if(StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)){
                //多次反向代理后会有多个ip值,第一个ip才是真实ip
                int index = XFor.indexOf(",");
                if(index != -1){
                    return XFor.substring(0,index);
                }else{
                    return XFor;
                }
            }
            XFor = Xip;
            if(StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)){
                return XFor;
            }
            if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
                XFor = request.getHeader("Proxy-Client-IP");
            }
            if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
                XFor = request.getHeader("WL-Proxy-Client-IP");
            }
            if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
                XFor = request.getHeader("HTTP_CLIENT_IP");
            }
            if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
                XFor = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
                XFor = request.getRemoteAddr();
            }
            return XFor;
        }
    
        // 获取方法的中文备注____用于记录用户的操作日志描述
        @SuppressWarnings("rawtypes")
        public static Map<String, Object> getMthodRemark(JoinPoint joinPoint)
                throws Exception {
            String targetName = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();
            Object[] arguments = joinPoint.getArgs();
            Map<String, Object> map = Maps.newHashMap();
            Class targetClass = Class.forName(targetName);
            Method[] method = targetClass.getMethods();
            String methode = "";
            for (Method m : method) {
                if (m.getName().equals(methodName)) {
                    Class[] tmpCs = m.getParameterTypes();
                    if (tmpCs.length == arguments.length) {
                        MethodLog methodCache = m.getAnnotation(MethodLog.class);
                        if (methodCache != null) {
                            methode = methodCache.content();
                            String operType = methodCache.operType();
                            int level = methodCache.operLevel();
                            map.put("content", methode);
                            map.put("operLevel", level);
                            map.put("operType", operType);
                        }
                        break;
                    }
                }
            }
            return map;
        }
    
    }

     具体是持久化方法之类的我就不贴了,这里只是提供一个思路,如果有问题的欢迎指正,谢谢

     

    展开全文
  • SpringBoot项目优雅日志打印请求参数及返回参数: 需求:1:请求参数及响应内容日志打印交给切面进行管理,避免手动创建log对象进行日志记录打印 2:基于注解的Controller的Method,添加注解进行打印,不添加注解不打印...

    SpringBoot项目优雅日志打印请求参数及返回参数:

    需求:1:请求参数及响应内容日志打印交给切面进行管理,避免手动创建log对象进行日志记录打印
            2:基于注解的Controller的Method,添加注解进行打印,不添加注解不打印日志,便于根据实际情况日志的输出.

     

    步骤:

    添加依赖:

    <!--aop-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.41</version>
    </dependency>

    创建自定义注解:

    
    
    import java.lang.annotation.*;
    
    @Retention(RetentionPolicy.RUNTIME)//注解不仅被保存到class文件中,jvm加载class文件之后,仍存在
    @Target(ElementType.METHOD) //注解添加的位置
    @Documented
    public @interface LogPrint {
         String description() default "";
    
    }
    

     

    写一个切面类进行日志输出管理:

    package com.group.**.config.aspect;
    
    import com.alibaba.fastjson.JSONObject;
    import com.techsun.industry.config.annotation.LogPrint;
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.context.annotation.Profile;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    import org.springframework.web.multipart.MultipartFile;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.lang.reflect.Method;
    
    @Aspect
    @Component
    @Profile({"dev","test"}) //一般生产环境不允许日志打印参数
    @Slf4j
    public class LogPrintAspect {
        /** 换行符 */
        private static final String LINE_SEPARATOR = System.lineSeparator();
    
        /** 以自定义 @LogPrint 注解为切点 */
        @Pointcut("@annotation(com.*.*.config.annotation.LogPrint)")
        public void logPrint() {}
    
        /**
         * 在切点之前织入
         * @param joinPoint
         * @throws Throwable
         */
        @Before("logPrint()")
        public void doBefore(JoinPoint joinPoint) throws Throwable {
            // 开始打印请求日志
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
    
            // 获取 @WebLog 注解的描述信息
            String methodDescription = getAspectLogDescription(joinPoint);
    
            // 打印请求相关参数
            log.info("========================================== Start ==========================================");
            // 打印请求 url
            log.info("URL            : {}", request.getRequestURL().toString());
            // 打印描述信息
            log.info("Description    : {}", methodDescription);
            // 打印 Http method
            log.info("HTTP Method    : {}", request.getMethod());
            // 打印调用 controller 的全路径以及执行方法
            log.info("Class Method   : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
            // 打印请求的 IP
            log.info("IP             : {}", request.getRemoteAddr());
            // 打印请求入参
            log.info("Request Args   : {}", getParams(joinPoint));
        }
    
        /**
         * 在切点之后织入
         * @throws Throwable
         */
        @After("logPrint()")
        public void doAfter() throws Throwable {
            // 接口结束后换行,方便分割查看
            log.info("=========================================== End ===========================================" + LINE_SEPARATOR);
        }
    
        /**
         * 环绕
         * @param proceedingJoinPoint
         * @return
         * @throws Throwable
         */
        @Around("logPrint()")
        public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            long startTime = System.currentTimeMillis();
            Object result = proceedingJoinPoint.proceed();
            // 打印出参
            log.info("Response Args  : {}",  JSONObject.toJSONString(result));
            // 执行耗时
            log.info("Time-Consuming : {} ms", System.currentTimeMillis() - startTime);
            return result;
        }
    
    
        /**
         * 获取切面注解的描述
         *
         * @param joinPoint 切点
         * @return 描述信息
         * @throws Exception
         */
        public String getAspectLogDescription(JoinPoint joinPoint)
                throws Exception {
            String targetName = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();
            Object[] arguments = joinPoint.getArgs();
            Class targetClass = Class.forName(targetName);
            Method[] methods = targetClass.getMethods();
            StringBuilder description = new StringBuilder("");
            for (Method method : methods) {
                if (method.getName().equals(methodName)) {
                    Class[] clazzs = method.getParameterTypes();
                    if (clazzs.length == arguments.length) {
                        description.append(method.getAnnotation(LogPrint.class).description());
                        break;
                    }
                }
            }
            return description.toString();
        }
    
        private String getParams(JoinPoint joinPoint) {
            String params = "";
            if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
                for (int i = 0; i < joinPoint.getArgs().length; i++) {
                    Object arg = joinPoint.getArgs()[i];
                    if ((arg instanceof HttpServletResponse) || (arg instanceof HttpServletRequest)
                            || (arg instanceof MultipartFile) || (arg instanceof MultipartFile[])) {
                        continue;
                    }
                    try {
                        params +=JSONObject.toJSONString(joinPoint.getArgs()[i]);
                    } catch (Exception e1) {
                        log.error(e1.getMessage());
                    }
                }
            }
            return params;
        }
    
    }
    
    
    

    现在看看效果吧:

     

    完!!!

     

     

    展开全文
  • JAVA记录操作日志步骤

    万次阅读 多人点赞 2019-08-06 14:01:55
    说明 系统日志不论是在日常的管理还是维护中都会起到很大的作用,但是在日志的记录中通常会存在很多的...记录出参入参这是日志记录最好操作的一部分,而这里会存在一定的重复性,因为每个请求都需要记录,这是重复操作,...

    项目地址:https://gitee.com/Selegant/logs-demo.git

    说明

    系统日志不论是在日常的管理还是维护中都会起到很大的作用,但是在日志的记录中通常会存在很多的问题

    1. 日志记录的不规范性
    2. 日志记录的重复性
    3. 日志记录的难分类

    目前日志主要记录的有三方面

    1. 请求的入参,出参
    2. 关于业务上的操作
    3. 异常日常日志的打印

    解决方案

    1.记录请求的出参入参

    记录出参入参这是日志记录最好操作的一部分,而这里会存在一定的重复性,因为每个请求都需要记录,这是重复操作,完全可以使用Spring AOP进行入参和出参的记录

    import org.apache.log4j.Logger;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    import javax.servlet.http.HttpServletRequest;
    import java.util.Arrays;
    
    /**
     * Web层日志切面
     */
    @Aspect    //这里使用@Aspect注解方式设置AOP
    @Order(5)  //值越小,越先加载
    @Component
    public class WebLogAspect {
    
        private Logger logger = Logger.getLogger(getClass());
    
        ThreadLocal<Long> startTime = new ThreadLocal<>();
    	
    	//这里@Pointcut设置切点可以设置为Controller层的地址
        @Pointcut("execution(public * com.training..*.*Controller(..))")
        public void webLog(){}
    
    	//@Before指在切点方法之前执行,也就是在Controller层方法执行之前执行,这里可以通过JoinPoint获取一些有关方法的信息,在这里也可以修改参数的值
        
    	//@Before()括号里设置的是切点方法的名称
    	@Before("webLog()")
        public void doBefore(JoinPoint joinPoint) throws Throwable {
            startTime.set(System.currentTimeMillis());
    
            // 接收到请求,记录请求内容
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
    
            // 记录下请求内容
            logger.info("URL : " + request.getRequestURL().toString());
            logger.info("HTTP_METHOD : " + request.getMethod());
            logger.info("IP : " + request.getRemoteAddr());
            logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
            logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
    
        }
    
        @AfterReturning(returning = "ret", pointcut = "webLog()")
        public void doAfterReturning(Object ret) throws Throwable {
            // 处理完请求,返回内容
            logger.info("RESPONSE : " + ret);
            logger.info("SPEND TIME : " + (System.currentTimeMillis() - startTime.get()));
        }
    
    }
    

    2.记录操作日志

    在系统中可能会有很多的增删改查或是会涉及到一些业务操作,这时候我们需要记录一下操作的入口,在此还可以记录下操作的类型,或是业务的名称.不过在就操作日志前需要构建日志的基础部件

    日志对象

    import java.util.Date;
    
    /**
     * 操作日志
     */
    public class OperationLog extends Base {
    
        private static final long serialVersionUID = 1L;
    
        /**
         * 日志类型
         */
        private String  logtype;
        /**
         * 日志名称
         */
        private String  logname;
        /**
         * 用户id
         */
        private Integer userid;
        /**
         * 类名称
         */
        private String  classname;
        /**
         * 方法名称
         */
        private String  method;
        /**
         * 创建时间
         */
        private Date    createtime;
        /**
         * 是否成功
         */
        private String  succeed;
        /**
         * 备注
         */
        private String  message;
    
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getLogtype() {
            return logtype;
        }
    
        public void setLogtype(String logtype) {
            this.logtype = logtype;
        }
    
        public String getLogname() {
            return logname;
        }
    
        public void setLogname(String logname) {
            this.logname = logname;
        }
    
        public Integer getUserid() {
            return userid;
        }
    
        public void setUserid(Integer userid) {
            this.userid = userid;
        }
    
        public String getClassname() {
            return classname;
        }
    
        public void setClassname(String classname) {
            this.classname = classname;
        }
    
        public String getMethod() {
            return method;
        }
    
        public void setMethod(String method) {
            this.method = method;
        }
    
        public Date getCreatetime() {
            return createtime;
        }
    
        public void setCreatetime(Date createtime) {
            this.createtime = createtime;
        }
    
        public String getSucceed() {
            return succeed;
        }
    
        public void setSucceed(String succeed) {
            this.succeed = succeed;
        }
    
        public String getMessage() {
            return message;
        }
    
        public void setMessage(String message) {
            this.message = message;
        }
    }
    

    日志对象创建工厂

    import com.stylefeng.guns.common.constant.state.LogSucceed;
    import com.stylefeng.guns.common.constant.state.LogType;
    import com.stylefeng.guns.common.persistence.model.LoginLog;
    import com.stylefeng.guns.common.persistence.model.OperationLog;
    
    import java.util.Date;
    
    /**
     * 日志对象创建工厂
     */
    public class LogFactory {
    
        /**
         * 创建操作日志
         */
        public static OperationLog createOperationLog(LogType logType, Integer userId, String bussinessName, String clazzName, String methodName, String msg, LogSucceed succeed) {
            OperationLog operationLog = new OperationLog();
            operationLog.setLogtype(logType.getMessage());
            operationLog.setLogname(bussinessName);
            operationLog.setUserid(userId);
            operationLog.setClassname(clazzName);
            operationLog.setMethod(methodName);
            operationLog.setCreatetime(new Date());
            operationLog.setSucceed(succeed.getMessage());
            operationLog.setMessage(msg);
            return operationLog;
        }
    
        /**
         * 创建登录日志
         */
        public static LoginLog createLoginLog(LogType logType, Integer userId, String msg,String ip) {
            LoginLog loginLog = new LoginLog();
            loginLog.setLogname(logType.getMessage());
            loginLog.setUserid(userId);
            loginLog.setCreatetime(new Date());
            loginLog.setSucceed(LogSucceed.SUCCESS.getMessage());
            loginLog.setIp(ip);
            loginLog.setMessage(msg);
            return loginLog;
        }
    }
    

    日志任务创建工厂

    日志任务创建工厂的作用是将日志记录存储到数据库中

    import com.stylefeng.guns.common.constant.state.LogSucceed;
    import com.stylefeng.guns.common.constant.state.LogType;
    import com.stylefeng.guns.common.persistence.dao.LoginLogMapper;
    import com.stylefeng.guns.common.persistence.dao.OperationLogMapper;
    import com.stylefeng.guns.common.persistence.model.LoginLog;
    import com.stylefeng.guns.common.persistence.model.OperationLog;
    import com.stylefeng.guns.core.log.LogManager;
    import com.stylefeng.guns.core.util.SpringContextHolder;
    import com.stylefeng.guns.core.util.ToolUtil;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.util.TimerTask;
    
    /**
     * 日志操作任务创建工厂
     */
    public class LogTaskFactory {
    
        private static Logger logger  = LoggerFactory.getLogger(LogManager.class);
    	//LoginLogMapper记录登录登出日志
        private static LoginLogMapper loginLogMapper = SpringContextHolder.getBean(LoginLogMapper.class);
    	//OperationLogMapper记录操作日志	    
    	private static OperationLogMapper operationLogMapper = SpringContextHolder.getBean(OperationLogMapper.class);
    
        public static TimerTask loginLog(final Integer userId, final String ip) {
            return new TimerTask() {
                @Override
                public void run() {
                    try {
                        LoginLog loginLog = LogFactory.createLoginLog(LogType.LOGIN, userId, null, ip);
                        loginLogMapper.insert(loginLog);
                    } catch (Exception e) {
                        logger.error("创建登录日志异常!", e);
                    }
                }
            };
        }
    
        public static TimerTask loginLog(final String username, final String msg, final String ip) {
            return new TimerTask() {
                @Override
                public void run() {
                    LoginLog loginLog = LogFactory.createLoginLog(
                            LogType.LOGIN_FAIL, null, "账号:" + username + "," + msg, ip);
                    try {
                        loginLogMapper.insert(loginLog);
                    } catch (Exception e) {
                        logger.error("创建登录失败异常!", e);
                    }
                }
            };
        }
    
        public static TimerTask exitLog(final Integer userId, final String ip) {
            return new TimerTask() {
                @Override
                public void run() {
                    LoginLog loginLog = LogFactory.createLoginLog(LogType.EXIT, userId, null,ip);
                    try {
                        loginLogMapper.insert(loginLog);
                    } catch (Exception e) {
                        logger.error("创建退出日志异常!", e);
                    }
                }
            };
        }
    
        public static TimerTask bussinessLog(final Integer userId, final String bussinessName, final String clazzName, final String methodName, final String msg) {
            return new TimerTask() {
                @Override
                public void run() {
                    OperationLog operationLog = LogFactory.createOperationLog(
                            LogType.BUSSINESS, userId, bussinessName, clazzName, methodName, msg, LogSucceed.SUCCESS);
                    try {
                        operationLogMapper.insert(operationLog);
                    } catch (Exception e) {
                        logger.error("创建业务日志异常!", e);
                    }
                }
            };
        }
    
        public static TimerTask exceptionLog(final Integer userId, final Exception exception) {
            return new TimerTask() {
                @Override
                public void run() {
                    String msg = ToolUtil.getExceptionMsg(exception);
                    OperationLog operationLog = LogFactory.createOperationLog(
                            LogType.EXCEPTION, userId, "", null, null, msg, LogSucceed.FAIL);
                    try {
                        operationLogMapper.insert(operationLog);
                    } catch (Exception e) {
                        logger.error("创建异常日志异常!", e);
                    }
                }
            };
        }
    }
    

    记录操作日志

    这一步是最关键的一环

    原理:通过自定义的注解@BussinessLog(可以任意命名),里面定义了业务的名称,被修改的实体的唯一标识,字典(用于查找key的中文名称和字段的中文名称),然后通过AOP,拦截所有添加了@BussinessLog注解的方法,解析其注解里面的属性,然后记录到对应的操作日志表中,完成操作日志的记录

    @BussinessLog

    import java.lang.annotation.*;
    
    /**
     * 标记需要做业务日志的方法
     */
    @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD})
    public @interface BussinessLog {
    
        /**
         * 业务的名称,例如:"修改菜单"
         */
        String value() default "";
    
        /**
         * 被修改的实体的唯一标识,例如:菜单实体的唯一标识为"id"
         */
        String key() default "id";
    
        /**
         * 字典(用于查找key的中文名称和字段的中文名称)
         */
        String dict() default "SystemDict";
    }
    

    @BussinessLog注解拦截AOP

    import com.stylefeng.guns.common.annotion.log.BussinessLog;
    import com.stylefeng.guns.common.constant.dictmap.base.AbstractDictMap;
    import com.stylefeng.guns.common.constant.dictmap.factory.DictMapFactory;
    import com.stylefeng.guns.core.log.LogManager;
    import com.stylefeng.guns.core.log.LogObjectHolder;
    import com.stylefeng.guns.core.log.factory.LogTaskFactory;
    import com.stylefeng.guns.core.shiro.ShiroKit;
    import com.stylefeng.guns.core.shiro.ShiroUser;
    import com.stylefeng.guns.core.support.HttpKit;
    import com.stylefeng.guns.core.util.Contrast;
    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.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    import java.lang.reflect.Method;
    import java.util.Map;
    
    /**
     * 日志记录
     */
    @Aspect
    @Component
    public class LogAop {
    
        private Logger log = LoggerFactory.getLogger(this.getClass());
    
        @Pointcut(value = "@annotation(com.stylefeng.guns.common.annotion.log.BussinessLog)")
        public void cutService() {
        }
    
        @Around("cutService()")
        public Object recordSysLog(ProceedingJoinPoint point) throws Throwable {
    
            //先执行业务
            Object result = point.proceed();
    
            try {
                handle(point);
            } catch (Exception e) {
                log.error("日志记录出错!", e);
            }
    
            return result;
        }
    
        private void handle(ProceedingJoinPoint point) throws Exception {
    
            //获取拦截的方法名
            Signature sig = point.getSignature();
            MethodSignature msig = null;
            if (!(sig instanceof MethodSignature)) {
                throw new IllegalArgumentException("该注解只能用于方法");
            }
            msig = (MethodSignature) sig;
            Object target = point.getTarget();
            Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
            String methodName = currentMethod.getName();
    
            //如果当前用户未登录,不做日志
            ShiroUser user = ShiroKit.getUser();
            if (null == user) {
                return;
            }
    
            //获取拦截方法的参数
            String className = point.getTarget().getClass().getName();
            Object[] params = point.getArgs();
    
            //获取操作名称
            BussinessLog annotation = currentMethod.getAnnotation(BussinessLog.class);
            String bussinessName = annotation.value();
            String key = annotation.key();
            String dictClass = annotation.dict();
    
            StringBuilder sb = new StringBuilder();
            for (Object param : params) {
                sb.append(param);
                sb.append(" & ");
            }
    
            //如果涉及到修改,比对变化
            String msg;
            if (bussinessName.indexOf("修改") != -1 || bussinessName.indexOf("编辑") != -1) {
                Object obj1 = LogObjectHolder.me().get();
                Map<String, String> obj2 = HttpKit.getRequestParameters();
                msg = Contrast.contrastObj(dictClass, key, obj1, obj2);
            } else {
                Map<String, String> parameters = HttpKit.getRequestParameters();
                AbstractDictMap dictMap = DictMapFactory.createDictMap(dictClass);
                msg = Contrast.parseMutiKey(dictMap,key,parameters);
            }
    
            LogManager.me().executeLog(LogTaskFactory.bussinessLog(user.getId(), bussinessName, className, methodName, msg));
        }
    }
    

    @BussinessLog使用实例

    /**
     * 新增字典
     @param dictValues 格式例如   "1:启用;2:禁用;3:冻结"
     */
    @BussinessLog(value = "添加字典记录", key = "dictName,dictValues", dict = com.stylefeng.guns.common.constant.Dict.DictMap)
    @RequestMapping(value = "/add")
    @Permission(Const.ADMIN_NAME)
    @ResponseBody
    public Object add(String dictName, String dictValues) {
        if (ToolUtil.isOneEmpty(dictName, dictValues)) {
            throw new BussinessException(BizExceptionEnum.REQUEST_NULL);
        }
        dictService.addDict(dictName, dictValues);
        return SUCCESS_TIP;
    }
    

    3.记录异常日志

    记录异常日志其实也是一个重复式的过程,这也可以通过统一的处理来记录异常抛出的日志

    import com.stylefeng.guns.common.constant.tips.ErrorTip;
    import com.stylefeng.guns.common.exception.BizExceptionEnum;
    import com.stylefeng.guns.common.exception.BussinessException;
    import com.stylefeng.guns.common.exception.InvalidKaptchaException;
    import com.stylefeng.guns.core.log.LogManager;
    import com.stylefeng.guns.core.log.factory.LogTaskFactory;
    import com.stylefeng.guns.core.shiro.ShiroKit;
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.CredentialsException;
    import org.apache.shiro.authc.DisabledAccountException;
    import org.apache.shiro.session.InvalidSessionException;
    import org.apache.shiro.session.UnknownSessionException;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.http.HttpStatus;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.ResponseStatus;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.lang.reflect.UndeclaredThrowableException;
    
    import static com.stylefeng.guns.core.support.HttpKit.getIp;
    import static com.stylefeng.guns.core.support.HttpKit.getRequest;
    
    /**
     * 全局的的异常拦截器(拦截所有的控制器)(带有@RequestMapping注解的方法上都会拦截)
     */
    @ControllerAdvice
    public class GlobalExceptionHandler {
    
        private Logger log = LoggerFactory.getLogger(this.getClass());
    
        /**
         * 拦截业务异常
         */
        @ExceptionHandler(BussinessException.class)
        @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
        @ResponseBody
        public ErrorTip notFount(BussinessException e) {
            LogManager.me().executeLog(LogTaskFactory.exceptionLog(ShiroKit.getUser().getId(), e));
            getRequest().setAttribute("tip", e.getMessage());
            log.error("业务异常:", e);
            return new ErrorTip(e.getCode(), e.getMessage());
        }
    
        /**
         * 用户未登录
         */
        @ExceptionHandler(AuthenticationException.class)
        @ResponseStatus(HttpStatus.UNAUTHORIZED)
        public String unAuth(AuthenticationException e) {
            log.error("用户未登陆:", e);
            return "/login.html";
        }
    
        /**
         * 账号被冻结
         */
        @ExceptionHandler(DisabledAccountException.class)
        @ResponseStatus(HttpStatus.UNAUTHORIZED)
        public String accountLocked(DisabledAccountException e, Model model) {
            String username = getRequest().getParameter("username");
            LogManager.me().executeLog(LogTaskFactory.loginLog(username, "账号被冻结", getIp()));
            model.addAttribute("tips", "账号被冻结");
            return "/login.html";
        }
    
        /**
         * 账号密码错误
         */
        @ExceptionHandler(CredentialsException.class)
        @ResponseStatus(HttpStatus.UNAUTHORIZED)
        public String credentials(CredentialsException e, Model model) {
            String username = getRequest().getParameter("username");
            LogManager.me().executeLog(LogTaskFactory.loginLog(username, "账号密码错误", getIp()));
            model.addAttribute("tips", "账号密码错误");
            return "/login.html";
        }
    
        /**
         * 验证码错误
         */
        @ExceptionHandler(InvalidKaptchaException.class)
        @ResponseStatus(HttpStatus.BAD_REQUEST)
        public String credentials(InvalidKaptchaException e, Model model) {
            String username = getRequest().getParameter("username");
            LogManager.me().executeLog(LogTaskFactory.loginLog(username, "验证码错误", getIp()));
            model.addAttribute("tips", "验证码错误");
            return "/login.html";
        }
    
        /**
         * 无权访问该资源
         */
        @ExceptionHandler(UndeclaredThrowableException.class)
        @ResponseStatus(HttpStatus.UNAUTHORIZED)
        @ResponseBody
        public ErrorTip credentials(UndeclaredThrowableException e) {
            getRequest().setAttribute("tip", "权限异常");
            log.error("权限异常!", e);
            return new ErrorTip(BizExceptionEnum.NO_PERMITION);
        }
    
        /**
         * 拦截未知的运行时异常
         */
        @ExceptionHandler(RuntimeException.class)
        @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
        @ResponseBody
        public ErrorTip notFount(RuntimeException e) {
            LogManager.me().executeLog(LogTaskFactory.exceptionLog(ShiroKit.getUser().getId(), e));
            getRequest().setAttribute("tip", "服务器未知运行时异常");
            log.error("运行时异常:", e);
            return new ErrorTip(BizExceptionEnum.SERVER_ERROR);
        }
    
        /**
         * session失效的异常拦截
         */
        @ExceptionHandler(InvalidSessionException.class)
        @ResponseStatus(HttpStatus.BAD_REQUEST)
        public String sessionTimeout(InvalidSessionException e, Model model, HttpServletRequest request, HttpServletResponse response) {
            model.addAttribute("tips", "session超时");
            assertAjax(request, response);
            return "/login.html";
        }
    
        /**
         * session异常
         */
        @ExceptionHandler(UnknownSessionException.class)
        @ResponseStatus(HttpStatus.BAD_REQUEST)
        public String sessionTimeout(UnknownSessionException e, Model model, HttpServletRequest request, HttpServletResponse response) {
            model.addAttribute("tips", "session超时");
            assertAjax(request, response);
            return "/login.html";
        }
    
        private void assertAjax(HttpServletRequest request, HttpServletResponse response) {
            if (request.getHeader("x-requested-with") != null
                    && request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")) {
                //如果是ajax请求响应头会有,x-requested-with
                response.setHeader("sessionstatus", "timeout");//在响应头设置session状态
            }
        }
    
    }
    

    项目地址:https://gitee.com/Selegant/logs-demo.git

    展开全文
  • 在工作中我们有时会遇到需要在request中获取请求参数的场景。比如说用来记录追踪日志,排查问题等。 一、当HTTP请求方式为get或delete时,有以下几种方式: 1.获取url中所有参数 request.getQueryString(); 2...
  • java中的request获取所有请求参数

    千次阅读 2018-07-10 13:56:44
    Enumeration em = request.getParameterNames(); while (em.hasMoreElements()) { String name = (String) em.nextElement(); String value = req.getParameter(name);}根据参数获取参数
  • 获取request请求中的流,将取出来的字符串保存在缓存中,同时再将该字符串再次转换成流,然后把它放入到新request对象中。 if ( requestWrapper == null ) { chain . doFilter ( request , response ) ;...
  • 今天搞了一个AOP的管理日志,蛋疼的很....老规矩贴代码吧 首先除了aop的包以外需要这三个包。自行度娘。(如果想切入controllers,请将这个代码写入你的mvc配置中,纠结了一上午切不进去就是这个原因.)(method为你...
  • 这个工具类可以实现每次请求接口,获取必要参数, 比如ip地址 方法名 接口名 接口参数方便你定位问题 还有一个特别重要的就是返回参数 我们可以通过AOP 的 @AfterReturning注解实现查看接口 返回参数内容 这里友情...
  • java操作日志实现

    千次阅读 2019-07-25 11:04:46
    以下是基于springboot+springcloud实现的操作日志功能 第一步:定义日志注解SysLog /** * 操作日志注解 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ...
  • 方便在后台日志直接看到请求参数等信息,可以快速定位bug原因 @Aspect @Configuration @Slf4j public class LogAspect { @Autowired private RedisOperate redisOperate; @Pointcut("execution(* ...
  • 默认输出日志打印,对往后续运维至关重要,请求一个Restfull接口的时,顺便打印些重要信息保存到日志记录 下面做一个简单的例子,可根据项目的调整 : import com.alibaba.fastjson.JSON; import lombok.extern.slf4j...
  • 通过过滤器OR拦截器参http请求进行拦截和过滤时,进行打印 HttpServletRequest ...//获取request对象 String rUrl = request.getRequestURI();//得到请求URL String rMet = request.getMethod();//请求方式po...
  • 最近有一个需要从接口请求参数后,打印日志,进行接口参数记录。 这里记录一下处理过程中出现的问题。 首先想到的就是request.getParameter(String )方法,但是这个方法只能在get请求中取到参数,post是不行的,...
  •  在项目开发已经完成多半的情况下,需要开发进行操作日志功能的开发,由于操作的重要性,需要记录下操作前的参数请求时的参数, 在网上找了很多,没找到可行的方法.由于操作日志用注解方式的AOP记录操作日志比较便捷,...
  • * 根据方法和传入的参数获取请求参数 */ private Object getParameter(Method method, Object[] args) { List<Object> argList = new ArrayList(); Parameter[] parameters = method.getParameters(); for ...
  • Tomcat日志记录post请求参数

    千次阅读 2020-04-26 22:51:00
    但是tomcat的访问日志默认是只能够记录get请求的请求参数的,因此我们需要做一些改动 首先是修改conf/server.xml文件中的内容,在Host标签下加入 这里简单介绍一下pattern的几个参数的含义 %a 这是记录访问者的IP,...
  • 1.请求示例 //通过用户ID获取用户信息 @DoSomething(key="#id" , cacheName=CACHE_NAME,needLog=true) public TUser getUserById(String id) { return tUserDao.queryById(Integer.parseInt(id));//核心代码 ...
  • Spring AOP日志记录接口请求参数,执行时间

    千次阅读 热门讨论 2018-07-19 17:53:48
    本文用spring aop方式对请求拦截,获取请求参数以及计算接口执行时间。注意:所需的环境以及依赖有:spring各包, jdk1.8,org.slf4j.Logger (请执行导入) 前言 在前后端分离的项目中,常因为不知道是前端还是...
  • 1,如何记录用户操作日志。 2,更加深入了解Spring的面向切面编程。 3,更加了解自定义注解类。 具体实现步骤大致四步: 1,创建日志记录实体和数据表。 2,自定义注解类。 3,创建切面类用于写日志记录的具体...
  • java实现日志操作记录

    千次阅读 2019-07-09 09:19:16
    //请求参数 String[] parameterNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames(); StringBuilder sb = null; if (Objects.nonNull(parameterNames)) { sb = new StringBuilder(); ...
  • t;&gt;&gt;&...1、获取当前项目请求URL的完整链接地址 String requestUrl = req.getScheme() //当前链接使用的协议 +"://" + req.getServerName()//服务器地址 + ":
  • java Web工程实现操作日志记录的方式有很多,比如通过spring aop方式实现,也可以通过Filter方式实现。 public class StoreLogFilter implements Filter { private static final Logger logger = LoggerFactory....
  • import java.lang.annotation.*; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface LoggerManage { /** * 说明 * @return */ public String description(); ...
  • Java编写的山寨QQ,多人聊天+用户在线 21个目标文件 摘要:JAVA源码,媒体网络,山寨QQ,Java聊天程序 Java编写的山寨QQ,多人聊天+用户在线,程序分服务端和客户端,典型C/S结构, 当用户发送第一次请求的时候,验证...
  • 用SpringAOP获取用户操作日志入库

    千次阅读 2018-08-20 19:23:43
    切service层中所有的方法,将有自定义注解的方法的操作日志入库,其中需要注意的几点: 注意aspectjweaver.jar包的版本,一般要1.6以上版本,否则会报错 注意是否使用了双重代理,spring.xml中不需要配置切面类的&...
  • 经常测试人员过来告诉你接口又又又又报错了, 有时小程序或其它客户端不好抓包,这时不如自己直接在后台日志中直接打印url 和json .但是springboot 的aop无法打印出入参的json ,这时首先想到的就是filter 中打印出入参...
  • Android Web检查器 受Google Chrome DevTool的启发,为开发人员提供了许多...首先,我们使用Java创建一个Javascript接口,当调用JS函数时,它将在Java中触发该函数,这对于存储从拦截结果中获取的数据很有用。 class

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 134,778
精华内容 53,911
关键字:

java获取操作日志的请求参数

java 订阅