一.搭建一个多模块Springboot项目
? 这里的建议 如果不会使用 idea 创建maven模块的 建议去复习一下哦,在这里本人浪费了很长时间:
? 先把 三级 按照层次 搭建起来之后 再引入相关配置
创建一个名字为guli_parent 的Springboot项目
-
懂得都懂,删除src目录; -
设置 packaging
?
<packaging>pom</packaging>
- 配置 properties 和 dependencyManagement
<properties>
<java.version>1.8</java.version>
<guli.version>0.0.1-SNAPSHOT</guli.version>
<mybatis-plus.version>3.0.5</mybatis-plus.version>
<velocity.version>2.0</velocity.version>
<swagger.version>2.7.0</swagger.version>
<aliyun.oss.version>2.8.3</aliyun.oss.version>
<jodatime.version>2.10.1</jodatime.version>
<poi.version>3.17</poi.version>
<commons-fileupload.version>1.3.1</commons-fileupload.version>
<commons-io.version>2.6</commons-io.version>
<httpclient.version>4.5.1</httpclient.version>
<jwt.version>0.7.0</jwt.version>
<aliyun-java-sdk-core.version>4.3.3</aliyun-java-sdk-core.version>
<aliyun-sdk-oss.version>3.1.0</aliyun-sdk-oss.version>
<aliyun-java-sdk-vod.version>2.15.2</aliyun-java-sdk-vod.version>
<aliyun-java-vod-upload.version>1.4.11</aliyun-java-vod-upload.version>
<aliyun-sdk-vod-upload.version>1.4.11</aliyun-sdk-vod-upload.version>
<fastjson.version>1.2.28</fastjson.version>
<gson.version>2.8.2</gson.version>
<json.version>20170516</json.version>
<commons-dbutils.version>1.7</commons-dbutils.version>
<canal.client.version>1.1.0</canal.client.version>
<docker.image.prefix>zx</docker.image.prefix>
<cloud-alibaba.version>0.2.2.RELEASE</cloud-alibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>${velocity.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>${aliyun.oss.version}</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>${jodatime.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons-fileupload.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpclient.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jwt.version}</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>${aliyun-java-sdk-core.version}</version>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>${aliyun-sdk-oss.version}</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-vod</artifactId>
<version>${aliyun-java-sdk-vod.version}</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-vod-upload</artifactId>
<version>${aliyun-java-vod-upload.version}</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-sdk-vod-upload</artifactId>
<version>${aliyun-sdk-vod-upload.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>${json.version}</version>
</dependency>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>${commons-dbutils.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.otter</groupId>
<artifactId>canal.client</artifactId>
<version>${canal.client.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
报错没事,是因为没有引用,只是配置里版本
创建service模块
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
点击 service 创建 service_edu 的子子模块
这个是具体的代码书写模块,先以这个讲师模块为例
整体原理:
? 在 guli_parent 中 配置所有的 properties 与 dependencyManagement
? 在 service 中进行 导入
? 在 service_edu 中进行 使用
配置applicatioin.properties
# 服务端口
server.port=8001
# 服务名
spring.application.name=service-edu
# 环境设置:dev、test、prod
spring.profiles.active=dev
# mysql数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=034312
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
使用Mybatis-Plus自带的代码生成器,生成基本项目框架
public class CodeGeneratorUtil {
@Test
public void main1() {
AutoGenerator mpg = new AutoGenerator();
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
System.out.println(projectPath);
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("atguigu");
gc.setOpen(false);
gc.setFileOverride(false);
gc.setServiceName("%sService");
gc.setIdType(IdType.ID_WORKER);
gc.setDateType(DateType.ONLY_DATE);
gc.setSwagger2(true);
mpg.setGlobalConfig(gc);
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("root");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
PackageConfig pc = new PackageConfig();
pc.setModuleName("serviceedu");
pc.setParent("com.atguigu");
pc.setController("controller");
pc.setEntity("entity");
pc.setService("service");
pc.setMapper("mapper");
mpg.setPackageInfo(pc);
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("edu_teacher");
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setTablePrefix(pc.getModuleName() + "_");
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
strategy.setControllerMappingHyphenStyle(true);
mpg.setStrategy(strategy);
mpg.execute();
}
}
二.牛刀小试
controller
@RestController
public class EduTeacherController {
@Autowired
private EduTeacherService eduTeacherService;
@GetMapping("/teacher")
public List<EduTeacher> selectAll(){
return eduTeacherService.list(null);
}
}
service
@Service
public class EduTeacherServiceImpl extends ServiceImpl<EduTeacherMapper, EduTeacher> implements EduTeacherService {
}
使用自动生成mp结构,他把 service的实现类 也做了封装,在继承的父类 中 就已经对 mapper 进行了注入,并且封装了 常用的简单方法, 是开发更加方便了
config
@Configuration
@MapperScan("com.atguigu.service_edu.mapper")
public class MybatisPlusConfig {
}
application
@SpringBootApplication
public class EduApplication {
public static void main(String[] args) {
SpringApplication.run(EduApplication.class,args);
}
}
在运行之前 需要把 pom 中 关于org.springframework.cloud 的依赖 注释一下 不然会报错
三.时间格式配置
返回的时间格式默认是 格林尼治格式的时间
在 application.properties 中进行配置
# 返回json的全局时间格式
spring.jackson.date-format=yy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT%2B8
四.配置逻辑删除
这个在 一 部分说过了哦,复习一下
-
在属性上 添加注解 @TableLogic -
配置 逻辑删除插件 (如果Mybatis-Plus版本很高的话不用配置) @Configuration
@MapperScan("com.atguigu.service_edu.mapper")
public class MybatisPlusConfig {
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
}
-
测试 @DeleteMapping("/delete/{id}")
@ApiOperation("删除操作")
public Boolean deleteEduById( @ApiParam(name = "id",value = "老师ID",required = true) @PathVariable("id") String id){
return eduTeacherService.removeById(id);
}
由于在浏览器 测试是看不出结果的,所以我们 配置 Swagger
五.Swagger配置
前后端分离开发模式中,api文档是最好的沟通方式
Swagger 是一个规范 和 完整的框架,用于生成、描述、调用和可视化RESTful风格的WEB服务
1.及时性(接口变更 ,更新及时)
2.规范性(接口地址,请求方式,参数及响应格式和错误信息)
3.一致性(与后端 接口保持一致)
4.可测性(方便测试)
在这里 我们新建一个在项目根目录下 创建一个 common的公共模块,在common引入相关依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>provided </scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<scope>provided </scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided </scope>
</dependency>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
在common下,在创建一个service_base模块,并且创建包 src/main/java/com/atguigu/service_base/config,在其下创建SwaggerConfig
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public 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的pom中进行引入
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>service_base</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
配置启动类,扫描组件 @ComponentScan(“com.atguigu”)
@SpringBootApplication
@ComponentScan("com.atguigu")
public class EduApplication {
public static void main(String[] args) {
SpringApplication.run(EduApplication.class,args);
}
}
这样就基本配置好了
Swagger基本使用
@Api() 类
@ApiOperate 方法
@ApiParam 参数
@ApiModelProperty 实体类属性
@RestController
@RequestMapping("/service_edu/edu-teacher")
@Api("EduTeacher API 文档")
public class EduTeacherController {
@Autowired
private EduTeacherService eduTeacherService;
@GetMapping("/selectAll")
@ApiOperation("查询老师列表")
public List<EduTeacher> selectAll() {
return eduTeacherService.list(null);
}
@DeleteMapping("/delete/{id}")
@ApiOperation("删除操作")
public Boolean deleteEduById( @ApiParam(name = "id",value = "老师ID",required = true) @PathVariable("id") String id){
return eduTeacherService.removeById(id);
}
}
六.统一返回数据格式
项目中 我们会将响应封装成json返回,一般我们会将所有的接口的数据格式统一,使前端(IOS Android,Web)对数据的操作更一致,轻松。
一般情况下,统一返回数据格式没有固定的格式,只要能描述清楚返回的数据状态以及要返回的具体数据就可以。但使一般都会包含状态码、返回消息、数据这几部分内容
{
"success": 布尔,
"code": 数字,
"message": 字符串,
"data": HashMap
}
抽取公共模块:在common下创建子模块 common_utils
创建接口定义返回值
创建包 com.atguigu.commono_utils 创建接口 ResultCode.java
public interface ResultCode {
Integer SUCCESS = 20001;
Integer ERROR = 20000;
}
封装结果类
@Data
public class Response {
@ApiModelProperty(value = "是否成功")
private Boolean success;
@ApiModelProperty(value = "响应码")
private Integer code;
@ApiModelProperty(value = "返回消息")
private String message;
@ApiModelProperty(value = "返回数据")
private Map<String, Object> data = new HashMap<>();
private Response(){}
public static Response ok(){
Response response = new Response();
response.setSuccess(true);
response.setCode(ResultCode.SUCCESS);
response.setMessage("成功");
return response;
}
public static Response err(){
Response response = new Response();
response.setSuccess(false);
response.setCode(ResultCode.ERROR);
response.setMessage("失败");
return response;
}
public Response success(Boolean success){
this.setSuccess(success);
return this;
}
public Response message(String message){
this.setMessage(message);
return this;
}
public Response code(Integer code){
this.setCode(code);
return this;
}
public Response data(Map<String,Object> map){
this.setData(map);
return this;
}
public Response data(String key,Object value){
this.data.put(key,value);
return this;
}
}
在service 模块中 引入 使用 pom 添加
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>common_utils</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
修改controller结果
@GetMapping("/selectAll")
@ApiOperation("查询老师列表")
public Response selectAll() {
return Response.ok().data("item",eduTeacherService.list(null));
}
@DeleteMapping("/delete/{id}")
@ApiOperation("删除操作")
public Response deleteEduById( @ApiParam(name = "id",value = "老师ID",required = true) @PathVariable("id") String id){
boolean isSuccess = eduTeacherService.removeById(id);
if(isSuccess){
return Response.ok();
}
return Response.err();
}
七.讲师分页查询
配置分页插件
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
添加分页方法
@GetMapping("/selectAllByPageHelper/{current}/{size}")
@ApiOperation("查询老师列表分页查询")
public Response selectAllByPageHelper(
@PathVariable("current") Integer current,
@PathVariable("size") Integer size
) {
Page<EduTeacher> page = new Page<>(current, size);
eduTeacherService.page(page,null);
Map<String, Object> map = new HashMap<>();
long total = page.getTotal();
List<EduTeacher> records = page.getRecords();
map.put("total",total);
map.put("item",records);
return Response.ok().data(map);
}
测试 swagger-ui.html
八.多条件分页查询
@PostMapping("/pageTeacherHelper/{current}/{size}")
public Response pageTeacherHelper(
@PathVariable("current") Integer current,
@PathVariable("size") Integer size,
@RequestBody(required = false) TeacherQuery teacherQuery
){
String name = teacherQuery.getName();
Integer level = teacherQuery.getLevel();
Date createTime = teacherQuery.getCreateTime();
QueryWrapper<EduTeacher> wrapper = new QueryWrapper<>();
if(!StringUtils.isEmpty(name)){
wrapper.like("name",name);
}
if(!StringUtils.isEmpty(level)){
wrapper.eq("level",level);
}
if(!StringUtils.isEmpty(createTime)){
wrapper.ge("gmt_create",createTime);
}
Page<EduTeacher> page = new Page<>(current,size);
eduTeacherService.page(page,wrapper);
long total = page.getTotal();
List<EduTeacher> records = page.getRecords();
return Response.ok().data("total",total).data("item",records);
}
注意点:
九.插入修改-自动填充
抽取公共模块:在service_base 下 src/main/java/com/atguigu/service_base 创建 handler,并创建类MyMetaObjectHandler
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("gmtCreate",new Date(),metaObject);
this.setFieldValByName("gmtModified",new Date(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("gmtModified",new Date(),metaObject);
}
}
启动类:扫描包@ComponentScan(“com.atguigu”)
实体类:@TableField
controller
@PostMapping("/addTeacher")
public Response addTeacher(
@RequestBody(required = false) EduTeacher eduTeacher){
boolean save = eduTeacherService.save(eduTeacher);
if(save){
return Response.ok();
}
return Response.err();
}
十.异常处理
我们想让异常结果也显示为统一的返回结果对象,并且统一处理系统的异常信息,需要统一异常处理
统一异常处理:创建统一异常处理器
在service-base中的handler包中创建统一异常处理类GlobalExceptionHandler.java:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseBody
public Response error(Exception e){
e.printStackTrace();
return Response.err().message("触发类全局异常");
}
}
然后导入 依赖 就可以了哦
特殊异常处理:与统一异常处理一样,只是换一下 异常类,
处理机制:当异常处理类中 触发了特殊异常 就不再执行统一异常了
自定义异常处理:需要手动抛出
-
定义一个异常 @Data
@AllArgsConstructor
@NoArgsConstructor
public class GuliException extends RuntimeException{
private Integer code;
private String message;
}
-
配置异常处理器 @ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseBody
public Response error(Exception e){
e.printStackTrace();
return Response.err().message("触发类全局异常");
}
@ExceptionHandler(GuliException.class)
@ResponseBody
public Response guliError(GuliException e){
e.printStackTrace();
return Response.err().code(e.getCode()).message(e.getMessage());
}
}
-
测试 @GetMapping("/teacher/{id}")
@ApiOperation("查询功能")
public Response selectTeacherById(@PathVariable("id") Integer id){
try {
System.out.println(10 / 0);
} catch (Exception e) {
throw new GuliException(20001,"触发了自定义异常");
}
return Response.ok().data("item", eduTeacherService.getById(id));
}
十一.日志
普通日志配置
日志记录器(Logger)的行为是分等级的。如下表示:
分为:OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL
默认情况下,spring boot 从控制台打印出来的日志级别只有INFO及以上级别,可以配置日志级别
# 设置日志级别
logging.level.root = WARN
这种方式,只能将日志打印到控制台
LogBack日志配置
Spring boot内部使用的Logback作为日志实现的框架
-
配置Logback日志
-
删除 application.properties中的日志配置 -
resources 中创建logback-spring.xml <?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
<contextName>logback</contextName>
<property name="log.path" value="D:/guli_log/edu" />
<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">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<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>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<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>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<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>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<springProfile name="dev">
<logger name="com.guli" level="INFO" />
<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>
这样 基本上就配置好了 -
将错误日志输出到文件 在 全局异常处理器类 上加上注解@Slf4j @ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {}
异常输出语句 log.error(e.getMessage())
-
将日志堆栈信息输出到文件 定义工具类 guli-framework-common下创建 util包,创建 ExceptionUtil.java工具类 public class ExceptionUtil {
public static String getMessage(Exception e) {
StringWriter sw = null;
PrintWriter pw = null;
try {
sw = new StringWriter();
pw = new PrintWriter(sw);
e.printStackTrace(pw);
pw.flush();
sw.flush();
} finally {
if (sw != null) {
try {
sw.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (pw != null) {
pw.close();
}
}
return sw.toString();
}
}
调用:log.error(ExceptionUtil.getMessage(e)); GuliException中创建toString方法 @Override
public String toString() {
return "GuliException{" +
"message=" + this.getMessage() +
", code=" + code +
'}';
}
|