1. 统一异常处理

在util包中添加,在出现异常时,java后端会进行异常处理, 打印异常信息,就不需要在controller层进行try{}catch{}

package com.ffyc.news.util;

import com.ffyc.news.model.Result;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

//基于AOP实现 全局 的统一异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 异常处理通知,当controller中的方法出现异常,执行该方法
     */
    @ExceptionHandler(Exception.class)
    public Result globalException(Exception e) {
        Result commonResult = new Result(500,"服务器忙,请稍后再试",e.getMessage());
        //测试期间
        e.printStackTrace();
        return commonResult;
    }
}

2. 日志功能

1. 概述

       日志可以对程序运行的过程进行检测,尤其在生产环境中,由于生产环境中没有控制台,需要把程序运行产生的一些数据存储到日志文件中,便于后期排查错误

2. 日志需要记录哪些信息(常问)

1.记录参数数据 例如进入某个方法,需要接受的参数,将参数进行保存

2.记录程序运行轨迹 进入不同的方法,打印不同日志 (先启动啥,然后初始化了啥,接下来干了啥.......)

3.记录异常信息 

3. 如何添加日志

(1) 用IO流将异常 参数 步骤信息等输出到指定文件中

(2) 通过市面上的日志组件,实现日志保存功能

市面上常用的日志组件:

slf4j(Simple Logging Facade for Java)

commons-logging   接口

Log4J

Log4J2

Logback

JUL(Java Utils Logging

在applicantion.yml中添加日志配置

logging:
   level:
    com.ffyc.news: debug   # 打印日志的文件 : 级别
  file:
    name: D:/log/log.log  # 日志文件打印地址

日志的级别划分:debug<info<warn<error 日志会打印自身及以上级别的信息

方法一:

其余信息在 logback 配置文件中 在类中使用 ,创建 Logger 对象

private static Logger logger = LoggerFactory.getLogger(当前类名.class);

在需要的位置调用具体的日志级别方法输出

logger.debug("user account:{},user password:{}", user.getAccount(),user.getPassword());

logger.info("user account:{},user password:{}", user.getAccount(),user.getPassword());

logger.warn("user account:{},user password:{}", user.getAccount(),user.getPassword());logger.error("user account:{},user password:{}", user.getAccount(),user.getPassword());

package com.ffyc.news.web;

import com.ffyc.news.model.Admin;
import com.ffyc.news.model.Result;
import com.ffyc.news.service.LoginService;
import com.ffyc.news.util.JWTUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;

//服务器
@RestController
@RequestMapping(path = "/api/loginCtl")
public class LoginController {
    //日志定义
    private static Logger logger = LoggerFactory.getLogger(LoginController.class);

    @Autowired
    private LoginService loginService;

    @PostMapping(path="/login")
    public Result login(@RequestBody Admin admin){
        
        //日志打印
        logger.info("enter login method");
        logger.debug("login account:{},password:{}",admin.getAccount(),admin.getPassword());
        logger.error("系统忙,请稍后再试");
        
        //参数保存
        admin = loginService.login(admin);
        //System.out.println(1/0);
        //判断登录是否成功
        if(admin==null){
            return new Result(201,"登录失败",null);
        }else {
            //登录成功,为管理员提供token
            String token = JWTUtil.getToken(admin);//为当前admin提供一个token
            admin.setToken(token);//将提供的token set到 admin对象里面
            return new Result(200,"登录成功",admin);
        }
    }
    @GetMapping(path = "/test")
    public String test(){
        System.out.println("test");
        return "success";
    }
    /*
    查询管理员菜单
     */
    @GetMapping(path = "/menus")
    public Result menus(@RequestHeader("token") String token){

        ArrayList menus=loginService.menus(token);

        return new Result(200,"查询成功",menus);

    }

}

方法二:  使用 AOP 统一打印日志

导入依赖 jar

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-aop</artifactId>

</dependency>

定义切面通知类

package com.ffyc.news.util;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;

@Component
@Aspect
public class LogAspect {
    private Logger logger = LoggerFactory.getLogger(LogAspect.class);
    //                   任意返回值  web包下任意类 任意方法
    @Before("execution(public * com.ffyc.news.web.*.*(..))")
    public void savelog(JoinPoint joinPoint) {
        ServletRequestAttributes attributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        Object[] objs = joinPoint.getArgs();//获取方法参数

        logger.info("method args:{}", Arrays.toString(objs));
        // 记录下请求内容
        logger.info("HTTP_METHOD :{} ", request.getMethod());
        logger.info("IP : {}", request.getRemoteAddr());//客户端 ip
    }
}

3. 集成 Swagger 在线文档 

1.概述

(1)api 文档:  目前开发是前后端分离的 ,后端开发人需要为前端开发人员提供一个api说明文档

(2)前提:   当代码修改时,也需要修改api文档 ,频繁修改文档,不方便 

(3)Swagger好处:           

使用Swagger可以直接通过代码生成文档,不需要自己手动编写接口文档

Swagger 生成的文档支持在线测试

(提供Web页面在线测试API参数和格式都定好了,直接在界面上输入参数的值即可在线测试)     

本次使用 knife4j (前身swagger-bootstrap-ui)实现接口文档生成

文档访问地址:http://ip:端口/doc.html

2.导入jar依赖

<dependency>

<groupId>com.github.xiaoymin</groupId><artifactId>knife4j-openapi2-spring-boot-starter</artifactId>

<version>4.4.0</version>

</dependency>

3.添加配置类

package com.ffyc.news.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

@Configuration//配置类,启动自动扫扫描
@EnableSwagger2WebMvc
public class Knife4jConfiguration {

    @Bean(value = "dockerBean")
    public Docket dockerBean() {
        //指定使用Swagger2规范
        Docket docket=new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(new ApiInfoBuilder()
                        //描述字段支持Markdown语法
                        .description("# Knife4j RESTful APIs")
                        .termsOfServiceUrl("https://doc.xiaominfo.com/")
                        .contact("xiaoymin@foxmail.com")
                        .version("1.0")
                        .build())
                //分组名称
                .groupName("用户服务")
                .select()
                //这里指定Controller扫描包路径
                .apis(RequestHandlerSelectors.basePackage("com.ffyc.news.web"))
                .paths(PathSelectors.any())
                .build();
        return docket;
    }
}

4. 注解介绍

Swagger 使用的注解及其说明

@Api:用在类上,说明该类的作用,tags 类的功能进行描述.

@Api(tags="用户登录控制器")

@ApiOperation:用在方法上,用于对方法功能说明。

@ApiOperation(value="方法概述")

@ApiImplicitParam:用来注解来给方法入参增加说明

@ApiModel:描述一个 Model 的信息(参数为实体类时使用)

@ApiModelProperty:描述一个 model 的属性

@ApiResponses:用于表示一组响应

@ApiResponse:用在@ApiResponses 中,一般用于表达响应信息

5. 测试

package com.ffyc.news.web;
//服务器
import com.ffyc.news.model.Admin;
import com.ffyc.news.model.Result;
import com.ffyc.news.service.LoginService;
import com.ffyc.news.util.JWTUtil;
import io.swagger.annotations.*;
import org.aspectj.apache.bcel.classfile.Code;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;

@Api("管理登录处理器")
@RestController
@RequestMapping(path = "/api/loginCtl")
public class LoginController {
    //日志定义
    private static Logger logger = LoggerFactory.getLogger(LoginController.class);

    @Autowired
    private LoginService loginService;

    @ApiOperation("管理员登录接口")
    @ApiResponses({
            @ApiResponse(code = 200,message = "响应成功"),
            @ApiResponse(code = 200,message = "响应成功"),
            @ApiResponse(code = 200,message = "响应成功"),
            @ApiResponse(code = 200,message = "响应成功"),

    })
    @PostMapping(path="/login")
    public Result login(@RequestBody Admin admin){

        //日志打印
        logger.info("enter login method");
        logger.debug("login account:{},password:{}",admin.getAccount(),admin.getPassword());
        logger.error("系统忙,请稍后再试");

        //参数保存
        admin = loginService.login(admin);
        //System.out.println(1/0);
        //判断登录是否成功
        if(admin==null){
            return new Result(201,"登录失败",null);
        }else {
            //登录成功,为管理员提供token
            String token = JWTUtil.getToken(admin);//为当前admin提供一个token
            admin.setToken(token);//将提供的token set到 admin对象里面
            return new Result(200,"登录成功",admin);
        }
    }

    @GetMapping(path = "/test")
    public String test(){
        System.out.println("test");
        return "success";
    }

    /**
    查询管理员菜单
     */
    @ApiOperation("查询管理员权限菜单")
    @ApiImplicitParams({
            @ApiImplicitParam(name="token",value = "管理员token",required = true,type = "String")

    })
    
    @GetMapping(path = "/menus")
    public Result menus(@RequestHeader("token") String token){

        ArrayList menus=loginService.menus(token);

        return new Result(200,"查询成功",menus);

    }

}

文档访问地址:http://ip:端口/doc.html

4.定时任务

(1)实现方式:

方式 1: 使用 java 自带的 TimerTask,Timer

public static void main(String[] args) {

// 定义一个任务

TimerTask timerTask = new TimerTask() {

@Override

public void run() {

System.out.println("打印当前时间:" + new Date());

}

};

// 计时器

Timer timer = new Timer();

// 开始执行任务 (延迟 1000 毫秒执行,每 3000 毫秒执行一次)

timer.schedule(timerTask, 1000, 3000);

}

方式 2: 使用 spring 框架中提供的定时任务

a.开启定时任务

在 SpringBoot 的启动类上声明 @EnableScheduling

b.添加定时任务

只需使用@Scheduled 注解标注即可,Spring Boot 启动后会自动加载并执行定时任务,无需手动操作

@Component

public class TestTask {

@Scheduled(cron = "*/6 * * * * ?")//每六秒执行一次

private void process() {

System.out.println("现在时间:" + new Date());

}

}

https://cron.qqe2.com

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐