Day224.医院设置需求、医院模块开发 -尚医通

尚医通

一、医院设置需求

1、需求

医院设置主要是用来保存开通医院的一些基本信息,每个医院一条信息,保存了医院编号(平台分配,全局唯一)和接口调用相关的签名key等信息,是整个流程的第一步,只有开通了医院设置信息,才可以上传医院相关信息。

我们所开发的功能就是基于单表的一个CRUD、锁定/解锁和发送签名信息这些基本功能。

2、表结构

image-20210318154226332

#
# Database "yygh_hosp"
#

CREATE DATABASE IF NOT EXISTS `yygh_hosp` CHARACTER SET utf8mb4;
USE `yygh_hosp`;

#
# Structure for table "hospital_set"
#

CREATE TABLE `hospital_set` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
  `hosname` varchar(100) DEFAULT NULL COMMENT '医院名称',
  `hoscode` varchar(30) DEFAULT NULL COMMENT '医院编号',
  `api_url` varchar(100) DEFAULT NULL COMMENT 'api基础路径',
  `sign_key` varchar(50) DEFAULT NULL COMMENT '签名秘钥',
  `contacts_name` varchar(20) DEFAULT NULL COMMENT '联系人',
  `contacts_phone` varchar(11) DEFAULT NULL COMMENT '联系人手机',
  `status` tinyint(3) NOT NULL DEFAULT '0' COMMENT '状态',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `is_deleted` tinyint(3) NOT NULL DEFAULT '0' COMMENT '逻辑删除(1:已删除,0:未删除)',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_hoscode` (`hoscode`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='医院设置表';

二、医院模块开发

1、 搭建医院模块service-hosp

1.1 搭建service-hosp

点击service,选择New–>Module,操作如下

image-20210318154727643

选择下一步

image-20210318154733856

选择下一步

image-20210318154739157

完成,结构如下:

image-20210318154800560

1.2 修改配置

1、修改pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>service</artifactId>
        <groupId>com.achang</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <packaging>jar</packaging>

    <artifactId>service-hosp</artifactId>
    <name>service-hosp</name>
    <description>service-hosp</description>

    <dependencies>
        <dependency>
            <groupId>com.achang</groupId>
            <artifactId>model</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>service-hosp</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

2、添加配置文件application.properties

#服务端口
server.port=8201

#服务名
spring.application.name=service-hosp

#环境设置
spring.profiles.active=dev

#mysql数据库连接
spring.datasource.url="jdbc:mysql://localhost:3306/yygh_hosp?characterEncoding=utf-8&useSSL=false"
spring.datasource.username=root
spring.datasource.password=00000
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

#返回json的全局时间格式
spring.jackson.time-zone=GMT+8
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss

##配置mapper.xml文件的路径
#mybatis-plus.mapper-locations=classpath:com.achang.yygh.mapper/xml/*.xml

##nacos服务地址
#spring.cloud.nacos.discovery.server-addr=localhost:8848
#
##开启sentinel
#spring.cloud.sentinel.enabled=true
#
##设置sentinel地址
#spring.cloud.sentinel.transport.dashboard=http://localhost:8858
#
##mongodb地址
#spring.data.mongodb.host=localhost
#spring.data.mongodb.port=27017
#spring.data.mongodb.database=yygh_hosp
#
##rabbitmq地址
#spring.rabbitmq.host=localhost
#spring.rabbitmq.port=5672
#spring.rabbitmq.username=guest
#spring.rabbitmq.password=guest

1.3 添加启动类

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

2、添加医院设置CURD

2.1 添加model

image-20210318162803814

说明:由于实体对象没有逻辑,我们已经统一导入

com.achang.yygh.model.hosp.HospitalSet

2.2 添加Mapper

添加com.achang.yygh.hosp.mapper.HospitalSetMapper

@Mapper
public interface HospitalSetMapper extends BaseMapper<HospitalSet> {
    
    
}
  • xml
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.achang.yygh.hosp.mapper.HospitalSetMapper">
</mapper>

2.3 添加service接口及实现类

  • 接口
public interface HospitalSetService extends IService<HospitalSet> {
    
    
}
  • impl
@Service
public class HospitalSetServiceImpl extends ServiceImpl<HospitalSetMapper, HospitalSet> implements HospitalSetService  {
    
    
}

2.4 添加controller

@RestController
@RequestMapping("/admin/hosp/hospitalSet")
public class HospitalSetController {
    
    
    @Autowired
    private HospitalSetService hospitalSetService;
}

2.5 医院设置CRUD

由于com.baomidou.mybatisplus.extension.service.impl.ServiceImpl类已经默认实现 了单表的CRUD,分页查询也有默认实现,能够更加灵活和代码简洁把分页查询功能实现。

2.6 添加controller方法

@RestController
@RequestMapping("/admin/hosp/hospitalSet")
public class HospitalSetController {
    
    
    @Autowired
    private HospitalSetService hospitalSetService;

    //查询医院设置表的所有信息
    @GetMapping("/getAll")
    public List<HospitalSet> getAll(){
    
    
        return hospitalSetService.list();
    }

    //逻辑删除医院
    @DeleteMapping("/deleteHospitalById/{id}")
    public boolean deleteHospitalById(@PathVariable Long id){
    
    
        return hospitalSetService.removeById(id);
    }

    //多条件分页查询
    @PostMapping("/findPageCondition/{page}/{limit}")
    public Page<HospitalSet> findPageCondition(@PathVariable long page,
                                  @PathVariable long limit,
                                  @RequestBody(required = false)HospitalSetQueryVo hospitalSetQueryVo){
    
    
        Page<HospitalSet> hospitalSetPage = new Page<>(page, limit);
        QueryWrapper<HospitalSet> wrapper = new QueryWrapper<>();
        String hoscode = hospitalSetQueryVo.getHoscode();
        String hosname = hospitalSetQueryVo.getHosname();

        //判断是否有传入医院编号
        if (!StringUtils.isEmpty(hoscode)){
    
    
            wrapper.eq("hoscode",hoscode);
        }
        //判断是否有传入医院名称
        if (!StringUtils.isEmpty(hosname)){
    
    
            wrapper.like("hosname",hosname);
        }

        //分页查询
        Page<HospitalSet> pageHospitalSet  = hospitalSetService.page(hospitalSetPage, wrapper);

        return pageHospitalSet;
    }

    //添加医院设置
    @PostMapping("addHospitalSet")
    public boolean addHospitalSet(@RequestBody HospitalSet hospitalSet){
    
    
        //设置状态: 1使用 , 0不能使用
        hospitalSet.setStatus(1);
        //设置签名秘钥
        Random random = new Random();
        hospitalSet.setSignKey(MD5.encrypt(System.currentTimeMillis()+""+random.nextInt(1000)));

        return hospitalSetService.save(hospitalSet);
    }

    //根据id获取医院设置
    @GetMapping("getHospitalSetById/{id}")
    public HospitalSet getHospitalSetById(@PathVariable Long id){
    
    
        return hospitalSetService.getById(id);
    }

    //修改医院设置
    @PostMapping("/updateHospital")
    public boolean updateHospital(@RequestBody HospitalSet hospitalSet){
    
    
        return hospitalSetService.updateById(hospitalSet);
    }

    //批量删除医院设置
    @DeleteMapping("/deleteBatch")
    public boolean deleteBatch(@RequestBody List<Long> Ids){
    
    
        return hospitalSetService.removeByIds(Ids);
    }

}

3、Swagger2介绍与集成

3.1 swagger2介绍

什么是swagger2

编写和维护接口文档是每个程序员的职责,根据Swagger2可以快速帮助我们编写最新的API接口文档,再也不用担心开会前仍忙于整理各种资料了,间接提升了团队开发的沟通效率。

常用注解

swagger通过注解表明该接口会生成文档,包括接口名、请求方法、参数、返回信息的等等。

@Api:修饰整个类,描述Controller的作用

@ApiOperation:描述一个类的一个方法,或者说一个接口

@ApiParam:单个参数描述

@ApiModel:用对象来接收参数

@ApiModelProperty:用对象接收参数时,描述对象的一个字段

@ApiImplicitParam:一个请求参数

@ApiImplicitParams:多个请求参数

3.2 swagger2集成

3.2.1 项目整合swagger2

在common模块pom.xml引入依赖

<!--swagger-->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
</dependency>

说明:我们在yygh-parent中的pom.xml中添加了版本控制,这里不需要添加版本,已引入就忽略

  • service模块引入service-utils
<dependency>
    <groupId>com.achang</groupId>
    <artifactId>service-util</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

3.2.2 添加swagger2配置类

在service-util模块添加配置类:

com.achang.yygh.common.config.Swagger2Config类

@Configuration
@EnableSwagger2//开启swagger
public class Swagger2Config {
    
    
    @Bean
    public Docket webApiConfig(){
    
    
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("webApi")
                .apiInfo(webApiInfo())
                .select()
                //只显示api路径下的页面
                .paths(Predicates.and(PathSelectors.regex("/api/.*")))
                .build();
    }

    @Bean
    public Docket adminApiConfig(){
    
    
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("adminApi")
                .apiInfo(adminApiInfo())
                .select()
                //只显示admin路径下的页面
                .paths(Predicates.and(PathSelectors.regex("/admin/.*")))
                .build();
    }

    private ApiInfo webApiInfo(){
    
    
        return new ApiInfoBuilder()
                .title("网站-API文档")
                .description("本文档描述了网站微服务接口定义")
                .version("1.0")
                .contact(new Contact("achang", "http://achang.com", "[email protected]"))
                .build();
    }

    private ApiInfo adminApiInfo(){
    
    
        return new ApiInfoBuilder()
                .title("后台管理系统-API文档")
                .description("本文档描述了后台管理系统微服务接口定义")
                .version("1.0")
                .contact(new Contact("achang", "http://achang.com", "[email protected]"))
                .build();
    }

}
  • service-hosp主启动类来扫描swagger配置文件
@SpringBootApplication
@MapperScan("com.achang.yygh.hosp.mapper")
@ComponentScan("com.achang")//扫描swagger
public class ServiceHospMain8201 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(ServiceHospMain8201.class,args);
    }
}
  • 使用同一返回类

com.achang.result.ResultCodeEnum

/**
 * 统一返回结果状态信息类
 */
@Getter
public enum ResultCodeEnum {
    
    

    SUCCESS(200,"成功"),
    FAIL(201, "失败"),
    PARAM_ERROR( 202, "参数不正确"),
    SERVICE_ERROR(203, "服务异常"),
    DATA_ERROR(204, "数据异常"),
    DATA_UPDATE_ERROR(205, "数据版本异常"),

    LOGIN_AUTH(208, "未登陆"),
    PERMISSION(209, "没有权限"),

    CODE_ERROR(210, "验证码错误"),
//    LOGIN_MOBLE_ERROR(211, "账号不正确"),
    LOGIN_DISABLED_ERROR(212, "改用户已被禁用"),
    REGISTER_MOBLE_ERROR(213, "手机号已被使用"),
    LOGIN_AURH(214, "需要登录"),
    LOGIN_ACL(215, "没有权限"),

    URL_ENCODE_ERROR( 216, "URL编码失败"),
    ILLEGAL_CALLBACK_REQUEST_ERROR( 217, "非法回调请求"),
    FETCH_ACCESSTOKEN_FAILD( 218, "获取accessToken失败"),
    FETCH_USERINFO_ERROR( 219, "获取用户信息失败"),
    //LOGIN_ERROR( 23005, "登录失败"),

    PAY_RUN(220, "支付中"),
    CANCEL_ORDER_FAIL(225, "取消订单失败"),
    CANCEL_ORDER_NO(225, "不能取消预约"),

    HOSCODE_EXIST(230, "医院编号已经存在"),
    NUMBER_NO(240, "可预约号不足"),
    TIME_NO(250, "当前时间不可以预约"),

    SIGN_ERROR(300, "签名错误"),
    HOSPITAL_OPEN(310, "医院未开通,暂时不能访问"),
    HOSPITAL_LOCK(320, "医院被锁定,暂时不能访问"),
    ;

    private Integer code;
    private String message;

    private ResultCodeEnum(Integer code, String message) {
    
    
        this.code = code;
        this.message = message;
    }
}
  • com.achang.result.Result
/**
 * 全局统一返回结果类
 */
@Data
@ApiModel(value = "全局统一返回结果")
public class Result<T> {
    
    

    @ApiModelProperty(value = "返回码")
    private Integer code;

    @ApiModelProperty(value = "返回消息")
    private String message;

    @ApiModelProperty(value = "返回数据")
    private T data;

    public Result(){
    
    }

    protected static <T> Result<T> build(T data) {
    
    
        Result<T> result = new Result<T>();
        if (data != null)
            result.setData(data);
        return result;
    }

    public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {
    
    
        Result<T> result = build(body);
        result.setCode(resultCodeEnum.getCode());
        result.setMessage(resultCodeEnum.getMessage());
        return result;
    }

    public static <T> Result<T> build(Integer code, String message) {
    
    
        Result<T> result = build(null);
        result.setCode(code);
        result.setMessage(message);
        return result;
    }

    public static<T> Result<T> ok(){
    
    
        return Result.ok(null);
    }

    /**
     * 操作成功
     * @param data
     * @param <T>
     * @return
     */
    public static<T> Result<T> ok(T data){
    
    
        Result<T> result = build(data);
        return build(data, ResultCodeEnum.SUCCESS);
    }

    public static<T> Result<T> fail(){
    
    
        return Result.fail(null);
    }

    /**
     * 操作失败
     * @param data
     * @param <T>
     * @return
     */
    public static<T> Result<T> fail(T data){
    
    
        Result<T> result = build(data);
        return build(data, ResultCodeEnum.FAIL);
    }

    public Result<T> message(String msg){
    
    
        this.setMessage(msg);
        return this;
    }

    public Result<T> code(Integer code){
    
    
        this.setCode(code);
        return this;
    }

    public boolean isOk() {
    
    
        if(this.getCode().intValue() == ResultCodeEnum.SUCCESS.getCode().intValue()) {
    
    
            return true;
        }
        return false;
    }
}
  • HospitalSetController改造
@RestController
@RequestMapping("/admin/hosp/hospitalSet")
public class HospitalSetController {
    
    
    @Autowired
    private HospitalSetService hospitalSetService;

    //查询医院设置表的所有信息
    @GetMapping("/getAll")
    public Result getAll(){
    
    
        List<HospitalSet> list = hospitalSetService.list();
        return Result.ok(list);
    }

    //逻辑删除医院
    @DeleteMapping("/deleteHospitalById/{id}")
    public Result deleteHospitalById(@PathVariable Long id){
    
    
        boolean flag = hospitalSetService.removeById(id);
        if (flag){
    
    
            return Result.ok();
        }else {
    
    
            return Result.fail();
        }
    }

    //多条件分页查询
    @PostMapping("/findPageCondition/{page}/{limit}")
    public Result findPageCondition(@PathVariable long page,
                                  @PathVariable long limit,
                                  @RequestBody(required = false)HospitalSetQueryVo hospitalSetQueryVo){
    
    
        Page<HospitalSet> hospitalSetPage = new Page<>(page, limit);
        QueryWrapper<HospitalSet> wrapper = new QueryWrapper<>();
        String hoscode = hospitalSetQueryVo.getHoscode();
        String hosname = hospitalSetQueryVo.getHosname();

        //判断是否有传入医院编号
        if (!StringUtils.isEmpty(hoscode)){
    
    
            wrapper.eq("hoscode",hoscode);
        }
        //判断是否有传入医院名称
        if (!StringUtils.isEmpty(hosname)){
    
    
            wrapper.like("hosname",hosname);
        }

        //分页查询
        Page<HospitalSet> pageHospitalSet  = hospitalSetService.page(hospitalSetPage, wrapper);

        return Result.ok(pageHospitalSet);
    }

    //添加医院设置
    @PostMapping("addHospitalSet")
    public Result addHospitalSet(@RequestBody HospitalSet hospitalSet){
    
    
        //设置状态: 1使用 , 0不能使用
        hospitalSet.setStatus(1);
        //设置签名秘钥
        Random random = new Random();
        hospitalSet.setSignKey(MD5.encrypt(System.currentTimeMillis()+""+random.nextInt(1000)));

        boolean flag = hospitalSetService.save(hospitalSet);
        if (flag){
    
    
            return Result.ok();
        }else {
    
    
            return Result.fail();
        }
    }

    //根据id获取医院设置
    @GetMapping("getHospitalSetById/{id}")
    public Result getHospitalSetById(@PathVariable Long id){
    
    
        HospitalSet hospitalSet = hospitalSetService.getById(id);
        return Result.ok(hospitalSet);
    }

    //修改医院设置
    @PostMapping("/updateHospital")
    public Result updateHospital(@RequestBody HospitalSet hospitalSet){
    
    
        boolean flag = hospitalSetService.updateById(hospitalSet);
        if (flag){
    
    
            return Result.ok();
        }else {
    
    
            return Result.fail();
        }
    }

    //批量删除医院设置
    @DeleteMapping("/deleteBatch")
    public Result deleteBatch(@RequestBody List<Long> Ids){
    
    
        boolean flag = hospitalSetService.removeByIds(Ids);
        if (flag){
    
    
            return Result.ok();
        }else {
    
    
            return Result.fail();
        }
    }

}

3.3 使用swagger2测试

访问:http://localhost:8201/swagger-ui.html/

image-20210318185147970


4、医院锁定与解锁

医院锁定后不能再上传数据

4.1 添加controller方法

在HospitalSetController类添加方法

    //医院设置锁定和解锁
    @PutMapping("/lockHospitalSet/{id}/{status}")
    public Result lockHospitalSet(@PathVariable Long id,@PathVariable Integer status){
    
    
        //根据id查询出医院设置信息
        HospitalSet hospitalSet = hospitalSetService.getById(id);
        //设置状态
        hospitalSet.setStatus(status);
        //修改信息
        boolean flag = hospitalSetService.updateById(hospitalSet);
        if (flag){
    
    
            return Result.ok();
        }else {
    
    
            return Result.fail();
        }
    }


    //发送签名秘钥
    @PutMapping("/sendKey/{id}")
    public Result sendKey(@PathVariable Long id){
    
    
        //根据id查询医院设置信息
        HospitalSet hospitalSet = hospitalSetService.getById(id);
        //获取对应的秘钥
        String signKey = hospitalSet.getSignKey();
        String hoscode = hospitalSet.getHoscode();
        //TODO 发送短信
        return Result.ok();
    }

6、全局异常处理

spring boot 默认情况下会映射到 /error 进行异常处理,但是提示并不十分友好,下面自定义异常处理,提供友好展示。

image-20210318214154647

6.1 自定义异常类

我们在搭建模块时在common-util模块已经添加了YyghException类,这里不做解释

/**
 * 自定义全局异常类
 */
@Data
@ApiModel(value = "自定义全局异常类")
public class YyghException extends RuntimeException {
    
    

    @ApiModelProperty(value = "异常状态码")
    private Integer code;

    /**
     * 通过状态码和错误消息创建异常对象
     * @param message
     * @param code
     */
    public YyghException(String message, Integer code) {
    
    
        super(message);
        this.code = code;
    }

    /**
     * 接收枚举类型对象
     * @param resultCodeEnum
     */
    public YyghException(ResultCodeEnum resultCodeEnum) {
    
    
        super(resultCodeEnum.getMessage());
        this.code = resultCodeEnum.getCode();
    }

    @Override
    public String toString() {
    
    
        return "YyghException{" +
                "code=" + code +
                ", message=" + this.getMessage() +
                '}';
    }
}

6.2 添加全局异常处理类

在service-util模块添加全局异常处理类

//全局异常处理类
@ControllerAdvice
public class GlobalExceptionHandler {
    
    

    //出什么异常会执行这个方法
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result error(Exception e){
    
    
        e.printStackTrace();
        return Result.fail();
    }

    /**
     * 自定义异常处理方法
     * @param e
     * @return
     */
    @ExceptionHandler(YyghException.class)
    @ResponseBody
    public Result error(YyghException e){
    
    
        return Result.build(e.getCode(), e.getMessage());
    }
}

6.3 集成测试

手动在controller任意方法制造异常(int i = 1/0),添加GlobalExceptionHandler类与不添加这个类区别


7、日志

7.1配置日志级别

日志记录器(Logger)的行为是分等级的。如下表所示:

分为:OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL

默认情况下,spring boot从控制台打印出来的日志级别只有INFO及以上级别,可以配置日志级别

  • application.properties
# 设置日志级别
logging.level.root=WARN

这种方式只能将日志打印在控制台上

7.2 Logback日志

spring boot内部使用Logback作为日志实现的框架。

Logback和log4j非常相似,如果你对log4j很熟悉,那对logback很快就会得心应手。

7.3 配置日志

resources/logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration  scan="true" scanPeriod="10 seconds">
    <!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
    <!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
    <!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
    <!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
    <contextName>logback</contextName>
    <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
    <property name="log.path" value="D:/yygh_log/edu" />
    <!-- 彩色日志 -->
    <!-- 配置格式变量:CONSOLE_LOG_PATTERN 彩色日志格式 -->
    <!-- magenta:洋红 -->
    <!-- boldMagenta:粗红-->
    <!-- cyan:青色 -->
    <!-- white:白色 -->
    <!-- magenta:洋红 -->
    <property name="CONSOLE_LOG_PATTERN"
              value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level) |%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n)"/>
    <!--输出到控制台-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
        <!-- 例如:如果此处配置了INFO级别,则后面其他位置即使配置了DEBUG级别的日志,也不会被输出 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <encoder>
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <!--输出到文件-->
    <!-- 时间滚动输出 level为 INFO 日志 -->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_info.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天日志归档路径以及格式 -->
            <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录info级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 时间滚动输出 level为 WARN 日志 -->
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_warn.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录warn级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>warn</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>


    <!-- 时间滚动输出 level为 ERROR 日志 -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_error.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!--
        <logger>用来设置某一个包或者具体的某一个类的日志打印级别、以及指定<appender>。
        <logger>仅有一个name属性,
        一个可选的level和一个可选的addtivity属性。
        name:用来指定受此logger约束的某一个包或者具体的某一个类。
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
              如果未设置此属性,那么当前logger将会继承上级的级别。
    -->
    <!--
        使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
        第一种把<root level="INFO">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
        第二种就是单独给mapper下目录配置DEBUG模式,代码如下,这样配置sql语句会打印,其他还是正常DEBUG级别:
     -->
    <!--开发环境:打印控制台-->
    <springProfile name="dev">
        <!--可以输出项目中的debug日志,包括mybatis的sql日志-->
        <logger name="com.guli" level="INFO" />

        <!--
            root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
            level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,默认是DEBUG
            可以包含零个或多个appender元素。
        -->
        <root level="INFO">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="WARN_FILE" />
            <appender-ref ref="ERROR_FILE" />
        </root>
    </springProfile>


    <!--生产环境:输出到文件-->
    <springProfile name="pro">

        <root level="INFO">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="DEBUG_FILE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="ERROR_FILE" />
            <appender-ref ref="WARN_FILE" />
        </root>
    </springProfile>
</configuration>

猜你喜欢

转载自blog.csdn.net/qq_43284469/article/details/114992648
今日推荐