From c9108cd74af0dd7e0bb48a588d5dac5d49ba2ffd Mon Sep 17 00:00:00 2001 From: liangwen <2357318727@qq.com> Date: Sat, 16 Dec 2023 16:02:50 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B1=80=E5=9F=9F=E7=BD=91minio=E9=85=8D?= =?UTF-8?q?=E5=A5=97=E6=9C=8D=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 95 ++ pom.xml | 137 +++ src/main/java/com/hb/Application.java | 14 + src/main/java/com/hb/Swagger2.java | 36 + src/main/java/com/hb/config/CorsConfig.java | 33 + .../config/FastJson2JsonRedisSerializer.java | 49 + .../java/com/hb/config/InterceptorConfig.java | 30 + src/main/java/com/hb/config/MinioConfig.java | 75 ++ src/main/java/com/hb/config/RedisConfig.java | 69 ++ src/main/java/com/hb/constant/Constants.java | 341 ++++++ src/main/java/com/hb/constant/HttpStatus.java | 94 ++ .../com/hb/controller/MinioController.java | 301 +++++ src/main/java/com/hb/domain/AjaxResult.java | 193 ++++ src/main/java/com/hb/domain/Fileinfo.java | 24 + .../com/hb/interceptor/MyInterceptor.java | 49 + .../java/com/hb/service/MinIOService.java | 9 + .../com/hb/service/impl/MinIOServiceImpl.java | 52 + src/main/java/com/hb/util/CharsetKit.java | 85 ++ src/main/java/com/hb/util/Convert.java | 1000 +++++++++++++++++ src/main/java/com/hb/util/DateUtil.java | 26 + src/main/java/com/hb/util/HttpUtils.java | 265 +++++ src/main/java/com/hb/util/MinioUtil.java | 194 ++++ src/main/java/com/hb/util/ServletUtils.java | 218 ++++ src/main/java/com/hb/util/StrFormatter.java | 90 ++ src/main/java/com/hb/util/StringUtils.java | 609 ++++++++++ src/main/resources/application.yml | 44 + src/main/resources/log4j2.xml | 97 ++ 27 files changed, 4229 insertions(+) create mode 100644 README.md create mode 100644 pom.xml create mode 100644 src/main/java/com/hb/Application.java create mode 100644 src/main/java/com/hb/Swagger2.java create mode 100644 src/main/java/com/hb/config/CorsConfig.java create mode 100644 src/main/java/com/hb/config/FastJson2JsonRedisSerializer.java create mode 100644 src/main/java/com/hb/config/InterceptorConfig.java create mode 100644 src/main/java/com/hb/config/MinioConfig.java create mode 100644 src/main/java/com/hb/config/RedisConfig.java create mode 100644 src/main/java/com/hb/constant/Constants.java create mode 100644 src/main/java/com/hb/constant/HttpStatus.java create mode 100644 src/main/java/com/hb/controller/MinioController.java create mode 100644 src/main/java/com/hb/domain/AjaxResult.java create mode 100644 src/main/java/com/hb/domain/Fileinfo.java create mode 100644 src/main/java/com/hb/interceptor/MyInterceptor.java create mode 100644 src/main/java/com/hb/service/MinIOService.java create mode 100644 src/main/java/com/hb/service/impl/MinIOServiceImpl.java create mode 100644 src/main/java/com/hb/util/CharsetKit.java create mode 100644 src/main/java/com/hb/util/Convert.java create mode 100644 src/main/java/com/hb/util/DateUtil.java create mode 100644 src/main/java/com/hb/util/HttpUtils.java create mode 100644 src/main/java/com/hb/util/MinioUtil.java create mode 100644 src/main/java/com/hb/util/ServletUtils.java create mode 100644 src/main/java/com/hb/util/StrFormatter.java create mode 100644 src/main/java/com/hb/util/StringUtils.java create mode 100644 src/main/resources/application.yml create mode 100644 src/main/resources/log4j2.xml diff --git a/README.md b/README.md new file mode 100644 index 0000000..3cedd1d --- /dev/null +++ b/README.md @@ -0,0 +1,95 @@ +# Spring-minio +MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。 +本项目集成Minio的java客户端SDK,对Minio文件服务器进行读写,将操作封装为MinioUtil工具,直接在项目中可以复用。其操作主要包括: +- 上传文件 +- 下载文件 +- 读取桶列表 +- 读取桶中的文件列表 +- 删除桶 +- 删除文件 +### 著作权 +#### 匠心巨制,震撼上市 +![输入图片说明](https://gitee.com/shenzhanwang/Spring-elastic_search/raw/master/pic/mmexport1680185330486.jpg) + +|购买地址| +|--| +|![输入图片说明](https://gitee.com/shenzhanwang/RuoYi-activiti/raw/ruoyi-activiti/pic/%E8%B4%AD%E4%B9%B0.jpg)| + +### 专利文章 +| | 标题 | 技术领域 | +|---|----|------| +| 1 | [一种基于微服务架构的车联网大数据分析系统](https://mp.weixin.qq.com/s?__biz=Mzg5MjY3OTk0OQ==&mid=2247484096&idx=1&sn=11677bc50cd18e448135319394238e80&chksm=c03b20a2f74ca9b41c7d1c1e60e1407e1530a98b86498822f387da26e551826f8136663b45a0#rd) | 微服务| +| 2 | [一种流式数据场景下Elasticsearch索引的自动化扩容方法](https://mp.weixin.qq.com/s?__biz=Mzg5MjY3OTk0OQ==&mid=2247484167&idx=1&sn=94587b5e196bbda2d6cc4b976b03d0c7&chksm=c03b2165f74ca873b77380a23c4e06b71adf6ffc40634440f467fb71c20aa4cc2fe72a5d65a9#rd) | 搜索引擎 | +| 3 | [大数据钻取分析方法、装置、设备及存储介质](https://mp.weixin.qq.com/s?__biz=Mzg5MjY3OTk0OQ==&mid=2247484385&idx=1&sn=6fe4a4ac34badd91db39b4cc042a3f18&chksm=c03b2183f74ca89508333f3d5c8330aa32248eda86e4cf7657a5a293e1bf9d49888fe78b1072#rd) | 大数据分析 | +| 4 | [一种基于工作流引擎的自动化办公方法和系统](https://mp.weixin.qq.com/s?__biz=Mzg5MjY3OTk0OQ==&mid=2247484895&idx=1&sn=1094f0b9abef603e8126dea68db75cca&chksm=c03b27bdf74caeab50d56ac110b9ab0d36bc9b9069e311083a5c4295ab03ee4b0595a00a3ba2#rd) | 工作流引擎 | + + + +### 视频教程 + +|
Elasticsearch数据搜索与分析实战演练
| +|--| +|
RuoYi-activiti开发指南
| + + +### 附录:中央技术储备仓库(Central Technique Reserve Repository) + +#### 基础篇:职业化,从做好OA系统开始 +1. [Spring boot整合Mybatis实现增删改查(支持多数据源)](https://gitee.com/shenzhanwang/SSM)![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg "在这里输入图片标题") +2. [Spring,SpringMVC和Hibernate的整合实现增删改查](https://gitee.com/shenzhanwang/SSH) +3. [Spring boot整合activiti工作流引擎实现OA开发](https://gitee.com/shenzhanwang/Spring-activiti)![输入图片说明](https://img.shields.io/badge/-%E6%8B%9B%E7%89%8C-yellow.svg) +4. [Ruoyi-boot集成工作流引擎Flowable实例](https://gitee.com/shenzhanwang/Ruoyi-flowable)![输入图片说明](https://img.shields.io/badge/-%E6%8B%9B%E7%89%8C-yellow.svg) +5. [Spring发布与调用REST风格的WebService](https://gitee.com/shenzhanwang/Spring-REST) +6. [Spring boot整合Axis调用SOAP风格的web服务](https://gitee.com/shenzhanwang/Spring-axis) +7. [Spring boot整合Apache Shiro实现RBAC权限控制](https://gitee.com/shenzhanwang/Spring-shiro) +8. [使用Spring security实现RBAC权限控制](https://gitee.com/shenzhanwang/spring-security-demo) +#### 中级篇:中间件的各种姿势 +9. [Spring boot整合mongoDB文档数据库实现增删改查](https://gitee.com/shenzhanwang/Spring-mongoDB) +10. [Spring连接Redis实现缓存](https://gitee.com/shenzhanwang/Spring-redis) +11. [Spring连接图存数据库Neo4j实现增删改查](https://gitee.com/shenzhanwang/Spring-neo4j) +12. Spring boot整合列存数据库hbase实现增删改查 +13. [Spring平台整合消息队列ActiveMQ实现发布订阅、生产者消费者模型(JMS)](https://gitee.com/shenzhanwang/Spring-activeMQ) +14. [Spring boot整合消息队列RabbitMQ实现四种消息模式(AMQP)](https://gitee.com/shenzhanwang/Spring-rabbitMQ) +15. Spring boot整合kafka 2.1.0实现大数据消息管道 +16. [Spring boot整合websocket实现即时通讯](https://gitee.com/shenzhanwang/Spring-websocket)![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg "在这里输入图片标题") +17. [Spring security整合oauth2实现token认证](https://gitee.com/shenzhanwang/Spring-security-oauth2) +18. [Spring boot整合MinIO客户端实现文件管理](https://gitee.com/shenzhanwang/Spring-minio) +19. 23种设计模式,源码、注释、使用场景 +20. [使用ETL工具Kettle的实例](https://gitee.com/shenzhanwang/Kettle-demo) +21. Git指南和分支管理策略 +22. 使用数据仓库进行OLAP数据分析(Mysql+Kettle+Zeppelin) +#### 高级篇:分布式系统和大数据开发 +23. [zookeeper原理、架构、使用场景和可视化](https://gitee.com/shenzhanwang/zookeeper-practice) +24. Spring boot整合Apache dubbo v2.7.5实现分布式服务治理(SOA架构) ![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg "在这里输入图片标题") +> 包含组件Spring boot v2.2.2+Dubbo v2.7.5+Nacos v1.1.1 +效果图 +25. 使用Spring Cloud Alibaba v2.2.7实现微服务架构(MSA架构)![输入图片说明](https://img.shields.io/badge/-%E6%8B%9B%E7%89%8C-yellow.svg) +> 包含组件Nacos+Feign+Gateway+Ribbon+Sentinel+Zipkin +效果图 +26. 使用jenkins+centos+git+maven搭建持续集成环境自动化部署分布式服务 +27. 使用docker+compose+jenkins+gitlab+spring cloud实现微服务的编排、持续集成和动态扩容 +28. 使用Spark进行分布式计算 +- Spark SQL做离线计算 +- Spark Streaming做实时计算 +- Structured Streaming做实时计算 +29. 使用Flink实现流批一体化的分布式计算 +30. 搭建高可用nginx集群和Tomcat负载均衡 +31. 使用mycat实现Mysql数据库的主从复制、读写分离、分表分库、负载均衡和高可用 +32. [《Elasticsearch数据搜索与分析实战》源码](https://gitee.com/shenzhanwang/Spring-elastic_search) ![输入图片说明](https://img.shields.io/badge/-%E6%8B%9B%E7%89%8C-yellow.svg "在这里输入图片标题") +#### 特别篇:分布式事务和并发控制 +33. 基于可靠消息最终一致性实现分布式事务(activeMQ) +34. Spring boot dubbo整合seata实现分布式事务![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg "在这里输入图片标题") +> 包含组件nacos v2.0.2 + seata v1.4.2 +spring boot dubbo v2.7.5 +效果图 +35. Spring cloud alibaba v2.2.7整合seata实现分布式事务 ![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg "在这里输入图片标题") +> 包含组件nacos v2.0.2 + seata v1.4.2 +spring cloud alibaba v2.2.7 +效果图 +36. 并发控制:数据库锁机制和事务隔离级别的实现![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg "在这里输入图片标题") +37. 并发控制:使用redission实现分布式锁 +38. 并发控制:使用zookeeper实现分布式锁 +39. 并发控制:Java多线程编程实例 +40. 并发控制:使用netty实现高性能NIO通信 + +### 关注微信公众号获取更多技术文章和源码 + +![输入图片说明](https://gitee.com/shenzhanwang/Spring-elastic_search/raw/master/pic/qrcode_for_gh_4c2318bb0f7f_258.jpg) diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..e7c7281 --- /dev/null +++ b/pom.xml @@ -0,0 +1,137 @@ + + 4.0.0 + hb + hb-minio + 1.0 + + + + org.springframework.boot + spring-boot-starter-thymeleaf + 2.1.6.RELEASE + + + org.springframework.boot + spring-boot-starter + 2.1.6.RELEASE + + + org.springframework.boot + spring-boot-starter-logging + + + + + + org.springframework.boot + spring-boot-starter-test + 2.1.6.RELEASE + test + + + + org.springframework.boot + spring-boot-starter-web + 2.1.6.RELEASE + + + org.springframework.boot + spring-boot-starter-logging + + + + + io.springfox + springfox-swagger2 + 2.9.2 + + + io.springfox + springfox-swagger-ui + 2.9.2 + + + com.alibaba + fastjson + 1.2.68 + + + org.springframework.boot + spring-boot-starter-log4j2 + 2.1.6.RELEASE + + + org.apache.commons + commons-lang3 + 3.9 + + + io.minio + minio + 8.2.0 + + + + org.springframework.boot + spring-boot-devtools + true + 2.1.6.RELEASE + + + + org.springframework.boot + spring-boot-starter-data-redis + 2.1.8.RELEASE + + + + redis.clients + jedis + 3.7.0 + + + com.alibaba.fastjson2 + fastjson2 + 2.0.9 + + + + hb-minio + + + org.springframework.boot + spring-boot-maven-plugin + 2.1.6.RELEASE + + true + + + + + repackage + + + + + + + + + + jdk-1.8 + + true + 1.8 + + + 1.8 + 1.8 + 1.8 + + + + + UTF-8 + + diff --git a/src/main/java/com/hb/Application.java b/src/main/java/com/hb/Application.java new file mode 100644 index 0000000..95a7232 --- /dev/null +++ b/src/main/java/com/hb/Application.java @@ -0,0 +1,14 @@ +package com.hb; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/src/main/java/com/hb/Swagger2.java b/src/main/java/com/hb/Swagger2.java new file mode 100644 index 0000000..707ee61 --- /dev/null +++ b/src/main/java/com/hb/Swagger2.java @@ -0,0 +1,36 @@ +package com.hb; + +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.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + + +@Configuration +@EnableSwagger2 +public class Swagger2 { + @Bean + public Docket createRestApi() { + return new Docket(DocumentationType.SWAGGER_2) + .apiInfo(apiInfo()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.hb.controller")) + .paths(PathSelectors.any()) + .build(); + } + + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title("hb minio api文档") + .description("minio操作API文档") + //.termsOfServiceUrl("http://gitee.com/shenzhanwang/projects") + .version("1.0") + .build(); + } +} diff --git a/src/main/java/com/hb/config/CorsConfig.java b/src/main/java/com/hb/config/CorsConfig.java new file mode 100644 index 0000000..e5cddc5 --- /dev/null +++ b/src/main/java/com/hb/config/CorsConfig.java @@ -0,0 +1,33 @@ +package com.hb.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class CorsConfig { + + @Bean + public WebMvcConfigurer corsConfigurer() { + return new WebMvcConfigurer() { + @Override + //重写父类提供的跨域请求处理的接口 + public void addCorsMappings(CorsRegistry registry) { + //添加映射路径 + registry.addMapping("/**") + //放行哪些原始域 + .allowedOrigins("*") + //是否发送Cookie信息 + .allowCredentials(true) + //放行哪些原始域(请求方式) + .allowedMethods("GET", "POST", "PUT", "DELETE") + //放行哪些原始域(头部信息) + .allowedHeaders("*") + //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息) + .exposedHeaders("token"); + + } + }; + } +} diff --git a/src/main/java/com/hb/config/FastJson2JsonRedisSerializer.java b/src/main/java/com/hb/config/FastJson2JsonRedisSerializer.java new file mode 100644 index 0000000..a0d5cf7 --- /dev/null +++ b/src/main/java/com/hb/config/FastJson2JsonRedisSerializer.java @@ -0,0 +1,49 @@ +package com.hb.config; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONReader; +import com.alibaba.fastjson2.JSONWriter; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.serializer.SerializationException; + +import java.nio.charset.Charset; + +/** + * Redis使用FastJson序列化 + * + * @author ruoyi + */ +public class FastJson2JsonRedisSerializer implements RedisSerializer +{ + public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); + + private Class clazz; + + public FastJson2JsonRedisSerializer(Class clazz) + { + super(); + this.clazz = clazz; + } + + @Override + public byte[] serialize(T t) throws SerializationException + { + if (t == null) + { + return new byte[0]; + } + return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName).getBytes(DEFAULT_CHARSET); + } + + @Override + public T deserialize(byte[] bytes) throws SerializationException + { + if (bytes == null || bytes.length <= 0) + { + return null; + } + String str = new String(bytes, DEFAULT_CHARSET); + + return JSON.parseObject(str, clazz, JSONReader.Feature.SupportAutoType); + } +} diff --git a/src/main/java/com/hb/config/InterceptorConfig.java b/src/main/java/com/hb/config/InterceptorConfig.java new file mode 100644 index 0000000..239f8d7 --- /dev/null +++ b/src/main/java/com/hb/config/InterceptorConfig.java @@ -0,0 +1,30 @@ +package com.hb.config; + +import com.hb.interceptor.MyInterceptor; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.*; + +/** + * @Auther: shaoming + * @Date: 2021/1/8 14:11 + * @Description: 注册拦截器配置类 + */ +@Configuration//表名这是springboot的配置类 +public class InterceptorConfig implements WebMvcConfigurer { + @Override + public void addInterceptors(InterceptorRegistry registry) { + //定义排除swagger访问的路径配置 + String[] swaggerExcludes=new String[]{"/swagger-ui.html","/swagger-resources/**","/webjars/**", "/getPicture"}; + + registry.addInterceptor(new MyInterceptor()) + // addPathPatterns 用于添加拦截规则 + .addPathPatterns("/**") + .excludePathPatterns(swaggerExcludes); + WebMvcConfigurer.super.addInterceptors(registry); + } + +} + + + + diff --git a/src/main/java/com/hb/config/MinioConfig.java b/src/main/java/com/hb/config/MinioConfig.java new file mode 100644 index 0000000..b8180f7 --- /dev/null +++ b/src/main/java/com/hb/config/MinioConfig.java @@ -0,0 +1,75 @@ +package com.hb.config; + +import okhttp3.OkHttpClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import io.minio.MinioClient; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.security.cert.X509Certificate; + +@Configuration +public class MinioConfig { + + @Value("${minio.url}") + private String url; + @Value("${minio.accessKey}") + private String accessKey; + @Value("${minio.secretKey}") + private String secretKey; + + /*@Bean + public MinioClient getMinioClient() { + MinioClient minioClient = MinioClient.builder().endpoint(url) + .credentials(accessKey, secretKey).build(); + return minioClient; + }*/ + + @Bean + public MinioClient minioClient(){ + + // Create a trust manager that does not validate certificate chains + TrustManager[] trustAllCerts = new TrustManager[] { + new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + + public void checkClientTrusted(X509Certificate[] certs, String authType) { + // Do nothing (trust any client certificate) + } + + public void checkServerTrusted(X509Certificate[] certs, String authType) { + // Do nothing (trust any server certificate) + } + } + }; + + // Install the all-trusting trust manager + SSLContext sslContext = null; + try { + sslContext = SSLContext.getInstance("SSL"); + sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); + } catch (Exception e) { + e.printStackTrace(); + } + + // Create a custom OkHttpClient that trusts all certificates + OkHttpClient customHttpClient = new OkHttpClient.Builder() + .sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustAllCerts[0]) + .hostnameVerifier((hostname, session) -> true) + .build(); + + // Set the custom SSLContext for MinioClient + return MinioClient.builder() + .endpoint(url) + .credentials(accessKey, secretKey) + .httpClient(customHttpClient) + .build(); + } + +} diff --git a/src/main/java/com/hb/config/RedisConfig.java b/src/main/java/com/hb/config/RedisConfig.java new file mode 100644 index 0000000..3483fb8 --- /dev/null +++ b/src/main/java/com/hb/config/RedisConfig.java @@ -0,0 +1,69 @@ +package com.hb.config; + +import org.springframework.cache.annotation.CachingConfigurerSupport; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.script.DefaultRedisScript; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +/** + * redis配置 + * + * @author ruoyi + */ +@Configuration +@EnableCaching +public class RedisConfig extends CachingConfigurerSupport +{ + @Bean + @SuppressWarnings(value = { "unchecked", "rawtypes" }) + public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) + { + RedisTemplate template = new RedisTemplate<>(); + template.setConnectionFactory(connectionFactory); + + FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class); + + // 使用StringRedisSerializer来序列化和反序列化redis的key值 + template.setKeySerializer(new StringRedisSerializer()); + template.setValueSerializer(serializer); + + // Hash的key也采用StringRedisSerializer的序列化方式 + template.setHashKeySerializer(new StringRedisSerializer()); + template.setHashValueSerializer(serializer); + + template.afterPropertiesSet(); + return template; + } + + @Bean + public DefaultRedisScript limitScript() + { + DefaultRedisScript redisScript = new DefaultRedisScript<>(); + redisScript.setScriptText(limitScriptText()); + redisScript.setResultType(Long.class); + return redisScript; + } + + /** + * 限流脚本 + */ + private String limitScriptText() + { + return "local key = KEYS[1]\n" + + "local count = tonumber(ARGV[1])\n" + + "local time = tonumber(ARGV[2])\n" + + "local current = redis.call('get', key);\n" + + "if current and tonumber(current) > count then\n" + + " return tonumber(current);\n" + + "end\n" + + "current = redis.call('incr', key)\n" + + "if tonumber(current) == 1 then\n" + + " redis.call('expire', key, time)\n" + + "end\n" + + "return tonumber(current);"; + } +} diff --git a/src/main/java/com/hb/constant/Constants.java b/src/main/java/com/hb/constant/Constants.java new file mode 100644 index 0000000..8167e21 --- /dev/null +++ b/src/main/java/com/hb/constant/Constants.java @@ -0,0 +1,341 @@ +package com.hb.constant; + +//import io.jsonwebtoken.Claims; + +/** + * 通用常量信息 + * + * @author ruoyi + */ +public class Constants +{ + /** + * UTF-8 字符集 + */ + public static final String UTF8 = "UTF-8"; + + /** + * GBK 字符集 + */ + public static final String GBK = "GBK"; + + /** + * www主域 + */ + public static final String WWW = "www."; + + /** + * http请求 + */ + public static final String HTTP = "http://"; + + /** + * https请求 + */ + public static final String HTTPS = "https://"; + + /** + * 通用成功标识 + */ + public static final String SUCCESS = "0"; + + /** + * 通用失败标识 + */ + public static final String FAIL = "1"; + + /** + * 登录成功 + */ + public static final String LOGIN_SUCCESS = "Success"; + + /** + * 注销 + */ + public static final String LOGOUT = "Logout"; + + /** + * 注册 + */ + public static final String REGISTER = "Register"; + + /** + * 登录失败 + */ + public static final String LOGIN_FAIL = "Error"; + + /** + + //MQ相关--------------------------------------------------------- + + /** + * 限流 redis key + */ + //public static final String DEVICE_HEART_KEY = "device:heart:"; + + /** + * 设备状态 redis key alarm存储用 暂时未用上 + */ + public static final String DEVICE_STATE_KEY = "device:state:"; + + /** + * 任务 -> 状态key + */ + //public static final String TASK_STATUS_KEY = "task:status:"; + + + /** + * 打印文件 redis key + */ + //public static final String TASK_JOBINFO_KEY = "task:jobInfo:"; + + + /** + * 用户登录 tel key + */ + public static final String LOGIN_TOKEN_ROLE_KEY = "login_token_role:"; + + + /** + * 用户登录 语言 + */ +// public static final String LOGIN_LANG_KEY = "login_lang:"; + + /** + * 设备 -> 权限key + */ + public static final String DEVICE_ROLE_KEY = "device:role:"; + + + /** + * 用户 -> 消息内容 + */ + public static final String USER_SEND_MSG_KEY = "user:send_msg:"; + + /** + * 用户 -> 消息内容 + */ + public static final String USER_WX_MSG_KEY = "user:wx_msg:"; + + /** + * 设备 -> 权限key 机器id + */ + public static final String MACHINE_ID = "machine_id"; + + + /** + * 设备 -> 权限key 权限Key + */ + public static final String ROLE_KEY = "role_key"; + public static final String DEVICE_CODE = "device_code"; + + public static final String UUID = "uuid"; + public static final String SUPER_ADMIN = "admin"; + + //--------------------------------------------------------- + + + + /** + * 验证码有效期(分钟) + */ + public static final Integer CAPTCHA_EXPIRATION = 2; + + /** + * 令牌 + */ + public static final String TOKEN = "token"; + + /** + * 令牌前缀 + */ + public static final String TOKEN_PREFIX = "Bearer "; + + /** + * 令牌前缀 + */ + public static final String LOGIN_USER_KEY = "login_user_key"; + + /** + * 用户ID + */ + public static final String JWT_USERID = "userid"; + + /** + * 用户名称 + */ + //public static final String JWT_USERNAME = Claims.SUBJECT; + + /** + * 用户头像 + */ + public static final String JWT_AVATAR = "avatar"; + + /** + * 创建时间 + */ + public static final String JWT_CREATED = "created"; + + /** + * 用户权限 + */ + public static final String JWT_AUTHORITIES = "authorities"; + + /** + * 资源映射路径 前缀 + */ + public static final String RESOURCE_PREFIX = "/profile"; + + /** + * 大屏映射路径 前缀 + */ + public static final String GOVIEW_PREFIX = "/goview"; + + /** + * RMI 远程方法调用 + */ + public static final String LOOKUP_RMI = "rmi:"; + + /** + * LDAP 远程方法调用 + */ + public static final String LOOKUP_LDAP = "ldap:"; + + /** + * LDAPS 远程方法调用 + */ + public static final String LOOKUP_LDAPS = "ldaps:"; + + /** + * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加) + */ + public static final String[] JOB_WHITELIST_STR = { "com.ruoyi" }; + + /** + * 用户语言 + */ + public static final String USER_LANGUAGE_KEY = "user:language:"; + + /** + * 首页大屏地址参数key + */ + public static final String MAIN_PAGE_URL_KEY = "mainPage.URL."; + + /** + * 评估子流程 + */ + public static final String ASSESS_INSTANCE_KEY = "process:instance:assess:"; + + /** + * 前处理子流程 + */ + public static final String OPTIMIZE_INSTANCE_KEY = "process:instance:optimize:"; + + /** + * 设备视频推流 + */ + public static final String VIDEO_STREAM_STATUS_KEY = "video:stream:status:"; + + /** + * 排版模型 + */ + public static final String COMPOSE_INSTANCE_KEY = "process:instance:compose:"; + + /** + * 打印仿真 + */ + public static final String PRINT_SIMULATE_INSTANCE_KEY = "process:instance:printSimulate:"; + + /** + * 打印仿真零件组合 + */ + public static final String PRINT_SIMULATE_CHILD_INSTANCE_KEY = "process:instance:child:printSimulate:"; + + /** + * 切片/路径规划子项 + */ + public static final String SLICE_PATH_PLANNING_CHILD_INSTANCE_KEY = "process:instance:child:slicePathPlanning:"; + + /** + * 切片/路径规划 + */ + public static final String SLICE_PATH_PLANNING_INSTANCE_KEY = "process:instance:slicePathPlanning:"; + + /** + * 在线排单 + */ + public static final String ONLINE_ORDER_CHILD_INSTANCE_KEY = "process:instance:child:onlineOrder:"; + + /** + * 在线排单 + */ + public static final String ONLINE_ORDER_INSTANCE_KEY = "process:instance:onlineOrder:"; + + /** + * 排单确认子项 + */ + public static final String SCHEDULE_CONFIRM_CHILD_INSTANCE_KEY = "process:instance:child:scheduleConfirm:"; + + /** + * 排单确认 + */ + public static final String SCHEDULE_CONFIRM_INSTANCE_KEY = "process:instance:scheduleConfirm:"; + + /** + * 打印任务子项 + */ + public static final String PRINT_TASK_CHILD_INSTANCE_KEY = "process:instance:child:printTask:"; + + /** + * 打印任务 + */ + public static final String PRINT_TASK_INSTANCE_KEY = "process:instance:printTask:"; + + /** + * 取件任务子项 + */ + public static final String COLLECT_PART_CHILD_INSTANCE_KEY = "process:instance:child:collectPart:"; + + /** + * 取件确认任务 + */ + public static final String COLLECT_PART_INSTANCE_KEY = "process:instance:collectPart:"; + + /** + * 取件确认任务子项 + */ + public static final String COLLECT_CONFIREM_CHILD_INSTANCE_KEY = "process:instance:child:collectConfirm:"; + + /** + * 取件确认任务 + */ + public static final String COLLECT_CONFIREM_INSTANCE_KEY = "process:instance:collectConfirm:"; + + /** + * 打印质检任务子项 PrintInspection + */ + public static final String PRINT_INSPECTION_CHILD_INSTANCE_KEY = "process:instance:child:printInspection:"; + + /** + * 打印质检任务 PrintInspection + */ + public static final String PRINT_INSPECTION_INSTANCE_KEY = "process:instance:printInspection:"; + /** + * 成品入库任务子项 warehouse + */ + public static final String WAREHOUSE_CHILD_INSTANCE_KEY = "process:instance:child:warehouse:"; + + /** + * 成品入库任务 + */ + public static final String WAREHOUSE_INSTANCE_KEY = "process:instance:warehouse:"; + + + /** + * 定时任务违规的字符 + */ + public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml", + "org.springframework", "org.apache", "com.ruoyi.common.utils.file", "com.ruoyi.common.config" }; + + public static final String VALIDATE_URL = "https://web.hb3dp.com:8090/wx/api/userInfo"; +} diff --git a/src/main/java/com/hb/constant/HttpStatus.java b/src/main/java/com/hb/constant/HttpStatus.java new file mode 100644 index 0000000..9a3d6d2 --- /dev/null +++ b/src/main/java/com/hb/constant/HttpStatus.java @@ -0,0 +1,94 @@ +package com.hb.constant; + +/** + * 返回状态码 + * + * @author ruoyi + */ +public class HttpStatus +{ + /** + * 操作成功 + */ + public static final int SUCCESS = 200; + + /** + * 对象创建成功 + */ + public static final int CREATED = 201; + + /** + * 请求已经被接受 + */ + public static final int ACCEPTED = 202; + + /** + * 操作已经执行成功,但是没有返回数据 + */ + public static final int NO_CONTENT = 204; + + /** + * 资源已被移除 + */ + public static final int MOVED_PERM = 301; + + /** + * 重定向 + */ + public static final int SEE_OTHER = 303; + + /** + * 资源没有被修改 + */ + public static final int NOT_MODIFIED = 304; + + /** + * 参数列表错误(缺少,格式不匹配) + */ + public static final int BAD_REQUEST = 400; + + /** + * 未授权 + */ + public static final int UNAUTHORIZED = 401; + + /** + * 访问受限,授权过期 + */ + public static final int FORBIDDEN = 403; + + /** + * 资源,服务未找到 + */ + public static final int NOT_FOUND = 404; + + /** + * 不允许的http方法 + */ + public static final int BAD_METHOD = 405; + + /** + * 资源冲突,或者资源被锁 + */ + public static final int CONFLICT = 409; + + /** + * 不支持的数据,媒体类型 + */ + public static final int UNSUPPORTED_TYPE = 415; + + /** + * 系统内部错误 + */ + public static final int ERROR = 500; + + /** + * 接口未实现 + */ + public static final int NOT_IMPLEMENTED = 501; + + /** + * 系统警告消息 + */ + public static final int WARN = 601; +} diff --git a/src/main/java/com/hb/controller/MinioController.java b/src/main/java/com/hb/controller/MinioController.java new file mode 100644 index 0000000..eb441ef --- /dev/null +++ b/src/main/java/com/hb/controller/MinioController.java @@ -0,0 +1,301 @@ +package com.hb.controller; + + +import java.io.InputStream; +import java.net.URLEncoder; +import java.util.*; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; + +import com.hb.util.DateUtil; +import com.hb.util.ServletUtils; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson2.JSON; +import io.swagger.annotations.*; +import org.apache.commons.lang3.StringUtils; +import org.apache.tomcat.util.http.fileupload.IOUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import com.hb.domain.AjaxResult; +import com.hb.util.MinioUtil; + +@Api(tags = "Minio操作接口") +@RestController +public class MinioController { + + @Autowired + MinioUtil minioUtil; + + /*@ApiOperation("列出所有的桶") + @RequestMapping(value = "/listBuckets", method = RequestMethod.GET) + @ResponseBody + public AjaxResult listBuckets() throws Exception { + return AjaxResult.success(minioUtil.listBuckets()); + }*/ + + @ApiOperation("上传一个文件") + @ApiImplicitParams({ + @ApiImplicitParam(name = "uploadfile", value = "MultipartFile文件对象", dataType="__file", paramType="form", required = true), + @ApiImplicitParam(name = "bucket", value = "桶名称", required = true), + @ApiImplicitParam(name = "objectName", value = "文件夹路径,例:20231215/002938", required = true), + @ApiImplicitParam(paramType = "header", name = "Authorization", value = "Bearer YOUR_TOKEN_HERE", required = true) + }) + @RequestMapping(value = "/uploadfile", method = RequestMethod.POST) + @ResponseBody + public AjaxResult fileupload(@RequestParam MultipartFile uploadfile, @RequestParam String bucket, + @RequestParam(required = false) String objectName) throws Exception { + minioUtil.createBucket(bucket); + if (objectName != null) { + minioUtil.uploadFile(uploadfile.getInputStream(), bucket, objectName + "/" + uploadfile.getOriginalFilename()); + } else { + minioUtil.uploadFile(uploadfile.getInputStream(), bucket, uploadfile.getOriginalFilename()); + } + return AjaxResult.success(); + } + + @ApiOperation("上传一个文件2") + @ApiImplicitParams({ + @ApiImplicitParam(name = "uploadfile", value = "MultipartFile文件对象", dataType="__file", paramType="form", required = true), + @ApiImplicitParam(name = "bucket", value = "桶名称", required = true), + @ApiImplicitParam(paramType = "header", name = "Authorization", value = "Bearer YOUR_TOKEN_HERE", required = true) + }) + @RequestMapping(value = "/uploadfile2", method = RequestMethod.POST) + @ResponseBody + public AjaxResult fileupload2(@RequestParam MultipartFile uploadfile, @RequestParam String bucket) throws Exception { + minioUtil.createBucket(bucket); + String fileDir = buildDir(); + String fileDirName = buildDirName(fileDir, uploadfile.getOriginalFilename()); + minioUtil.uploadFile2(uploadfile, bucket, fileDirName); + return AjaxResult.success(); + } + + @ApiOperation("递归列出一个桶中的所有文件和目录") + @ApiImplicitParams({ + @ApiImplicitParam(name = "bucket", value = "桶名称", required = true), + @ApiImplicitParam(paramType = "header", name = "Authorization", value = "Bearer YOUR_TOKEN_HERE", required = true) + }) + @RequestMapping(value = "/listFiles", method = RequestMethod.GET) + @ResponseBody + public AjaxResult listFiles(@RequestParam String bucket) throws Exception { + return AjaxResult.success("200", minioUtil.listFiles(bucket)); + } + + @ApiOperation("下载一个文件") + @ApiImplicitParams({ + @ApiImplicitParam(name = "bucket", value = "桶名称", required = true), + @ApiImplicitParam(name = "objectName", value = "文件全路径,例:20231215/002938/gh_03ace048af5d_344 (1) (2).jpg", required = true), + @ApiImplicitParam(paramType = "header", name = "Authorization", value = "Bearer YOUR_TOKEN_HERE", required = true) + }) + @RequestMapping(value = "/downloadFile", method = RequestMethod.GET) + @ResponseBody + public void downloadFile(@RequestParam String bucket, @RequestParam String objectName, + HttpServletResponse response) throws Exception { + InputStream stream = minioUtil.download(bucket, objectName); + ServletOutputStream output = response.getOutputStream(); + response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(objectName.substring(objectName.lastIndexOf("/") + 1), "UTF-8")); + response.setContentType("application/octet-stream"); + response.setCharacterEncoding("UTF-8"); + IOUtils.copy(stream, output); + } + + @ApiOperation("下载一个文件") + @ApiImplicitParams({ + @ApiImplicitParam(name = "bucket", value = "桶名称", required = true), + @ApiImplicitParam(name = "objectName", value = "文件全路径,例:20231215/002938/gh_03ace048af5d_344 (1) (2).jpg", required = true), + @ApiImplicitParam(paramType = "header", name = "Authorization", value = "Bearer YOUR_TOKEN_HERE", required = true) + }) + @RequestMapping(value = "/getPicture", method = RequestMethod.GET) + @ResponseBody + public void getLocalPicture(@RequestParam String bucket, @RequestParam String objectName, + HttpServletResponse response) { + try { + String contentType = minioUtil.getContenType(bucket, objectName); + // 判断文件类型是否为图片 + boolean isImage = contentType != null && contentType.startsWith("image/"); + if (!isImage) { + ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error("文件类型不是图片,无法查看!"))); + } else { + InputStream stream = minioUtil.download(bucket, objectName); + ServletOutputStream output = response.getOutputStream(); + //response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(objectName.substring(objectName.lastIndexOf("/") + 1), "UTF-8")); + //response.setContentType("application/octet-stream"); + //response.setCharacterEncoding("UTF-8"); + IOUtils.copy(stream, output); + } + }catch (Exception e) { + e.printStackTrace(); + ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(e.getMessage()))); + } + } + + + @ApiOperation("删除一个文件") + @RequestMapping(value = "/deleteFile", method = RequestMethod.GET) + @ResponseBody + public AjaxResult deleteFile(@RequestParam String bucket, @RequestParam String objectName) throws Exception { + minioUtil.deleteObject(bucket, objectName); + return AjaxResult.success(); + } + + @ApiOperation(value = "单个直传", notes = "单文件生成签名地址,前端直接传") + @ApiImplicitParams({ + @ApiImplicitParam(name = "fileName", value = "文件名称", required = true), + @ApiImplicitParam(name = "bucket", value = "桶名称", required = true), + @ApiImplicitParam(paramType = "header", name = "Authorization", value = "Bearer YOUR_TOKEN_HERE", required = true) + }) + @ApiResponses( + { + @ApiResponse(code = 200, message = "生成地址成功"), + @ApiResponse(code = 1001, message = "生成失败,文件名不能为空"), + @ApiResponse(code = 1002, message = "生成失败,桶名不能为空"), + @ApiResponse(code = 1003, message = "生成地址出错"), + } + ) + @PostMapping("/buildOnePutURL") + @ResponseBody + public AjaxResult buildOnePutURL(String fileName, String bucket) { + AjaxResult ajaxResult = new AjaxResult(); + if (StringUtils.isEmpty(fileName)) { + ajaxResult.put("code", 1001); + ajaxResult.put("msg", "生成失败,文件名不能为空"); + return ajaxResult; + } + if (StringUtils.isEmpty(bucket)) { + ajaxResult.put("code", 1002); + ajaxResult.put("msg", "生成失败,桶名不能为空"); + return ajaxResult; + } + + try { + String fileDir = buildDir(); //目录 + String fileCode = UUID.randomUUID().toString(); //文件编号,放在数据库用 + //JSONObject jsonData = getOneURL(0, fileCode, fileDir, fileName, bucket); + String fileDirName = buildDirName(fileDir, fileName); + minioUtil.createBucket(bucket); + String putURL = minioUtil.getOneURL(fileDirName, bucket); + JSONObject jsonData = new JSONObject(); + jsonData.put("index", 0); + jsonData.put("fileCode", fileCode); + jsonData.put("fileDir", fileDir); + jsonData.put("fileName", fileName); + jsonData.put("fileDirName", fileDirName); + jsonData.put("putURL", putURL); + if (jsonData == null) { + ajaxResult.put("code", 1003); + ajaxResult.put("msg", "生成失败,Minio操作失败"); + return ajaxResult; + } + ajaxResult.put("code", 200); + ajaxResult.put("msg", "success"); + ajaxResult.put("data", jsonData); + } catch (Exception e) { + e.printStackTrace(); + ajaxResult.put("code", 500); + ajaxResult.put("msg", "生成失败"); + } + return ajaxResult; + } + + /*@ApiOperation("删除一个桶") + @RequestMapping(value = "/deleteBucket", method = RequestMethod.GET) + @ResponseBody + public AjaxResult deleteBucket(@RequestParam String bucket) throws Exception { + minioUtil.deleteBucket(bucket); + return AjaxResult.success(); + }*/ + + @ApiOperation(value = "生成文件预览临时url", notes = "生成文件预览临时url(有效期7天)") + @ApiImplicitParams({ + @ApiImplicitParam(name = "fileDirName", value = "文件全路径", required = true), + @ApiImplicitParam(paramType = "header", name = "Authorization", value = "Bearer YOUR_TOKEN_HERE", required = true) + }) + @ApiResponses( + { + @ApiResponse(code = 200, message = "生成成功,返回文件预览url"), + @ApiResponse(code = 1001, message = "文件全路径不能为空"), + @ApiResponse(code = 1002, message = "桶名不能为空"), + @ApiResponse(code = 500, message = "生成失败"), + } + ) + @PostMapping("/getMinioURL") + @ResponseBody + public AjaxResult getMinioURL(String bucket, String fileDirName) { + AjaxResult ajaxResult = new AjaxResult(); + if (StringUtils.isEmpty(fileDirName)) { + ajaxResult.put("code", 1001); + ajaxResult.put("msg", "生成失败,文件全路径不能为空"); + return ajaxResult; + } + if (StringUtils.isEmpty(bucket)) { + ajaxResult.put("code", 1002); + ajaxResult.put("msg", "生成失败,桶名不能为空"); + return ajaxResult; + } + try { + String url = minioUtil.getMinioURL(bucket, fileDirName); + ajaxResult.put("code", 200); + ajaxResult.put("msg", "success"); + ajaxResult.put("url", url); + } catch (Exception e) { + e.printStackTrace(); + ajaxResult.put("code", 500); + ajaxResult.put("msg", "success"); + } + return ajaxResult; + } + + @ApiOperation(value = "生成多个文件预览临时url", notes = "生成多个文件预览临时url(有效期7天)") + @ApiImplicitParams({ + @ApiImplicitParam(name = "fileDirNames", value = "文件全路径数组", required = true), + @ApiImplicitParam(paramType = "header", name = "Authorization", value = "Bearer YOUR_TOKEN_HERE", required = true) + }) + @ApiResponses( + { + @ApiResponse(code = 200, message = "生成成功,返回文件预览url"), + @ApiResponse(code = 1001, message = "文件全路径不能为空"), + @ApiResponse(code = 1002, message = "文件全路径不能为空"), + @ApiResponse(code = 500, message = "生成失败"), + } + ) + @PostMapping("/getMinioURLs") + public AjaxResult getMinioURLs(String bucket, String[] fileDirNames) { + AjaxResult ajaxResult = new AjaxResult(); + if (fileDirNames == null || (fileDirNames != null && fileDirNames.length <= 0)) { + ajaxResult.put("code", 1001); + ajaxResult.put("msg", "文件全路径不能为空"); + return ajaxResult; + } + if (StringUtils.isEmpty(bucket)) { + ajaxResult.put("code", 1002); + ajaxResult.put("msg", "生成失败,桶名不能为空"); + return ajaxResult; + } + try { + //List urlList = minioUtil.getMinioURLs(bucket, fileDirNames); + List urlList = new ArrayList<>(); + for (String fileDirName : fileDirNames) { + String url = minioUtil.getMinioURL(bucket, fileDirName); + urlList.add(url); + } + ajaxResult.put("code", 200); + ajaxResult.put("msg", "success"); + ajaxResult.put("urlList", urlList); + } catch (Exception e) { + e.printStackTrace(); + ajaxResult.put("code", 500); + ajaxResult.put("msg", "success"); + } + return ajaxResult; + } + + private String buildDir() { + return DateUtil.getDateTime("yyyyMMdd/HHmmss"); + } + + public String buildDirName(String fileDir, String fileName) { + return String.format("%s/%s", fileDir, fileName); + } +} diff --git a/src/main/java/com/hb/domain/AjaxResult.java b/src/main/java/com/hb/domain/AjaxResult.java new file mode 100644 index 0000000..9ecb50c --- /dev/null +++ b/src/main/java/com/hb/domain/AjaxResult.java @@ -0,0 +1,193 @@ +package com.hb.domain; + +import java.util.HashMap; + +/** + * + */ +public class AjaxResult extends HashMap +{ + private static final long serialVersionUID = 1L; + + /** 状态码 */ + public static final String CODE_TAG = "code"; + + /** 返回内容 */ + public static final String MSG_TAG = "msg"; + + /** 数据对象 */ + public static final String DATA_TAG = "data"; + + /** + * 状态类型 + */ + public enum Type + { + /** 成功 */ + SUCCESS(200), + /** 警告 */ + WARN(301), + /** 错误 */ + ERROR(500); + private final int value; + + Type(int value) + { + this.value = value; + } + + public int value() + { + return this.value; + } + } + + /** + * 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。 + */ + public AjaxResult() + { + } + + /** + * 初始化一个新创建的 AjaxResult 对象 + * + * @param type 状态类型 + * @param msg 返回内容 + */ + public AjaxResult(Type type, String msg) + { + super.put(CODE_TAG, type.value); + super.put(MSG_TAG, msg); + } + + /** + * 初始化一个新创建的 AjaxResult 对象 + * + * @param type 状态类型 + * @param msg 返回内容 + * @param data 数据对象 + */ + public AjaxResult(Type type, String msg, Object data) + { + super.put(CODE_TAG, type.value); + super.put(MSG_TAG, msg); + if (data != null) + { + super.put(DATA_TAG, data); + } + } + + /** + * 方便链式调用 + * + * @param key 键 + * @param value 值 + * @return 数据对象 + */ + @Override + public AjaxResult put(String key, Object value) + { + super.put(key, value); + return this; + } + + /** + * 返回成功消息 + * + * @return 成功消息 + */ + public static AjaxResult success() + { + return AjaxResult.success("操作成功"); + } + + /** + * 返回成功数据 + * + * @return 成功消息 + */ + public static AjaxResult success(Object data) + { + return AjaxResult.success("操作成功", data); + } + + /** + * 返回成功消息 + * + * @param msg 返回内容 + * @return 成功消息 + */ + public static AjaxResult success(String msg) + { + return AjaxResult.success(msg, null); + } + + /** + * 返回成功消息 + * + * @param msg 返回内容 + * @param data 数据对象 + * @return 成功消息 + */ + public static AjaxResult success(String msg, Object data) + { + return new AjaxResult(Type.SUCCESS, msg, data); + } + + /** + * 返回警告消息 + * + * @param msg 返回内容 + * @return 警告消息 + */ + public static AjaxResult warn(String msg) + { + return AjaxResult.warn(msg, null); + } + + /** + * 返回警告消息 + * + * @param msg 返回内容 + * @param data 数据对象 + * @return 警告消息 + */ + public static AjaxResult warn(String msg, Object data) + { + return new AjaxResult(Type.WARN, msg, data); + } + + /** + * 返回错误消息 + * + * @return + */ + public static AjaxResult error() + { + return AjaxResult.error("操作失败"); + } + + /** + * 返回错误消息 + * + * @param msg 返回内容 + * @return 警告消息 + */ + public static AjaxResult error(String msg) + { + return AjaxResult.error(msg, null); + } + + /** + * 返回错误消息 + * + * @param msg 返回内容 + * @param data 数据对象 + * @return 警告消息 + */ + public static AjaxResult error(String msg, Object data) + { + return new AjaxResult(Type.ERROR, msg, data); + } +} diff --git a/src/main/java/com/hb/domain/Fileinfo.java b/src/main/java/com/hb/domain/Fileinfo.java new file mode 100644 index 0000000..b18294e --- /dev/null +++ b/src/main/java/com/hb/domain/Fileinfo.java @@ -0,0 +1,24 @@ +package com.hb.domain; + +public class Fileinfo { + String filename; + + Boolean directory; + + public String getFilename() { + return filename; + } + + public void setFilename(String filename) { + this.filename = filename; + } + + public Boolean getDirectory() { + return directory; + } + + public void setDirectory(Boolean directory) { + this.directory = directory; + } + +} diff --git a/src/main/java/com/hb/interceptor/MyInterceptor.java b/src/main/java/com/hb/interceptor/MyInterceptor.java new file mode 100644 index 0000000..ddface2 --- /dev/null +++ b/src/main/java/com/hb/interceptor/MyInterceptor.java @@ -0,0 +1,49 @@ +package com.hb.interceptor; + +import com.hb.constant.Constants; +import com.hb.constant.HttpStatus; +import com.hb.domain.AjaxResult; +import com.hb.util.HttpUtils; +import com.hb.util.ServletUtils; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import org.springframework.util.StringUtils; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class MyInterceptor extends HandlerInterceptorAdapter { + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + //在请求处理之前进行拦截处理 + //System.out.println("测试拦截器------preHandle------" + request.getRequestURL()); + //返回true表示继续执行请求,返回false表示停止执行请求; + String token = request.getHeader("Authorization"); + if (StringUtils.hasText(token)){ + //验证token的合法性,根据自己的业务逻辑补充 + String result = HttpUtils.sendPost(Constants.VALIDATE_URL, "token=" + token); + if (!StringUtils.isEmpty(result)) { + JSONObject resultJSON = JSONObject.parseObject(result); + int code = resultJSON.getIntValue("code"); + if (code == 200) { + return true; + } + } + } + //没有token,说明没有登录 + //使用response设置响应给前端的信息,根据自己的业务需求 + int code = HttpStatus.UNAUTHORIZED; + String msg = com.hb.util.StringUtils.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI()); + ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(msg))); + return false; + } + + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { + //在请求处理之后进行拦截处理 + //System.out.println("测试拦截器------postHandle"); + } +} diff --git a/src/main/java/com/hb/service/MinIOService.java b/src/main/java/com/hb/service/MinIOService.java new file mode 100644 index 0000000..f0cc351 --- /dev/null +++ b/src/main/java/com/hb/service/MinIOService.java @@ -0,0 +1,9 @@ +package com.hb.service; + + + + +public interface MinIOService { + + +} diff --git a/src/main/java/com/hb/service/impl/MinIOServiceImpl.java b/src/main/java/com/hb/service/impl/MinIOServiceImpl.java new file mode 100644 index 0000000..f49a53b --- /dev/null +++ b/src/main/java/com/hb/service/impl/MinIOServiceImpl.java @@ -0,0 +1,52 @@ +package com.hb.service.impl; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import com.hb.service.MinIOService; +import io.minio.BucketExistsArgs; +import io.minio.MakeBucketArgs; +import io.minio.MinioClient; +import io.minio.errors.MinioException; + +@Service("minIOService") +public class MinIOServiceImpl implements MinIOService { + + private static final Logger LOG = LoggerFactory.getLogger(MinIOServiceImpl.class); + + public static void main(String[] args) throws IOException, NoSuchAlgorithmException, InvalidKeyException { + try { + // Create a minioClient with the MinIO server playground, its access + // key and secret key. + MinioClient minioClient = MinioClient.builder().endpoint("http://192.168.7.250:9000") + .credentials("minioadmin", "minioadmin").build(); + + // Make 'asiatrip' bucket if not exist. + boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket("abc").build()); + if (!found) { + // Make a new bucket called 'asiatrip'. + minioClient.makeBucket(MakeBucketArgs.builder().bucket("abc").build()); + } else { + System.out.println("Bucket 'abc' already exists."); + } + + // Upload '/home/user/Photos/asiaphotos.zip' as object name + // 'asiaphotos-2015.zip' to bucket + // 'asiatrip'. +// minioClient.uploadObject(UploadObjectArgs.builder().bucket("abc").object("1.txt") +// .filename("D:\\实时监控数据.txt").build()); +// System.out.println("'实时监控数据.txt' is successfully uploaded as " +// + "object '1.txt' to bucket 'abc'."); + + + } catch (MinioException e) { + System.out.println("Error occurred: " + e); + System.out.println("HTTP trace: " + e.httpTrace()); + } + } +} diff --git a/src/main/java/com/hb/util/CharsetKit.java b/src/main/java/com/hb/util/CharsetKit.java new file mode 100644 index 0000000..649dfdb --- /dev/null +++ b/src/main/java/com/hb/util/CharsetKit.java @@ -0,0 +1,85 @@ +package com.hb.util; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +/** + * 字符集工具类 + * + * @author ruoyi + */ +public class CharsetKit +{ + /** ISO-8859-1 */ + public static final String ISO_8859_1 = "ISO-8859-1"; + /** UTF-8 */ + public static final String UTF_8 = "UTF-8"; + /** GBK */ + public static final String GBK = "GBK"; + + /** ISO-8859-1 */ + public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1); + /** UTF-8 */ + public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8); + /** GBK */ + public static final Charset CHARSET_GBK = Charset.forName(GBK); + + /** + * 转换为Charset对象 + * + * @param charset 字符集,为空则返回默认字符集 + * @return Charset + */ + public static Charset charset(String charset) + { + return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset); + } + + /** + * 转换字符串的字符集编码 + * + * @param source 字符串 + * @param srcCharset 源字符集,默认ISO-8859-1 + * @param destCharset 目标字符集,默认UTF-8 + * @return 转换后的字符集 + */ + public static String convert(String source, String srcCharset, String destCharset) + { + return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset)); + } + + /** + * 转换字符串的字符集编码 + * + * @param source 字符串 + * @param srcCharset 源字符集,默认ISO-8859-1 + * @param destCharset 目标字符集,默认UTF-8 + * @return 转换后的字符集 + */ + public static String convert(String source, Charset srcCharset, Charset destCharset) + { + if (null == srcCharset) + { + srcCharset = StandardCharsets.ISO_8859_1; + } + + if (null == destCharset) + { + destCharset = StandardCharsets.UTF_8; + } + + if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset)) + { + return source; + } + return new String(source.getBytes(srcCharset), destCharset); + } + + /** + * @return 系统字符集编码 + */ + public static String systemCharset() + { + return Charset.defaultCharset().name(); + } +} diff --git a/src/main/java/com/hb/util/Convert.java b/src/main/java/com/hb/util/Convert.java new file mode 100644 index 0000000..2b9e87a --- /dev/null +++ b/src/main/java/com/hb/util/Convert.java @@ -0,0 +1,1000 @@ +package com.hb.util; + +import org.apache.commons.lang3.ArrayUtils; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.text.NumberFormat; +import java.util.Set; + +/** + * 类型转换器 + * + * @author ruoyi + */ +public class Convert +{ + /** + * 转换为字符串
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static String toStr(Object value, String defaultValue) + { + if (null == value) + { + return defaultValue; + } + if (value instanceof String) + { + return (String) value; + } + return value.toString(); + } + + /** + * 转换为字符串
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static String toStr(Object value) + { + return toStr(value, null); + } + + /** + * 转换为字符
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Character toChar(Object value, Character defaultValue) + { + if (null == value) + { + return defaultValue; + } + if (value instanceof Character) + { + return (Character) value; + } + + final String valueStr = toStr(value, null); + return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0); + } + + /** + * 转换为字符
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Character toChar(Object value) + { + return toChar(value, null); + } + + /** + * 转换为byte
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Byte toByte(Object value, Byte defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Byte) + { + return (Byte) value; + } + if (value instanceof Number) + { + return ((Number) value).byteValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Byte.parseByte(valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为byte
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Byte toByte(Object value) + { + return toByte(value, null); + } + + /** + * 转换为Short
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Short toShort(Object value, Short defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Short) + { + return (Short) value; + } + if (value instanceof Number) + { + return ((Number) value).shortValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Short.parseShort(valueStr.trim()); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为Short
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Short toShort(Object value) + { + return toShort(value, null); + } + + /** + * 转换为Number
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Number toNumber(Object value, Number defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Number) + { + return (Number) value; + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return NumberFormat.getInstance().parse(valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为Number
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Number toNumber(Object value) + { + return toNumber(value, null); + } + + /** + * 转换为int
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Integer toInt(Object value, Integer defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Integer) + { + return (Integer) value; + } + if (value instanceof Number) + { + return ((Number) value).intValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Integer.parseInt(valueStr.trim()); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为int
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Integer toInt(Object value) + { + return toInt(value, null); + } + + /** + * 转换为Integer数组
+ * + * @param str 被转换的值 + * @return 结果 + */ + public static Integer[] toIntArray(String str) + { + return toIntArray(",", str); + } + + /** + * 转换为Long数组
+ * + * @param str 被转换的值 + * @return 结果 + */ + public static Long[] toLongArray(String str) + { + return toLongArray(",", str); + } + + /** + * 转换为Integer数组
+ * + * @param split 分隔符 + * @param split 被转换的值 + * @return 结果 + */ + public static Integer[] toIntArray(String split, String str) + { + if (StringUtils.isEmpty(str)) + { + return new Integer[] {}; + } + String[] arr = str.split(split); + final Integer[] ints = new Integer[arr.length]; + for (int i = 0; i < arr.length; i++) + { + final Integer v = toInt(arr[i], 0); + ints[i] = v; + } + return ints; + } + + /** + * 转换为Long数组
+ * + * @param split 分隔符 + * @param str 被转换的值 + * @return 结果 + */ + public static Long[] toLongArray(String split, String str) + { + if (StringUtils.isEmpty(str)) + { + return new Long[] {}; + } + String[] arr = str.split(split); + final Long[] longs = new Long[arr.length]; + for (int i = 0; i < arr.length; i++) + { + final Long v = toLong(arr[i], null); + longs[i] = v; + } + return longs; + } + + /** + * 转换为String数组
+ * + * @param str 被转换的值 + * @return 结果 + */ + public static String[] toStrArray(String str) + { + return toStrArray(",", str); + } + + /** + * 转换为String数组
+ * + * @param split 分隔符 + * @param split 被转换的值 + * @return 结果 + */ + public static String[] toStrArray(String split, String str) + { + return str.split(split); + } + + /** + * 转换为long
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Long toLong(Object value, Long defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Long) + { + return (Long) value; + } + if (value instanceof Number) + { + return ((Number) value).longValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + // 支持科学计数法 + return new BigDecimal(valueStr.trim()).longValue(); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为long
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Long toLong(Object value) + { + return toLong(value, null); + } + + /** + * 转换为double
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Double toDouble(Object value, Double defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Double) + { + return (Double) value; + } + if (value instanceof Number) + { + return ((Number) value).doubleValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + // 支持科学计数法 + return new BigDecimal(valueStr.trim()).doubleValue(); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为double
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Double toDouble(Object value) + { + return toDouble(value, null); + } + + /** + * 转换为Float
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Float toFloat(Object value, Float defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Float) + { + return (Float) value; + } + if (value instanceof Number) + { + return ((Number) value).floatValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Float.parseFloat(valueStr.trim()); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为Float
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Float toFloat(Object value) + { + return toFloat(value, null); + } + + /** + * 转换为boolean
+ * String支持的值为:true、false、yes、ok、no,1,0 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Boolean toBool(Object value, Boolean defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Boolean) + { + return (Boolean) value; + } + String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + valueStr = valueStr.trim().toLowerCase(); + switch (valueStr) + { + case "true": + case "yes": + case "ok": + case "1": + return true; + case "false": + case "no": + case "0": + return false; + default: + return defaultValue; + } + } + + /** + * 转换为boolean
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Boolean toBool(Object value) + { + return toBool(value, null); + } + + /** + * 转换为Enum对象
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * + * @param clazz Enum的Class + * @param value 值 + * @param defaultValue 默认值 + * @return Enum + */ + public static > E toEnum(Class clazz, Object value, E defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (clazz.isAssignableFrom(value.getClass())) + { + @SuppressWarnings("unchecked") + E myE = (E) value; + return myE; + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Enum.valueOf(clazz, valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为Enum对象
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * + * @param clazz Enum的Class + * @param value 值 + * @return Enum + */ + public static > E toEnum(Class clazz, Object value) + { + return toEnum(clazz, value, null); + } + + /** + * 转换为BigInteger
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static BigInteger toBigInteger(Object value, BigInteger defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof BigInteger) + { + return (BigInteger) value; + } + if (value instanceof Long) + { + return BigInteger.valueOf((Long) value); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return new BigInteger(valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为BigInteger
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static BigInteger toBigInteger(Object value) + { + return toBigInteger(value, null); + } + + /** + * 转换为BigDecimal
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof BigDecimal) + { + return (BigDecimal) value; + } + if (value instanceof Long) + { + return new BigDecimal((Long) value); + } + if (value instanceof Double) + { + return BigDecimal.valueOf((Double) value); + } + if (value instanceof Integer) + { + return new BigDecimal((Integer) value); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return new BigDecimal(valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为BigDecimal
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static BigDecimal toBigDecimal(Object value) + { + return toBigDecimal(value, null); + } + + /** + * 将对象转为字符串
+ * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @return 字符串 + */ + public static String utf8Str(Object obj) + { + return str(obj, CharsetKit.CHARSET_UTF_8); + } + + /** + * 将对象转为字符串
+ * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @param charsetName 字符集 + * @return 字符串 + */ + public static String str(Object obj, String charsetName) + { + return str(obj, Charset.forName(charsetName)); + } + + /** + * 将对象转为字符串
+ * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @param charset 字符集 + * @return 字符串 + */ + public static String str(Object obj, Charset charset) + { + if (null == obj) + { + return null; + } + + if (obj instanceof String) + { + return (String) obj; + } + else if (obj instanceof byte[]) + { + return str((byte[]) obj, charset); + } + else if (obj instanceof Byte[]) + { + byte[] bytes = ArrayUtils.toPrimitive((Byte[]) obj); + return str(bytes, charset); + } + else if (obj instanceof ByteBuffer) + { + return str((ByteBuffer) obj, charset); + } + return obj.toString(); + } + + /** + * 将byte数组转为字符串 + * + * @param bytes byte数组 + * @param charset 字符集 + * @return 字符串 + */ + public static String str(byte[] bytes, String charset) + { + return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset)); + } + + /** + * 解码字节码 + * + * @param data 字符串 + * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 + * @return 解码后的字符串 + */ + public static String str(byte[] data, Charset charset) + { + if (data == null) + { + return null; + } + + if (null == charset) + { + return new String(data); + } + return new String(data, charset); + } + + /** + * 将编码的byteBuffer数据转换为字符串 + * + * @param data 数据 + * @param charset 字符集,如果为空使用当前系统字符集 + * @return 字符串 + */ + public static String str(ByteBuffer data, String charset) + { + if (data == null) + { + return null; + } + + return str(data, Charset.forName(charset)); + } + + /** + * 将编码的byteBuffer数据转换为字符串 + * + * @param data 数据 + * @param charset 字符集,如果为空使用当前系统字符集 + * @return 字符串 + */ + public static String str(ByteBuffer data, Charset charset) + { + if (null == charset) + { + charset = Charset.defaultCharset(); + } + return charset.decode(data).toString(); + } + + // ----------------------------------------------------------------------- 全角半角转换 + /** + * 半角转全角 + * + * @param input String. + * @return 全角字符串. + */ + public static String toSBC(String input) + { + return toSBC(input, null); + } + + /** + * 半角转全角 + * + * @param input String + * @param notConvertSet 不替换的字符集合 + * @return 全角字符串. + */ + public static String toSBC(String input, Set notConvertSet) + { + char[] c = input.toCharArray(); + for (int i = 0; i < c.length; i++) + { + if (null != notConvertSet && notConvertSet.contains(c[i])) + { + // 跳过不替换的字符 + continue; + } + + if (c[i] == ' ') + { + c[i] = '\u3000'; + } + else if (c[i] < '\177') + { + c[i] = (char) (c[i] + 65248); + + } + } + return new String(c); + } + + /** + * 全角转半角 + * + * @param input String. + * @return 半角字符串 + */ + public static String toDBC(String input) + { + return toDBC(input, null); + } + + /** + * 替换全角为半角 + * + * @param text 文本 + * @param notConvertSet 不替换的字符集合 + * @return 替换后的字符 + */ + public static String toDBC(String text, Set notConvertSet) + { + char[] c = text.toCharArray(); + for (int i = 0; i < c.length; i++) + { + if (null != notConvertSet && notConvertSet.contains(c[i])) + { + // 跳过不替换的字符 + continue; + } + + if (c[i] == '\u3000') + { + c[i] = ' '; + } + else if (c[i] > '\uFF00' && c[i] < '\uFF5F') + { + c[i] = (char) (c[i] - 65248); + } + } + String returnString = new String(c); + + return returnString; + } + + /** + * 数字金额大写转换 先写个完整的然后将如零拾替换成零 + * + * @param n 数字 + * @return 中文大写数字 + */ + public static String digitUppercase(double n) + { + String[] fraction = { "角", "分" }; + String[] digit = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" }; + String[][] unit = { { "元", "万", "亿" }, { "", "拾", "佰", "仟" } }; + + String head = n < 0 ? "负" : ""; + n = Math.abs(n); + + String s = ""; + for (int i = 0; i < fraction.length; i++) + { + s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", ""); + } + if (s.length() < 1) + { + s = "整"; + } + int integerPart = (int) Math.floor(n); + + for (int i = 0; i < unit[0].length && integerPart > 0; i++) + { + String p = ""; + for (int j = 0; j < unit[1].length && n > 0; j++) + { + p = digit[integerPart % 10] + unit[1][j] + p; + integerPart = integerPart / 10; + } + s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s; + } + return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整"); + } +} diff --git a/src/main/java/com/hb/util/DateUtil.java b/src/main/java/com/hb/util/DateUtil.java new file mode 100644 index 0000000..e54bb91 --- /dev/null +++ b/src/main/java/com/hb/util/DateUtil.java @@ -0,0 +1,26 @@ +package com.hb.util; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Locale; + +public class DateUtil { + + public static String buildAlarmMsgCode() { + return "A" + getDateTime("yyyyMMddHHmmssSSS"); + } + + public static String buildNoticeMsgCode() { + return "N" + getDateTime("yyyyMMddHHmmssSSS"); + } + + public static String getDateTime(String timeFmt) { + LocalDateTime dateTime = LocalDateTime.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(timeFmt, Locale.CHINA); + return dateTime.format(formatter); + } + + public static String getDateTime() { + return getDateTime("yyyy-MM-dd HH:mm:ss"); + } +} diff --git a/src/main/java/com/hb/util/HttpUtils.java b/src/main/java/com/hb/util/HttpUtils.java new file mode 100644 index 0000000..c225974 --- /dev/null +++ b/src/main/java/com/hb/util/HttpUtils.java @@ -0,0 +1,265 @@ +package com.hb.util; + +import com.hb.constant.Constants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.*; +import java.io.*; +import java.net.ConnectException; +import java.net.SocketTimeoutException; +import java.net.URL; +import java.net.URLConnection; +import java.nio.charset.StandardCharsets; +import java.security.cert.X509Certificate; + +/** + * 通用http发送方法 + * + * @author ruoyi + */ +public class HttpUtils +{ + private static final Logger log = LoggerFactory.getLogger(HttpUtils.class); + + /** + * 向指定 URL 发送GET方法的请求 + * + * @param url 发送请求的 URL + * @return 所代表远程资源的响应结果 + */ + public static String sendGet(String url) + { + return sendGet(url, StringUtils.EMPTY); + } + + /** + * 向指定 URL 发送GET方法的请求 + * + * @param url 发送请求的 URL + * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 + * @return 所代表远程资源的响应结果 + */ + public static String sendGet(String url, String param) + { + return sendGet(url, param, Constants.UTF8); + } + + /** + * 向指定 URL 发送GET方法的请求 + * + * @param url 发送请求的 URL + * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 + * @param contentType 编码类型 + * @return 所代表远程资源的响应结果 + */ + public static String sendGet(String url, String param, String contentType) + { + StringBuilder result = new StringBuilder(); + BufferedReader in = null; + try + { + String urlNameString = StringUtils.isNotBlank(param) ? url + "?" + param : url; + log.info("sendGet - {}", urlNameString); + URL realUrl = new URL(urlNameString); + URLConnection connection = realUrl.openConnection(); + connection.setRequestProperty("accept", "*/*"); + connection.setRequestProperty("connection", "Keep-Alive"); + connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); + connection.connect(); + in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType)); + String line; + while ((line = in.readLine()) != null) + { + result.append(line); + } + log.info("recv - {}", result); + } + catch (ConnectException e) + { + log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e); + } + catch (SocketTimeoutException e) + { + log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e); + } + catch (IOException e) + { + log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e); + } + catch (Exception e) + { + log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e); + } + finally + { + try + { + if (in != null) + { + in.close(); + } + } + catch (Exception ex) + { + log.error("调用in.close Exception, url=" + url + ",param=" + param, ex); + } + } + return result.toString(); + } + + /** + * 向指定 URL 发送POST方法的请求 + * + * @param url 发送请求的 URL + * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 + * @return 所代表远程资源的响应结果 + */ + public static String sendPost(String url, String param) + { + PrintWriter out = null; + BufferedReader in = null; + StringBuilder result = new StringBuilder(); + try + { + log.info("sendPost - {}", url); + URL realUrl = new URL(url); + URLConnection conn = realUrl.openConnection(); + conn.setRequestProperty("accept", "*/*"); + conn.setRequestProperty("connection", "Keep-Alive"); + conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); + conn.setRequestProperty("Accept-Charset", "utf-8"); + conn.setRequestProperty("contentType", "utf-8"); + conn.setDoOutput(true); + conn.setDoInput(true); + out = new PrintWriter(conn.getOutputStream()); + out.print(param); + out.flush(); + in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8)); + String line; + while ((line = in.readLine()) != null) + { + result.append(line); + } + log.info("recv - {}", result); + } + catch (ConnectException e) + { + log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e); + } + catch (SocketTimeoutException e) + { + log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e); + } + catch (IOException e) + { + log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e); + } + catch (Exception e) + { + log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e); + } + finally + { + try + { + if (out != null) + { + out.close(); + } + if (in != null) + { + in.close(); + } + } + catch (IOException ex) + { + log.error("调用in.close Exception, url=" + url + ",param=" + param, ex); + } + } + return result.toString(); + } + + public static String sendSSLPost(String url, String param) + { + StringBuilder result = new StringBuilder(); + String urlNameString = url + "?" + param; + try + { + log.info("sendSSLPost - {}", urlNameString); + SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom()); + URL console = new URL(urlNameString); + HttpsURLConnection conn = (HttpsURLConnection) console.openConnection(); + conn.setRequestProperty("accept", "*/*"); + conn.setRequestProperty("connection", "Keep-Alive"); + conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); + conn.setRequestProperty("Accept-Charset", "utf-8"); + conn.setRequestProperty("contentType", "utf-8"); + conn.setDoOutput(true); + conn.setDoInput(true); + + conn.setSSLSocketFactory(sc.getSocketFactory()); + conn.setHostnameVerifier(new TrustAnyHostnameVerifier()); + conn.connect(); + InputStream is = conn.getInputStream(); + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + String ret = ""; + while ((ret = br.readLine()) != null) + { + if (ret != null && !"".equals(ret.trim())) + { + result.append(new String(ret.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8)); + } + } + log.info("recv - {}", result); + conn.disconnect(); + br.close(); + } + catch (ConnectException e) + { + log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e); + } + catch (SocketTimeoutException e) + { + log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e); + } + catch (IOException e) + { + log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e); + } + catch (Exception e) + { + log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e); + } + return result.toString(); + } + + private static class TrustAnyTrustManager implements X509TrustManager + { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) + { + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) + { + } + + @Override + public X509Certificate[] getAcceptedIssuers() + { + return new X509Certificate[] {}; + } + } + + private static class TrustAnyHostnameVerifier implements HostnameVerifier + { + @Override + public boolean verify(String hostname, SSLSession session) + { + return true; + } + } +} diff --git a/src/main/java/com/hb/util/MinioUtil.java b/src/main/java/com/hb/util/MinioUtil.java new file mode 100644 index 0000000..fe0a81a --- /dev/null +++ b/src/main/java/com/hb/util/MinioUtil.java @@ -0,0 +1,194 @@ +package com.hb.util; + +import java.io.InputStream; +import java.util.*; +import java.util.concurrent.TimeUnit; + +import io.minio.*; +import io.minio.http.Method; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import com.hb.domain.Fileinfo; +import io.minio.messages.Bucket; +import io.minio.messages.Item; +import org.springframework.web.multipart.MultipartFile; + +@Component +public class MinioUtil { + @Autowired + private MinioClient minioClient; + + @Autowired + private RedisTemplate redisTemplate; + + /** + * 创建一个桶 + */ + public void createBucket(String bucket) throws Exception { + boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucket).build()); + if (!found) { + minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucket).build()); + } + } + + /** + * 上传一个文件 + */ + public void uploadFile(InputStream stream, String bucket, String objectName) throws Exception { + minioClient.putObject(PutObjectArgs.builder().bucket(bucket).object(objectName) + .stream(stream, -1, 10485760).build()); + } + + + + /** + * 列出所有的桶 + */ + public List listBuckets() throws Exception { + List list = minioClient.listBuckets(); + List names = new ArrayList<>(); + list.forEach(b -> { + names.add(b.name()); + }); + return names; + } + + /** + * 列出一个桶中的所有文件和目录 + */ + public List listFiles(String bucket) throws Exception { + Iterable> results = minioClient.listObjects( + ListObjectsArgs.builder().bucket(bucket).recursive(true).build()); + + List infos = new ArrayList<>(); + results.forEach(r->{ + Fileinfo info = new Fileinfo(); + try { + Item item = r.get(); + info.setFilename(item.objectName()); + info.setDirectory(item.isDir()); + infos.add(info); + } catch (Exception e) { + e.printStackTrace(); + } + }); + return infos; + } + + /** + * 下载一个文件 + */ + public InputStream download(String bucket, String objectName) throws Exception { + InputStream stream = minioClient.getObject( + GetObjectArgs.builder().bucket(bucket).object(objectName).build()); + return stream; + } + + /** + * 删除一个桶 + */ + public void deleteBucket(String bucket) throws Exception { + minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucket).build()); + } + + /** + * 删除一个对象 + */ + public void deleteObject(String bucket, String objectName) throws Exception { + minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucket).object(objectName).build()); + } + + /** + * 生成直传链接 + * @param fileDirName + * @param bucket + * @return + */ + public String getOneURL(String fileDirName, String bucket) throws Exception{ + boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucket).build()); + if (!found) { + throw new RuntimeException("桶不存在!"); + } + + Map reqParams = new HashMap(); + reqParams.put("response-content-type", "application/json"); + return minioClient.getPresignedObjectUrl( + GetPresignedObjectUrlArgs.builder() + .method(Method.PUT) //这里必须是PUT,如果是GET的话就是文件访问地址了。如果是POST上传会报错. + .bucket(bucket) // 存储桶 + .object(fileDirName) // 文件名 + .expiry(60 * 60 * 24) + .extraQueryParams(reqParams) + .build()); + } + + public String getMinioURL(String bucket, String fileDirName) throws Exception{ + String key = bucket + ":" + fileDirName.replaceAll("/", ":"); + String url = (String) redisTemplate.opsForValue().get(key); + if (StringUtils.isEmpty(url)) { + int timeout = 60 * 60 * 24 * 7; + GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs.builder() + .method(Method.GET) + .bucket(bucket) + .object(fileDirName) + .expiry(timeout, TimeUnit.SECONDS) //生成的预签名url可访问的有效时间,最大期限7天 + .build(); + url = minioClient.getPresignedObjectUrl(build); + redisTemplate.opsForValue().set(key, url); + redisTemplate.expire(key, timeout, TimeUnit.SECONDS); + } + return url; + } + + public List getMinioURLs(String bucket, String[] fileDirNames) throws Exception{ + List urlList = new ArrayList<>(); + for (String fileDirName : fileDirNames) { + GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs.builder() + .method(Method.GET) + .bucket(bucket) + .object(fileDirName) + .expiry(60 * 60 * 24 * 7) //生成的预签名url可访问的有效时间,最大期限7天 + .build(); + String url = minioClient.getPresignedObjectUrl(build); + urlList.add(url); + } + return urlList; + } + + public String getContenType(String bucket, String objectName) throws Exception{ + // 创建StatObjectArgs对象 + StatObjectArgs statObjectArgs = StatObjectArgs.builder() + .bucket(bucket) + .object(objectName) + .build(); + + // 获取对象信息 + StatObjectResponse statObjectResponse = minioClient.statObject(statObjectArgs); + + if (statObjectResponse == null) { + throw new RuntimeException("文件不存在!"); + } + + // 获取文件类型 + String contentType = statObjectResponse.contentType(); + System.out.println("文件类型:" + contentType); + return contentType; + } + + public void uploadFile2(MultipartFile file, String bucket, String fileDirName) throws Exception{ + + Long fileSize = file.getSize(); + String fileType = file.getContentType(); + String fileName = file.getOriginalFilename(); + + minioClient.putObject(PutObjectArgs.builder() + .bucket(bucket) // 存储桶 + .object(fileDirName) // 文件名 + .stream(file.getInputStream(), fileSize, -1) // 文件内容 + .contentType(fileType) // 文件类型 + .build()); + } + +} diff --git a/src/main/java/com/hb/util/ServletUtils.java b/src/main/java/com/hb/util/ServletUtils.java new file mode 100644 index 0000000..598f951 --- /dev/null +++ b/src/main/java/com/hb/util/ServletUtils.java @@ -0,0 +1,218 @@ +package com.hb.util; + +import com.hb.constant.Constants; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * 客户端工具类 + * + * @author ruoyi + */ +public class ServletUtils +{ + /** + * 获取String参数 + */ + public static String getParameter(String name) + { + return getRequest().getParameter(name); + } + + /** + * 获取String参数 + */ + public static String getParameter(String name, String defaultValue) + { + return Convert.toStr(getRequest().getParameter(name), defaultValue); + } + + /** + * 获取Integer参数 + */ + public static Integer getParameterToInt(String name) + { + return Convert.toInt(getRequest().getParameter(name)); + } + + /** + * 获取Integer参数 + */ + public static Integer getParameterToInt(String name, Integer defaultValue) + { + return Convert.toInt(getRequest().getParameter(name), defaultValue); + } + + /** + * 获取Boolean参数 + */ + public static Boolean getParameterToBool(String name) + { + return Convert.toBool(getRequest().getParameter(name)); + } + + /** + * 获取Boolean参数 + */ + public static Boolean getParameterToBool(String name, Boolean defaultValue) + { + return Convert.toBool(getRequest().getParameter(name), defaultValue); + } + + /** + * 获得所有请求参数 + * + * @param request 请求对象{@link ServletRequest} + * @return Map + */ + public static Map getParams(ServletRequest request) + { + final Map map = request.getParameterMap(); + return Collections.unmodifiableMap(map); + } + + /** + * 获得所有请求参数 + * + * @param request 请求对象{@link ServletRequest} + * @return Map + */ + public static Map getParamMap(ServletRequest request) + { + Map params = new HashMap<>(); + for (Map.Entry entry : getParams(request).entrySet()) + { + params.put(entry.getKey(), StringUtils.join(entry.getValue(), ",")); + } + return params; + } + + /** + * 获取request + */ + public static HttpServletRequest getRequest() + { + return getRequestAttributes().getRequest(); + } + + /** + * 获取response + */ + public static HttpServletResponse getResponse() + { + return getRequestAttributes().getResponse(); + } + + /** + * 获取session + */ + public static HttpSession getSession() + { + return getRequest().getSession(); + } + + public static ServletRequestAttributes getRequestAttributes() + { + RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); + return (ServletRequestAttributes) attributes; + } + + /** + * 将字符串渲染到客户端 + * + * @param response 渲染对象 + * @param string 待渲染的字符串 + */ + public static void renderString(HttpServletResponse response, String string) + { + try + { + response.setStatus(200); + response.setContentType("application/json"); + response.setCharacterEncoding("utf-8"); + response.getWriter().print(string); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + /** + * 是否是Ajax异步请求 + * + * @param request + */ + public static boolean isAjaxRequest(HttpServletRequest request) + { + String accept = request.getHeader("accept"); + if (accept != null && accept.contains("application/json")) + { + return true; + } + + String xRequestedWith = request.getHeader("X-Requested-With"); + if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest")) + { + return true; + } + + String uri = request.getRequestURI(); + if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml")) + { + return true; + } + + String ajax = request.getParameter("__ajax"); + return StringUtils.inStringIgnoreCase(ajax, "json", "xml"); + } + + /** + * 内容编码 + * + * @param str 内容 + * @return 编码后的内容 + */ + public static String urlEncode(String str) + { + try + { + return URLEncoder.encode(str, Constants.UTF8); + } + catch (UnsupportedEncodingException e) + { + return StringUtils.EMPTY; + } + } + + /** + * 内容解码 + * + * @param str 内容 + * @return 解码后的内容 + */ + public static String urlDecode(String str) + { + try + { + return URLDecoder.decode(str, Constants.UTF8); + } + catch (UnsupportedEncodingException e) + { + return StringUtils.EMPTY; + } + } +} diff --git a/src/main/java/com/hb/util/StrFormatter.java b/src/main/java/com/hb/util/StrFormatter.java new file mode 100644 index 0000000..e61970d --- /dev/null +++ b/src/main/java/com/hb/util/StrFormatter.java @@ -0,0 +1,90 @@ +package com.hb.util; + +/** + * 字符串格式化 + * + * @author ruoyi + */ +public class StrFormatter +{ + public static final String EMPTY_JSON = "{}"; + public static final char C_BACKSLASH = '\\'; + public static final char C_DELIM_START = '{'; + public static final char C_DELIM_END = '}'; + + /** + * 格式化字符串
+ * 此方法只是简单将占位符 {} 按照顺序替换为参数
+ * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可
+ * 例:
+ * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
+ * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a
+ * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
+ * + * @param strPattern 字符串模板 + * @param argArray 参数列表 + * @return 结果 + */ + public static String format(final String strPattern, final Object... argArray) + { + if (StringUtils.isEmpty(strPattern) || StringUtils.isEmpty(argArray)) + { + return strPattern; + } + final int strPatternLength = strPattern.length(); + + // 初始化定义好的长度以获得更好的性能 + StringBuilder sbuf = new StringBuilder(strPatternLength + 50); + + int handledPosition = 0; + int delimIndex;// 占位符所在位置 + for (int argIndex = 0; argIndex < argArray.length; argIndex++) + { + delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition); + if (delimIndex == -1) + { + if (handledPosition == 0) + { + return strPattern; + } + else + { // 字符串模板剩余部分不再包含占位符,加入剩余部分后返回结果 + sbuf.append(strPattern, handledPosition, strPatternLength); + return sbuf.toString(); + } + } + else + { + if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH) + { + if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH) + { + // 转义符之前还有一个转义符,占位符依旧有效 + sbuf.append(strPattern, handledPosition, delimIndex - 1); + sbuf.append(Convert.utf8Str(argArray[argIndex])); + handledPosition = delimIndex + 2; + } + else + { + // 占位符被转义 + argIndex--; + sbuf.append(strPattern, handledPosition, delimIndex - 1); + sbuf.append(C_DELIM_START); + handledPosition = delimIndex + 1; + } + } + else + { + // 正常占位符 + sbuf.append(strPattern, handledPosition, delimIndex); + sbuf.append(Convert.utf8Str(argArray[argIndex])); + handledPosition = delimIndex + 2; + } + } + } + // 加入最后一个占位符后所有的字符 + sbuf.append(strPattern, handledPosition, strPattern.length()); + + return sbuf.toString(); + } +} diff --git a/src/main/java/com/hb/util/StringUtils.java b/src/main/java/com/hb/util/StringUtils.java new file mode 100644 index 0000000..92e5f26 --- /dev/null +++ b/src/main/java/com/hb/util/StringUtils.java @@ -0,0 +1,609 @@ +package com.hb.util; + +import com.hb.constant.Constants; +import org.springframework.util.AntPathMatcher; + +import java.util.*; + +/** + * 字符串工具类 + * + * @author ruoyi + */ +public class StringUtils extends org.apache.commons.lang3.StringUtils +{ + /** 空字符串 */ + private static final String NULLSTR = ""; + + /** 下划线 */ + private static final char SEPARATOR = '_'; + + /** + * 获取参数不为空值 + * + * @param value defaultValue 要判断的value + * @return value 返回值 + */ + public static T nvl(T value, T defaultValue) + { + return value != null ? value : defaultValue; + } + + /** + * * 判断一个Collection是否为空, 包含List,Set,Queue + * + * @param coll 要判断的Collection + * @return true:为空 false:非空 + */ + public static boolean isEmpty(Collection coll) + { + return isNull(coll) || coll.isEmpty(); + } + + /** + * * 判断一个Collection是否非空,包含List,Set,Queue + * + * @param coll 要判断的Collection + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Collection coll) + { + return !isEmpty(coll); + } + + /** + * * 判断一个对象数组是否为空 + * + * @param objects 要判断的对象数组 + ** @return true:为空 false:非空 + */ + public static boolean isEmpty(Object[] objects) + { + return isNull(objects) || (objects.length == 0); + } + + /** + * * 判断一个对象数组是否非空 + * + * @param objects 要判断的对象数组 + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Object[] objects) + { + return !isEmpty(objects); + } + + /** + * * 判断一个Map是否为空 + * + * @param map 要判断的Map + * @return true:为空 false:非空 + */ + public static boolean isEmpty(Map map) + { + return isNull(map) || map.isEmpty(); + } + + /** + * * 判断一个Map是否为空 + * + * @param map 要判断的Map + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Map map) + { + return !isEmpty(map); + } + + /** + * * 判断一个字符串是否为空串 + * + * @param str String + * @return true:为空 false:非空 + */ + public static boolean isEmpty(String str) + { + return isNull(str) || NULLSTR.equals(str.trim()); + } + + /** + * * 判断一个字符串是否为非空串 + * + * @param str String + * @return true:非空串 false:空串 + */ + public static boolean isNotEmpty(String str) + { + return !isEmpty(str); + } + + /** + * * 判断一个对象是否为空 + * + * @param object Object + * @return true:为空 false:非空 + */ + public static boolean isNull(Object object) + { + return object == null; + } + + /** + * * 判断一个对象是否非空 + * + * @param object Object + * @return true:非空 false:空 + */ + public static boolean isNotNull(Object object) + { + return !isNull(object); + } + + /** + * * 判断一个对象是否是数组类型(Java基本型别的数组) + * + * @param object 对象 + * @return true:是数组 false:不是数组 + */ + public static boolean isArray(Object object) + { + return isNotNull(object) && object.getClass().isArray(); + } + + /** + * 去空格 + */ + public static String trim(String str) + { + return (str == null ? "" : str.trim()); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @return 结果 + */ + public static String substring(final String str, int start) + { + if (str == null) + { + return NULLSTR; + } + + if (start < 0) + { + start = str.length() + start; + } + + if (start < 0) + { + start = 0; + } + if (start > str.length()) + { + return NULLSTR; + } + + return str.substring(start); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @param end 结束 + * @return 结果 + */ + public static String substring(final String str, int start, int end) + { + if (str == null) + { + return NULLSTR; + } + + if (end < 0) + { + end = str.length() + end; + } + if (start < 0) + { + start = str.length() + start; + } + + if (end > str.length()) + { + end = str.length(); + } + + if (start > end) + { + return NULLSTR; + } + + if (start < 0) + { + start = 0; + } + if (end < 0) + { + end = 0; + } + + return str.substring(start, end); + } + + /** + * 格式化文本, {} 表示占位符
+ * 此方法只是简单将占位符 {} 按照顺序替换为参数
+ * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可
+ * 例:
+ * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
+ * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a
+ * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
+ * + * @param template 文本模板,被替换的部分用 {} 表示 + * @param params 参数值 + * @return 格式化后的文本 + */ + public static String format(String template, Object... params) + { + if (isEmpty(params) || isEmpty(template)) + { + return template; + } + return StrFormatter.format(template, params); + } + + /** + * 是否为http(s)://开头 + * + * @param link 链接 + * @return 结果 + */ + public static boolean ishttp(String link) + { + return StringUtils.startsWithAny(link, Constants.HTTP, Constants.HTTPS); + } + + /** + * 字符串转set + * + * @param str 字符串 + * @param sep 分隔符 + * @return set集合 + */ + public static final Set str2Set(String str, String sep) + { + return new HashSet(str2List(str, sep, true, false)); + } + + /** + * 字符串转list + * + * @param str 字符串 + * @param sep 分隔符 + * @param filterBlank 过滤纯空白 + * @param trim 去掉首尾空白 + * @return list集合 + */ + public static final List str2List(String str, String sep, boolean filterBlank, boolean trim) + { + List list = new ArrayList(); + if (StringUtils.isEmpty(str)) + { + return list; + } + + // 过滤空白字符串 + if (filterBlank && StringUtils.isBlank(str)) + { + return list; + } + String[] split = str.split(sep); + for (String string : split) + { + if (filterBlank && StringUtils.isBlank(string)) + { + continue; + } + if (trim) + { + string = string.trim(); + } + list.add(string); + } + + return list; + } + + /** + * 判断给定的set列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value + * + * @param collection 给定的集合 + * @param array 给定的数组 + * @return boolean 结果 + */ + public static boolean containsAny(Collection collection, String... array) + { + if (isEmpty(collection) || isEmpty(array)) + { + return false; + } + else + { + for (String str : array) + { + if (collection.contains(str)) + { + return true; + } + } + return false; + } + } + + /** + * 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写 + * + * @param cs 指定字符串 + * @param searchCharSequences 需要检查的字符串数组 + * @return 是否包含任意一个字符串 + */ + public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) + { + if (isEmpty(cs) || isEmpty(searchCharSequences)) + { + return false; + } + for (CharSequence testStr : searchCharSequences) + { + if (containsIgnoreCase(cs, testStr)) + { + return true; + } + } + return false; + } + + /** + * 驼峰转下划线命名 + */ + public static String toUnderScoreCase(String str) + { + if (str == null) + { + return null; + } + StringBuilder sb = new StringBuilder(); + // 前置字符是否大写 + boolean preCharIsUpperCase = true; + // 当前字符是否大写 + boolean curreCharIsUpperCase = true; + // 下一字符是否大写 + boolean nexteCharIsUpperCase = true; + for (int i = 0; i < str.length(); i++) + { + char c = str.charAt(i); + if (i > 0) + { + preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1)); + } + else + { + preCharIsUpperCase = false; + } + + curreCharIsUpperCase = Character.isUpperCase(c); + + if (i < (str.length() - 1)) + { + nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1)); + } + + if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) + { + sb.append(SEPARATOR); + } + else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) + { + sb.append(SEPARATOR); + } + sb.append(Character.toLowerCase(c)); + } + + return sb.toString(); + } + + /** + * 是否包含字符串 + * + * @param str 验证字符串 + * @param strs 字符串组 + * @return 包含返回true + */ + public static boolean inStringIgnoreCase(String str, String... strs) + { + if (str != null && strs != null) + { + for (String s : strs) + { + if (str.equalsIgnoreCase(trim(s))) + { + return true; + } + } + } + return false; + } + + /** + * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld + * + * @param name 转换前的下划线大写方式命名的字符串 + * @return 转换后的驼峰式命名的字符串 + */ + public static String convertToCamelCase(String name) + { + StringBuilder result = new StringBuilder(); + // 快速检查 + if (name == null || name.isEmpty()) + { + // 没必要转换 + return ""; + } + else if (!name.contains("_")) + { + // 不含下划线,仅将首字母大写 + return name.substring(0, 1).toUpperCase() + name.substring(1); + } + // 用下划线将原始字符串分割 + String[] camels = name.split("_"); + for (String camel : camels) + { + // 跳过原始字符串中开头、结尾的下换线或双重下划线 + if (camel.isEmpty()) + { + continue; + } + // 首字母大写 + result.append(camel.substring(0, 1).toUpperCase()); + result.append(camel.substring(1).toLowerCase()); + } + return result.toString(); + } + + /** + * 驼峰式命名法 + * 例如:user_name->userName + */ + public static String toCamelCase(String s) + { + if (s == null) + { + return null; + } + if (s.indexOf(SEPARATOR) == -1) + { + return s; + } + s = s.toLowerCase(); + StringBuilder sb = new StringBuilder(s.length()); + boolean upperCase = false; + for (int i = 0; i < s.length(); i++) + { + char c = s.charAt(i); + + if (c == SEPARATOR) + { + upperCase = true; + } + else if (upperCase) + { + sb.append(Character.toUpperCase(c)); + upperCase = false; + } + else + { + sb.append(c); + } + } + return sb.toString(); + } + + /** + * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串 + * + * @param str 指定字符串 + * @param strs 需要检查的字符串数组 + * @return 是否匹配 + */ + public static boolean matches(String str, List strs) + { + if (isEmpty(str) || isEmpty(strs)) + { + return false; + } + for (String pattern : strs) + { + if (isMatch(pattern, str)) + { + return true; + } + } + return false; + } + + /** + * 判断url是否与规则配置: + * ? 表示单个字符; + * * 表示一层路径内的任意字符串,不可跨层级; + * ** 表示任意层路径; + * + * @param pattern 匹配规则 + * @param url 需要匹配的url + * @return + */ + public static boolean isMatch(String pattern, String url) + { + AntPathMatcher matcher = new AntPathMatcher(); + return matcher.match(pattern, url); + } + + @SuppressWarnings("unchecked") + public static T cast(Object obj) + { + return (T) obj; + } + + /** + * 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。 + * + * @param num 数字对象 + * @param size 字符串指定长度 + * @return 返回数字的字符串格式,该字符串为指定长度。 + */ + public static final String padl(final Number num, final int size) + { + return padl(num.toString(), size, '0'); + } + + /** + * 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。 + * + * @param s 原始字符串 + * @param size 字符串指定长度 + * @param c 用于补齐的字符 + * @return 返回指定长度的字符串,由原字符串左补齐或截取得到。 + */ + public static final String padl(final String s, final int size, final char c) + { + final StringBuilder sb = new StringBuilder(size); + if (s != null) + { + final int len = s.length(); + if (s.length() <= size) + { + for (int i = size - len; i > 0; i--) + { + sb.append(c); + } + sb.append(s); + } + else + { + return s.substring(len - size, len); + } + } + else + { + for (int i = size; i > 0; i--) + { + sb.append(c); + } + } + return sb.toString(); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..79839db --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,44 @@ +server: + port: 8888 + +logging: + config: classpath:log4j2.xml + +spring: + servlet: + multipart: + max-file-size: 100MB + max-request-size: 1000MB + # redis 配置 + redis: + # 地址 + host: 192.168.12.71 + # 端口,默认为6379 + port: 6379 + # 数据库索引 + database: 0 + # 密码 + password: 123456 + # 连接超时时间 + timeout: 10s + lettuce: + pool: + # 连接池中的最小空闲连接 + min-idle: 0 + # 连接池中的最大空闲连接 + max-idle: 8 + # 连接池的最大数据库连接数 + max-active: 8 + # #连接池最大阻塞等待时间(使用负值表示没有限制) + max-wait: -1ms + +#minio配置 +minio: + url: https://192.168.12.71:9000 #对象存储服务的URL + accessKey: QVoCEhy0xek0pquP #Access key账户 + secretKey: g89JlYE4Nnii66g6JmGRoSF7S4bc0hm6 #Secret key密码 + +#minio: +# url: https://192.168.12.180:9091 +# accessKey: Iws9bNohJkz8fRhU +# secretKey: DaPp2vzxsX87fFfyYa51fWaeclxGfcwN diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000..7b79eb4 --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,97 @@ + + + + + ./logs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file