spring boot(6)打印日志log和前台抛错

1.pom.xml (注意,这里要把spring boot自己依赖的log.jar包去掉不然报错)

Caused by: java.lang.IllegalStateException: Detected both log4j-over-slf4j.jar AND bound slf4j-log4j12.jar on the class path, preempting StackOverflowError. See also http://www.slf4j.org/codes.html#log4jDelegationLoop for more details.

at org.slf4j.impl.Log4jLoggerFactory.

去掉方法

<exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-logging</artifactId>
				</exclusion>
			</exclusions>
 <!-- 核心模块,包括自动配置支持、日志和YAML -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <!--   Spring Boot在所有内部日志中使用Commons Logging,我们其使用其他日志时,需要在spring-boot-starter依赖上 exclusions来排除不需要的依赖。-->
            <!--<exclusions>-->
                <!--<exclusion>-->
                    <!--<groupId>org.springframework.boot</groupId>-->
                    <!--<artifactId>spring-boot-starter-logging</artifactId>-->
                <!--</exclusion>-->
            <!--</exclusions>-->
            <exclusions>
            	<exclusion>
            		<artifactId>spring-boot-starter-logging</artifactId>
            		<groupId>org.springframework.boot</groupId>
            	</exclusion>
            </exclusions>
        </dependency>

  

<!-- spring boot 使用Thymeleaf模板引擎渲染web依赖
            spring boot 官方推荐
         -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!--
           Spring Boot在所有内部日志中使用Commons Logging,我们其使用其他日志时,需要在spring-boot-starter依赖上 exclusions来排除不需要的依赖。
           <exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-logging</artifactId>
				</exclusion>
			</exclusions>
        -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j</artifactId>
            <version>1.3.2.RELEASE</version>
        </dependency>

        <!-- aop相关依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

  2. application.properties

#Servlet端口号
server.port=8088


# AOP
# Add @EnableAspectJAutoProxy.
spring.aop.auto=true

# Whether subclass-based (CGLIB) proxies are to be created (true) as opposed to standard Java interface-based proxies (false).
# 即当我们需要使用CGLIB来实现AOP的时候,需要配置spring.aop.proxy-target-class=true,不然默认使用的是标准Java的实现。
spring.aop.proxy-target-class=false

  3.log4j.properties

# LOG4J配置
#OFF,systemOut,logFile,logDailyFile,logRollingFile,logMail,logDB,ALL
#  level是日志记录的优先级,分为OFF,TRACE,DEBUG,INFO,WARN,ERROR,FATAL,ALL
#  Log4j建议只使用四个级别,优先级从低到高分别是DEBUG,INFO,WARN,ERROR ,注:log4j.rootLogger 给定的级别会继承,且重定义级别不能优先于父定义的级别
#  systemOut,logFile,logDailyFile,logRollingFile 指定日志信息输出到哪个地方;
log4j.rootLogger=DEBUG,systemOut,logFile,logDailyFile,logRollingFile

#输出到控制台(控制台)
log4j.appender.systemOut= org.apache.log4j.ConsoleAppender
log4j.appender.systemOut.layout= org.apache.log4j.PatternLayout
log4j.appender.systemOut.layout.ConversionPattern= [%-5p][%-22d{yyyy-MM-dd HH:mm:ssS}][%l]%n%m%n
#指定日志消息的输出最低层次
log4j.appender.systemOut.Threshold= DEBUG
log4j.appender.systemOut.ImmediateFlush= TRUE
log4j.appender.systemOut.Target= System.out

#输出到文件(文件)
log4j.appender.logFile= org.apache.log4j.FileAppender
log4j.appender.logFile.layout= org.apache.log4j.PatternLayout
log4j.appender.logFile.layout.ConversionPattern= [%-5p][%-22d{yyyy-MM-dd HH:mm:ssS}][%l]%n%m%n
log4j.appender.logFile.Threshold= DEBUG
log4j.appender.logFile.ImmediateFlush= TRUE
log4j.appender.logFile.Append= TRUE
log4j.appender.logFile.File=logs/log4j.log
log4j.appender.logFile.Encoding= UTF-8

#按DatePattern输出到文件(每天产生一个日志文件)
log4j.appender.logDailyFile= org.apache.log4j.DailyRollingFileAppender
log4j.appender.logDailyFile.layout= org.apache.log4j.PatternLayout
log4j.appender.logDailyFile.layout.ConversionPattern= [%-5p][%-22d{yyyy-MM-dd HH:mm:ssS}][%l]%n%m%n
log4j.appender.logDailyFile.Threshold= DEBUG
log4j.appender.logDailyFile.ImmediateFlush= TRUE
log4j.appender.logDailyFile.Append= TRUE
log4j.appender.logDailyFile.File= logs/log4j
log4j.appender.logDailyFile.DatePattern= '_'yyyy-MM-dd'.log'
log4j.appender.logDailyFile.Encoding= UTF-8

#设定文件大小输出到文件(文件大小到达指定尺寸的时候产生一个新的文件)
log4j.appender.logRollingFile= org.apache.log4j.RollingFileAppender
log4j.appender.logRollingFile.layout= org.apache.log4j.PatternLayout
log4j.appender.logRollingFile.layout.ConversionPattern= [%-5p][%-22d{yyyy-MM-dd HH:mm:ssS}][%l]%n%m%n
log4j.appender.logRollingFile.Threshold= DEBUG
log4j.appender.logRollingFile.ImmediateFlush= TRUE
log4j.appender.logRollingFile.Append= TRUE
log4j.appender.logRollingFile.File= logs/log4j.log
log4j.appender.logRollingFile.MaxFileSize= 1MB
log4j.appender.logRollingFile.MaxBackupIndex= 10
log4j.appender.logRollingFile.Encoding= UTF-8

  4.Application.java

package com.guilf;



import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


/**
 * 注:启动类不要放在main/java 根目录下,启动会报错
 */
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

  5.WebLogAspect.java

package com.guilf.aspect;

import org.apache.tomcat.util.http.fileupload.RequestContext;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestHeader;
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.util.Arrays;
import java.util.Date;

/**
 * 日志切面类.
 * Created by hong on 2017/5/19.
 */

/**
 * 可以使用@Order注解指定切面的优先级,值越小优先级越高
 **/
@Order(2)
/**
 * 注解将一个java类定义为切面类
 **/
@Aspect
@Component
public class WebLogAspect {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 根据需要在切入点不同位置的切入内容:
     *     使用 @Before 在切入点开始处切入内容 ( 前置通知 )
     *     使用 @After 在切入点结尾处切入内容 ( 后置通知 )
     *     使用 @AfterReturning 在切入点return内容之后切入内容(可以用来对处理返回值做一些加工处理) (  配置后置返回通知 )
     *     使用 @Around 在切入点前后切入内容,并自己控制何时执行切入点自身的内容 (  环绕通知 )
     *     使用 @AfterThrowing 用来处理当切入内容部分抛出异常之后的处理逻辑 (  异常通知 )
     */


    /**
     * 定义个方法,注解上@Pointcut 及其规则表达式,定义成一个切入点(如下例中某个package下的所有函数,也可以是一个注解等。);
     * Controller层切点
     */
    @Pointcut("execution(public * com.guilf.mvc..*.*(..))")
    public void webLog() {
    }


    /**
     * 前置通知 用于拦截Controller层记录的参数
     *
     * @param joinPoint
     * @Before 接收的参数是前面定义的切入点方法
     */
    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) {
        logger.info("==========执行 weblog() 切入点 前置通知===============");

        // 接收到请求,记录请求内容
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();

        // 记录下请求内容
        logger.info("URL : " + request.getRequestURL().toString());
        logger.info("HTTP_METHOD : " + request.getMethod());
        logger.info("IP : " + request.getLocalAddr());
        logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
    }

    /**
     * 后置通知
     */
    @After("webLog()")
    public void after(JoinPoint joinPoint) {
        logger.info("==========执行 weblog() 切入点 后置通知===============");
        logger.info("PARAM : " + Arrays.toString(joinPoint.getArgs()));
    }


    /**
     * 环绕通知 用来监控目标执行前后情况(例如:用来监控切入点执行时间).
     * 注: 在使用@Around 时,需要有返回值,不然同时使用 @AfterReturning 获取不到返回参数 .
     * 环绕通知需要携带ProceedingJoinPoint类型的参数
     *
     * @param joinPoint
     */
//    @Around("webLog()")
//    public Object around(ProceedingJoinPoint joinPoint) {
//        logger.info("[==========开始 weblog() 切入点 环绕通知===============]");
//
//        long start = System.currentTimeMillis();
//        Object ret = null;
//        try {
//            // 环绕通知 ProceedingJoinPoint 执行proceed方法的作用是让目标方法执行
//            // 环绕通知=前置+目标方法执行+后置通知,proceed方法就是用于启动目标方法执行的
//            // 也就是说,环绕通知可以用来代替同时使用前置、后置通知的情况
//            ret = joinPoint.proceed();
//            long end = System.currentTimeMillis();
//
//            // 其作用是因为Debug,Info和Trace一般会打印比较详细的信息,而且打印的次数较多,如果我们不加log.isDebugEnabled()等
//            // 进行预先判断,当系统loglevel设置高于Debug或Info或Trace时,虽然系统不会打应出这些级别的日志,但是每次预先拼接log打印中的参数字符串,影响系统的性能。
//            if (logger.isInfoEnabled()) {
//                logger.info("监控到========= " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName() + "执行时间:" + (end - start) + "ms!");
//            }
//            logger.info("[==========结束 weblog() 切入点 环绕通知===============]");
//        } catch (Throwable throwable) {
//            throwable.printStackTrace();
//        }
//
//        return ret;
//    }


    /**
     * 后置返回通知 用来监控返回值
     */
    @AfterReturning(pointcut = "webLog()", returning = "ret")
    public void afterReturn(JoinPoint joinPoint, Object ret) {
        logger.info("==========开始 weblog() 切入点 环绕通知===============");
        logger.info("==========开始 weblog() 切入点 环绕通知===============");
        logger.info("=========监控到 " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName() + "返回的值:");
        logger.info(ret.toString());
    }


    /**
     * 异常通知 用于拦截异常,记录日志
     *
     * @param joinPoint
     * @param ex
     */
    @AfterThrowing(pointcut = "webLog()", throwing = "ex")
    public void AfterThrowing(JoinPoint joinPoint, Throwable ex) {
        logger.info("==========开始 weblog() 切入点 异常通知===============");
        logger.info("=========监控到 " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        logger.info("发生异常: " + ex.getMessage());
        logger.info("请求参数: ");
       // Stream.of(joinPoint.getArgs()).forEach(arg -> logger.info(arg.toString()));
        logger.info("异常时间: " + new Date());
    }

}

  6.HelloController.java

package com.guilf.mvc;

import com.guilf.exception.MyException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {


    @RequestMapping("/helloEx")
    public String hello() throws Exception {
        throw   new Exception("发生异常");
    }


    @RequestMapping("myhello")
    public String myHello() throws MyException {
        throw  new MyException("发生异常");
    }

    @RequestMapping("/json")
    @ResponseBody
    public String json(){
        return "json";
    }


    @RequestMapping("/index")
    public String index(){
        return "index";
    }

}

  7.启动的话可以看到打印的日志。日志在项目里,log会记录日志,

 8.前台抛错

9. ErrorInfo.java

package com.guilf.dto;

public class ErrorInfo<T> {

    public static final Integer OK = 0;
    public static final Integer ERROR = 500;

    private Integer code;
    private String message;
    private String url;
    private T data;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public static Integer getOK() {
        return OK;
    }

    public static Integer getERROR() {
        return ERROR;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
    
}

  10.MyException.java

package com.guilf.exception;


public class MyException extends Exception {

    public MyException(String message) {
        super(message);
    }
}

  11.MyExceptionHandler.java

package com.guilf.exception;

import com.guilf.dto.ErrorInfo;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;

/**
 * @ClassName: MyExceptionHandler
 * @Description: (统一异常处理)
 * 
 * @version v1.1
 */
@ControllerAdvice
public class MyExceptionHandler {


    /**
     * 异常处理, 返回视图
     * @param req
     * @param e
     * @return
     * @throws Exception
     */
    @ExceptionHandler(value = Exception.class)
    public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("exception", e);
        modelAndView.addObject("url", req.getRequestURL());
        modelAndView.setViewName("error");
        return modelAndView;
    }


    /**
     * 异常处理,返回自定义的异常对象json
     * @param req
     * @param e
     * @return
     * @throws Exception
     */
    @ExceptionHandler(value = MyException.class)
    @ResponseBody
    public ErrorInfo<String> jsonErrorHandler(HttpServletRequest req, MyException e) throws Exception {
        ErrorInfo<String> r = new ErrorInfo<>();
        r.setMessage(e.getMessage());
        r.setCode(ErrorInfo.ERROR);
        r.setData("Some Data");
        r.setUrl(req.getRequestURL().toString());
        return r;
    }



    @ModelAttribute
    public Model newUser(Model model) {
        System.out.println("============应用到所有@RequestMapping注解方法,在其执行之前把返回值放入Model");
        model.addAttribute("user","guilf");
        return model;
    }

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        System.out.println("============应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器");
    }

}

  12 error.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>Title</title>
</head>
<body>
 请求地址:
 <span th:text="${url}"></span>
 <p>发生了异常...</p>
</body>
</html>

  13 index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>Title</title>
</head>
<body>
hello world!
</body>
</html>

  

log日志

猜你喜欢

转载自www.cnblogs.com/guilf/p/9415586.html