springboot工具类

本文最后更新于:2 年前

javaweb中图片文件上传和下载

使用springboot创建web项目

服务端要接收客户端页面上传的文件,通常都会使用Apache的两个组件:

commons-fileupload
commons-io

Spring框架在spring-web包中对文件上传进行了封装,大大简化了服务端代码,实现步骤如下:

1.创建Controller

因为图片上传是一个公共接口所以可以创建一个名为CommonController的文件,url地址为/common

/**
 * 主要用于文件上传和下载
 */

@RestController
@RequestMapping("/common")
public class CommonController {
	@Value("${reggie.path}") // 保存图片的路径
    private String basePath;
}

上传图片

/**
 * 文件上传
 * @param file
 * @return
 */
@PostMapping("/upload")
public R<String> upload(MultipartFile file){
    // file是一个临时文件,后续需要进行转存
    // file需要与前端上传的参数名保持一致,否则无法获取到上传的文件
    // 转存之前需要对文件名进行处理
    String originalFilename = file.getOriginalFilename();
    String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));

    // 防止文件被覆盖,使用uuid作为文件名
    String filename = UUID.randomUUID().toString();
    filename = filename + suffix;

    File dir = new File(basePath); // 判断文件夹是否存在不存在则创建
    if (!dir.exists()){
        dir.mkdir();
    }
    // 将图片保存的指定位置
    try {
        file.transferTo(new File(basePath + filename));
    } catch (IOException e) {
        e.printStackTrace();
    }
    return R.success(filename);
}

下载图片

@GetMapping("/download")
public void download(String name, HttpServletResponse response) throws IOException {
    // 文件输入流读取本地文件
    FileInputStream fileInputStream = null;
    // 使用响应输出流将图片显示在网页上
    ServletOutputStream outputStream = null;

    try {
        fileInputStream = new FileInputStream(new File(basePath + name));
        outputStream = response.getOutputStream();
        response.setContentType("image/jpeg");
        byte[] bytes = new byte[1024];
        int len = 0;
        // 读取服务器上的图片后 由响应输出流
        while( (len = fileInputStream.read(bytes)) != -1){
            outputStream.write(bytes, 0, len);
            outputStream.flush();
        }

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        fileInputStream.close();
        outputStream.close();
    }
}

2.前端页面

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>文件上传</title>
  <!-- 引入样式 -->
  <link rel="stylesheet" href="../../plugins/element-ui/index.css" />
  <link rel="stylesheet" href="../../styles/common.css" />
  <link rel="stylesheet" href="../../styles/page.css" />
</head>
<body>
   <div class="addBrand-container" id="food-add-app">
    <div class="container">
        <el-upload class="avatar-uploader"
                action="/common/upload"
                :show-file-list="false"
                :on-success="handleAvatarSuccess"
                :before-upload="beforeUpload"
                ref="upload">
            <img v-if="imageUrl" :src="imageUrl" class="avatar"></img>
            <i v-else class="el-icon-plus avatar-uploader-icon"></i>
        </el-upload>
    </div>
  </div>
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="../../plugins/vue/vue.js"></script>
    <!-- 引入组件库 -->
    <script src="../../plugins/element-ui/index.js"></script>
    <!-- 引入axios -->
    <script src="../../plugins/axios/axios.min.js"></script>
    <script src="../../js/index.js"></script>
    <script>
      new Vue({
        el: '#food-add-app',
        data() {
          return {
            imageUrl: ''
          }
        },
        methods: {
          handleAvatarSuccess (response, file, fileList) {
              this.imageUrl = `/common/download?name=${response.data}`
          },
          beforeUpload (file) {
            if(file){
              const suffix = file.name.split('.')[1]
              const size = file.size / 1024 / 1024 < 2
              if(['png','jpeg','jpg'].indexOf(suffix) < 0){
                this.$message.error('上传图片只支持 png、jpeg、jpg 格式!')
                this.$refs.upload.clearFiles()
                return false
              }
              if(!size){
                this.$message.error('上传文件大小不能超过 2MB!')
                return false
              }
              return file
            }
          }
        }
      })
    </script>
</body>
</html>

mybatis-plus-generator

MP的代码生成器,可以节约创建文件的时间

1.导入依赖

<!--代码生成器-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.2</version>
</dependency>

2.编写生成器代码

可以放在专门的工具类包下

package com.sunzy.utils;

import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.util.Collections;

/**
 * mp代码生成器
 */
public class CodeGenreator {
    public static void main(String[] args) {
        generator();
    }

    public static void generator(){
        FastAutoGenerator.create("jdbc:mysql://localhost:3306/admin_demo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true",
                "username", "password")
                .globalConfig(builder -> {
                    builder.author("sunzy") // 设置作者
                            .enableSwagger() // 开启 swagger 模式
                            .fileOverride() // 覆盖已生成文件
                            .outputDir("E:\\Sunzh\\java\\admin_demo\\src\\main\\java\\"); // 指定输出目录
                })
                .packageConfig(builder -> {
                    builder.parent("com.sunzy") // 设置父包名
                            .moduleName("") // 设置父包模块名
                            .pathInfo(Collections.singletonMap(OutputFile.xml, "E:\\Sunzh\\java\\admin_demo\\src\\main\\resources\\mapper\\")); // 设置mapperXml生成路径 OutputEile.xml这里可能会报错 根据版本修改
                })
                .strategyConfig(builder -> {
                    builder.entityBuilder().enableLombok();
                    builder.mapperBuilder().enableMapperAnnotation().build();
                    builder.controllerBuilder().enableHyphenStyle()  // 连字符转驼峰
                            .enableRestStyle();  // 开启rest控制器
                    builder.addInclude("sys_user") // 设置需要生成的表名
                            .addTablePrefix("t_", "sys_"); // 设置过滤表前缀
                })
//                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                .execute();

    }
}

完成后,直接运行改工具类就可以直接生成以下文件:

UserMapper.java IUserService.java UserServiceImpl.java UserController.java

3.Controller模板

可以根据需要修改自己的模板

package ${package.Controller};


import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import ${package.Service}.${table.serviceName};
import ${package.Entity}.${entity};

#if(${restControllerStyle})
import org.springframework.web.bind.annotation.RestController;
#else
import org.springframework.stereotype.Controller;
#end
#if(${superControllerClassPackage})
import ${superControllerClassPackage};
#end

/**
 * <p>
 * $!{table.comment} 前端控制器
 * </p>
 *
 * @author ${author}
 * @since ${date}
 */
#if(${restControllerStyle})
@RestController
#else
@Controller
#end
@RequestMapping("#if(${package.ModuleName})/${package.ModuleName}#end/#if(${controllerMappingHyphenStyle})${controllerMappingHyphen}#else${table.entityPath}#end")
#if(${kotlin})
class ${table.controllerName}#if(${superControllerClass}) : ${superControllerClass}()#end

#else
    #if(${superControllerClass})
    public class ${table.controllerName} extends ${superControllerClass} {
    #else
    public class ${table.controllerName} {
    #end

@Resource
private ${table.serviceName} ${table.entityPath}Service;

// 新增或者更新
@PostMapping
public boolean save(@RequestBody ${entity} ${table.entityPath}) {
        return ${table.entityPath}Service.saveOrUpdate(${table.entityPath});
}

@DeleteMapping("/{id}")
public Boolean delete(@PathVariable Integer id) {
        return ${table.entityPath}Service.removeById(id);
}

@PostMapping("/del/batch")
public boolean deleteBatch(@RequestBody List<Integer> ids) {
        return ${table.entityPath}Service.removeById(ids);
}

@GetMapping
public List<${entity}> findAll() {
        return ${table.entityPath}Service.list();
}

@GetMapping("/{id}")
public ${entity} findOne(@PathVariable Integer id) {
        return ${table.entityPath}Service.getById(id);
}

@GetMapping("/page")
public Page<${entity}> findPage(@RequestParam Integer pageNum,
@RequestParam Integer pageSize) {
        LambdaQueryWrapper<${entity}> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc("id");
        return ${table.entityPath}Service.page(new Page<>(pageNum, pageSize), queryWrapper);
	}
}

#end

更多的模板可以到com.baomidou.mybatis-plus-generator包中复制到项目的resources\templates中,根据自己的需求修改模板

image-20220513194907662

Swagger

1.导入依赖

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>

2.创建配置类

com.sunzy.fmmall.config.SwaggerConfig路径下创建swagger的配置类

配置文档的封面信息 包括标题,版本,作者信息

修改需要扫面的controller包位置即可

package com.sunzy.fmmall.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.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 {
    /**
     * swagger可以自动生成接口文档
     * 1.配置生成文档的信息
     * 2.配置生成规则
     *
     */

    /**
     * Docket用来封装接口文档
     *
     * @return
     */

    @Bean
    public Docket getDocket(){
        //创建封面信息对象
        ApiInfoBuilder apiInfoBuilder = new ApiInfoBuilder();
        apiInfoBuilder.title("《锋迷商城》后端接口说明")
                .description("此文档详细说明了锋迷商城项目后端接口规范....")
                .version("v 2.0.1")
                .contact( new Contact("sunzy","www.suzny.com","sunzy@wang.com") );
        ApiInfo apiInfo =  apiInfoBuilder.build();

        Docket docket = new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo) //指定生成的文档中的封面信息:文档标题、版本、作者
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.sunzy.fmmall.controller"))
                .paths(PathSelectors.any())
                .build();

        return docket;
    }
}

启动springboot项目访问项目地址/swagger-ui.html即可看到相关接口信息,并可以进行测试

image-20220710113522350

3.swagger注解说明

Swagger提供一套详细的注解可以对接口进行详细的说明

@Api 类注解,对控制器类添加此注解可以对控制器进行功能说明

@Api(value = "用户管理", tags = "提供用户注册和登录服务")

@ApiOperation 方法注解,对每个方法作用进行详细说明

@ApiOperation("用户登录接口")

@ApiImplicitParams和@ApiImplicitParam 对方法中的参数进行详细的说明,包括字段名,备注,是否必须,以及默认值

@ApiImplicitParams(
        @ApiImplicitParam(dataType = "string", name = "username", value = "用户账号", required = true),
        @ApiImplicitParam(dataType = "string", name = "password", value = "用户密码", required = true)
)

@ApiModel 当接口参数和返回值类型为对象类型是需要添加此注解

@ApiModel(value = "ResultVO对象",description = "封装接口返回给前端的数据")

@ApiModelProperty 模型中的成员变量进行说明

@ApiModelProperty(value = "响应状态码",dataType = "int")
private int code;

@ApiIngnore接口方法注解,添加此注解的方法不会出现在接口文档中

4.swagger-ui插件

导入插件依赖

<!--swagger-ui插件依赖-->
<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>swagger-bootstrap-ui</artifactId>
    <version>1.9.6</version>
</dependency>

访问url:http://localhost:8080/doc.html ,ui界面设计更加美观

image-20220710133641781

tkMapper

整合tkmapper

1.导入依赖

<dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper-spring-boot-starter</artifactId>
    <version>2.1.5</version>
</dependency>

2.配置application.yml文件

spring:
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      username: root
      password: root
      url: jdbc:mysql://localhost:3306/fmmall?characterEncoding=utf-8&useSSL=false
mybatis:
  mapper-locations: classpath:mapper/*Mapper.xml
  type-aliases-package: com.sunzy.fmmall.dao

3.修改启动类

注意MapperScan需要使用tkmapper包中的

package com.sunzy.tkmapper;

//import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import tk.mybatis.spring.annotation.MapperScan;

@SpringBootApplication
//@MapperScan("com.sunzy.tkmapper.dao")
@MapperScan("com.sunzy.tkmapper.dao")
public class TkmapperDemoApplication {

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

}

4.逆向工程

导入插件依赖

<plugin>
               <groupId>org.mybatis.generator</groupId>
               <artifactId>mybatis-generator-maven-plugin</artifactId>
               <version>1.3.5</version>
               <dependencies>
                   <dependency>
                       <groupId>mysql</groupId>
                       <artifactId>mysql-connector-java</artifactId>
                       <version>5.1.47</version>
                   </dependency>
                   <dependency>
                       <groupId>tk.mybatis</groupId>
                       <artifactId>mapper</artifactId>
                       <version>3.4.4</version>
                   </dependency>
               </dependencies>
           </plugin>

添加配置文件GeneratorConfig.xml

记得修改对应包名<!--**-->标记处需要修改

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration
1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!-- 引⼊数据库连接配置 -->
    <!-- <properties resource="jdbc.properties"/>-->
    <context id="Mysql" targetRuntime="MyBatis3Simple"
             defaultModelType="flat">
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>
        <!-- 配置 GeneralDAO -->
        <plugin type="tk.mybatis.mapper.generator.MapperPlugin"> 
            <property name="mappers"
                      value="com.sunzy.fmmall.general.GeneralDao"/><!--**-->
        </plugin>
        <!-- 配置数据库连接 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/fmmall?useSSL=false" 
                        userId="root" password="root"><!--**-->
        </jdbcConnection>
        <!-- 配置实体类存放路径 -->
        <javaModelGenerator
                targetPackage="com.sunzy.fmmall.entity"
                targetProject="src/main/java"/>   <!--**-->
        <!-- 配置 XML 存放路径 -->
        <sqlMapGenerator targetPackage="/"
                         targetProject="src/main/resources/mapper"/> <!--**-->
        <!-- 配置 DAO 存放路径 -->
        <javaClientGenerator targetPackage="com.sunzy.fmmall.dao"
                             targetProject="src/main/java" type="XMLMAPPER"/>  <!--**-->
        <!-- 配置需要指定⽣成的数据库和表,% 代表所有表 -->
        <table tableName="%">
            <!-- mysql 配置 -->
            <!-- <generatedKey column="id" sqlStatement="Mysql"
            identity="true"/>-->
        </table>
        <!-- <table tableName="tb_roles">-->
        <!-- &lt;!&ndash; mysql 配置 &ndash;&gt;-->
        <!-- <generatedKey column="roleid" sqlStatement="Mysql"
        identity="true"/>-->
        <!-- </table>-->
        <!-- <table tableName="tb_permissions">-->
        <!-- &lt;!&ndash; mysql 配置 &ndash;&gt;-->
        <!-- <generatedKey column="perid" sqlStatement="Mysql"
        identity="true"/>-->
        <!-- </table>-->
    </context>
</generatorConfiguration>

创建com.sunzy.fmmall.general.GeneralDao

package com.sunzy.fmmall.general;

import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;

public interface GeneralDao<T> extends Mapper<T>, MySqlMapper<T> {
}

在pom.xml中添加配置文件的位置

image-20220710225357498

使用插件进行代码生成

image-20220710225431382

JWT实现登录权限认证

1.导入JWT依赖

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.10.3</version>
</dependency>

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

2.生成对应的token并返回给前端

// 验证成功则生成对应的token
// 使用jwt生成token
JwtBuilder builder = Jwts.builder();
Map<String, Object> map = new HashMap<>();
map.put("key1", "value2");
map.put("key2", "value2");
JwtBuilder jwtBuilder = builder.setSubject(username)    //设置subject
    .setIssuedAt(new Date())        // 设置token生成的时间
    .setId(user.getUserId() + "")        // 设置userid为token的唯一id
    .setClaims(map)                 // map中可以存放用户的角色和权限信息
    .setExpiration(new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000 * 2))               // 设置token的过期时间 为两天
    .signWith(SignatureAlgorithm.HS256, "sunzy123456");// 设置token的加密方式和加密密钥

String token = jwtBuilder.compact();   // 获取token
return new ResultVO(ResStatus.OK, token, user);

3.前端进行登录验证时获取对应的token

image-20220711172838166

4.JWT进行token解析

if(token == null || "".equals(token)){
    return new ResultVO(ResStatus.NO, "failed", null);
}else {
    JwtParser parser = Jwts.parser();
    parser.setSigningKey("sunzy123456"); // 密钥需要与加密时使用的一致
    try{
        // 如果token正确 且在有效期内 则解析正常否则会出现异常
        Jws<Claims> claimsJws = parser.parseClaimsJws(token);
        Claims body = claimsJws.getBody();  // 获取token中的用户数据
        String subject = body.getSubject();  // 获取token中发subject
        String key1 = body.get("key1", String.class);  /// 获取添加在map中的值
    }catch(UnsupportedJwtException e){
        return new ResultVO(ResStatus.NO, "token不合法请重新登录!", null);
    }catch(ExpiredJwtException e){
        return new ResultVO(ResStatus.NO, "token已过期,请重新登录!", null);
    }
    catch (Exception e){
        return new ResultVO(ResStatus.NO, "未知错误", null);
    }

5.使用拦截器验证token

  • 创建拦截器

    package com.sunzy.fmmall.interceptor;
    
    import com.alibaba.fastjson.JSON;
    import com.sunzy.fmmall.vo.ResStatus;
    import com.sunzy.fmmall.vo.ResultVO;
    import io.jsonwebtoken.*;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.stereotype.Component;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    @Component
    public class CheckTokenInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            String token = request.getParameter("token");
    
            if (token == null || "".equals(token)) {
                doResponse(response, "请先登录!");
                return false;
            } else {
                JwtParser parser = Jwts.parser();
                parser.setSigningKey("sunzy123456"); // 密钥需要与加密时使用的一致
                try {
                    // 如果token正确 且在有效期内 则解析正常否则会出现异常
                    Jws<Claims> claimsJws = parser.parseClaimsJws(token);
                    Claims body = claimsJws.getBody();  // 获取token中的用户数据
                    String subject = body.getSubject();  // 获取token中发subject
                    String key1 = body.get("key1", String.class);  /// 获取添加在map中的值
                    return true;
                } catch (UnsupportedJwtException e) {
                    doResponse(response,"token不合法,请重新登录!");
                } catch (ExpiredJwtException e) {
                    doResponse(response,"token已过期,请重新登录!");
                } catch (Exception e) {
                    doResponse(response,"未知错误!");
                }
    
                return false;
            }
        }
    
        private void  doResponse(HttpServletResponse response, String msg) throws IOException {
            ResultVO resultVO = new ResultVO(ResStatus.NO, msg, null);
            String string = JSON.toJSONString(resultVO);
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            PrintWriter writer = response.getWriter();
            writer.write(string);
            writer.flush();
            writer.close();
        }
    
    }
    
  • 配置拦截器

    package com.sunzy.fmmall.config;
    
    import com.sunzy.fmmall.interceptor.CheckTokenInterceptor;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    /**
     * 拦截器的配置类
     */
    @Configuration
    public class InterceptorConfig implements WebMvcConfigurer {
    
        @Autowired
        private CheckTokenInterceptor checkTokenInterceptor;
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            // registry是拦截器的注册器
            // 将自己创建的拦截器加入进来 即可实现拦截功能
            registry.addInterceptor(checkTokenInterceptor)
            .addPathPatterns("/**")  // 拦截所有路径
            .excludePathPatterns("/user/**"); // 除了用户登录和注册路径
        }
    }
    

加密使用到工具类

1.md5

package com.qfedu.fmmall.utils;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

//MD5 生成器
public class MD5Utils {
	public static String md5(String password){
		//生成一个md5加密器
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			//计算MD5 的值
			md.update(password.getBytes());
			//BigInteger 将8位的字符串 转成16位的字符串 得到的字符串形式是哈希码值
			//BigInteger(参数1,参数2) 参数1 是 1为正数 0为0 -1为负数
			return new BigInteger(1, md.digest()).toString(16);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return null;
	}
}

2.base64

package com.qfedu.fmmall.utils;

import java.util.Base64;

//base64 加密 解密 激活邮件的时候 为 邮箱地址 code验证码 进行加密
//当 回传回来后 进行邮箱地址 和 code 的解密
public class Base64Utils {
	//加密
	public static String encode(String msg){
		return Base64.getEncoder().encodeToString(msg.getBytes());
	}
	//解密
	public static String decode(String msg){
		return new String(Base64.getDecoder().decode(msg));
	}
}

logback日志

添加xml文件

在springboot项目的resource目录下创建logback-spring.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <springProfile name="dev">
                <pattern>%d{yyyy-MM-dd-HH:mm:ss E} %level [%thread]-%class[%line]: %msg%n</pattern>
            </springProfile>
            <springProfile name="!dev">
                <pattern>%d{yyyy-MM-dd-HH:mm:ss E} %level [%thread]-%class[%line]: %msg%n</pattern>
            </springProfile>
            <!--日志的编码格式-->
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <appender name="timeFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--TimeBasedRollingPolicy  基于时间的滚动策略-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>log/log-%d{yyyy-MM-dd-HH}.log</fileNamePattern>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd-HH:mm:ss.SSS} %level [%thread]-%class:%line>>%msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <root level="info">
        <appender-ref ref="stdout"/>
        <appender-ref ref="timeFile"/>
    </root>

</configuration>

在sercie实现类创建Logger对象,输⼊⽇志

image-20220719162517298

日志会被记录到项目的/log目录下,且是按每日记录

log/log-%d{yyyy-MM-dd-HH}.log

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

 目录

Copyright © 2020 my blog
载入天数... 载入时分秒...