宋子宪博客 - Spring Boot
type: channel
link: https://www.songzixian.com/category/springboot
description: Spring Boot
items: Spring Boot整合ZXing实现二维码和条形码生成
items: Spring Boot 优雅进行数据脱敏
items: Spring Boot优雅实现注解切换多数据源
items: Java整合Jsch实现SFTP连接对服务器文件增删改查操作
items: Spring Boot启动jar包动态添加配置文件参数
items: spring boot整合WebSocket实现群聊功能 通俗易懂教程
items: Spring Boot整合RocketMQ实现延迟消息消费
items: spring boot项目使用maven插件将项目和jar包依赖以及静态资源分离打包
items: Spring Boot动态识别生产和测试环境文件
items: Spring Boot整合Hutool实现防止文件重复上传

Spring Boot整合ZXing实现二维码和条形码生成
type: item
date: 2023-12-18T11:30:00+08:00
description: 1. 添加ZXing依赖到Spring Boot项目场景描述: 在需要快速、高效地生成二维码或条形码的应用中，如电子票务、产品追踪、个人身份验证等，集成ZXing库至Spring Boot项目是至关重要的一步。在项目的pom.xml文件中添加以下依赖以引入ZXing库：xmlCopy code<dependencies> <dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>3.5.2</version> </dependency> </dependencies>使用最新版本的ZXing库可以确保你的应用具备最新的二维码和条形码生成能力，包括更好的性能和支持更多格式。2. 创建二维码生成服务场景描述: 此服务类适用于需要将URL、文本信息或其他数据快速转换为二维码图像的场合，如商业广告、社交媒体共享、安全验证等。代码示例与注释:import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.MultiFormatWriter; import com.google.zxing.common.BitMatrix; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.util.HashMap; import java.util.Map; /** * 生成二维码图像类 * * @author songzixian */ public class QRCodeService { /** * 生成二维码图像 * * @param text 要编码的文本 * @param width 二维码图像宽度 * @param height 二维码图像高度 * @param filePath 文件存储路径 * @return 生成的二维码图像的字节数组 */ public void generateQRCode(String text, int width, int height, String filePath) { try { // 定义二维码参数 Map<EncodeHintType, Object> hints = new HashMap<>(); // 设置字符编码 hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 错误纠正级别 hints.put(EncodeHintType.ERROR_CORRECTION, com.google.zxing.qrcode.decoder.ErrorCorrectionLevel.H); // 二维码边距 hints.put(EncodeHintType.MARGIN, 1); // 使用QRCodeWriter生成二维码矩阵信息 MultiFormatWriter writer = new MultiFormatWriter(); BitMatrix bitMatrix = writer.encode(text, BarcodeFormat.QR_CODE, width, height, hints); // 将二维码矩阵信息转换为图像 BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { image.setRGB(x, y, bitMatrix.get(x, y) ? Color.BLACK.getRGB() : Color.WHITE.getRGB()); } } // 江二维码保存成文件 File qrCodeFile = new File(filePath); ImageIO.write(image, "png", qrCodeFile); System.out.println("二维码生成成功: " + filePath); } catch (Exception e) { e.printStackTrace(); } } /** * 测试 */ public static void main(String[] args) { QRCodeServi…

Spring Boot 优雅进行数据脱敏
type: item
date: 2023-09-24T19:59:00+08:00
description: 文详细解析在Spring Boot应用中优雅地脱敏敏感信息，如手机号、邮箱、身份证等，使用的是Jackson库中的JsonSerializer。1. 创建自定义脱敏序列化器首先，创建一个继承自JsonSerializer<String>的序列化器。以MobileSerializer为例，代码如下：import cn.hutool.core.util.DesensitizedUtil; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; /** * * 自定义手机序列号器 * * * @author snogzixian * @since 2023-09-24 */ public class MobileSerializer extends JsonSerializer<String> { /** * 自定义序列化方法，用于对手机号进行脱敏处理并写入JSON生成器。 * * @param mobile 要序列化的手机号 * @param jsonGenerator JSON生成器，用于写入序列化后的数据 * @param serializerProvider 序列化提供者，提供序列化所需的服务 * @throws IOException 如果在序列化过程中发生I/O错误 */ @Override public void serialize(String mobile, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { // 检查手机号是否为null或者是否是有效的手机号 if (mobile == null || !isValidMobile(mobile)) { // 如果手机号无效，直接输出原始手机号 jsonGenerator.writeString(mobile); return; } // 调用脱敏工具类对手机号进行脱敏处理 String mobileDesensitized = DesensitizedUtil.mobilePhone(mobile); // 将脱敏后的手机号字符串写入到JSON生成器jsonGenerator中 jsonGenerator.writeString(mobileDesensitized); } /** * 检查手机号的合法性 * * @param mobile 手机号 * @return 如果手机号合法则返回true，否则返回false */ private boolean isValidMobile(String mobile) { // 在此处添加对手机号合法性的检查逻辑 return true; } }其中，serialize方法用于处理数据的脱敏逻辑，isValidMobile用于检查数据的合法性。2. 使用自定义序列化器在实体类中，使用@JsonSerialize注解指定字段使用自定义序列化器。例如，对于一个用户的手机号，我们在实体类中如下使用：/** * * 实体类 * * * @author snogzixian * @since 2023-09-24 */ public class User { @JsonSerialize(using = MobileSerializer.class) private String mobile; // 其他字段和getter、setter }3. 扩展性 - 支持多类型数据脱敏为支持多类型数据（如邮箱、身份证等）脱敏，你可以为每种数据类型创建对应的序列化器类，类似于MobileSerializer。例如，创建一个EmailSerializer处理邮箱脱敏：public class EmailSerializer extends JsonSerializer<String> { // 实现邮箱的脱敏逻辑 }在实体类中，对应字段使用@JsonSerialize注解指定使用EmailSerializer。public class User { @JsonSerialize(using = EmailSerializer.class) private String email; // 其他字段和getter、setter }

Spring Boot优雅实现注解切换多数据源
type: item
date: 2023-03-15T11:36:00+08:00
description: 请帮我完善这篇文档,并且里面的代码添加注释实现注解切换多数据源需要以下步骤：1.首先添加了AOP、MyBatis、Druid和MySQL的依赖。 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.0</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.6</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.27</version> </dependency>2.配置两个数据源，一个是master，一个是slave，同时设置了Druid连接池的参数，以及MyBatis的相关配置。spring: datasource: druid: defaultAutoCommit: true initialSize: 5 maxActive: 20 maxWait: 60000 minIdle: 5 testOnBorrow: false testOnReturn: false testWhileIdle: true timeBetweenEvictionRunsMillis: 60000 validationQuery: SELECT 1 FROM DUAL filters: stat,wall,log4j2 connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 master: url: jdbc:mysql://localhost:3306/master?useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: root driver-class-name: com.mysql.jdbc.Driver slave: url: jdbc:mysql://localhost:3306/slave?useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: root driver-class-name: com.mysql.jdbc.Driver mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.demo.entity configuration: map-underscore-to-camel-case: true3.创建一个枚举类，用于区分不同的数据源。/** * * 枚举类，用于区分不同的数据源 * * * @author snogzixian * @Url 宋子宪博客 www.songzixian.com * @since 2023-03-15 */ public enum DataSourceType { /** * 主数据源 */ MASTER("master"), /** * 从数据源 */ SLAVE("slave"); private final String value; DataSourceType(String value) { this.value = value; } public String getValue() { return value; } }4.创建一个注解类，用于标识需要使用哪个数据源。import com.songzixian.enums.DataSourceType; import java.lang.annotation.*; /** * * 注解类，用于标识需要使用哪个数据源 * * * @author snogzixian * @Url 宋子宪博客 www.songz…

Java整合Jsch实现SFTP连接对服务器文件增删改查操作
type: item
date: 2023-03-13T15:37:00+08:00
description: 我们在开发中，有时候需要操作服务器上的文件，Spring Boot可以使用JSch库来连接SFTP并进行操作服务器上的文件读写。创建一个SFTP连接需要以下步骤：1.创建JSch对象2.使用JSch对象创建Session对象3.使用Session对象连接到SFTP服务器4.打开SFTP通道5.使用SFTP通道打开SFTP连接1.添加依赖在pom.xml文件中添加以下依赖：<dependency> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>0.1.55</version> </dependency>2.创建SftpConfig配置类import lombok.Getter; import lombok.Setter; /** * * SFTP连接参数配置类 * description: 如果后续只需要操作一台固定不变的服务器,可以从配置文件中读取 * * * @author snogzixian * @Url 宋子宪博客 www.songzixian.com * @since 2023-03-13 */ @Setter @Getter public class SftpConfig { /** * SFTP服务器地址 */ private String host; /** * SFTP服务器端口 */ private int port; /** * SFTP服务器用户名 */ private String username; /** * SFTP服务器密码 如果不使用密码方式则留空 */ private String password; /** * 密钥文件路径，如果不使用密钥连接则留空 */ private String privateKeyPath; /** * 密钥文件口令，如果不使用密钥连接则留空 */ private String passphrase; /** * 连接SFTP服务器超时时间 2秒 */ private Integer sessionConnectTimeoutTime = 2000; /** * 打开通道超时时间 2秒 */ private Integer channelSftpConnectTimeoutTime = 2000; /** * 密码方式连接方法 * * @param host SFTP服务器地址 * @param port SFTP服务器端口 * @param username SFTP服务器用户名 * @param password SFTP服务器密码 如果不使用连接则留空 */ public SftpConfig(String host, int port, String username, String password) { this.host = host; this.port = port; this.username = username; this.password = password; } /** * 秘钥方式连接方法 * * @param host SFTP服务器地址 * @param port SFTP服务器端口 * @param username SFTP服务器用户名 * @param privateKeyPath 密钥文件路径，如果不使用密钥连接则留空 * @param passphrase 密钥文件口令，如果不使用密钥连接则留空 */ public SftpConfig(String host, int port, String username,String privateKeyPath, String passphrase) { this.host = host; this.port = port; this.username = username; this.privateKeyPath = privateKeyPath; this.passphrase = passphrase; } }3.创建SFTP操作工具类import com.jcraft.jsch.*; import com.risk.riskControl.config.SftpConfig; import java.io.*; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; /** * * SFTP操作工具类 * * * @author snogzixian * @Url 宋子宪博客 www.songzixian.com * @since 2023-03-1…

Spring Boot启动jar包动态添加配置文件参数
type: item
date: 2023-03-12T22:15:00+08:00
description: Spring Boot项目动态启动设置参数的好处有以下几点：灵活性：通过动态设置参数，可以根据不同的环境和需求来灵活地配置应用程序，适应不同的场景。可维护性：动态设置参数可以避免硬编码，使得应用程序更易于维护和升级。安全性：通过动态设置参数，可以避免敏感信息（如数据库密码、密钥等）被硬编码到代码中，提高应用程序的安全性。可扩展性：通过动态设置参数，可以方便地扩展应用程序的功能，增加新的配置项，而不需要修改应用程序的代码。自动化部署：通过动态设置参数，可以方便地实现自动化部署，使得部署过程更加简洁、高效。以下可以设置的参数大概有这些--server.port：指定服务端口号。 --spring.profiles.active：指定激活的Spring配置文件。 --logging.level.root：指定日志级别。 --management.server.port：指定管理端口号。 --spring.config.name：指定配置文件的名称。 --spring.config.location：指定配置文件的路径。 --spring.application.name：指定应用程序名称。 --spring.datasource.url：指定数据源URL。 --spring.datasource.username：指定数据源用户名。 --spring.datasource.password：指定数据源密码。 --spring.jpa.show-sql：指定是否显示SQL语句。 --spring.jpa.hibernate.ddl-auto：指定Hibernate的DDL模式。 --spring.main.banner-mode：指定启动Banner模式。 --spring.main.web-application-type：指定应用程序类型。 --spring.main.allow-bean-definition-overriding：指定是否允许Bean覆盖。 --spring.main.lazy-initialization：指定是否启用懒加载。 --spring.main.sources：指定应用程序的源。 --spring.main.web-environment：指定Web环境类型。 --spring.profiles.include：指定需要包含的Spring配置文件。 --spring.profiles.exclude：指定需要排除的Spring配置文件。使用示例:例如启动szxBlog.jar包指定服务端口号为8080：java -jar szxblog.jar --server.port=8080指定激活的Spring配置文件为dev：java -jar szxblog.jar --spring.profiles.active=dev指定日志级别为DEBUG：java -jar szxblog.jar --logging.level.root=DEBUG指定管理端口号为8081：java -jar szxblog.jar --management.server.port=8081指定配置文件的名称为application：java -jar szxblog.jar --spring.config.name=application指定配置文件的路径为/etc/szxblog/：java -jar szxblog.jar --spring.config.location=file:/etc/szxblog/指定应用程序名称为szxblog：java -jar szxblog.jar --spring.application.name=szxblog指定数据源URL为jdbc:mysql://localhost:3306/szxblog：java -jar szxblog.jar --spring.datasource.url=jdbc:mysql://localhost:3306/szxblog指定数据源用户名为myuser：java -jar szxblog.jar --spring.datasource.username=myuser指定数据源密码为mypassword：java -jar szxblog.jar --spring.datasource.password=mypassword注意：以上命令中的参数值需要根据实际情况进行修改。

spring boot整合WebSocket实现群聊功能 通俗易懂教程
type: item
date: 2023-03-11T23:35:00+08:00
description: 首先获取消息的内容，即payload。将payload转换为JSONObject对象，并从中获取消息类型type。如果消息类型是"join"，则从消息中获取群组ID，并将当前WebSocketSession的ID加入到该群组对应的Set中。如果消息类型是"leave"，则从消息中获取群组ID，并从该群组对应的Set中移除当前WebSocketSession的ID。如果消息类型是"message"，则从消息中获取群组ID，并获取该群组对应的所有WebSocketSession，逐一向这些Session发送消息。其中，groups和sessions是两个Map，分别用来存储群组与其对应的WebSocketSessions。computeIfAbsent和computeIfPresent方法分别用来向Map中添加元素和更新元素。sendMessage方法用来向客户端发送消息。导入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>创建MyWebSocketHandler类import com.songzixain.service.MyWebSocketHandler; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; import org.springframework.web.socket.server.standard.ServerEndpointExporter; /** * * Description: WebSocketConfig配置类 * * * @author songzixian * @version v2.0.0 * @create 2023-03-11 15:57 * @see com.songzixain.config */ @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(new MyWebSocketHandler(), "/ws").setAllowedOrigins("*"); 创建MyWebSocketHandler类这段代码是一个WebSocket处理器中的消息处理方法，用来处理WebSocket客户端发送的消息/** * * Description: MyWebSocketHandler用 来处理WebSocket客户端发送的消息 * * * @author songzixian * @version v2.0.0 * @create 2023-03-11 22:44 * @see com.songzixain.service */ @Slf4j public class MyWebSocketHandler implements WebSocketHandler { private static final Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>(); private static final Map<String, Set<String>> groups = new ConcurrentHashMap<>(); @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { sessions.put(session.getId(), session); } @Override public void handleM…

Spring Boot整合RocketMQ实现延迟消息消费
type: item
date: 2023-03-11T13:45:00+08:00
description: 导包 <dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-spring-boot-starter</artifactId> <version>2.0.3</version> </dependency> 添加配置信息application配置文件# rocketMq地址 rocketmq.name-server=106.52.60.215:9876 # 生产者分组 rocketmq.producer.group=myGroup rocketmq.producer.topics=topic1 # 消费者分组 rocketmq.consumer.group=myGroup # topic rocketmq.consumer.topics=topic1 # 表示顺序消费模式 rocketmq.consumer.consume-mode=ORDERLY # 消费者的最大线程数，即消费消息的线程池大小。默认值为20，如果不需要处理大量的消息，可以将其调小。 rocketmq.consumer.consume-thread-max=1 # 表示每次消费消息的最大数量，即一次性消费的最大消息数。默认值为1，即每次只消费一条消息。如果需要批量消费消息，可以将其调大。但是需要注意的是，批量消费消息可能会影响消费的效率和消息的顺序性。 rocketmq.consumer.consume-message-batch-max-size=1yml配置文件rocketmq: consumer: consume-message-batch-max-size: 1 consume-mode: ORDERLY consume-thread-max: 1 group: myGroup topics: topic1 name-server: 106.52.60.215:9876 producer: group: myGroup topics: topic1 生产者发送消息同步发现消息在Spring Boot中，可以使用RocketMQTemplate来发送消息。设置消息的延迟级别，可以使用RocketMQTemplate的send(Message message, long timeout, int delayLevel)方法，其中delayLevel为延迟级别，单位为秒RocketMQ支持18个级别的延迟时间，分别为1s、5s、10s、30s、1m、2m、3m、4m、5m、6m、7m、8m、9m、10m、20m、30m、1h、2himport com.songzixain.Blog; import lombok.extern.slf4j.Slf4j; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.messaging.Message; import org.springframework.messaging.support.MessageBuilder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; /** * * Description: 消息生产者 * * * @author songzixian * @version v2.0.0 * @create 2023-03-11 21:10 * @see com.songzixain.controller */ @Slf4j @RestController public class MyProducer1 { @Value("${rocketmq.producer.topics}") private Str…

spring boot项目使用maven插件将项目和jar包依赖以及静态资源分离打包
type: item
date: 2023-01-07T13:29:00+08:00
description: 将spring boot的pom.xml文件中的build替换为以下,然后刷新maven,打包即可 <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <excludes> <include>*.*</include> </excludes> <archive> <manifest> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> <useUniqueVersions>false</useUniqueVersions> <mainClass>com.songzixian.SzxBlogApplication </mainClass> </manifest> <manifestEntries> <Class-Path>config/</Class-Path> </manifestEntries> </archive> <outputDirectory>${project.build.directory}</outputDirectory> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>copy-dependencies</id> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>${project.build.directory}/lib</outputDirectory> </configuration> </execution> </executions> </plugin> <!-- 这个插件是用来复制项目的静态资源 windows命令 java -jar -Dloader.path=config,lib rocket-web-1.0-SNAPSHOT.jar Linux 命令 nohup java -jar -Dloader.path=config,lib rocket-web-1.0-SNAPSHOT.jar >> dispatche.log & --> <plugin> <artifactId>maven-resources-plugin</artifactId> <executions> <execution> <id>copy-resources</id> <phase>package</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>*.*</include> </includes> </resource> </resources> <outputDirectory>${project.build.directory}/config</outputDirectory> </configuration> </execution> </executions> </plugin> </plugins> </build> 使用maven命令,或者IDEA插件打包mvn clean package打包后target目录会生成包含以下三个文件,config(配置) ,lib(jar包依赖),*.jar是项目包,将这3个目录文件拷贝到服务器,即可启动,这样打包的好处就是讲项目jar包和依赖分开,一般小项目jar包几百kb左右前台启动java -jar -Dloader.path=config,lib szxblog-1.0-SNAPSHOT.jar后台启动nohup java -jar -Dloader.path=config,lib szxblog-1.0-SNAPSHOT.jar > szxblog.log 2>&1 &带JVM参数的后台启动nohup java -Xms2048m -Xmx4096m -jar -Dloader.path=conf…

Spring Boot动态识别生产和测试环境文件
type: item
date: 2022-10-11T17:46:00+08:00
description: 首先创建以下4个spring boot配置文件application.yml bootstrap.yml // 默认公共文件 dev和prod可以重写配置 bootstrap-dev.yml //开发环境文件 bootstrap-prod.yml //生成环境在启动类里新增加载配置文件代码 import cn.hutool.core.net.NetUtil; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Spirng Boot启动类 */ @SpringBootApplication public class BlogApplication { public static void main(String[] args) { // 自动加载是开发环境还是生产环境 String environment = "--spring.profiles.active="; if (!String.join("", args).contains(environment)) { List<String> argList = new ArrayList<String>(Arrays.asList(args)); // 生成环境内网ip String prodIntranetIp = ""; // ping生产服务器的内网IP,如果能ping通代表是生成环境 boolean ping = NetUtil.ping(prodIntranetIp); if (ping == true) { // 生成环境配置文件 environment = "--spring.profiles.active=prod"; } else { // 测试环境配置文件 environment = "--spring.profiles.active=dev"; } // 添加环境参数到集合中 argList.add(environment); // list转数组 args = argList.toArray(args); } SpringApplication.run(BlogApplication.class, args); } }

Spring Boot整合Hutool实现防止文件重复上传
type: item
date: 2022-07-16T14:39:00+08:00
description: 1.需要先搭建Spring Boot工程2.引入hutool工具类依赖<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.4</version> </dependency>文档:Spring MVC的MultipartFile接口常用API方法功能描述String getOriginalFilename()获取上传文件的原始文件名，即该文件在客户端中的文件名boolean isEmpty()判断上传的文件是否为空，当没有选择文件就直接上传，或者选中的文件是0字节的空文件时，返回true，否则返回falselong getSize()获取上传的文件大小，以字节为单位String getContentType()根据所上传的文件的扩展名决定该文件的MIME类型，例如上传.jpg格式的图片，将返回image/jpegInputStream getInputStream()获取上传文件的输入字节流，通常用于自定义读取所上传的文件的过程，该方法与transferTo()方法不可以同时使用void transferTo(File dest)保存上传的文件，该方法与getInputStream()方法不可以同时使用核心代码/** * description 文件上传 * * @return {@link AjaxResult} * @param: [multipartFile] * @Date 2022/7/16 */ @PostMapping("fileUpload") public String fileUpload(MultipartFile multipartFile) throws IOException { String PATH = "D:\\file\\"; log.info("multipartFile:{}", multipartFile); //判断上传的文件是否为空 if (multipartFile ==null || multipartFile.isEmpty()){ return "请选选择文件再上传，参数名multipartFile"; } String contentType = multipartFile.getContentType(); log.info("文件类型:{}",contentType); //获取文件名 String fileName = multipartFile.getOriginalFilename(); //获取文件后缀名 没有点符号 String fileSuffix = FileUtil.extName(fileName); //限制文件类型 if (!(fileSuffix.equals("jpg") || fileSuffix.equals("png") || fileSuffix.equals("xls") || fileSuffix.equals("xlsx"))) { return "当前只支持上传:jpg png xls xlsx类型"; } //获取文件大小 long size = multipartFile.getSize(); //使用时间戳+3位随机数作为新的文件名 long milli = Instant.now().toEpochMilli(); String randomNumbers = RandomUtil.randomNumbers(3); //生成新的文件名 String newFileName = milli + randomNumbers + "." + fileSuffix; //创建文件夹,如果存在则不创建 FileUtil.mkdir(PATH); //文件路径 String filePath = PATH + newFileName; //生成文件唯一has256值 String shaValue = DigestUtil.sha256Hex(multipartFile.getBytes()); //相同的文件每次上传has256值都是一样的,可以根据该值判断文件是否存在 if (shaValue.equals("数据库中的has256值")) { return "改文件已存在"; } log.info("has256:{}", shaValue); try { //实现文件存储 FileUtil.writeBytes(multipartFile.getBytes(), filePath); return "文件上传成功"; } catch (IOException e) { log.error("文件…