目录
- 一、医院设置模块需求
- 二、医院设置表结构
- 三、医院模块配置
- 四、医院查询功能
- 1、创建包结构,创建SpringBoot启动类
- 2、编写controller代码
- 3、创建SpringBoot配置类
- 5、运行启动类
- 6、统一返回的json时间格式
- 五、医院设置逻辑删除功能
- 1、HospitalSetController添加删除方法
- 2、使用postman测试删除
- 六、配置Swagger2生成API接口文档
- 1、创建common模块
- 2、在common中引入相关依赖
- 3、在common下面创建子模块service_utils
- 4、在模块service-utils中,创建swagger的配置类
- 5、在模块service模块中引入service_utils
- 6、在service_hosp启动类上添加注解,进行测试
- 7、通过地址访问测试
- 8、定义接口说明和参数说明
- 七、统一返回数据格式
- 1、在子模块service_utils创建接口定义返回码
- 2、创建结果类
- 3、修改Controller中的返回结果
- 八、分页和条件查询
- 1、HospPlusConfig中配置分页插件
- 2、条件分页Controller方法
- 3、Controller方法
- 4、Swagger中测试
- 九、新增和修改医院设置工具
- 1、新增
- 2、根据id查询
- 3、根据id修改
- 十、批量删除医院设置和锁定医院设置接口
- 1、批量删除
- 2、锁定和解锁
- 十一、统一异常处理
- 1、创建统一异常处理器
- 2、添加异常处理方法
- 3、测试
- 4、自定义异常类
- 十二、统一日志
- 1、配置日志级别
- 2、Logback日志
- 3、配置logback日志
- 4、将错误日志输出到文件
一、医院设置模块需求
医院设置主要是用来保存开通医院的一些基本信息,每个医院一条信息,保存了医院编号(平台分配,全局唯一)和接口调用相关的签名key等信息,是整个流程的第一步,只有开通了医院设置信息,才可以上传医院相关信息。我们所开发的功能就是基于单表的一个CRUD、锁定/解锁和发送签名信息这些基本功能。
二、医院设置表结构
hosname:医院名称
hoscode:医院编号(平台分配,全局唯一,api接口必填信息)
api_url:医院回调的基础url(如:预约下单,我们要调用该地址去医院下单)
sign_key:双方api接口调用的签名key,有平台生成
contacts_name:医院联系人姓名
contacts_phone:医院联系人手机
status:状态(锁定/解锁)
三、医院模块配置
1、在service下面service_hosp模块中创建配置文件
resources目录下创建文件 application.properties
# 服务端口
server.port=8201
# 服务名
spring.application.name=service-hosp
# 环境设置:dev、test、prod
spring.profiles.active=dev
# mysql数据库连接
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/yygh_hosp?characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
#返回json的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
乱码解决方案
https://donglin.blog.csdn.net/article/details/125453678
四、医院查询功能
1、创建包结构,创建SpringBoot启动类
创建启动类ServiceHospApplication.java,注意启动类的创建位置
@SpringBootApplication
public class ServiceHospApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceHospApplication.class,args);
}
}
2、编写controller代码
//医院设置接口
@RestController
@RequestMapping("/admin/hosp/hospitalSet")
public class HospitalSetController {
@Autowired
private HospitalSetService hospitalSetService;
//查询所有医院设置
@GetMapping("findAll")
public List<HospitalSet> findAll() {
List<HospitalSet> list = hospitalSetService.list();
return list;
}
}
3、创建SpringBoot配置类
创建config包,创建HospConfig.java
@Configuration
@EnableTransactionManagement
@MapperScan("com.donglin.yygh.hosp.mapper")
public class HospConfig {
}
5、运行启动类
访问http://localhost:8201/admin/hosp/hospitalSet/findAll
得到json数据
千万注意:将代码生成器生成的entity实体类去掉,用yygh-parent父工程下model模块的实体类。
6、统一返回的json时间格式
默认情况下json时间格式带有时区,并且是世界标准时间,和我们的时间差了八个小时
在application.properties中设置
#返回json的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
五、医院设置逻辑删除功能
1、HospitalSetController添加删除方法
@DeleteMapping("{id}")
public boolean removeById(@PathVariable String id){
return hospitalSetService.removeById(id);
}
2、使用postman测试删除
测试结果:数据库中的is_deleted字段被修改为1
六、配置Swagger2生成API接口文档
Swagger2介绍
前后端分离开发模式中,api文档是最好的沟通方式。
Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。
- 1.及时性 (接口变更后,能够及时准确地通知相关前后端开发人员)
- 2.规范性 (并且保证接口的规范性,如接口的地址,请求方式,参数及响应格式和错误信息)
- 3.一致性 (接口信息一致,不会出现因开发人员拿到的文档版本不一致,而出现分歧)
- 4.可测性 (直接在接口文档上进行测试,以方便理解业务)
配置Swagger2
1、创建common模块
在yygh_parent下创建模块common
2、在common中引入相关依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>provided </scope>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<scope>provided </scope>
</dependency>
<!--lombok用来简化实体类:需要安装lombok插件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
</dependencies>
3、在common下面创建子模块service_utils
4、在模块service-utils中,创建swagger的配置类
创建包com.donglin.yygh.common.config,创建类Swagger2Config
import com.google.common.base.Predicates;
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.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket webApiConfig(){
return new Docket(DocumentationType.SWAGGER_2)
.groupName("admin")
.apiInfo(getAdminApiInfo())
.select()
//只显示api路径下的页面
.paths(Predicates.and(PathSelectors.regex("/admin/.*")))
.build();
}
private ApiInfo getAdminApiInfo(){
return new ApiInfoBuilder()
.title("管理员系统")
.description("本文档描述了网站微服务接口定义")
.version("1.0")
.contact(new Contact("donglin", "http://donglin.com", "1909529369@qq.com"))
.build();
}
@Bean
public Docket userApiConfig(){
return new Docket(DocumentationType.SWAGGER_2)
.groupName("user")
.apiInfo(getUserApiInfo())
.select()
//只显示admin路径下的页面
.paths(Predicates.and(PathSelectors.regex("/user/.*")))
.build();
}
private ApiInfo getUserApiInfo(){
return new ApiInfoBuilder()
.title("用户系统")
.description("本文档描述了网站微服务接口定义")
.version("1.0")
.contact(new Contact("donglin", "http://donglin.com", "1909529369@qq.com"))
.build();
}
@Bean
public Docket apiConfig(){
return new Docket(DocumentationType.SWAGGER_2)
.groupName("api")
.apiInfo(getApiInfo())
.select()
//只显示admin路径下的页面
.paths(Predicates.and(PathSelectors.regex("/api/.*")))
.build();
}
private ApiInfo getApiInfo(){
return new ApiInfoBuilder()
.title("Api系统")
.description("本文档描述了网站微服务接口定义")
.version("1.0")
.contact(new Contact("donglin", "http://donglin.com", "1909529369@qq.com"))
.build();
}
}
5、在模块service模块中引入service_utils
<dependency>
<groupId>com.donglin</groupId>
<artifactId>service_utils</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
6、在service_hosp启动类上添加注解,进行测试
因为swagger在common模块下,在不同模块下,我们需要使用@ComponentScan才能扫描导Swagger
7、通过地址访问测试
可以添加一些自定义设置,例如:
定义样例数据
@ApiModelProperty(value = "创建时间", example = "2019-01-01 8:00:00")
@TableField(fill = FieldFill.INSERT)
private Date gmtCreate;
@ApiModelProperty(value = "更新时间", example = "2019-01-01 8:00:00")
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmtModified;
8、定义接口说明和参数说明
@Api(tags=“”):标记在接口类上
@ApiOperation(value=“”):标记在方法上
@ApiParam(value=“”):标记在参数上
@ApiModel(description=“”):对POJO类做说明
@ApiModelProperty(value=“”):对POJO类属性做说明
//医院设置接口
@Api(description = "医院设置接口")
@RestController
@RequestMapping("/admin/hosp/hospitalSet")
public class HospitalSetController {
@Autowired
private HospitalSetService hospitalSetService;
//查询所有医院设置
@ApiOperation(value = "医院设置列表")
@GetMapping("findAll")
public List<HospitalSet> findAll() {
List<HospitalSet> list = hospitalSetService.list();
return list;
}
@ApiOperation(value = "医院设置删除")
@DeleteMapping("{id}")
public boolean removeById(@ApiParam(name = "id", value = "医院设置ID", required = true) @PathVariable String id){
return hospitalSetService.removeById(id);
}
}
七、统一返回数据格式
项目中我们会将响应封装成json返回,一般我们会将所有接口的数据格式统一, 使前端(iOS Android, Web)对数据的操作更一致、轻松。
一般情况下,统一返回数据格式没有固定的格式,只要能描述清楚返回的数据状态以及要返回的具体数据就可以。但是一般会包含状态码、返回消息、数据这几部分内容
例如,我们的系统要求返回的基本数据格式如下:
列表:
{
"success": true,
"code": 20000,
"message": "成功",
"data": {
"items": [
{
"id": "1",
"name": "刘德华",
"intro": "毕业于师范大学数学系,热爱教育事业,执教数学思维6年有余"
}
]
}
}
分页:
{
"success": true,
"code": 20000,
"message": "成功",
"data": {
"total": 17,
"rows": [
{
"id": "1",
"name": "刘德华",
"intro": "毕业于师范大学数学系,热爱教育事业,执教数学思维6年有余"
}
]
}
}
没有返回数据:
{
"success": true,
"code": 20000,
"message": "成功",
"data": {}
}
失败:
{
"success": false,
"code": 20001,
"message": "失败",
"data": {}
}
因此,我们定义统一结果
{
"success": 布尔, //响应是否成功
"code": 数字, //响应码
"message": 字符串, //返回消息
"data": HashMap //返回数据,放在键值对中
}
1、在子模块service_utils创建接口定义返回码
创建包com.donglin.yygh.common.result,创建接口 REnum .java
public enum REnum {
SUCCESS(20000,"成功",true),
ERROR(20001,"失败",false)
;
//枚举项:
private Integer code;
private String message;
private Boolean flag;
REnum(Integer code, String message, Boolean flag) {
this.code = code;
this.message = message;
this.flag = flag;
}
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 Boolean getFlag() {
return flag;
}
public void setFlag(Boolean flag) {
this.flag = flag;
}
}
2、创建结果类
创建类 R.java
@Data
public class R {
private Integer code;
private Boolean success;
private String message;
private Map<String,Object> data = new HashMap<>();
private R(){
}
public static R ok(){
R r = new R();
r.setCode(REnum.SUCCESS.getCode());
r.setSuccess(REnum.SUCCESS.getFlag());
r.setMessage(REnum.SUCCESS.getMessage());
return r;
}
public static R error(){
R r = new R();
r.setCode(REnum.ERROR.getCode());
r.setSuccess(REnum.ERROR.getFlag());
r.setMessage(REnum.ERROR.getMessage());
return r;
}
public R code(Integer code){
this.code = code;
return this;
}
public R success(Boolean success){
this.success = success;
return this;
}
public R message(String message){
this.message = message;
return this;
}
public R data(String key,Object value){
this.data.put(key,value);
return this;
}
public R data(Map<String,Object> map){
this.data = map;
return this;
}
}
3、修改Controller中的返回结果
@ApiOperation(value = "医院设置列表")
@GetMapping("findAll")
public R findAll(){
List<HospitalSet> list = hospitalSetService.list();
return R.ok().data("items",list);
}
@ApiOperation(value = "医院设置删除")
@DeleteMapping("{id}")
public R removeId(@ApiParam(name = "id",value = "医院编号",required = true) @PathVariable Integer id){
hospitalSetService.removeById(id);
return R.ok();
}
八、分页和条件查询
1、HospPlusConfig中配置分页插件
放在不同模块下记得在启动类模块下添加@ComponentScan
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class PageConfig {
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
2、条件分页Controller方法
我们只需要两个字段医院名称和医院编号,所以我们使用VO类,而不是用POJO类
3、Controller方法
@ApiOperation(value = "带查询的条件的分页")
@PostMapping("/page/{pageNum}/{size}")
public R getPageInfo(@ApiParam(name = "pageNum",value = "当前页") @PathVariable Integer pageNum,
@ApiParam(name = "size",value = "每页显示多少条数据") @PathVariable Integer size,
@RequestBody HospitalSetQueryVo hospitalSetQueryVo
){
Page<HospitalSet> page = new Page<>(pageNum, size);
QueryWrapper<HospitalSet> queryWrapper = new QueryWrapper<>();
if (!StringUtils.isEmpty(hospitalSetQueryVo.getHosname())){
queryWrapper.like("hosname",hospitalSetQueryVo.getHosname());
}
if (!StringUtils.isEmpty(hospitalSetQueryVo.getHoscode())){
queryWrapper.eq("hoscode",hospitalSetQueryVo.getHoscode());
}
hospitalSetService.page(page,queryWrapper);
return R.ok().data("total",page.getTotal()).data("rows",page.getRecords());
}
4、Swagger中测试
九、新增和修改医院设置工具
1、新增
@ApiOperation(value = "新增接口")
@PostMapping("save")
public R save(@RequestBody HospitalSet hospitalSet){
//设置状态 1 使用 0 不能使用
hospitalSet.setStatus(1);
//签名秘钥
Random random = new Random();
hospitalSet.setSignKey(MD5.encrypt(System.currentTimeMillis()+""+random.nextInt(1000)));
hospitalSetService.save(hospitalSet);
return R.ok();
}
2、根据id查询
//修改之回显数据
@ApiOperation(value = "根据id查询医院设置")
@GetMapping("/detail/{id}")
public R detail(@PathVariable Integer id){
return R.ok().data("items",hospitalSetService.getById(id));
}
3、根据id修改
//修改之修改数据
@ApiOperation(value = "根据ID修改医院设置")
@PutMapping("/update")
public R update(@RequestBody HospitalSet hospitalSet){
hospitalSetService.updateById(hospitalSet);
return R.ok();
}
十、批量删除医院设置和锁定医院设置接口
1、批量删除
//批量删除医院设置
@ApiOperation(value = "批量删除")
@DeleteMapping("/delete")
public R delete(@RequestBody List<Integer> ids){
hospitalSetService.removeByIds(ids);
return R.ok();
}
2、锁定和解锁
@ApiOperation(value = "锁定与解锁")
@DeleteMapping("/status/{id}/{status}")
public R status(@PathVariable Long id, @PathVariable Integer status){
//HospitalSet byId = hospitalSetService.getById(id); //乐观锁
HospitalSet hospitalSet = new HospitalSet();
hospitalSet.setId(id);
hospitalSet.setStatus(status);
hospitalSetService.updateById(hospitalSet);
return R.ok();
}
十一、统一异常处理
1、创建统一异常处理器
在service_utils中创建com.donglin.yygh.common.handler包,建统一异常处理类GlobalExceptionHandler.java:
import com.donglin.yygh.common.result.R;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
//凡是由@ControllerAdvice 标记的类都表示全局异常类
@RestControllerAdvice //@ControllerAdvice+@RequestBody=@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = Exception.class) //粒度有点大
public R handleException(Exception ex){
ex.printStackTrace();
return R.error().message(ex.getMessage());
}
}
JAVA异常getMessage(),printStackTrace()方法的区别https://donglin.blog.csdn.net/article/details/125471865
2、添加异常处理方法
GlobalExceptionHandler.java中添加
@ExceptionHandler(value = SQLException.class)
public R handleException(SQLException ex){
ex.printStackTrace();
return R.error().message("Sql异常");
}
@ExceptionHandler(value = ArithmeticException.class)
public R handleException(ArithmeticException ex){
ex.printStackTrace();
return R.error().message("数学异常");
}
3、测试
返回统一错误结果
4、自定义异常类
1、创建自定义异常类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class YyghException extends RuntimeException {
@ApiModelProperty(value = "状态码")
private Integer code;
private String message;
}
2、业务中需要的位置抛出Exception
try {
int a = 10/0;
}catch(Exception e) {
throw new YyghException(40000,"xxx异常");
}
3、添加异常处理方法
GlobalExceptionHandler.java中添加
@ExceptionHandler(value = YyghException.class)
public R handleException(YyghException ex){
ex.printStackTrace();
return R.error().message(ex.getMessage()).code(ex.getCode());
}
十二、统一日志
1、配置日志级别
日志记录器(Logger)的行为是分等级的。如下表所示:
分为:OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL
默认情况下,spring boot从控制台打印出来的日志级别只有INFO及以上级别,可以配置日志级别
# 设置日志级别
logging.level.root=WARN
这种方式只能将日志打印在控制台上
2、Logback日志
pring boot内部使用Logback作为日志实现的框架。
Logback和log4j非常相似,如果你对log4j很熟悉,那对logback很快就会得心应手。
3、配置logback日志
删除application.properties中的日志配置
安装idea彩色日志插件:grep-console
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:/hosptial project/yygh" />
<!-- 彩色日志 -->
<!-- 配置格式变量: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.donglin" 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>
4、将错误日志输出到文件
GlobalExceptionHandler.java 中
类上添加注解
@Slf4j
异常输出语句
log.error(e.getMessage());