commit
eb2a2137c1
|
@ -59,5 +59,11 @@
|
|||
<groupId>com.github.pagehelper</groupId>
|
||||
<artifactId>pagehelper</artifactId>
|
||||
</dependency>
|
||||
<!-- 查询ip地址 -->
|
||||
<dependency>
|
||||
<groupId>org.lionsoul</groupId>
|
||||
<artifactId>ip2region</artifactId>
|
||||
<version>2.6.5</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
package cn.bunny.common.service.utils;
|
||||
|
||||
/**
|
||||
* 计算 kb mb gb
|
||||
*/
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class FileUtil {
|
||||
/**
|
||||
* * 获取文件大小字符串
|
||||
*/
|
||||
public static String getSize(Long fileSize) {
|
||||
double fileSizeInKB = fileSize / 1024.00;
|
||||
double fileSizeInMB = fileSizeInKB / 1024;
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
package cn.bunny.common.service.utils;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.lionsoul.ip2region.xdb.Searcher;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class IpUtil {
|
||||
private static Searcher searcher;
|
||||
|
||||
/**
|
||||
* 判断是否为合法 IP
|
||||
*/
|
||||
public static boolean checkIp(String ipAddress) {
|
||||
String ip = "([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}";
|
||||
Pattern pattern = Pattern.compile(ip);
|
||||
Matcher matcher = pattern.matcher(ipAddress);
|
||||
return matcher.matches();
|
||||
}
|
||||
|
||||
/**
|
||||
* 在服务启动时,将 ip2region 加载到内存中
|
||||
*/
|
||||
@PostConstruct
|
||||
private static void initIp2Region() {
|
||||
try {
|
||||
InputStream inputStream = new ClassPathResource("/ipdb/ip2region.xdb").getInputStream();
|
||||
byte[] bytes = FileCopyUtils.copyToByteArray(inputStream);
|
||||
searcher = Searcher.newWithBuffer(bytes);
|
||||
} catch (Exception exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 ip 所属地址
|
||||
*
|
||||
* @param ip ip
|
||||
*/
|
||||
public static String getIpRegion(String ip) {
|
||||
if (ip.equals("0:0:0:0:0:0:0:1")) ip = "127.0.0.1";
|
||||
boolean isIp = checkIp(ip);
|
||||
if (isIp) {
|
||||
initIp2Region();
|
||||
try {
|
||||
// searchIpInfo 的数据格式: 国家|区域|省份|城市|ISP
|
||||
String searchIpInfo = searcher.search(ip);
|
||||
String[] splitIpInfo = searchIpInfo.split("\\|");
|
||||
if (splitIpInfo.length > 0) {
|
||||
if ("中国".equals(splitIpInfo[0])) {
|
||||
// 国内属地返回省份
|
||||
return splitIpInfo[2];
|
||||
} else if ("0".equals(splitIpInfo[0])) {
|
||||
if ("内网IP".equals(splitIpInfo[4])) {
|
||||
// 内网 IP
|
||||
return splitIpInfo[4];
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
} else {
|
||||
// 国外属地返回国家
|
||||
return splitIpInfo[0];
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
} else {
|
||||
throw new IllegalArgumentException("非法的IP地址");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,4 +9,4 @@ public class ResponseHandlerUtil {
|
|||
ResponseUtil.out(response, Result.error(loginAuth));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package cn.bunny.pojo.file;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class MinioFIlePath {
|
||||
private String filename;
|
||||
private String uuidFilename;
|
||||
private String timeUuidFilename;
|
||||
private String filepath;
|
||||
private String bucketNameFilepath;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package cn.bunny.pojo.result.constant;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
public class MinioConstant {
|
||||
public static final String favicon = "favicon";
|
||||
public static final String avatar = "avatar";
|
||||
public static final String article = "article";
|
||||
public static final String carousel = "carousel";
|
||||
public static final String feedback = "feedback";
|
||||
public static final String articleCovers = "articleCovers";
|
||||
public static final String articleAttachment = "articleAttachment";
|
||||
private static final Map<String, String> typeMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
typeMap.put(favicon, "/favicon/");
|
||||
typeMap.put(avatar, "/avatar/");
|
||||
typeMap.put(article, "/article/");
|
||||
typeMap.put(carousel, "/carousel/");
|
||||
typeMap.put(feedback, "/feedback/");
|
||||
typeMap.put("articleImages", "/articleImages/");
|
||||
typeMap.put("articleVideo", "/articleVideo/");
|
||||
typeMap.put(articleCovers, "/articleCovers/");
|
||||
typeMap.put(articleAttachment, "/articleAttachment/");
|
||||
typeMap.put("images", "/images/");
|
||||
typeMap.put("video", "/video/");
|
||||
typeMap.put("default", "/default/");
|
||||
}
|
||||
|
||||
public static String getType(String type) {
|
||||
String value = typeMap.get(type);
|
||||
if (value != null) return value;
|
||||
throw new RuntimeException(FileMessageConstant.COMPOSE_OBJECT_EXCEPTION);
|
||||
}
|
||||
}
|
|
@ -2,16 +2,23 @@ package cn.bunny.module.minio.utils;
|
|||
|
||||
import cn.bunny.common.service.exception.BunnyException;
|
||||
import cn.bunny.module.minio.properties.MinioProperties;
|
||||
import cn.bunny.pojo.file.MinioFIlePath;
|
||||
import cn.bunny.pojo.result.constant.FileMessageConstant;
|
||||
import cn.bunny.pojo.result.constant.MinioConstant;
|
||||
import io.minio.*;
|
||||
import io.minio.messages.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Minio操作工具类 简化操作步骤
|
||||
|
@ -26,16 +33,121 @@ public class MinioUtil {
|
|||
private MinioClient minioClient;
|
||||
|
||||
/**
|
||||
* 获取Minio全路径名
|
||||
*
|
||||
* @param objectName 对象名称
|
||||
* @return 全路径
|
||||
* 获取Minio文件路径
|
||||
*/
|
||||
public String getFullPath(String objectName) {
|
||||
String url = properties.getEndpointUrl();
|
||||
public static MinioFIlePath getMinioFilePath(String buckName, String minioPreType, MultipartFile file) {
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
// 定义日期时间格式
|
||||
LocalDateTime currentDateTime = LocalDateTime.now();
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM-dd");
|
||||
String extension = "";
|
||||
|
||||
// 原始文件名
|
||||
String filename = file.getOriginalFilename();
|
||||
if (filename.contains(".")) {
|
||||
extension = "." + filename.substring(filename.lastIndexOf(".") + 1);
|
||||
}
|
||||
|
||||
// UUID防止重名
|
||||
String uuidFilename = uuid + extension;
|
||||
|
||||
// 拼接时间+UUID文件名
|
||||
String timeUuidFilename = currentDateTime.format(formatter) + "/" + uuidFilename;// 加上时间路径
|
||||
|
||||
// 上传根文件夹+拼接时间+UUID文件名
|
||||
String filepath = MinioConstant.getType(minioPreType) + timeUuidFilename;
|
||||
|
||||
// 桶名称+上传根文件夹+拼接时间+UUID文件名
|
||||
String buckNameFilepath = "/" + buckName + MinioConstant.getType(minioPreType) + timeUuidFilename;
|
||||
|
||||
// 设置及Minio基础信息
|
||||
MinioFIlePath minioFIlePath = new MinioFIlePath();
|
||||
minioFIlePath.setFilename(filename);
|
||||
minioFIlePath.setUuidFilename(uuidFilename);
|
||||
minioFIlePath.setTimeUuidFilename(timeUuidFilename);
|
||||
minioFIlePath.setFilepath(filepath);
|
||||
minioFIlePath.setBucketNameFilepath(buckNameFilepath);
|
||||
|
||||
return minioFIlePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*
|
||||
* @return 返回上传路径
|
||||
*/
|
||||
public String uploadFile(MultipartFile file, String bucketName, String minioPreType) throws IOException {
|
||||
return getUploadFilePath(file, bucketName, minioPreType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*
|
||||
* @return 返回上传路径
|
||||
*/
|
||||
public String uploadFile(MultipartFile file, String minioPreType) throws IOException {
|
||||
// 如果buckName为空,设置为默认的桶
|
||||
String bucketName = properties.getBucketName();
|
||||
|
||||
return url + "/" + bucketName + objectName;
|
||||
return getUploadFilePath(file, bucketName, minioPreType);
|
||||
}
|
||||
|
||||
/**
|
||||
* * 上传文件
|
||||
*
|
||||
* @return 上传路径
|
||||
*/
|
||||
private String getUploadFilePath(MultipartFile file, String bucketName, String minioPreType) throws IOException {
|
||||
if (file != null) {
|
||||
MinioFIlePath minioFile = getMinioFilePath(bucketName, minioPreType, file);
|
||||
String bucketNameFilepath = minioFile.getBucketNameFilepath();
|
||||
String filepath = minioFile.getFilepath();
|
||||
|
||||
// 上传对象
|
||||
putObject(bucketName, filepath, file.getInputStream(), file.getSize());
|
||||
|
||||
// 设置图片地址
|
||||
return bucketNameFilepath;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* * 上传文件
|
||||
*
|
||||
* @return 上传路径
|
||||
*/
|
||||
public MinioFIlePath getUploadMinioObjectFilePath(MultipartFile file, String bucketName, String minioPreType) throws IOException {
|
||||
if (file != null) {
|
||||
MinioFIlePath minioFile = getMinioFilePath(bucketName, minioPreType, file);
|
||||
String filepath = minioFile.getFilepath();
|
||||
|
||||
// 上传对象
|
||||
putObject(bucketName, filepath, file.getInputStream(), file.getSize());
|
||||
|
||||
// 设置图片地址
|
||||
return minioFile;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* * 上传文件并返回处理信息
|
||||
*/
|
||||
public MinioFIlePath getUploadMinioObjectFilePath(MultipartFile file, String minioPreType) throws IOException {
|
||||
// 如果buckName为空,设置为默认的桶
|
||||
String bucketName = properties.getBucketName();
|
||||
if (file != null) {
|
||||
MinioFIlePath minioFile = getMinioFilePath(bucketName, minioPreType, file);
|
||||
String filepath = minioFile.getFilepath();
|
||||
|
||||
// 上传对象
|
||||
putObject(bucketName, filepath, file.getInputStream(), file.getSize());
|
||||
|
||||
// 设置图片地址
|
||||
return minioFile;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -56,7 +168,65 @@ public class MinioUtil {
|
|||
}
|
||||
throw new BunnyException(FileMessageConstant.GET_BUCKET_EXCEPTION);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取默认bucket文件,并返回字节数组
|
||||
*
|
||||
* @param objectName 对象名称
|
||||
* @return 文件流对象
|
||||
*/
|
||||
public byte[] getBucketObjectByte(String objectName) {
|
||||
// 如果buckName为空,设置为默认的桶
|
||||
String bucketName = properties.getBucketName();
|
||||
|
||||
try {
|
||||
objectName = objectName.replace("/" + bucketName, "");
|
||||
GetObjectResponse getObjectResponse = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
|
||||
|
||||
return getObjectResponse.readAllBytes();
|
||||
} catch (Exception exception) {
|
||||
exception.getStackTrace();
|
||||
}
|
||||
throw new BunnyException(FileMessageConstant.GET_BUCKET_EXCEPTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Minio全路径名,Object带有桶名称
|
||||
*
|
||||
* @param objectName 对象名称
|
||||
* @return 全路径
|
||||
*/
|
||||
public String getObjectNameFullPath(String objectName) {
|
||||
String url = properties.getEndpointUrl();
|
||||
|
||||
return url + objectName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Minio全路径名-默认桶名称
|
||||
*
|
||||
* @param objectName 对象名称
|
||||
* @return 全路径
|
||||
*/
|
||||
public String getDefaultBuckNameFullPath(String objectName) {
|
||||
String url = properties.getEndpointUrl();
|
||||
String bucketName = properties.getBucketName();
|
||||
|
||||
return url + "/" + bucketName + objectName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Minio全路径名,自定义桶名称
|
||||
*
|
||||
* @param objectName 对象名称
|
||||
* @return 全路径
|
||||
*/
|
||||
public String getBuckNameFullPath(String bucketName, String objectName) {
|
||||
String url = properties.getEndpointUrl();
|
||||
|
||||
return url + "/" + bucketName + objectName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断桶是否存在
|
||||
*
|
||||
|
|
27
pom.xml
27
pom.xml
|
@ -144,4 +144,31 @@
|
|||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<profiles>
|
||||
<!--dev环境-->
|
||||
<profile>
|
||||
<id>dev</id>
|
||||
<properties>
|
||||
<profiles.active>dev</profiles.active>
|
||||
</properties>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
</profile>
|
||||
<!--test环境-->
|
||||
<profile>
|
||||
<id>test</id>
|
||||
<properties>
|
||||
<profiles.active>test</profiles.active>
|
||||
</properties>
|
||||
</profile>
|
||||
<!--prod环境-->
|
||||
<profile>
|
||||
<id>prod</id>
|
||||
<properties>
|
||||
<profiles.active>prod</profiles.active>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
bunny:
|
||||
datasource:
|
||||
host: 192.168.1.4
|
||||
port: 3306
|
||||
sqlData: bunny_docs
|
||||
username: root
|
||||
password: "02120212"
|
||||
|
||||
redis:
|
||||
host: 192.168.1.4
|
||||
port: 6379
|
||||
database: 3
|
||||
password: "123456"
|
||||
|
||||
minio:
|
||||
endpointUrl: "http://192.168.1.4:9000"
|
||||
bucket-name: test
|
||||
accessKey: bunny
|
||||
secretKey: "02120212"
|
|
@ -3,7 +3,7 @@ server:
|
|||
|
||||
spring:
|
||||
profiles:
|
||||
active: dev
|
||||
active: @profiles.active@
|
||||
application:
|
||||
name: bunny-service
|
||||
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,45 @@
|
|||
<body style="margin: 0; padding: 0; background-color: #f5f5f5;">
|
||||
<div style="max-width: 600px; margin: 0 auto;">
|
||||
<table style="width: 100%; border-collapse: collapse; background-color: #ffffff; font-family: Arial, sans-serif;">
|
||||
<tr>
|
||||
<th style="height: 60px; padding: 20px; background-color: #0074d3; border-radius: 5px 5px 0 0;"
|
||||
valign="middle">
|
||||
<h1 style="margin: 0; color: #ffffff; font-size: 24px;">BunnyBBS邮箱验证码</h1>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 20px;">
|
||||
<div style="background-color: #ffffff; padding: 25px;">
|
||||
<h2 style="margin: 10px 0; font-size: 18px; color: #333333;">
|
||||
尊敬的用户,
|
||||
</h2>
|
||||
<p style="margin: 10px 0; font-size: 16px; color: #333333;">
|
||||
感谢您注册我们的产品. 您的账号正在进行电子邮件验证.
|
||||
</p>
|
||||
<p style="margin: 10px 0; font-size: 16px; color: #333333;">
|
||||
验证码为: <span class="button" style="color: #1100ff;">${verifyCode}</span>
|
||||
</p>
|
||||
<p style="margin: 10px 0; font-size: 16px; color: #333333;">
|
||||
验证码的有效期只有一分钟,请抓紧时间进行验证吧!
|
||||
</p>
|
||||
<p style="margin: 10px 0; font-size: 16px; color: #dc1818;">
|
||||
如果非本人操作,请忽略此邮件
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: center; padding: 20px; background-color: #f5f5f5;">
|
||||
<p style="margin: 0; font-size: 12px; color: #747474;">
|
||||
XXXXX<br>
|
||||
Contact us: XXXXXXX@qq.com
|
||||
</p>
|
||||
<p style="margin: 10px 0; font-size: 12px; color: #747474;">
|
||||
This is an automated email, please do not reply.<br>
|
||||
© Company Name
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
|
@ -0,0 +1,16 @@
|
|||
package cn.bunny.ipdb;
|
||||
|
||||
import cn.bunny.common.service.utils.IpUtil;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class IpDbTest {
|
||||
@Test
|
||||
public void test() {
|
||||
String ip = "220.248.12.158"; // IpRegion:上海
|
||||
// String ip = "47.52.236.180"; // IpRegion:香港
|
||||
// String ip = "172.22.12.123"; // IpRegion:内网IP
|
||||
// String ip = "164.114.53.60"; // IpRegion:美国
|
||||
String ipRegion = IpUtil.getIpRegion(ip);
|
||||
System.out.println(ipRegion);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue