minio集成
This commit is contained in:
parent
2c6ccdf0fc
commit
fed8f1ed54
@ -12,21 +12,10 @@
|
|||||||
<version>0.0.1-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
<name>ebike-operations</name>
|
<name>ebike-operations</name>
|
||||||
<description>ebike-operations</description>
|
<description>ebike-operations</description>
|
||||||
<url/>
|
|
||||||
<licenses>
|
|
||||||
<license/>
|
|
||||||
</licenses>
|
|
||||||
<developers>
|
|
||||||
<developer/>
|
|
||||||
</developers>
|
|
||||||
<scm>
|
|
||||||
<connection/>
|
|
||||||
<developerConnection/>
|
|
||||||
<tag/>
|
|
||||||
<url/>
|
|
||||||
</scm>
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>17</java.version>
|
<java.version>17</java.version>
|
||||||
|
<docker.image.prefix>ebike_plus</docker.image.prefix>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -177,6 +166,11 @@
|
|||||||
<artifactId>core</artifactId>
|
<artifactId>core</artifactId>
|
||||||
<version>3.5.1</version>
|
<version>3.5.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.minio</groupId>
|
||||||
|
<artifactId>minio</artifactId>
|
||||||
|
<version>${minio.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<profiles>
|
<profiles>
|
||||||
|
|||||||
@ -0,0 +1,81 @@
|
|||||||
|
package com.cdzy.operations.config;
|
||||||
|
|
||||||
|
import com.cdzy.operations.utils.MinioUtil;
|
||||||
|
import io.minio.BucketExistsArgs;
|
||||||
|
import io.minio.MakeBucketArgs;
|
||||||
|
import io.minio.MinioClient;
|
||||||
|
import io.minio.SetBucketPolicyArgs;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "minio")
|
||||||
|
public class MinioConfig {
|
||||||
|
private String endpoint;
|
||||||
|
private String accessKey;
|
||||||
|
private String secretKey;
|
||||||
|
private String bucketName;
|
||||||
|
private String showUrl;
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public MinioClient minioClient() throws Exception {
|
||||||
|
// 1. 创建MinioClient实例
|
||||||
|
MinioClient minioClient = MinioClient.builder()
|
||||||
|
.endpoint(endpoint)
|
||||||
|
.credentials(accessKey, secretKey)
|
||||||
|
.build();
|
||||||
|
// 2. 检查存储桶是否存在,不存在则创建
|
||||||
|
initializeBucket(minioClient, bucketName);
|
||||||
|
MinioUtil.setBaseUrl(showUrl+"/"+bucketName);
|
||||||
|
MinioUtil.setBucketName(bucketName);
|
||||||
|
return minioClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeBucket(MinioClient minioClient, String bucketName) throws Exception {
|
||||||
|
try {
|
||||||
|
// 检查存储桶是否存在:cite[1]:cite[5]
|
||||||
|
boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder()
|
||||||
|
.bucket(bucketName)
|
||||||
|
.build());
|
||||||
|
|
||||||
|
if (!isExist) {
|
||||||
|
// 创建存储桶:cite[1]:cite[5]
|
||||||
|
minioClient.makeBucket(MakeBucketArgs.builder()
|
||||||
|
.bucket(bucketName)
|
||||||
|
.build());
|
||||||
|
// 设置存储桶策略为公共可读
|
||||||
|
String policyJson = """
|
||||||
|
{
|
||||||
|
"Version": "2012-10-17",
|
||||||
|
"Statement": [
|
||||||
|
{
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Principal": "*",
|
||||||
|
"Action": ["s3:GetObject"],
|
||||||
|
"Resource": ["arn:aws:s3:::%s/*"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
""".formatted(bucketName);
|
||||||
|
|
||||||
|
minioClient.setBucketPolicy(SetBucketPolicyArgs.builder()
|
||||||
|
.bucket(bucketName)
|
||||||
|
.config(policyJson)
|
||||||
|
.build());
|
||||||
|
log.info("存储桶 {} 创建成功", bucketName);
|
||||||
|
} else {
|
||||||
|
log.info("存储桶 {} 已存在", bucketName);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new Exception("初始化Minio存储桶失败: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
package com.cdzy.operations.controller;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电池二维码 控制层。
|
||||||
|
*
|
||||||
|
* @author attiya
|
||||||
|
* @since 2025-09-15
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ebikeBatteryInfo")
|
||||||
|
public class EbikeBatteryQrController {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,175 @@
|
|||||||
|
package com.cdzy.operations.utils;
|
||||||
|
|
||||||
|
import io.minio.*;
|
||||||
|
import io.minio.http.Method;
|
||||||
|
import io.minio.messages.Bucket;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class MinioUtil {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private static String baseUrl;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private static String bucketName;
|
||||||
|
|
||||||
|
private static final String bikeUrl = "/bike-qr/";
|
||||||
|
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private MinioClient minioClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建桶
|
||||||
|
* @param bucket 数据桶名称
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
public void createBucket(String bucket) throws Exception {
|
||||||
|
//查看桶是否存在
|
||||||
|
boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
|
||||||
|
if (!exists){
|
||||||
|
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传文件
|
||||||
|
* @param inputStream 文件流
|
||||||
|
* @param bucket 数据桶名称
|
||||||
|
* @param objectName 文件名称
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
public void uploadFile(InputStream inputStream, String bucket, String objectName) throws Exception{
|
||||||
|
//上传文件
|
||||||
|
minioClient.putObject(PutObjectArgs.builder().bucket(bucket).object(objectName)
|
||||||
|
.stream(inputStream,-1,Integer.MAX_VALUE).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传文件至默认桶内
|
||||||
|
* @param inputStream 文件流
|
||||||
|
* @param objectName 文件名称
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
public void uploadFile(InputStream inputStream, String objectName) throws Exception{
|
||||||
|
//上传文件
|
||||||
|
minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName)
|
||||||
|
.stream(inputStream,-1,Integer.MAX_VALUE).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文件分析连接(7天有效
|
||||||
|
* @param bucket 数据桶名称
|
||||||
|
* @param fileName 文件名称
|
||||||
|
* @return url
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
public String getFileUrl(String bucket, String fileName) throws Exception {
|
||||||
|
|
||||||
|
return minioClient.getPresignedObjectUrl(
|
||||||
|
GetPresignedObjectUrlArgs.builder()
|
||||||
|
.method(Method.GET)
|
||||||
|
.bucket(bucket)
|
||||||
|
.object(fileName)
|
||||||
|
.expiry(7, TimeUnit.DAYS) // 有效期7天
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取默认桶内文件分析连接(7天有效
|
||||||
|
* @param fileName 文件名称
|
||||||
|
* @return url
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
public String getFileUrl(String fileName) throws Exception {
|
||||||
|
|
||||||
|
return minioClient.getPresignedObjectUrl(
|
||||||
|
GetPresignedObjectUrlArgs.builder()
|
||||||
|
.method(Method.GET)
|
||||||
|
.bucket(bucketName)
|
||||||
|
.object(fileName)
|
||||||
|
.expiry(7, TimeUnit.DAYS) // 有效期7天
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有的桶
|
||||||
|
* @return 数据桶名称列表
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
public List<String> getAllBucket() throws Exception{
|
||||||
|
List<Bucket> buckets = minioClient.listBuckets();
|
||||||
|
return buckets.stream().map(Bucket::name).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载文件
|
||||||
|
* @param bucket 数据桶名称
|
||||||
|
* @param objectName 文件名称
|
||||||
|
* @return 文件流
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
public InputStream downLoad(String bucket,String objectName) throws Exception{
|
||||||
|
return minioClient.getObject(GetObjectArgs.builder().bucket(bucket).object(objectName).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载默认桶内文件
|
||||||
|
* @param objectName 文件名称
|
||||||
|
* @return 文件流
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
public InputStream downLoad(String objectName) throws Exception{
|
||||||
|
return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除桶
|
||||||
|
* @param bucket 数据桶名称
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
public void deleteBucket(String bucket) throws Exception{
|
||||||
|
minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucket).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除文件
|
||||||
|
* @param bucket 数据桶名称
|
||||||
|
* @param objectName 文件名称
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
public void deleteObject(String bucket,String objectName) throws Exception{
|
||||||
|
minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucket).object(objectName).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除默认桶内文件
|
||||||
|
* @param objectName 文件名称
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
public void deleteObject(String objectName) throws Exception{
|
||||||
|
minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取车辆二维码展示路径
|
||||||
|
* @param objectName 文件名称
|
||||||
|
*/
|
||||||
|
public String getBikeQrShowUrl(String objectName){
|
||||||
|
return baseUrl+bikeUrl+objectName;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -74,10 +74,79 @@ public class QRGenUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//public static void main(String[] args) {
|
|
||||||
// String content = "B72650"; // 二维码内容
|
|
||||||
// String base64 = generateQRCodeBase64(content);
|
|
||||||
// System.out.println("Base64 二维码: " + base64);
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成二维码
|
||||||
|
* <p>增加内容文字
|
||||||
|
*
|
||||||
|
* @param content 二维码内容
|
||||||
|
* @param text 文字内容
|
||||||
|
* @return Base64编码的二维码
|
||||||
|
*/
|
||||||
|
public static BufferedImage generateQRCode(String content, String text) {
|
||||||
|
// 1. 生成基础二维码
|
||||||
|
try (ByteArrayOutputStream qrStream = QRCode.from(content)
|
||||||
|
.withSize(300, 300)
|
||||||
|
.withCharset("UTF-8")
|
||||||
|
.withErrorCorrection(ErrorCorrectionLevel.H) // 纠错等级(H为最高)
|
||||||
|
.to(ImageType.PNG) // 输出格式
|
||||||
|
.stream()) {
|
||||||
|
if(text == null || text.isEmpty()){
|
||||||
|
throw new RuntimeException("二维码内容为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 将二维码转换为 BufferedImage
|
||||||
|
ByteArrayInputStream inputStream = new ByteArrayInputStream(qrStream.toByteArray());
|
||||||
|
BufferedImage qrImage = ImageIO.read(inputStream);
|
||||||
|
|
||||||
|
// 3. 创建新 BufferedImage 并绘制文字
|
||||||
|
BufferedImage finalImage = new BufferedImage(
|
||||||
|
qrImage.getWidth(), qrImage.getHeight()+ 20, // 增加文字区域高度,
|
||||||
|
BufferedImage.TYPE_INT_ARGB
|
||||||
|
);
|
||||||
|
Graphics2D g2d = finalImage.createGraphics();
|
||||||
|
g2d.drawImage(qrImage, 0, 0, null);
|
||||||
|
|
||||||
|
// 设置文字样式
|
||||||
|
g2d.setFont(new Font("Arial", Font.BOLD, 20));
|
||||||
|
g2d.setColor(Color.BLACK);
|
||||||
|
|
||||||
|
// 计算文字位置(底部居中)
|
||||||
|
int textWidth = g2d.getFontMetrics().stringWidth(text);
|
||||||
|
int x = (qrImage.getWidth() - textWidth) / 2;
|
||||||
|
int y = qrImage.getHeight() - 2; // 底部留白
|
||||||
|
|
||||||
|
// 添加文字说明
|
||||||
|
g2d.drawString(text, x, y);
|
||||||
|
g2d.dispose();
|
||||||
|
|
||||||
|
// 使用 Java 8+ 的 Base64 编码(避免自动换行问题)
|
||||||
|
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||||
|
ImageIO.write(finalImage, "PNG", stream);
|
||||||
|
return finalImage;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("生成二维码失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static ByteArrayInputStream generateQRCodeInputStearm(String content, String text) {
|
||||||
|
// 1. 生成基础二维码
|
||||||
|
try (ByteArrayOutputStream qrStream = QRCode.from(content)
|
||||||
|
.withSize(300, 300)
|
||||||
|
.withCharset("UTF-8")
|
||||||
|
.withErrorCorrection(ErrorCorrectionLevel.H) // 纠错等级(H为最高)
|
||||||
|
.to(ImageType.PNG) // 输出格式
|
||||||
|
.stream()) {
|
||||||
|
if(text == null || text.isEmpty()){
|
||||||
|
throw new RuntimeException("二维码内容为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 将二维码转换为 BufferedImage
|
||||||
|
|
||||||
|
return new ByteArrayInputStream(qrStream.toByteArray());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("生成二维码失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,198 @@
|
|||||||
|
package com.cdzy.operations.utils;
|
||||||
|
|
||||||
|
import java.net.NetworkInterface;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 车辆编号生成工具类 - 静态方法版本
|
||||||
|
* 基于Snowflake算法改进,保证微服务环境下不重复
|
||||||
|
*/
|
||||||
|
public final class VehicleNumberUtil {
|
||||||
|
|
||||||
|
// 私有构造方法,防止实例化
|
||||||
|
private VehicleNumberUtil() {
|
||||||
|
throw new AssertionError("不能实例化工具类");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 起始时间戳(2024-01-01)
|
||||||
|
private static final long START_TIMESTAMP = 1704067200000L;
|
||||||
|
|
||||||
|
// 机器ID位数、序列号位数
|
||||||
|
private static final long WORKER_ID_BITS = 5L;
|
||||||
|
private static final long SEQUENCE_BITS = 12L;
|
||||||
|
|
||||||
|
// 最大机器ID、序列号
|
||||||
|
private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);
|
||||||
|
private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);
|
||||||
|
|
||||||
|
// 移位偏移量
|
||||||
|
private static final long WORKER_ID_SHIFT = SEQUENCE_BITS;
|
||||||
|
private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;
|
||||||
|
|
||||||
|
// 实例变量转为静态变量,使用Atomic保证线程安全
|
||||||
|
private static final long WORKER_ID;
|
||||||
|
private static final AtomicLastTimestamp LAST_TIMESTAMP = new AtomicLastTimestamp(-1L);
|
||||||
|
private static final AtomicLong SEQUENCE = new AtomicLong(0L);
|
||||||
|
|
||||||
|
private static final SecureRandom RANDOM = new SecureRandom();
|
||||||
|
|
||||||
|
// 静态初始化块
|
||||||
|
static {
|
||||||
|
WORKER_ID = generateWorkerId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成8位车辆编号(静态方法)
|
||||||
|
* @return 8位数字的车辆编号字符串
|
||||||
|
*/
|
||||||
|
public static String generateVehicleNumber() {
|
||||||
|
long timestamp = System.currentTimeMillis();
|
||||||
|
long sequence;
|
||||||
|
|
||||||
|
synchronized (VehicleNumberUtil.class) {
|
||||||
|
long lastTimestamp = LAST_TIMESTAMP.get();
|
||||||
|
|
||||||
|
if (timestamp < lastTimestamp) {
|
||||||
|
throw new RuntimeException("时钟回拨异常,拒绝生成ID");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timestamp == lastTimestamp) {
|
||||||
|
sequence = SEQUENCE.incrementAndGet() & MAX_SEQUENCE;
|
||||||
|
if (sequence == 0) {
|
||||||
|
timestamp = waitNextMillis(lastTimestamp);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 新的时间戳,重置序列号为随机值
|
||||||
|
SEQUENCE.set(RANDOM.nextInt((int) MAX_SEQUENCE / 2));
|
||||||
|
sequence = SEQUENCE.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
LAST_TIMESTAMP.set(timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成ID
|
||||||
|
long id = ((timestamp - START_TIMESTAMP) << TIMESTAMP_SHIFT)
|
||||||
|
| (WORKER_ID << WORKER_ID_SHIFT)
|
||||||
|
| sequence;
|
||||||
|
|
||||||
|
return formatTo8Digits(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量生成车辆编号
|
||||||
|
* @param count 生成数量
|
||||||
|
* @return 车辆编号数组
|
||||||
|
*/
|
||||||
|
public static String[] generateVehicleNumbers(int count) {
|
||||||
|
if (count <= 0) {
|
||||||
|
throw new IllegalArgumentException("生成数量必须大于0");
|
||||||
|
}
|
||||||
|
if (count > 1000) {
|
||||||
|
throw new IllegalArgumentException("单次生成数量不能超过1000");
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] numbers = new String[count];
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
numbers[i] = generateVehicleNumber();
|
||||||
|
}
|
||||||
|
return numbers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化为8位数字
|
||||||
|
*/
|
||||||
|
private static String formatTo8Digits(long id) {
|
||||||
|
// 取绝对值,避免负数
|
||||||
|
long positiveId = Math.abs(id);
|
||||||
|
|
||||||
|
// 取后8位,确保是8位数
|
||||||
|
String numberStr = String.valueOf(positiveId % 100000000L);
|
||||||
|
|
||||||
|
// 不足8位前面补随机数
|
||||||
|
if (numberStr.length() < 8) {
|
||||||
|
StringBuilder sb = new StringBuilder(numberStr);
|
||||||
|
while (sb.length() < 8) {
|
||||||
|
sb.insert(0, RANDOM.nextInt(10));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return numberStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 等待下一毫秒
|
||||||
|
*/
|
||||||
|
private static long waitNextMillis(long lastTimestamp) {
|
||||||
|
long timestamp = System.currentTimeMillis();
|
||||||
|
while (timestamp <= lastTimestamp) {
|
||||||
|
timestamp = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成机器ID - 基于MAC地址和PID
|
||||||
|
*/
|
||||||
|
private static long generateWorkerId() {
|
||||||
|
try {
|
||||||
|
long workerId = 0L;
|
||||||
|
|
||||||
|
// 基于MAC地址生成
|
||||||
|
Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
|
||||||
|
while (networkInterfaces.hasMoreElements()) {
|
||||||
|
NetworkInterface networkInterface = networkInterfaces.nextElement();
|
||||||
|
if (networkInterface.isLoopback() || !networkInterface.isUp()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
byte[] mac = networkInterface.getHardwareAddress();
|
||||||
|
if (mac != null) {
|
||||||
|
for (byte b : mac) {
|
||||||
|
workerId = ((workerId << 8) | (b & 0xFF)) % (MAX_WORKER_ID + 1);
|
||||||
|
}
|
||||||
|
break; // 使用第一个有效的MAC地址
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 结合进程ID增加唯一性
|
||||||
|
String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
|
||||||
|
if (processName.contains("@")) {
|
||||||
|
long pid = Long.parseLong(processName.split("@")[0]);
|
||||||
|
workerId = (workerId + pid) % (MAX_WORKER_ID + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return workerId;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 如果获取失败,使用随机数
|
||||||
|
return RANDOM.nextInt((int) MAX_WORKER_ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Worker ID(用于调试)
|
||||||
|
*/
|
||||||
|
public static long getWorkerId() {
|
||||||
|
return WORKER_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义AtomicLastTimestamp类,用于处理时间戳的原子操作
|
||||||
|
*/
|
||||||
|
private static class AtomicLastTimestamp {
|
||||||
|
private volatile long value;
|
||||||
|
|
||||||
|
public AtomicLastTimestamp(long initialValue) {
|
||||||
|
this.value = initialValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long get() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(long newValue) {
|
||||||
|
this.value = newValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -87,4 +87,11 @@ management:
|
|||||||
health:
|
health:
|
||||||
show-details: always
|
show-details: always
|
||||||
|
|
||||||
|
minio:
|
||||||
|
endpoint: http://47.109.141.125:9000 # MinIO服务器地址
|
||||||
|
access-key: ZIF4HF1LXH0RTB9MZ52O # 访问密钥
|
||||||
|
secret-key: YuFoH+VJVzQbNLRqVMo39dM5pWXCEcMvrCrtgwB0 # 私有密钥
|
||||||
|
bucket-name: operations-objects
|
||||||
|
show-url: http://47.109.141.125:9000
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,30 @@
|
|||||||
package com.cdzy.operations;
|
package com.cdzy.operations;
|
||||||
|
|
||||||
|
import com.cdzy.operations.utils.MinioUtil;
|
||||||
|
import com.cdzy.operations.utils.QRGenUtil;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
class EbikeOperationsApplicationTests {
|
class EbikeOperationsApplicationTests {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MinioUtil minioUtil;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void contextLoads() {
|
void contextLoads() throws Exception {
|
||||||
|
// List<String> allBucket = minioUtil.getAllBucket();
|
||||||
|
// System.out.println(allBucket.contains("bike-qr"));
|
||||||
|
ByteArrayInputStream byteArrayInputStream = QRGenUtil.generateQRCodeInputStearm("https://www.cdzhuojing.cn/qrcode?number=" + "060002" + "&_tbScancodeApproach_=scan", "060002");
|
||||||
|
minioUtil.uploadFile(byteArrayInputStream,"operations-objects","/bike-qr/test.jpg");
|
||||||
|
// minioUtil.deleteObject("bike-qr","test.jpg");
|
||||||
|
String showUrl = minioUtil.getBikeQrShowUrl("test.jpg");
|
||||||
|
System.out.println(showUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>17</java.version>
|
<java.version>17</java.version>
|
||||||
<docker.image.prefix>cdzy_ebike</docker.image.prefix>
|
<docker.image.prefix>ebike_plus</docker.image.prefix>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,7 @@ class EbikeStaffApplicationTests {
|
|||||||
private static final String mapperPath="D:/ebike_plus/ebike-operations/resources/mapper";
|
private static final String mapperPath="D:/ebike_plus/ebike-operations/resources/mapper";
|
||||||
private static final String packageName ="com.cdzy.operations";
|
private static final String packageName ="com.cdzy.operations";
|
||||||
private static final String[] tables= new String[]{
|
private static final String[] tables= new String[]{
|
||||||
"ebike_agreement"
|
"ebike_inventory","ebike_inventory_record"
|
||||||
};
|
};
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user