diff --git a/common/service-utils/pom.xml b/common/service-utils/pom.xml index a8cb4d0..32bafae 100644 --- a/common/service-utils/pom.xml +++ b/common/service-utils/pom.xml @@ -59,5 +59,11 @@ com.github.pagehelper pagehelper + + + org.lionsoul + ip2region + 2.6.5 + diff --git a/common/service-utils/src/main/java/cn/bunny/common/service/utils/FileUtil.java b/common/service-utils/src/main/java/cn/bunny/common/service/utils/FileUtil.java index aa60bc2..3daf5cd 100644 --- a/common/service-utils/src/main/java/cn/bunny/common/service/utils/FileUtil.java +++ b/common/service-utils/src/main/java/cn/bunny/common/service/utils/FileUtil.java @@ -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; diff --git a/common/service-utils/src/main/java/cn/bunny/common/service/utils/IpUtil.java b/common/service-utils/src/main/java/cn/bunny/common/service/utils/IpUtil.java new file mode 100644 index 0000000..c1d83f6 --- /dev/null +++ b/common/service-utils/src/main/java/cn/bunny/common/service/utils/IpUtil.java @@ -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地址"); + } + } +} diff --git a/common/service-utils/src/main/java/cn/bunny/common/service/utils/ResponseHandlerUtil.java b/common/service-utils/src/main/java/cn/bunny/common/service/utils/ResponseHandlerUtil.java index 624a91a..2376798 100644 --- a/common/service-utils/src/main/java/cn/bunny/common/service/utils/ResponseHandlerUtil.java +++ b/common/service-utils/src/main/java/cn/bunny/common/service/utils/ResponseHandlerUtil.java @@ -9,4 +9,4 @@ public class ResponseHandlerUtil { ResponseUtil.out(response, Result.error(loginAuth)); return false; } -} \ No newline at end of file +} diff --git a/dao/src/main/java/cn/bunny/pojo/file/MinioFIlePath.java b/dao/src/main/java/cn/bunny/pojo/file/MinioFIlePath.java new file mode 100644 index 0000000..f283278 --- /dev/null +++ b/dao/src/main/java/cn/bunny/pojo/file/MinioFIlePath.java @@ -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; +} diff --git a/dao/src/main/java/cn/bunny/pojo/result/constant/MinioConstant.java b/dao/src/main/java/cn/bunny/pojo/result/constant/MinioConstant.java new file mode 100644 index 0000000..c080b1f --- /dev/null +++ b/dao/src/main/java/cn/bunny/pojo/result/constant/MinioConstant.java @@ -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 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); + } +} diff --git a/module/module-minio/src/main/java/cn/bunny/module/minio/utils/MinioUtil.java b/module/module-minio/src/main/java/cn/bunny/module/minio/utils/MinioUtil.java index 5f717fd..a83d2f9 100644 --- a/module/module-minio/src/main/java/cn/bunny/module/minio/utils/MinioUtil.java +++ b/module/module-minio/src/main/java/cn/bunny/module/minio/utils/MinioUtil.java @@ -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; + } + /** * 判断桶是否存在 * diff --git a/pom.xml b/pom.xml index e897960..1937036 100644 --- a/pom.xml +++ b/pom.xml @@ -144,4 +144,31 @@ + + + + + dev + + dev + + + true + + + + + test + + test + + + + + prod + + prod + + + diff --git a/service/src/main/resources/application-prod.yml b/service/src/main/resources/application-prod.yml new file mode 100644 index 0000000..de30295 --- /dev/null +++ b/service/src/main/resources/application-prod.yml @@ -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" \ No newline at end of file diff --git a/service/src/main/resources/application.yml b/service/src/main/resources/application.yml index fb30ebc..60bc9fa 100644 --- a/service/src/main/resources/application.yml +++ b/service/src/main/resources/application.yml @@ -3,7 +3,7 @@ server: spring: profiles: - active: dev + active: @profiles.active@ application: name: bunny-service diff --git a/service/src/main/resources/ipdb/ip2region.xdb b/service/src/main/resources/ipdb/ip2region.xdb new file mode 100644 index 0000000..7052c05 Binary files /dev/null and b/service/src/main/resources/ipdb/ip2region.xdb differ diff --git a/service/src/main/resources/templates/email-template.html b/service/src/main/resources/templates/email-template.html new file mode 100644 index 0000000..b2b89b4 --- /dev/null +++ b/service/src/main/resources/templates/email-template.html @@ -0,0 +1,45 @@ + +
+ + + + + + + + + + +
+

BunnyBBS邮箱验证码

+
+
+

+ 尊敬的用户, +

+

+ 感谢您注册我们的产品. 您的账号正在进行电子邮件验证. +

+

+ 验证码为: ${verifyCode} +

+

+ 验证码的有效期只有一分钟,请抓紧时间进行验证吧! +

+

+ 如果非本人操作,请忽略此邮件 +

+
+
+

+ XXXXX
+ Contact us: XXXXXXX@qq.com +

+

+ This is an automated email, please do not reply.
+ © Company Name +

+
+
+ \ No newline at end of file diff --git a/service/src/test/java/cn/bunny/ipdb/IpDbTest.java b/service/src/test/java/cn/bunny/ipdb/IpDbTest.java new file mode 100644 index 0000000..97f1016 --- /dev/null +++ b/service/src/test/java/cn/bunny/ipdb/IpDbTest.java @@ -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); + } +}