谷粒学苑_第二天
第二天:
讲师管理模块(后端):
1.导入(设计)数据库
项目结构
创建父工程 pom类型 管理依赖的版本,放公共依赖
guli_parent
子工程:详细的功能模块
service
子子模块:更细分的功能模块
service_edu
application.yml
server:port: 8001
spring:application:name: service-eduprofiles:active: dev #环境设置: dev,test,proddatasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8username: rootpassword: 148963mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImplglobal-config:db-config:id-type: ASSIGN_UUID
编写controller service mapper
使用mp的代码生成器
个人使用mybatisX插件进行自动生成
MybatisX导入edu_teacher
按照管理只要改这4个就行
拼接成一个完整的路径
module path(模块路径名)/base path(项目路径名)/base package(包名)/relative package(实体类的包名)
注意:1.可能各个路径会自动给错,需要检查手动修改
2.base package要用点隔离
上面斟酌选择(我加了一个Lombok,maven导入的是3以上的版本,选择mybatis-plus3),下面可以删掉不需要的内容
如果出现导的包报错,就调整这两个地方的maven版本一致就行
注意修改一些字段,有些字段和属性不能匹配
讲师列表
编写第一个controller
1.创建类,添加注解(默认Rest风格)
@RestController
@RequestMapping(“/eduservice/teacher”)
2.注入Service
private EduTeacherService eduTeacherService;
创建一个findAllTeacher方法,使用的GetMapping方法
package com.lkw.serviceedu.controller;import com.lkw.serviceedu.entity.EduTeacher;
import com.lkw.serviceedu.service.EduTeacherService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;@RestController
@RequestMapping("/eduservice/teacher")
public class EduTeacherController {//注入service@Autowiredprivate EduTeacherService eduTeacherService;//http://localhost:8001/eduservice/teacher/findAll//GetMapping,获取全部的教师列表@GetMapping("findAll")public List<EduTeacher> findAllTeacher(){//调用service的list,查询条件为null(查到的所有都返回)List<EduTeacher> list=eduTeacherService.list(null);return list;}
}
config包
里面可以加分页,逻辑删除,性能测试之类的配置
package com.lkw.eduservice.config;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;@Configuration
@MapperScan("com.lkw.eduservice.mapper")
public class EduConfig {//乐观锁//自动填充//分页//逻辑删除//性能插件}
启动测试
注意把service的pom.xml的这些多余依赖注释掉,然后刷新maven
启动并且查询成功
检查链接:http://localhost:8001/eduservice/teacher/findAll
配置时间格式
在application.yml添加
spring:jackson:date-format: yyyy-MM-dd HH:mm:sstime-zone: GMT+8
讲师删除
使用的逻辑删除,在配置类添加逻辑删除插件
//mp版本大于3.1.1不需要配置逻辑删除插件
继续编写EduTeacherController,使用@deleteMapping(“{id}”)
//http://localhost:8001/eduservice/teacher/delete/1//逻辑删除讲师@DeleteMapping("{id}")public boolean removeTeacher(@PathVariable String id){return eduTeacherService.removeById(id);}
讲师删除测试
本项目使用的swagger2,3版本暂时不能配上
swagger3快速上手
丝袜哥的作用:获取项目的api,生成准确实时的接口文档
依赖:
<!--swagger3-->
<dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version>
</dependency>
添加一个配置类
package com.lkw.servicebase;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;@Configuration
@EnableOpenApi
public class SwaggerConfig {@Beanpublic Docket docket(){return new Docket(DocumentationType.OAS_30).apiInfo(apiInfo()).enable(true).groupName("这是组名").select().apis(RequestHandlerSelectors.withClassAnnotation(RestController.class)).paths(PathSelectors.any()).build();}@SuppressWarnings("all")public ApiInfo apiInfo(){return new ApiInfo("这是标题","这是描述","v1.0","2279719702@qq.com", //开发者团队的邮箱"lkw","许可证", //许可证"http://www.baidu.com" //许可证链接);}
}
在启动类添加注解**@EnableWebMvc**
启动并访问:http://localhost:8080/swagger-ui/index.html
其他的交给翻译,然后自己看吧
springcloud+swagger2
建立一个common子模块和service_base子子模块,为了所有模块都能用
引入common模块的依赖,删除common的src目录:
<dependencies><!-- redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- spring2.X集成redis所需common-pool2--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.6.0</version></dependency><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><scope>provided </scope></dependency><!--swagger--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><scope>provided </scope></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><scope>provided </scope></dependency><!-- redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- spring2.X集成redis所需common-pool2<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.6.0</version></dependency>--></dependencies>
创建SwaggerConfig
package com.lkw.servicebase;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 SwaggerConfig {@Beanpublic Docket webApiConfig(){return new Docket(DocumentationType.SWAGGER_2).groupName("webApi").apiInfo(webApiInfo()).select()
// .paths(Predicates.not(PathSelectors.regex("/admin/.*"))).paths(Predicates.not(PathSelectors.regex("/error.*"))).build();}private ApiInfo webApiInfo(){return new ApiInfoBuilder().title("网站-课程中心API文档").description("本文档描述了课程中心微服务接口定义").version("1.0").contact(new Contact("Helen", "http://atguigu.com", "55317332@qq.com")).build();}
}
service模块的maven引入service_base模块
<dependency><groupId>com.lkw.servicebase</groupId><artifactId>service_base</artifactId><version>0.0.1-SNAPSHOT</version></dependency>
在EduApplication启动类添加组件扫描注解
@ComponentScan(basePackages={“com.lkw.*”})
http://localhost:8001/swagger-ui.html
springcloud+swagger3
直接改依赖和注解就行
http://localhost:8001/swagger-ui/
最后注意给Controller添加注解:@Api(value=“讲师管理模块”)
给方法添加注解
统一返回数据格式
将响应封装成一个json使得所有的接口数据格式都统一,方便前端使用,方便维护
因为json数据格式只有两种(对象,数组),可以设计出较为合适的返回值类型
{"success": 布尔,//相应是否成功"code": 数字,//响应码"message": 字符串,//返回消息"data": HashMap //返回数据,放在键值对里
}
在common创建子模块:common_utils
创建interface,定义返回状态码
例如成功:20001 失败20001
package com.lkw.commonutils;public interface ResultCode {public static Integer SUCCESS = 20000;//成功public static Integer ERROR = 20001;//失败
}
统一返回结果类:R
package com.lkw.commonutils;import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.util.HashMap;
import java.util.Map;@Data
public class R {@ApiModelProperty(value = "是否成功")private Boolean success;@ApiModelProperty(value = "返回码")private Integer code;@ApiModelProperty(value = "返回消息")private String message;@ApiModelProperty(value = "返回数据")private Map<String, Object> data = new HashMap<String, Object>();//构造器私有化,使得不能new该对象private R() {}//成功静态方法public static R ok() {R r = new R();r.setSuccess(true);r.setCode(ResultCode.SUCCESS);r.setMessage("成功");return r;}//失败静态方法public static R error() {R r = new R();r.setSuccess(false);r.setCode(ResultCode.ERROR);r.setMessage("失败");return r;}public R success(Boolean success) {this.setSuccess(success);return this;}public R message(String message) {this.setMessage(message);return this;}public R code(Integer code) {this.setCode(code);return this;}public R data(String key, Object value) {this.data.put(key, value);return this;}public R data(Map<String, Object> map) {this.setData(map);return this;}
}
引入依赖到service
<dependency><groupId>com.lkw.commonutils</groupId><artifactId>common_utils</artifactId><version>0.0.1-SNAPSHOT</version>
</dependency>
修改Controller的返回结果
package com.lkw.eduservice.controller;import com.lkw.commonutils.R;
import com.lkw.eduservice.entity.EduTeacher;
import com.lkw.eduservice.service.EduTeacherService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.List;@Api(value = "讲师管理功能")//注解还有其他输出功能,暂时不写
@RestController
@RequestMapping("/eduservice/teacher")
public class EduTeacherController {//注入service@Autowiredprivate EduTeacherService eduTeacherService;//GetMapping,获取全部的教师列表//http://localhost:8001/eduservice/teacher/findAll@ApiOperation(value = "所有讲师列表")@GetMapping("findAll")public R findAllTeacher(){//调用service的list,查询条件为null(查到的所有都返回)List<EduTeacher> list=eduTeacherService.list(null);return R.ok().data("items",list);}//http://localhost:8001/eduservice/teacher/delete/1@ApiOperation(value = "逻辑删除讲师")@DeleteMapping("{id}")public R removeTeacher(@PathVariable String id){boolean b = eduTeacherService.removeById(id);if(b){return R.ok();}else {return R.error();}}
}
丝袜哥测试
讲师分页功能
配置mybatis的分页插件,在service_edu的config里
@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 添加分页插件PaginationInnerInterceptor pageInterceptor = new PaginationInnerInterceptor();// 设置请求的页面大于最大页后操作,true调回到首页,false继续请求。默认falsepageInterceptor.setOverflow(false);// 单页分页条数限制,默认无限制pageInterceptor.setMaxLimit(500L);// 设置数据库类型pageInterceptor.setDbType(DbType.MYSQL);interceptor.addInnerInterceptor(pageInterceptor);return interceptor;}
添加新方法:
//{current}/{limit}======当前页/最多限制页数
@ApiOperation(value = "教师列表分页" )
@GetMapping("pageTeacher/{current}/{limit}")
public R pageListTeacher(@PathVariable long current ,@PathVariable long limit){//创建page对象Page<EduTeacher> eduTeacherPage=new Page<>(current,limit);//调用方法实现分页,会把得到的数据封装给eduTeacherPage,查询条件为nulleduTeacherService.page(eduTeacherPage,null);//得到总记录数long total = eduTeacherPage.getTotal();//得到list数据集合List<EduTeacher> records = eduTeacherPage.getRecords();//返回的可以自己创建一个map集合,然后将两个对象合成一个对象,但是这里用的链式编程,两种结果都一样return R.ok().data("total",total).data("rows",records);
}
丝袜哥测试
返回总数量17,两个讲师数据
条件分页查询
把条件封装成对象,再传递到接口,所以应该创建一个vo类,
几大分层的定义
DTO(Data Transfer Object)数据传输对象
VO (view object/value object)表示层对象
BO(bussines object)业务层对象//由PO继续包装成的对象
PO(persistent object)持久对象
DO(domain object)领域实体对象
创建一个vo类
在entity创建一个vo.TeacherQuery.java
package com.lkw.eduservice.entity.vo;import io.swagger.annotations.ApiModelProperty;
import lombok.Data;@Data
public class TeacherQuery {private static final long serialVersionUID = 1L;@ApiModelProperty(value = "教师名称,模糊查询")private String name;@ApiModelProperty(value = "头衔 1高级讲师 2首席讲师")private Integer level;@ApiModelProperty(value = "查询开始时间", example = "2019-01-01 10:10:10")private String begin;//注意,这里使用的是String类型,前端传过来的数据无需进行类型转换@ApiModelProperty(value = "查询结束时间", example = "2019-12-01 10:10:10")private String end;}
编写controller
//4.条件查询分页方法
@ApiOperation(value = "条件查询分页方法")
@PostMapping("pageTeacherCondition/{current}/{limit}")
public R pageTeacherCondition(@PathVariable Long current,@PathVariable Long limit,@RequestBody(required = false) TeacherQuery teacherQuery) {//创建pagePage<EduTeacher> pageCondition = new Page<>(current, limit);//QueryWrapper,构建条件QueryWrapper<EduTeacher> wrapper = new QueryWrapper<>();//多条件组合查询,动态sqlString name = teacherQuery.getName();Integer level = teacherQuery.getLevel();String begin = teacherQuery.getBegin();String end = teacherQuery.getEnd();//判断条件是否为空,拼接条件if (!StringUtils.isEmpty(level)) {wrapper.eq("level", level);}if (!StringUtils.isEmpty(name)) {wrapper.like("name", name);}if (!StringUtils.isEmpty(begin)) {wrapper.ge("gmt_create", begin);//大于等于}if (!StringUtils.isEmpty(end)) {wrapper.le("gmt_create", end);//小于等于}wrapper.orderByDesc("gmt_create");//调用方法,实现分页查询eduTeacherService.page(pageCondition, wrapper);long total = pageCondition.getTotal();//获取总记录数List<EduTeacher> records = pageCondition.getRecords();//获取分页后的list集合HashMap<String, Object> map = new HashMap<>();map.put("total", total);map.put("rows", records);return R.ok().data(map);
}
@RequestMapping,@RequestBody与@ResponseBody
@RequestMapping:请求映射,
用于映射(匹配?) url地址 与 类或方法,
一般放在Controller类上
@RequestBody:请求,
使用json接收传输,转化封装成对应对象
(后面的(required=false表示该值不是必须的,可以忽略))
@ResponseBody:响应,
java对象转json直接写入到HTTP响应正文,
丝袜哥测试
新增讲师
在eduteacher类添加自动填充的注解,
@TableField(fill= FieldFill.INSERT)
private Date gmtCreate;@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmtModified;
添加内容:
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {@Overridepublic void insertFill(MetaObject metaObject) {//fieldName不是字段名(gmt_create),而是类的属性名(gmtCreate)this.setFieldValByName("gmtCreate", new Date(), metaObject);this.setFieldValByName("gmtModified", new Date(), metaObject);}@Overridepublic void updateFill(MetaObject metaObject) {this.setFieldValByName("gmtModified", new Date(), metaObject);}
}
添加接口方法
@ApiOperation("添加教师")
@PostMapping("addTeacher")
public R addTeacher(@RequestBody EduTeacher eduTeacher) {//可能缺一点数据判断boolean save = eduTeacherService.save(eduTeacher);if (save) {return R.ok();} elsereturn R.error();
}
根据id查询讲师,修改讲师
@ApiOperation("根据ID查询教师")
@GetMapping("getTeacher/{id}")
public R getTeacher(@PathVariable String id) {EduTeacher eduTeacher = eduTeacherService.getById(id);return R.ok().data("teacher", eduTeacher);
}@ApiOperation("修改教师")
@PostMapping("updateTeacher")
public R updateTeacher(@RequestBody EduTeacher eduTeacher) {boolean b = eduTeacherService.updateById(eduTeacher);if (b) {return R.ok();} elsereturn R.error();
}
丝袜哥测试
如果一直500,检查一下eduTeacher类的属性和字段是不是匹配的
异常处理
package com.lkw.servicebase.exceptionhandler;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** 自定义异常类*/
@Data
@AllArgsConstructor //有参数构造器
@NoArgsConstructor //生成无参数构造
public class GuliException extends RuntimeException {private Integer code;//状态码private String msg;//输出消息
}
package com.lkw.servicebase.exceptionhandler;import com.lkw.commonutils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {//全局异常处理@ExceptionHandler(Exception.class)public R error(Exception e){e.printStackTrace();return R.error().message("执行全局异常处理");}//指定异常执行方法(算术异常)@ExceptionHandler(ArithmeticException.class)@ResponseBody//为了能够返回数据public R error(ArithmeticException e){e.printStackTrace();return R.error().message("方法执行ArithmeticException异常!");}//自定义的异常处理@ExceptionHandler(GuliException.class)@ResponseBodypublic R error(GuliException e){log.error(e.getMessage());e.printStackTrace();return R.error().code(e.getCode()).message(e.getMsg());}}
随便在一个controller里加int i=10/0;,来模拟算术异常
再在随便一个方法里模拟一个自定义异常:
/*
//模拟的自定义异常try {int i=10/0;} catch (Exception e) {throw new GuliException(20001,"执行了自定义异常");}
*/
丝袜哥测试
全局异常处理:
略
初学用全局就行吧
详细异常处理待补全
统一日志处理
日志级别
高 低
OFF,FATAL,ERROR,WARN,INFO,DEBUG,ALL
在yml里配置当前的控制台的日志级别:
logging:level:root: warn
默认是info级别
Logback
,一个类似于log4j的东西
在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:/guli_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>
在第十行改日志路径
启动测试
有文件,有内容,搞定,
将 异常 输出到文件
在GlobalExceptionHandler类添加注解:@Slf4j
打上这个注解,用log.info()来代替System.out.println();更省性能(好像是自带多线程)
启动测试
略
添加到github
详细看我的主页里有关git上传的博客
复制链接
输入链接
成功: