This commit is contained in:
Jane
2023-12-22 10:59:10 +08:00
parent 751c43e199
commit d1ede2d4aa
2774 changed files with 291509 additions and 0 deletions

8
studio/.gitignore vendored Normal file
View File

@@ -0,0 +1,8 @@
### IDEA ###
.idea/*
*.iml
*/target/*
*/*.iml
/.gradle/
application.pid
spy.log

0
studio/.gitkeep Normal file
View File

40
studio/assembly/pom.xml Normal file
View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>studio</artifactId>
<groupId>com.platform</groupId>
<version>0.4.x</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>assembly</artifactId>
<packaging>pom</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<finalName>${project.parent.artifactId}-release-${project.version}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>src/main/assembly/package.xml</descriptor>
</descriptors>
<outputDirectory>${project.parent.basedir}/build/</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,424 @@
<assembly>
<id>${project.version}</id>
<formats>
<format>tar.gz</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.parent.basedir}/install/16gmaster</directory>
<outputDirectory>./16gmaster</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/install/sql</directory>
<outputDirectory>./sql</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/install/16gslave</directory>
<outputDirectory>./16gslave</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/install/16gdata</directory>
<outputDirectory>./16gdata</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/install</directory>
<outputDirectory>./</outputDirectory>
<includes>
<include>README.md</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/config/target
</directory>
<outputDirectory>./16gmaster/config</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/config/target/classes
</directory>
<outputDirectory>./16gmaster/config</outputDirectory>
<includes>
<include>bootstrap.yml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/eureka/target
</directory>
<outputDirectory>./16gslave/eureka</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/eureka/target/classes
</directory>
<outputDirectory>./16gslave/eureka</outputDirectory>
<includes>
<include>bootstrap.yml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/gateway/target</directory>
<outputDirectory>./16gdata/gateway</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/gateway/target/classes</directory>
<outputDirectory>./16gdata/gateway</outputDirectory>
<includes>
<include>bootstrap.yml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-market-service-parent/data-market-service-integration/target
</directory>
<outputDirectory>./16gmaster/data-market-service-integration</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-market-service-parent/data-market-service-integration/target/classes
</directory>
<outputDirectory>./16gmaster/data-market-service-integration</outputDirectory>
<includes>
<include>bootstrap.yml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-compare-service-parent/data-compare-service/target
</directory>
<outputDirectory>./16gmaster/data-compare-service</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-compare-service-parent/data-compare-service/target/classes
</directory>
<outputDirectory>./16gmaster/data-compare-service</outputDirectory>
<includes>
<include>bootstrap.yml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-cluster-service-parent/data-cluster-service/target
</directory>
<outputDirectory>./16gslave/data-cluster-service</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-cluster-service-parent/data-cluster-service/target/classes
</directory>
<outputDirectory>./16gslave/data-cluster-service</outputDirectory>
<includes>
<include>bootstrap.yml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-system-service-parent/data-system-service/target
</directory>
<outputDirectory>./16gmaster/data-system-service</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-system-service-parent/data-system-service/target/classes
</directory>
<outputDirectory>./16gmaster/data-system-service</outputDirectory>
<includes>
<include>bootstrap.yml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/service-data-dts-parent/service-data-dts/target
</directory>
<outputDirectory>./16gmaster/service-data-dts</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/service-data-dts-parent/service-data-dts/target/classes
</directory>
<outputDirectory>./16gmaster/service-data-dts</outputDirectory>
<includes>
<include>bootstrap.yml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/system-service-parent/system-service/target
</directory>
<outputDirectory>./16gmaster/system-service</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/system-service-parent/system-service/target/classes
</directory>
<outputDirectory>./16gmaster/system-service</outputDirectory>
<includes>
<include>bootstrap.yml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-market-service-parent/data-market-service/target
</directory>
<outputDirectory>./16gmaster/data-market-service</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-market-service-parent/data-market-service/target/classes
</directory>
<outputDirectory>./16gmaster/data-market-service</outputDirectory>
<includes>
<include>bootstrap.yml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-market-service-parent/data-market-service-mapping/target
</directory>
<outputDirectory>./16gslave/data-market-service-mapping</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-market-service-parent/data-market-service-mapping/target/classes
</directory>
<outputDirectory>./16gslave/data-market-service-mapping</outputDirectory>
<includes>
<include>bootstrap.yml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-masterdata-service-parent/data-masterdata-service/target
</directory>
<outputDirectory>./16gslave/data-masterdata-service</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-masterdata-service-parent/data-masterdata-service/target/classes
</directory>
<outputDirectory>./16gslave/data-masterdata-service</outputDirectory>
<includes>
<include>bootstrap.yml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-metadata-service-parent/data-metadata-service-console/target
</directory>
<outputDirectory>./16gslave/data-metadata-service-console</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-metadata-service-parent/data-metadata-service-console/target/classes
</directory>
<outputDirectory>./16gslave/data-metadata-service-console</outputDirectory>
<includes>
<include>bootstrap.yml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-metadata-service-parent/data-metadata-service/target
</directory>
<outputDirectory>./16gmaster/data-metadata-service</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-metadata-service-parent/data-metadata-service/target/classes
</directory>
<outputDirectory>./16gmaster/data-metadata-service</outputDirectory>
<includes>
<include>bootstrap.yml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-quality-service-parent/data-quality-service/target
</directory>
<outputDirectory>./16gslave/data-quality-service</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-quality-service-parent/data-quality-service/target/classes
</directory>
<outputDirectory>./16gslave/data-quality-service</outputDirectory>
<includes>
<include>bootstrap.yml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-standard-service-parent/data-standard-service/target
</directory>
<outputDirectory>./16gdata/data-standard-service</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-standard-service-parent/data-standard-service/target/classes
</directory>
<outputDirectory>./16gdata/data-standard-service</outputDirectory>
<includes>
<include>bootstrap.yml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-visual-service-parent/data-visual-service/target
</directory>
<outputDirectory>./16gdata/data-visual-service</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/data-visual-service-parent/data-visual-service/target/classes
</directory>
<outputDirectory>./16gdata/data-visual-service</outputDirectory>
<includes>
<include>bootstrap.yml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/quartz-service-parent/quartz-service/target
</directory>
<outputDirectory>./16gdata/quartz-service</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/quartz-service-parent/quartz-service/target/classes
</directory>
<outputDirectory>./16gdata/quartz-service</outputDirectory>
<includes>
<include>bootstrap.yml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/workflow-service-parent/workflow-service/target
</directory>
<outputDirectory>./16gslave/workflow-service</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/workflow-service-parent/workflow-service/target/classes
</directory>
<outputDirectory>./16gslave/workflow-service</outputDirectory>
<includes>
<include>bootstrap.yml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/email-service-parent/email-service/target
</directory>
<outputDirectory>./16gdata/email-service</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/email-service-parent/email-service/target/classes
</directory>
<outputDirectory>./16gdata/email-service</outputDirectory>
<includes>
<include>bootstrap.yml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/file-service-parent/file-service/target
</directory>
<outputDirectory>./16gdata/file-service</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/modules/file-service-parent/file-service/target/classes
</directory>
<outputDirectory>./16gdata/file-service</outputDirectory>
<includes>
<include>bootstrap.yml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.parent.basedir}/ui</directory>
<outputDirectory>./16gmaster/ui</outputDirectory>
</fileSet>
</fileSets>
</assembly>

73
studio/box/pom.xml Normal file
View File

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>studio</artifactId>
<groupId>com.platform</groupId>
<version>0.4.x</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>box</artifactId>
<name>box</name>
<properties>
<mail.version>1.4.7</mail.version>
<qiniu.version>7.9.3</qiniu.version>
<alipay.version>4.22.57.ALL</alipay.version>
</properties>
<dependencies>
<!-- 同时需要common模块和logging模块只需要引入logging模块即可 -->
<dependency>
<groupId>com.platform</groupId>
<artifactId>logging</artifactId>
<version>0.4.x</version>
</dependency>
<!--Spring boot Web容器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--邮件依赖-->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>${mail.version}</version>
</dependency>
<!--七牛云存储-->
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>${qiniu.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!--支付宝依赖-->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>${alipay.version}</version>
</dependency>
<!--Spring boot Web容器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.platform</groupId>
<artifactId>common-mybatis</artifactId>
<version>0.4.x</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,34 @@
package com.platform.config;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.MultipartConfigElement;
import java.io.File;
/**
* @date 2023-01-27
* @author AllDataDC
* https://blog.csdn.net/llibin1024530411/article/details/79474953
*/
@Configuration
public class MultipartConfig {
/**
* 文件上传临时路径
*/
@Bean
MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
String location = System.getProperty("user.home") + "/.studio/file/tmp";
File tmpFile = new File(location);
if (!tmpFile.exists()) {
if (!tmpFile.mkdirs()) {
System.out.println("create was not successful.");
}
}
factory.setLocation(location);
return factory.createMultipartConfig();
}
}

View File

@@ -0,0 +1,62 @@
package com.platform.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/**
* 支付宝配置类
* @author AllDataDC
* @date 2023-01-27
*/
@Data
@Entity
@Table(name = "tool_alipay_config")
public class AlipayConfig implements Serializable {
@Id
@Column(name = "config_id")
@ApiModelProperty(value = "ID", hidden = true)
private Long id;
@NotBlank
@ApiModelProperty(value = "应用ID")
private String appId;
@NotBlank
@ApiModelProperty(value = "商户私钥")
private String privateKey;
@NotBlank
@ApiModelProperty(value = "支付宝公钥")
private String publicKey;
@ApiModelProperty(value = "签名方式")
private String signType="RSA2";
@Column(name = "gateway_url")
@ApiModelProperty(value = "支付宝开放安全地址", hidden = true)
private String gatewayUrl = "https://openapi.alipaydev.com/gateway.do";
@ApiModelProperty(value = "编码", hidden = true)
private String charset= "utf-8";
@NotBlank
@ApiModelProperty(value = "异步通知地址")
private String notifyUrl;
@NotBlank
@ApiModelProperty(value = "订单完成后返回的页面")
private String returnUrl;
@ApiModelProperty(value = "类型")
private String format="JSON";
@NotBlank
@ApiModelProperty(value = "商户号")
private String sysServiceProviderId;
}

View File

@@ -0,0 +1,44 @@
package com.platform.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/**
* 邮件配置类,数据存覆盖式存入数据存
* @author AllDataDC
* @date 2023-01-27
*/
@Entity
@Data
@Table(name = "tool_email_config")
public class EmailConfig implements Serializable {
@Id
@Column(name = "config_id")
@ApiModelProperty(value = "ID", hidden = true)
private Long id;
@NotBlank
@ApiModelProperty(value = "邮件服务器SMTP地址")
private String host;
@NotBlank
@ApiModelProperty(value = "邮件服务器 SMTP 端口")
private String port;
@NotBlank
@ApiModelProperty(value = "发件者用户名")
private String user;
@NotBlank
@ApiModelProperty(value = "密码")
private String pass;
@NotBlank
@ApiModelProperty(value = "收件人")
private String fromUser;
}

View File

@@ -0,0 +1,59 @@
package com.platform.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.platform.base.BaseEntity;
import javax.persistence.*;
import java.io.Serializable;
/**
* @author AllDataDC
* @date 2023-01-27
*/
@Getter
@Setter
@Entity
@Table(name="tool_local_storage")
@NoArgsConstructor
public class LocalStorage extends BaseEntity implements Serializable {
@Id
@Column(name = "storage_id")
@ApiModelProperty(value = "ID", hidden = true)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ApiModelProperty(value = "真实文件名")
private String realName;
@ApiModelProperty(value = "文件名")
private String name;
@ApiModelProperty(value = "后缀")
private String suffix;
@ApiModelProperty(value = "路径")
private String path;
@ApiModelProperty(value = "类型")
private String type;
@ApiModelProperty(value = "大小")
private String size;
public LocalStorage(String realName,String name, String suffix, String path, String type, String size) {
this.realName = realName;
this.name = name;
this.suffix = suffix;
this.path = path;
this.type = type;
this.size = size;
}
public void copy(LocalStorage source){
BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
}
}

View File

@@ -0,0 +1,55 @@
package com.platform.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/**
* 七牛云对象存储配置类
* @author AllDataDC
* @date 2023-01-27
*/
@Data
@Entity
@Table(name = "tool_qiniu_config")
public class QiniuConfig implements Serializable {
@Id
@Column(name = "config_id")
@ApiModelProperty(value = "ID")
private Long id;
@NotBlank
@ApiModelProperty(value = "accessKey")
private String accessKey;
@NotBlank
@ApiModelProperty(value = "secretKey")
private String secretKey;
@NotBlank
@ApiModelProperty(value = "存储空间名称作为唯一的 Bucket 识别符")
private String bucket;
/**
* Zone表示与机房的对应关系
* 华东 Zone.zone0()
* 华北 Zone.zone1()
* 华南 Zone.zone2()
* 北美 Zone.zoneNa0()
* 东南亚 Zone.zoneAs0()
*/
@NotBlank
@ApiModelProperty(value = "Zone表示与机房的对应关系")
private String zone;
@NotBlank
@ApiModelProperty(value = "外链域名,可自定义,需在七牛云绑定")
private String host;
@ApiModelProperty(value = "空间类型:公开/私有")
private String type = "公开";
}

View File

@@ -0,0 +1,50 @@
package com.platform.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.hibernate.annotations.UpdateTimestamp;
import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp;
/**
* 上传成功后,存储结果
* @author AllDataDC
* @date 2023-01-27
*/
@Data
@Entity
@Table(name = "tool_qiniu_content")
public class QiniuContent implements Serializable {
@Id
@Column(name = "content_id")
@ApiModelProperty(value = "ID", hidden = true)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
@ApiModelProperty(value = "文件名")
private String key;
@ApiModelProperty(value = "空间名")
private String bucket;
@ApiModelProperty(value = "大小")
private String size;
@ApiModelProperty(value = "文件地址")
private String url;
@ApiModelProperty(value = "文件类型")
private String suffix;
@ApiModelProperty(value = "空间类型:公开/私有")
private String type = "公开";
@UpdateTimestamp
@ApiModelProperty(value = "创建或更新时间")
@Column(name = "update_time")
private Timestamp updateTime;
}

View File

@@ -0,0 +1,30 @@
package com.platform.domain.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import java.util.List;
/**
* 发送邮件时,接收参数的类
* @author AllDataDC
* @date 2023-01-27 12:02:14
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class EmailVo {
/** 收件人,支持多个收件人 */
@NotEmpty
private List<String> tos;
@NotBlank
private String subject;
@NotBlank
private String content;
}

View File

@@ -0,0 +1,49 @@
package com.platform.domain.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.sql.Date;
import java.sql.Timestamp;
/**
* 交易详情,按需应该存入数据库,这里存入数据库,仅供临时测试
* @author AllDataDC
* @date 2023-01-27
*/
@Data
public class TradeVo {
/** (必填)商品描述 */
@NotBlank
private String body;
/** (必填)商品名称 */
@NotBlank
private String subject;
/** (必填)商户订单号,应该由后台生成 */
@ApiModelProperty(hidden = true)
private String outTradeNo;
/** (必填)第三方订单号 */
@ApiModelProperty(hidden = true)
private String tradeNo;
/** (必填)价格 */
@NotBlank
private String totalAmount;
/** 订单状态,已支付,未支付,作废 */
@ApiModelProperty(hidden = true)
private String state;
/** 创建时间,存入数据库时需要 */
@ApiModelProperty(hidden = true)
private Timestamp createTime;
/** 作废时间,存入数据库时需要 */
@ApiModelProperty(hidden = true)
private Date cancelTime;
}

View File

@@ -0,0 +1,12 @@
package com.platform.repository;
import com.platform.domain.AlipayConfig;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* @author AllDataDC
* @date 2023-01-27
*/
public interface AliPayRepository extends JpaRepository<AlipayConfig,Long> {
}

View File

@@ -0,0 +1,12 @@
package com.platform.repository;
import com.platform.domain.EmailConfig;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* @author AllDataDC
* @date 2023-01-27
*/
public interface EmailRepository extends JpaRepository<EmailConfig,Long> {
}

View File

@@ -0,0 +1,13 @@
package com.platform.repository;
import com.platform.domain.LocalStorage;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
/**
* @author AllDataDC
* @date 2023-01-27
*/
public interface LocalStorageRepository extends JpaRepository<LocalStorage, Long>, JpaSpecificationExecutor<LocalStorage> {
}

View File

@@ -0,0 +1,22 @@
package com.platform.repository;
import com.platform.domain.QiniuConfig;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
/**
* @author AllDataDC
* @date 2023-01-27
*/
public interface QiNiuConfigRepository extends JpaRepository<QiniuConfig,Long> {
/**
* 编辑类型
* @param type
*/
@Modifying
@Query(value = "update QiniuConfig set type = ?1")
void update(String type);
}

View File

@@ -0,0 +1,20 @@
package com.platform.repository;
import com.platform.domain.QiniuContent;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
/**
* @author AllDataDC
* @date 2023-01-27
*/
public interface QiniuContentRepository extends JpaRepository<QiniuContent,Long>, JpaSpecificationExecutor<QiniuContent> {
/**
* 根据key查询
* @param key 文件名
* @return QiniuContent
*/
QiniuContent findByKey(String key);
}

View File

@@ -0,0 +1,121 @@
package com.platform.rest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import com.platform.annotation.rest.AnonymousAccess;
import com.platform.annotation.Log;
import com.platform.annotation.rest.AnonymousGetMapping;
import com.platform.domain.vo.TradeVo;
import com.platform.domain.AlipayConfig;
import com.platform.utils.AliPayStatusEnum;
import com.platform.utils.AlipayUtils;
import com.platform.service.AliPayService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/**
* @author AllDataDC
* @date 2023-01-27
*/
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/aliPay")
@Api(tags = "工具:支付宝管理")
public class AliPayController {
private final AlipayUtils alipayUtils;
private final AliPayService alipayService;
@GetMapping
public ResponseEntity<AlipayConfig> queryAliConfig() {
return new ResponseEntity<>(alipayService.find(), HttpStatus.OK);
}
@Log("配置支付宝")
@ApiOperation("配置支付宝")
@PutMapping
public ResponseEntity<Object> updateAliPayConfig(@Validated @RequestBody AlipayConfig alipayConfig) {
alipayService.config(alipayConfig);
return new ResponseEntity<>(HttpStatus.OK);
}
@Log("支付宝PC网页支付")
@ApiOperation("PC网页支付")
@PostMapping(value = "/toPayAsPC")
public ResponseEntity<String> toPayAsPc(@Validated @RequestBody TradeVo trade) throws Exception {
AlipayConfig aliPay = alipayService.find();
trade.setOutTradeNo(alipayUtils.getOrderCode());
String payUrl = alipayService.toPayAsPc(aliPay, trade);
return ResponseEntity.ok(payUrl);
}
@Log("支付宝手机网页支付")
@ApiOperation("手机网页支付")
@PostMapping(value = "/toPayAsWeb")
public ResponseEntity<String> toPayAsWeb(@Validated @RequestBody TradeVo trade) throws Exception {
AlipayConfig alipay = alipayService.find();
trade.setOutTradeNo(alipayUtils.getOrderCode());
String payUrl = alipayService.toPayAsWeb(alipay, trade);
return ResponseEntity.ok(payUrl);
}
@ApiIgnore
@AnonymousGetMapping("/return")
@ApiOperation("支付之后跳转的链接")
public ResponseEntity<String> returnPage(HttpServletRequest request, HttpServletResponse response) {
AlipayConfig alipay = alipayService.find();
response.setContentType("text/html;charset=" + alipay.getCharset());
//内容验签,防止黑客篡改参数
if (alipayUtils.rsaCheck(request, alipay)) {
//商户订单号
String outTradeNo = new String(request.getParameter("out_trade_no").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
//支付宝交易号
String tradeNo = new String(request.getParameter("trade_no").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
System.out.println("商户订单号" + outTradeNo + " " + "第三方交易号" + tradeNo);
// 根据业务需要返回数据这里统一返回OK
return new ResponseEntity<>("payment successful", HttpStatus.OK);
} else {
// 根据业务需要返回数据
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}
@ApiIgnore
@RequestMapping("/notify")
@AnonymousAccess
@ApiOperation("支付异步通知(要公网访问)接收异步通知检查通知内容app_id、out_trade_no、total_amount是否与请求中的一致根据trade_status进行后续业务处理")
public ResponseEntity<Object> notify(HttpServletRequest request) {
AlipayConfig alipay = alipayService.find();
Map<String, String[]> parameterMap = request.getParameterMap();
//内容验签,防止黑客篡改参数
if (alipayUtils.rsaCheck(request, alipay)) {
//交易状态
String tradeStatus = new String(request.getParameter("trade_status").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
// 商户订单号
String outTradeNo = new String(request.getParameter("out_trade_no").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
//支付宝交易号
String tradeNo = new String(request.getParameter("trade_no").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
//付款金额
String totalAmount = new String(request.getParameter("total_amount").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
//验证
if (tradeStatus.equals(AliPayStatusEnum.SUCCESS.getValue()) || tradeStatus.equals(AliPayStatusEnum.FINISHED.getValue())) {
// 验证通过后应该根据业务需要处理订单
}
return new ResponseEntity<>(HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}

View File

@@ -0,0 +1,49 @@
package com.platform.rest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import com.platform.annotation.Log;
import com.platform.domain.vo.EmailVo;
import com.platform.domain.EmailConfig;
import com.platform.service.EmailService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* 发送邮件
* @author AllDataDC
* @date 2023-01-27 6:55:53
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("api/email")
@Api(tags = "工具:邮件管理")
public class EmailController {
private final EmailService emailService;
@GetMapping
public ResponseEntity<Object> queryEmailConfig(){
return new ResponseEntity<>(emailService.find(),HttpStatus.OK);
}
@Log("配置邮件")
@PutMapping
@ApiOperation("配置邮件")
public ResponseEntity<Object> updateEmailConfig(@Validated @RequestBody EmailConfig emailConfig) throws Exception {
emailService.config(emailConfig,emailService.find());
return new ResponseEntity<>(HttpStatus.OK);
}
@Log("发送邮件")
@PostMapping
@ApiOperation("发送邮件")
public ResponseEntity<Object> sendEmail(@Validated @RequestBody EmailVo emailVo){
emailService.send(emailVo,emailService.find());
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@@ -0,0 +1,84 @@
package com.platform.rest;
import lombok.RequiredArgsConstructor;
import com.platform.annotation.Log;
import com.platform.domain.LocalStorage;
import com.platform.exception.BadRequestException;
import com.platform.service.LocalStorageService;
import com.platform.service.dto.LocalStorageQueryCriteria;
import com.platform.utils.FileUtil;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import io.swagger.annotations.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author AllDataDC
* @date 2023-01-27
*/
@RestController
@RequiredArgsConstructor
@Api(tags = "工具:本地存储管理")
@RequestMapping("/api/localStorage")
public class LocalStorageController {
private final LocalStorageService localStorageService;
@GetMapping
@ApiOperation("查询文件")
@PreAuthorize("@el.check('storage:list')")
public ResponseEntity<Object> queryFile(LocalStorageQueryCriteria criteria, Pageable pageable){
return new ResponseEntity<>(localStorageService.queryAll(criteria,pageable),HttpStatus.OK);
}
@ApiOperation("导出数据")
@GetMapping(value = "/download")
@PreAuthorize("@el.check('storage:list')")
public void exportFile(HttpServletResponse response, LocalStorageQueryCriteria criteria) throws IOException {
localStorageService.download(localStorageService.queryAll(criteria), response);
}
@PostMapping
@ApiOperation("上传文件")
@PreAuthorize("@el.check('storage:add')")
public ResponseEntity<Object> createFile(@RequestParam String name, @RequestParam("file") MultipartFile file){
localStorageService.create(name, file);
return new ResponseEntity<>(HttpStatus.CREATED);
}
@ApiOperation("上传图片")
@PostMapping("/pictures")
public ResponseEntity<Object> uploadPicture(@RequestParam MultipartFile file){
// 判断文件是否为图片
String suffix = FileUtil.getExtensionName(file.getOriginalFilename());
if(!FileUtil.IMAGE.equals(FileUtil.getFileType(suffix))){
throw new BadRequestException("只能上传图片");
}
LocalStorage localStorage = localStorageService.create(null, file);
return new ResponseEntity<>(localStorage, HttpStatus.OK);
}
@PutMapping
@Log("修改文件")
@ApiOperation("修改文件")
@PreAuthorize("@el.check('storage:edit')")
public ResponseEntity<Object> updateFile(@Validated @RequestBody LocalStorage resources){
localStorageService.update(resources);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
@Log("删除文件")
@DeleteMapping
@ApiOperation("多选删除")
public ResponseEntity<Object> deleteFile(@RequestBody Long[] ids) {
localStorageService.deleteAll(ids);
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@@ -0,0 +1,108 @@
package com.platform.rest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import com.platform.annotation.Log;
import com.platform.domain.QiniuConfig;
import com.platform.domain.QiniuContent;
import com.platform.service.dto.QiniuQueryCriteria;
import com.platform.service.QiNiuService;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* 发送邮件
* @author AllDataDC
* @date 2023-01-27 6:55:53
*/
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/qiNiuContent")
@Api(tags = "工具:七牛云存储管理")
public class QiniuController {
private final QiNiuService qiNiuService;
@GetMapping(value = "/config")
public ResponseEntity<Object> queryQiNiuConfig(){
return new ResponseEntity<>(qiNiuService.find(), HttpStatus.OK);
}
@Log("配置七牛云存储")
@ApiOperation("配置七牛云存储")
@PutMapping(value = "/config")
public ResponseEntity<Object> updateQiNiuConfig(@Validated @RequestBody QiniuConfig qiniuConfig){
qiNiuService.config(qiniuConfig);
qiNiuService.update(qiniuConfig.getType());
return new ResponseEntity<>(HttpStatus.OK);
}
@ApiOperation("导出数据")
@GetMapping(value = "/download")
public void exportQiNiu(HttpServletResponse response, QiniuQueryCriteria criteria) throws IOException {
qiNiuService.downloadList(qiNiuService.queryAll(criteria), response);
}
@ApiOperation("查询文件")
@GetMapping
public ResponseEntity<Object> queryQiNiu(QiniuQueryCriteria criteria, Pageable pageable){
return new ResponseEntity<>(qiNiuService.queryAll(criteria,pageable),HttpStatus.OK);
}
@Log("上传文件")
@ApiOperation("上传文件")
@PostMapping
public ResponseEntity<Object> uploadQiNiu(@RequestParam MultipartFile file){
QiniuContent qiniuContent = qiNiuService.upload(file,qiNiuService.find());
Map<String,Object> map = new HashMap<>(3);
map.put("id",qiniuContent.getId());
map.put("errno",0);
map.put("data",new String[]{qiniuContent.getUrl()});
return new ResponseEntity<>(map,HttpStatus.OK);
}
@Log("同步七牛云数据")
@ApiOperation("同步七牛云数据")
@PostMapping(value = "/synchronize")
public ResponseEntity<Object> synchronizeQiNiu(){
qiNiuService.synchronize(qiNiuService.find());
return new ResponseEntity<>(HttpStatus.OK);
}
@Log("下载文件")
@ApiOperation("下载文件")
@GetMapping(value = "/download/{id}")
public ResponseEntity<Object> downloadQiNiu(@PathVariable Long id){
Map<String,Object> map = new HashMap<>(1);
map.put("url", qiNiuService.download(qiNiuService.findByContentId(id),qiNiuService.find()));
return new ResponseEntity<>(map,HttpStatus.OK);
}
@Log("删除文件")
@ApiOperation("删除文件")
@DeleteMapping(value = "/{id}")
public ResponseEntity<Object> deleteQiNiu(@PathVariable Long id){
qiNiuService.delete(qiNiuService.findByContentId(id),qiNiuService.find());
return new ResponseEntity<>(HttpStatus.OK);
}
@Log("删除多张图片")
@ApiOperation("删除多张图片")
@DeleteMapping
public ResponseEntity<Object> deleteAllQiNiu(@RequestBody Long[] ids) {
qiNiuService.deleteAll(ids, qiNiuService.find());
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@@ -0,0 +1,43 @@
package com.platform.service;
import com.platform.domain.vo.TradeVo;
import com.platform.domain.AlipayConfig;
/**
* @author AllDataDC
* @date 2023-01-27
*/
public interface AliPayService {
/**
* 查询配置
* @return AlipayConfig
*/
AlipayConfig find();
/**
* 更新配置
* @param alipayConfig 支付宝配置
* @return AlipayConfig
*/
AlipayConfig config(AlipayConfig alipayConfig);
/**
* 处理来自PC的交易请求
* @param alipay 支付宝配置
* @param trade 交易详情
* @return String
* @throws Exception 异常
*/
String toPayAsPc(AlipayConfig alipay, TradeVo trade) throws Exception;
/**
* 处理来自手机网页的交易请求
* @param alipay 支付宝配置
* @param trade 交易详情
* @return String
* @throws Exception 异常
*/
String toPayAsWeb(AlipayConfig alipay, TradeVo trade) throws Exception;
}

View File

@@ -0,0 +1,35 @@
package com.platform.service;
import com.platform.domain.vo.EmailVo;
import com.platform.domain.EmailConfig;
/**
* @author AllDataDC
* @date 2023-01-27
*/
public interface EmailService {
/**
* 更新邮件配置
* @param emailConfig 邮箱配置
* @param old /
* @return /
* @throws Exception /
*/
EmailConfig config(EmailConfig emailConfig, EmailConfig old) throws Exception;
/**
* 查询配置
* @return EmailConfig 邮件配置
*/
EmailConfig find();
/**
* 发送邮件
* @param emailVo 邮件发送的内容
* @param emailConfig 邮件配置
* @throws Exception /
*/
void send(EmailVo emailVo, EmailConfig emailConfig);
}

View File

@@ -0,0 +1,68 @@
package com.platform.service;
import com.platform.domain.LocalStorage;
import com.platform.service.dto.LocalStorageDto;
import com.platform.service.dto.LocalStorageQueryCriteria;
import org.springframework.data.domain.Pageable;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/**
* @author AllDataDC
* @date 2023-01-27
*/
public interface LocalStorageService {
/**
* 分页查询
* @param criteria 条件
* @param pageable 分页参数
* @return /
*/
Object queryAll(LocalStorageQueryCriteria criteria, Pageable pageable);
/**
* 查询全部数据
* @param criteria 条件
* @return /
*/
List<LocalStorageDto> queryAll(LocalStorageQueryCriteria criteria);
/**
* 根据ID查询
* @param id /
* @return /
*/
LocalStorageDto findById(Long id);
/**
* 上传
* @param name 文件名称
* @param file 文件
* @return
*/
LocalStorage create(String name, MultipartFile file);
/**
* 编辑
* @param resources 文件信息
*/
void update(LocalStorage resources);
/**
* 多选删除
* @param ids /
*/
void deleteAll(Long[] ids);
/**
* 导出数据
* @param localStorageDtos 待导出的数据
* @param response /
* @throws IOException /
*/
void download(List<LocalStorageDto> localStorageDtos, HttpServletResponse response) throws IOException;
}

View File

@@ -0,0 +1,104 @@
package com.platform.service;
import com.platform.domain.QiniuConfig;
import com.platform.domain.QiniuContent;
import com.platform.service.dto.QiniuQueryCriteria;
import org.springframework.data.domain.Pageable;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/**
* @author AllDataDC
* @date 2023-01-27
*/
public interface QiNiuService {
/**
* 查配置
* @return QiniuConfig
*/
QiniuConfig find();
/**
* 修改配置
* @param qiniuConfig 配置
* @return QiniuConfig
*/
QiniuConfig config(QiniuConfig qiniuConfig);
/**
* 分页查询
* @param criteria 条件
* @param pageable 分页参数
* @return /
*/
Object queryAll(QiniuQueryCriteria criteria, Pageable pageable);
/**
* 查询全部
* @param criteria 条件
* @return /
*/
List<QiniuContent> queryAll(QiniuQueryCriteria criteria);
/**
* 上传文件
* @param file 文件
* @param qiniuConfig 配置
* @return QiniuContent
*/
QiniuContent upload(MultipartFile file, QiniuConfig qiniuConfig);
/**
* 查询文件
* @param id 文件ID
* @return QiniuContent
*/
QiniuContent findByContentId(Long id);
/**
* 下载文件
* @param content 文件信息
* @param config 配置
* @return String
*/
String download(QiniuContent content, QiniuConfig config);
/**
* 删除文件
* @param content 文件
* @param config 配置
*/
void delete(QiniuContent content, QiniuConfig config);
/**
* 同步数据
* @param config 配置
*/
void synchronize(QiniuConfig config);
/**
* 删除文件
* @param ids 文件ID数组
* @param config 配置
*/
void deleteAll(Long[] ids, QiniuConfig config);
/**
* 更新数据
* @param type 类型
*/
void update(String type);
/**
* 导出数据
* @param queryAll /
* @param response /
* @throws IOException /
*/
void downloadList(List<QiniuContent> queryAll, HttpServletResponse response) throws IOException;
}

View File

@@ -0,0 +1,28 @@
package com.platform.service.dto;
import lombok.Getter;
import lombok.Setter;
import com.platform.base.BaseDTO;
import java.io.Serializable;
/**
* @author AllDataDC
* @date 2023-01-27
*/
@Getter
@Setter
public class LocalStorageDto extends BaseDTO implements Serializable {
private Long id;
private String realName;
private String name;
private String suffix;
private String type;
private String size;
}

View File

@@ -0,0 +1,22 @@
package com.platform.service.dto;
import lombok.Data;
import java.sql.Timestamp;
import java.util.List;
import com.platform.annotation.Query;
/**
* @author AllDataDC
* @date 2023-01-27
*/
@Data
public class LocalStorageQueryCriteria{
@Query(blurry = "name,suffix,type,createBy,size")
private String blurry;
@Query(type = Query.Type.BETWEEN)
private List<Timestamp> createTime;
}

View File

@@ -0,0 +1,26 @@
package com.platform.service.dto;
import lombok.Data;
import com.platform.annotation.Query;
import java.sql.Timestamp;
import java.util.List;
/**
* sm.ms图床
*
* @author AllDataDC
* @date 2023-01-27 09:52:09
*/
@Data
public class PictureQueryCriteria{
@Query(type = Query.Type.INNER_LIKE)
private String filename;
@Query(type = Query.Type.INNER_LIKE)
private String username;
@Query(type = Query.Type.BETWEEN)
private List<Timestamp> createTime;
}

View File

@@ -0,0 +1,22 @@
package com.platform.service.dto;
import lombok.Data;
import com.platform.annotation.Query;
import java.sql.Timestamp;
import java.util.List;
/**
* @author AllDataDC
* @date 2023-01-27 09:54:37
*/
@Data
public class QiniuQueryCriteria{
@Query(type = Query.Type.INNER_LIKE)
private String key;
@Query(type = Query.Type.BETWEEN)
private List<Timestamp> createTime;
}

View File

@@ -0,0 +1,105 @@
package com.platform.service.impl;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import lombok.RequiredArgsConstructor;
import com.platform.domain.vo.TradeVo;
import com.platform.domain.AlipayConfig;
import com.platform.exception.BadRequestException;
import com.platform.repository.AliPayRepository;
import com.platform.service.AliPayService;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
/**
* @author AllDataDC
* @date 2023-01-27
*/
@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = "aliPay")
public class AliPayServiceImpl implements AliPayService {
private final AliPayRepository alipayRepository;
@Override
@Cacheable(key = "'config'")
public AlipayConfig find() {
Optional<AlipayConfig> alipayConfig = alipayRepository.findById(1L);
return alipayConfig.orElseGet(AlipayConfig::new);
}
@Override
@CachePut(key = "'config'")
@Transactional(rollbackFor = Exception.class)
public AlipayConfig config(AlipayConfig alipayConfig) {
alipayConfig.setId(1L);
return alipayRepository.save(alipayConfig);
}
@Override
public String toPayAsPc(AlipayConfig alipay, TradeVo trade) throws Exception {
if(alipay.getId() == null){
throw new BadRequestException("请先添加相应配置,再操作");
}
AlipayClient alipayClient = new DefaultAlipayClient(alipay.getGatewayUrl(), alipay.getAppId(), alipay.getPrivateKey(), alipay.getFormat(), alipay.getCharset(), alipay.getPublicKey(), alipay.getSignType());
// 创建API对应的request(电脑网页版)
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
// 订单完成后返回的页面和异步通知地址
request.setReturnUrl(alipay.getReturnUrl());
request.setNotifyUrl(alipay.getNotifyUrl());
// 填充订单参数
request.setBizContent("{" +
" \"out_trade_no\":\""+trade.getOutTradeNo()+"\"," +
" \"product_code\":\"FAST_INSTANT_TRADE_PAY\"," +
" \"total_amount\":"+trade.getTotalAmount()+"," +
" \"subject\":\""+trade.getSubject()+"\"," +
" \"body\":\""+trade.getBody()+"\"," +
" \"extend_params\":{" +
" \"sys_service_provider_id\":\""+alipay.getSysServiceProviderId()+"\"" +
" }"+
" }");//填充业务参数
// 调用SDK生成表单, 通过GET方式口可以获取url
return alipayClient.pageExecute(request, "GET").getBody();
}
@Override
public String toPayAsWeb(AlipayConfig alipay, TradeVo trade) throws Exception {
if(alipay.getId() == null){
throw new BadRequestException("请先添加相应配置,再操作");
}
AlipayClient alipayClient = new DefaultAlipayClient(alipay.getGatewayUrl(), alipay.getAppId(), alipay.getPrivateKey(), alipay.getFormat(), alipay.getCharset(), alipay.getPublicKey(), alipay.getSignType());
double money = Double.parseDouble(trade.getTotalAmount());
double maxMoney = 5000;
if(money <= 0 || money >= maxMoney){
throw new BadRequestException("测试金额过大");
}
// 创建API对应的request(手机网页版)
AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
request.setReturnUrl(alipay.getReturnUrl());
request.setNotifyUrl(alipay.getNotifyUrl());
request.setBizContent("{" +
" \"out_trade_no\":\""+trade.getOutTradeNo()+"\"," +
" \"product_code\":\"FAST_INSTANT_TRADE_PAY\"," +
" \"total_amount\":"+trade.getTotalAmount()+"," +
" \"subject\":\""+trade.getSubject()+"\"," +
" \"body\":\""+trade.getBody()+"\"," +
" \"extend_params\":{" +
" \"sys_service_provider_id\":\""+alipay.getSysServiceProviderId()+"\"" +
" }"+
" }");
return alipayClient.pageExecute(request, "GET").getBody();
}
}

View File

@@ -0,0 +1,91 @@
package com.platform.service.impl;
import cn.hutool.extra.mail.Mail;
import cn.hutool.extra.mail.MailAccount;
import lombok.RequiredArgsConstructor;
import com.platform.domain.EmailConfig;
import com.platform.domain.vo.EmailVo;
import com.platform.exception.BadRequestException;
import com.platform.repository.EmailRepository;
import com.platform.service.EmailService;
import com.platform.utils.EncryptUtils;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
/**
* @author AllDataDC
* @date 2023-01-27
*/
@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = "email")
public class EmailServiceImpl implements EmailService {
private final EmailRepository emailRepository;
@Override
@CachePut(key = "'config'")
@Transactional(rollbackFor = Exception.class)
public EmailConfig config(EmailConfig emailConfig, EmailConfig old) throws Exception {
emailConfig.setId(1L);
if(!emailConfig.getPass().equals(old.getPass())){
// 对称加密
emailConfig.setPass(EncryptUtils.desEncrypt(emailConfig.getPass()));
}
return emailRepository.save(emailConfig);
}
@Override
@Cacheable(key = "'config'")
public EmailConfig find() {
Optional<EmailConfig> emailConfig = emailRepository.findById(1L);
return emailConfig.orElseGet(EmailConfig::new);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void send(EmailVo emailVo, EmailConfig emailConfig){
if(emailConfig.getId() == null){
throw new BadRequestException("请先配置,再操作");
}
// 封装
MailAccount account = new MailAccount();
// 设置用户
String user = emailConfig.getFromUser().split("@")[0];
account.setUser(user);
account.setHost(emailConfig.getHost());
account.setPort(Integer.parseInt(emailConfig.getPort()));
account.setAuth(true);
try {
// 对称解密
account.setPass(EncryptUtils.desDecrypt(emailConfig.getPass()));
} catch (Exception e) {
throw new BadRequestException(e.getMessage());
}
account.setFrom(emailConfig.getUser()+"<"+emailConfig.getFromUser()+">");
// ssl方式发送
account.setSslEnable(true);
// 使用STARTTLS安全连接
account.setStarttlsEnable(true);
String content = emailVo.getContent();
// 发送
try {
int size = emailVo.getTos().size();
Mail.create(account)
.setTos(emailVo.getTos().toArray(new String[size]))
.setTitle(emailVo.getSubject())
.setContent(content)
.setHtml(true)
//关闭session
.setUseGlobalSession(false)
.send();
}catch (Exception e){
throw new BadRequestException(e.getMessage());
}
}
}

View File

@@ -0,0 +1,119 @@
package com.platform.service.impl;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import com.platform.config.FileProperties;
import com.platform.domain.LocalStorage;
import com.platform.service.dto.LocalStorageDto;
import com.platform.service.dto.LocalStorageQueryCriteria;
import com.platform.service.mapstruct.LocalStorageMapper;
import com.platform.exception.BadRequestException;
import com.platform.utils.*;
import com.platform.repository.LocalStorageRepository;
import com.platform.service.LocalStorageService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
/**
* @author AllDataDC
* @date 2023-01-27
*/
@Service
@RequiredArgsConstructor
public class LocalStorageServiceImpl implements LocalStorageService {
private final LocalStorageRepository localStorageRepository;
private final LocalStorageMapper localStorageMapper;
private final FileProperties properties;
@Override
public Object queryAll(LocalStorageQueryCriteria criteria, Pageable pageable){
Page<LocalStorage> page = localStorageRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
return PageUtil.toPage(page.map(localStorageMapper::toDto));
}
@Override
public List<LocalStorageDto> queryAll(LocalStorageQueryCriteria criteria){
return localStorageMapper.toDto(localStorageRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
}
@Override
public LocalStorageDto findById(Long id){
LocalStorage localStorage = localStorageRepository.findById(id).orElseGet(LocalStorage::new);
ValidationUtil.isNull(localStorage.getId(),"LocalStorage","id",id);
return localStorageMapper.toDto(localStorage);
}
@Override
@Transactional(rollbackFor = Exception.class)
public LocalStorage create(String name, MultipartFile multipartFile) {
FileUtil.checkSize(properties.getMaxSize(), multipartFile.getSize());
String suffix = FileUtil.getExtensionName(multipartFile.getOriginalFilename());
String type = FileUtil.getFileType(suffix);
File file = FileUtil.upload(multipartFile, properties.getPath().getPath() + type + File.separator);
if(ObjectUtil.isNull(file)){
throw new BadRequestException("上传失败");
}
try {
name = StringUtils.isBlank(name) ? FileUtil.getFileNameNoEx(multipartFile.getOriginalFilename()) : name;
LocalStorage localStorage = new LocalStorage(
file.getName(),
name,
suffix,
file.getPath(),
type,
FileUtil.getSize(file.length())
);
return localStorageRepository.save(localStorage);
}catch (Exception e){
FileUtil.del(file);
throw e;
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void update(LocalStorage resources) {
LocalStorage localStorage = localStorageRepository.findById(resources.getId()).orElseGet(LocalStorage::new);
ValidationUtil.isNull( localStorage.getId(),"LocalStorage","id",resources.getId());
localStorage.copy(resources);
localStorageRepository.save(localStorage);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteAll(Long[] ids) {
for (Long id : ids) {
LocalStorage storage = localStorageRepository.findById(id).orElseGet(LocalStorage::new);
FileUtil.del(storage.getPath());
localStorageRepository.delete(storage);
}
}
@Override
public void download(List<LocalStorageDto> queryAll, HttpServletResponse response) throws IOException {
List<Map<String, Object>> list = new ArrayList<>();
for (LocalStorageDto localStorageDTO : queryAll) {
Map<String,Object> map = new LinkedHashMap<>();
map.put("文件名", localStorageDTO.getRealName());
map.put("备注名", localStorageDTO.getName());
map.put("文件类型", localStorageDTO.getType());
map.put("文件大小", localStorageDTO.getSize());
map.put("创建者", localStorageDTO.getCreateBy());
map.put("创建日期", localStorageDTO.getCreateTime());
list.add(map);
}
FileUtil.downloadExcel(list, response);
}
}

View File

@@ -0,0 +1,223 @@
package com.platform.service.impl;
import com.alibaba.fastjson.JSON;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.storage.model.FileInfo;
import com.qiniu.util.Auth;
import lombok.RequiredArgsConstructor;
import com.platform.domain.QiniuConfig;
import com.platform.domain.QiniuContent;
import com.platform.repository.QiniuContentRepository;
import com.platform.service.dto.QiniuQueryCriteria;
import com.platform.utils.QiNiuUtil;
import com.platform.exception.BadRequestException;
import com.platform.repository.QiNiuConfigRepository;
import com.platform.service.QiNiuService;
import com.platform.utils.FileUtil;
import com.platform.utils.PageUtil;
import com.platform.utils.QueryHelp;
import com.platform.utils.ValidationUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
/**
* @author AllDataDC
* @date 2023-01-27
*/
@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = "qiNiu")
public class QiNiuServiceImpl implements QiNiuService {
private final QiNiuConfigRepository qiNiuConfigRepository;
private final QiniuContentRepository qiniuContentRepository;
@Value("${qiniu.max-size}")
private Long maxSize;
@Override
@Cacheable(key = "'config'")
public QiniuConfig find() {
Optional<QiniuConfig> qiniuConfig = qiNiuConfigRepository.findById(1L);
return qiniuConfig.orElseGet(QiniuConfig::new);
}
@Override
@CachePut(key = "'config'")
@Transactional(rollbackFor = Exception.class)
public QiniuConfig config(QiniuConfig qiniuConfig) {
qiniuConfig.setId(1L);
String http = "http://", https = "https://";
if (!(qiniuConfig.getHost().toLowerCase().startsWith(http)||qiniuConfig.getHost().toLowerCase().startsWith(https))) {
throw new BadRequestException("外链域名必须以http://或者https://开头");
}
return qiNiuConfigRepository.save(qiniuConfig);
}
@Override
public Object queryAll(QiniuQueryCriteria criteria, Pageable pageable){
return PageUtil.toPage(qiniuContentRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable));
}
@Override
public List<QiniuContent> queryAll(QiniuQueryCriteria criteria) {
return qiniuContentRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder));
}
@Override
@Transactional(rollbackFor = Exception.class)
public QiniuContent upload(MultipartFile file, QiniuConfig qiniuConfig) {
FileUtil.checkSize(maxSize, file.getSize());
if(qiniuConfig.getId() == null){
throw new BadRequestException("请先添加相应配置,再操作");
}
// 构造一个带指定Zone对象的配置类
Configuration cfg = new Configuration(QiNiuUtil.getRegion(qiniuConfig.getZone()));
UploadManager uploadManager = new UploadManager(cfg);
Auth auth = Auth.create(qiniuConfig.getAccessKey(), qiniuConfig.getSecretKey());
String upToken = auth.uploadToken(qiniuConfig.getBucket());
try {
String key = file.getOriginalFilename();
if(qiniuContentRepository.findByKey(key) != null) {
key = QiNiuUtil.getKey(key);
}
Response response = uploadManager.put(file.getBytes(), key, upToken);
//解析上传成功的结果
DefaultPutRet putRet = JSON.parseObject(response.bodyString(), DefaultPutRet.class);
QiniuContent content = qiniuContentRepository.findByKey(FileUtil.getFileNameNoEx(putRet.key));
if(content == null){
//存入数据库
QiniuContent qiniuContent = new QiniuContent();
qiniuContent.setSuffix(FileUtil.getExtensionName(putRet.key));
qiniuContent.setBucket(qiniuConfig.getBucket());
qiniuContent.setType(qiniuConfig.getType());
qiniuContent.setKey(FileUtil.getFileNameNoEx(putRet.key));
qiniuContent.setUrl(qiniuConfig.getHost()+"/"+putRet.key);
qiniuContent.setSize(FileUtil.getSize(Integer.parseInt(file.getSize()+"")));
return qiniuContentRepository.save(qiniuContent);
}
return content;
} catch (Exception e) {
throw new BadRequestException(e.getMessage());
}
}
@Override
public QiniuContent findByContentId(Long id) {
QiniuContent qiniuContent = qiniuContentRepository.findById(id).orElseGet(QiniuContent::new);
ValidationUtil.isNull(qiniuContent.getId(),"QiniuContent", "id",id);
return qiniuContent;
}
@Override
public String download(QiniuContent content,QiniuConfig config){
String finalUrl;
String type = "公开";
if(type.equals(content.getType())){
finalUrl = content.getUrl();
} else {
Auth auth = Auth.create(config.getAccessKey(), config.getSecretKey());
// 1小时可以自定义链接过期时间
long expireInSeconds = 3600;
finalUrl = auth.privateDownloadUrl(content.getUrl(), expireInSeconds);
}
return finalUrl;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void delete(QiniuContent content, QiniuConfig config) {
//构造一个带指定Zone对象的配置类
Configuration cfg = new Configuration(QiNiuUtil.getRegion(config.getZone()));
Auth auth = Auth.create(config.getAccessKey(), config.getSecretKey());
BucketManager bucketManager = new BucketManager(auth, cfg);
try {
bucketManager.delete(content.getBucket(), content.getKey() + "." + content.getSuffix());
qiniuContentRepository.delete(content);
} catch (QiniuException ex) {
qiniuContentRepository.delete(content);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void synchronize(QiniuConfig config) {
if(config.getId() == null){
throw new BadRequestException("请先添加相应配置,再操作");
}
//构造一个带指定Zone对象的配置类
Configuration cfg = new Configuration(QiNiuUtil.getRegion(config.getZone()));
Auth auth = Auth.create(config.getAccessKey(), config.getSecretKey());
BucketManager bucketManager = new BucketManager(auth, cfg);
//文件名前缀
String prefix = "";
//每次迭代的长度限制最大1000推荐值 1000
int limit = 1000;
//指定目录分隔符,列出所有公共前缀(模拟列出目录效果)。缺省值为空字符串
String delimiter = "";
//列举空间文件列表
BucketManager.FileListIterator fileListIterator = bucketManager.createFileListIterator(config.getBucket(), prefix, limit, delimiter);
while (fileListIterator.hasNext()) {
//处理获取的file list结果
QiniuContent qiniuContent;
FileInfo[] items = fileListIterator.next();
for (FileInfo item : items) {
if(qiniuContentRepository.findByKey(FileUtil.getFileNameNoEx(item.key)) == null){
qiniuContent = new QiniuContent();
qiniuContent.setSize(FileUtil.getSize(Integer.parseInt(item.fsize+"")));
qiniuContent.setSuffix(FileUtil.getExtensionName(item.key));
qiniuContent.setKey(FileUtil.getFileNameNoEx(item.key));
qiniuContent.setType(config.getType());
qiniuContent.setBucket(config.getBucket());
qiniuContent.setUrl(config.getHost()+"/"+item.key);
qiniuContentRepository.save(qiniuContent);
}
}
}
}
@Override
public void deleteAll(Long[] ids, QiniuConfig config) {
for (Long id : ids) {
delete(findByContentId(id), config);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void update(String type) {
qiNiuConfigRepository.update(type);
}
@Override
public void downloadList(List<QiniuContent> queryAll, HttpServletResponse response) throws IOException {
List<Map<String, Object>> list = new ArrayList<>();
for (QiniuContent content : queryAll) {
Map<String,Object> map = new LinkedHashMap<>();
map.put("文件名", content.getKey());
map.put("文件类型", content.getSuffix());
map.put("空间名称", content.getBucket());
map.put("文件大小", content.getSize());
map.put("空间类型", content.getType());
map.put("创建日期", content.getUpdateTime());
list.add(map);
}
FileUtil.downloadExcel(list, response);
}
}

View File

@@ -0,0 +1,17 @@
package com.platform.service.mapstruct;
import com.platform.base.BaseMapper;
import com.platform.service.dto.LocalStorageDto;
import com.platform.domain.LocalStorage;
import org.mapstruct.Mapper;
import org.mapstruct.ReportingPolicy;
/**
* @author AllDataDC
* @date 2023-01-27
*/
@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface LocalStorageMapper extends BaseMapper<LocalStorageDto, LocalStorage> {
}

View File

@@ -0,0 +1,32 @@
package com.platform.utils;
/**
* 支付状态
* @author AllDataDC
* @date 2023-01-27
*/
public enum AliPayStatusEnum {
/** 交易成功 */
FINISHED("TRADE_FINISHED"),
/** 支付成功 */
SUCCESS("TRADE_SUCCESS"),
/** 交易创建 */
BUYER_PAY("WAIT_BUYER_PAY"),
/** 交易关闭 */
CLOSED("TRADE_CLOSED");
private final String value;
AliPayStatusEnum(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}

View File

@@ -0,0 +1,71 @@
package com.platform.utils;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.platform.domain.AlipayConfig;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* 支付宝工具类
* @author AllDataDC
* @date 2023-01-27 14:04:35
*/
@Component
public class AlipayUtils {
/**
* 生成订单号
* @return String
*/
public String getOrderCode() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
int a = (int)(Math.random() * 9000.0D) + 1000;
System.out.println(a);
Date date = new Date();
String str = sdf.format(date);
String[] split = str.split("-");
String s = split[0] + split[1] + split[2];
String[] split1 = s.split(" ");
String s1 = split1[0] + split1[1];
String[] split2 = s1.split(":");
return split2[0] + split2[1] + split2[2] + a;
}
/**
* 校验签名
* @param request HttpServletRequest
* @param alipay 阿里云配置
* @return boolean
*/
public boolean rsaCheck(HttpServletRequest request, AlipayConfig alipay){
// 获取支付宝POST过来反馈信息
Map<String,String> params = new HashMap<>(1);
Map<String, String[]> requestParams = request.getParameterMap();
for (Object o : requestParams.keySet()) {
String name = (String) o;
String[] values = requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i]
: valueStr + values[i] + ",";
}
params.put(name, valueStr);
}
try {
return AlipaySignature.rsaCheckV1(params,
alipay.getPublicKey(),
alipay.getCharset(),
alipay.getSignType());
} catch (AlipayApiException e) {
return false;
}
}
}

View File

@@ -0,0 +1,57 @@
package com.platform.utils;
import com.qiniu.storage.Region;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 七牛云存储工具类
* @author AllDataDC
* @date 2023-01-27
*/
public class QiNiuUtil {
private static final String HUAD = "华东";
private static final String HUAB = "华北";
private static final String HUAN = "华南";
private static final String BEIM = "北美";
/**
* 得到机房的对应关系
* @param zone 机房名称
* @return Region
*/
public static Region getRegion(String zone){
if(HUAD.equals(zone)){
return Region.huadong();
} else if(HUAB.equals(zone)){
return Region.huabei();
} else if(HUAN.equals(zone)){
return Region.huanan();
} else if (BEIM.equals(zone)){
return Region.beimei();
// 否则就是东南亚
} else {
return Region.qvmHuadong();
}
}
/**
* 默认不指定key的情况下以文件内容的hash值作为文件名
* @param file 文件名
* @return String
*/
public static String getKey(String file){
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
Date date = new Date();
return FileUtil.getFileNameNoEx(file) + "-" +
sdf.format(date) +
"." +
FileUtil.getExtensionName(file);
}
}

Binary file not shown.

View File

@@ -0,0 +1,115 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>common</artifactId>
<groupId>com.platform</groupId>
<version>0.4.x</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<version>0.4.x</version>
<artifactId>common-core</artifactId>
<dependencies>
<!-- SpringWeb模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<scope>provided</scope>
</dependency>
<!--io常用工具类 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons.io.version}</version>
</dependency>
<!--文件上传工具类 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons.fileupload.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>${commons.beanutils.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<!--jackson模块-->
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
</dependency>
<!-- jwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>com.platform</groupId>
<artifactId>common-service-api</artifactId>
<version>0.4.x</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.platform</groupId>
<artifactId>common-log</artifactId>
<version>0.4.x</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,5 @@
package cn.datax.common.base;
public abstract class BaseController {
}

View File

@@ -0,0 +1,15 @@
package cn.datax.common.base;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface BaseDao<T> extends BaseMapper<T> {
List<T> selectListDataScope(@Param("ew") Wrapper<T> queryWrapper, @Param("dataScope") DataScope dataScope);
IPage<T> selectPageDataScope(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper, @Param("dataScope") DataScope dataScope);
}

View File

@@ -0,0 +1,7 @@
package cn.datax.common.base;
import com.baomidou.mybatisplus.extension.service.IService;
public interface BaseService<T> extends IService<T> {
}

View File

@@ -0,0 +1,10 @@
package cn.datax.common.base;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
public abstract class BaseServiceImpl<M extends BaseDao<T>, T> extends ServiceImpl<M, T> implements BaseService<T> {
@Autowired
protected M baseDao;
}

View File

@@ -0,0 +1,25 @@
package cn.datax.common.base;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public abstract class DataFlowBaseEntity extends DataScopeBaseEntity {
private static final long serialVersionUID = 1L;
/**
* 工作流状态1待提交2已退回3审核中4通过5不通过6已撤销
*/
@TableField(value = "flow_status", fill = FieldFill.INSERT)
private String flowStatus;
/**
* 流程实例ID
*/
@TableField(value = "process_instance_id")
private String processInstanceId;
}

View File

@@ -0,0 +1,24 @@
package cn.datax.common.base;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 数据权限查询参数
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DataScope {
/**
* 表的部门字段
*/
private String deptScopeName = "create_dept";
/**
* 表的用户字段
*/
private String userScopeName = "create_by";
}

View File

@@ -0,0 +1,19 @@
package cn.datax.common.base;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public abstract class DataScopeBaseEntity extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 创建人所属部门
*/
@TableField(value = "create_dept", fill = FieldFill.INSERT)
private String createDept;
}

View File

@@ -0,0 +1,75 @@
package cn.datax.common.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.TimeZone;
@Configuration
public class JacksonConfig {
@Bean
@Primary
@ConditionalOnMissingBean(ObjectMapper.class)
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder){
builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss");
ObjectMapper objectMapper = builder.createXmlMapper(false)
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.featuresToDisable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
.timeZone(TimeZone.getTimeZone("Asia/Shanghai"))
.build();
// null数据不返回
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 反序列化时候遇到不匹配的属性并不抛出异常
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 序列化时候遇到空对象不抛出异常
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
// 反序列化的时候如果是无效子类型,不抛出异常
objectMapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false);
// 不使用默认的dateTime进行序列化,
objectMapper.configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, false);
// 数据精度问题
SimpleModule simpleModule = new SimpleModule()
.addSerializer(Long.class, ToStringSerializer.instance)
.addSerializer(Long.TYPE, ToStringSerializer.instance)
.addSerializer(BigInteger.class, ToStringSerializer.instance)
.addSerializer(BigDecimal.class, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(LocalDateTime.class,new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
javaTimeModule.addSerializer(LocalDate.class,new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
javaTimeModule.addSerializer(LocalTime.class,new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
javaTimeModule.addDeserializer(LocalDateTime.class,new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
javaTimeModule.addDeserializer(LocalDate.class,new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
javaTimeModule.addDeserializer(LocalTime.class,new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
objectMapper.registerModule(javaTimeModule).registerModule(new ParameterNamesModule());
return objectMapper;
}
}

View File

@@ -0,0 +1,24 @@
package cn.datax.common.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory){
return new RestTemplate(factory);
}
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout(5000);
factory.setConnectTimeout(5000);
return factory;
}
}

View File

@@ -0,0 +1,211 @@
package cn.datax.common.core;
public class DataConstant {
/**
* Oauth2安全相关常量
*/
public enum Security {
//请求头TOKEN名称
TOKENHEADER("gatewayToken"),
//请求头TOKEN值
TOKENVALUE("datax:gateway:123456"),
//OAUTH2请求头
AUTHORIZATION("Authorization"),
//OAUTH2令牌类型
TOKENTYPE("bearer "),
//security授权角色前缀
ROLEPREFIX("ROLE_");
Security(String val){
this.val = val;
}
private final String val;
public String getVal() {
return val;
}
}
/**
* 通用的是否
*/
public enum TrueOrFalse {
FALSE("0",false),
TRUE("1",true);
TrueOrFalse(String key, boolean val){
this.key = key;
this.val = val;
}
private final String key;
private final boolean val;
public String getKey() {
return key;
}
public boolean getVal() {
return val;
}
}
/**
* 用户认证返回额外信息
*/
public enum UserAdditionalInfo {
LICENSE("license", "datax"),
USER("user", "用户"),
USERID("user_id", "用户ID"),
USERNAME("username", "用户名"),
NICKNAME("nickname", "用户昵称"),
DEPT("user_dept", "用户部门"),
ROLE("user_role", "用户角色"),
POST("user_post", "用户岗位");
UserAdditionalInfo(String key, String val){
this.key = key;
this.val = val;
}
private final String key;
private final String val;
public String getKey() {
return key;
}
public String getVal() {
return val;
}
}
/**
* 通用的启用禁用状态
*/
public enum EnableState {
DISABLE("0","禁用"),
ENABLE("1","启用");
EnableState(String key, String val){
this.key = key;
this.val = val;
}
private final String key;
private final String val;
public String getKey() {
return key;
}
public String getVal() {
return val;
}
}
/**
* 流程审核状态
*/
public enum AuditState{
WAIT("1","待提交"),
BACK("2", "已退回"),
AUDIT("3","审核中"),
AGREE("4","通过"),
REJECT("5","不通过"),
CANCEL("6", "已撤销");
AuditState(String key, String val){
this.key = key;
this.val = val;
}
private final String key;
private final String val;
public String getKey() {
return key;
}
public String getVal() {
return val;
}
}
/**
* 菜单类型
*/
public enum MenuType{
MODULE("0","模块"),
MENU("1","菜单"),
BUTTON("2","按钮");
MenuType(String key, String val){
this.key = key;
this.val = val;
}
private final String key;
private final String val;
public String getKey() {
return key;
}
public String getVal() {
return val;
}
}
/**
* 数据范围
*/
public enum DataScope{
ALL("1","全部数据权限"),
CUSTOM("2","自定义数据权限"),
DEPT("3","本部门数据权限"),
DEPTANDCHILD("4","本部门及以下数据权限"),
SELF("5","仅本人数据权限");
DataScope(String key, String val){
this.key = key;
this.val = val;
}
private final String key;
private final String val;
public String getKey() {
return key;
}
public String getVal() {
return val;
}
}
/**
* Api状态
*/
public enum ApiState{
WAIT("1","待发布"),
RELEASE("2","已发布"),
CANCEL("3","已下线");
ApiState(String key, String val){
this.key = key;
this.val = val;
}
private final String key;
private final String val;
public String getKey() {
return key;
}
public String getVal() {
return val;
}
}
}

View File

@@ -0,0 +1,14 @@
package cn.datax.common.core;
import lombok.Data;
import java.io.Serializable;
@Data
public class DataRole implements Serializable {
private static final long serialVersionUID=1L;
private String id;
private String dataScope;
}

View File

@@ -0,0 +1,85 @@
package cn.datax.common.core;
import cn.hutool.core.util.ObjectUtil;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import java.util.Collection;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
public class DataUser extends User {
private String id;
private String nickname;
private String dept;
private List<DataRole> roles;
private List<String> posts;
public DataUser(String id, String nickname, String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
this.id = id;
this.nickname = nickname;
}
public boolean isAdmin() {
return isAdmin(this.getUsername());
}
public static boolean isAdmin(String username) {
return ObjectUtil.equal(username, "admin");
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getDept() {
return dept;
}
public void setDept(String dept) {
this.dept = dept;
}
public List<DataRole> getRoles() {
return roles;
}
public void setRoles(List<DataRole> roles) {
this.roles = roles;
}
public List<String> getPosts() {
return posts;
}
public void setPosts(List<String> posts) {
this.posts = posts;
}
@Override
public String toString() {
return "DataUser{" +
"id='" + id + '\'' +
", nickname='" + nickname + '\'' +
", dept='" + dept + '\'' +
", roles=" + roles +
", posts=" + posts +
'}';
}
}

View File

@@ -0,0 +1,26 @@
package cn.datax.common.core;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
@Data
@Accessors(chain = true)
public class JsonPage<T> implements Serializable {
private static final long serialVersionUID = 1L;
private Integer pageNum;
private Integer pageSize;
private Integer total;
private List<T> data;
public JsonPage(Long pageNum, Long pageSize, Long total, List<T> data) {
this.pageNum = pageNum.intValue();
this.pageSize = pageSize.intValue();
this.total = total.intValue();
this.data = data;
}
}

View File

@@ -0,0 +1,88 @@
package cn.datax.common.core;
import lombok.Getter;
import java.io.Serializable;
@Getter
public class R implements Serializable {
private static final long serialVersionUID = 1L;
private boolean success;
private int code;
private String msg;
private Object data;
private long timestamp;
private R() {}
public static R error() {
return error(null);
}
public static R error(String message) {
return error(null, message);
}
public static R error(Integer code, String message) {
if(code == null) {
code = 500;
}
if(message == null) {
message = "服务器内部错误";
}
return build(code, false, message);
}
public static R ok() {
return ok(null);
}
public static R ok(String message) {
return ok(null, message);
}
public static R ok(Integer code, String message) {
if(code == null) {
code = 200;
}
if(message == null) {
message = "操作成功";
}
return build(code, true, message);
}
public static R build(int code, boolean success, String message) {
return new R()
.setCode(code)
.setSuccess(success)
.setMessage(message)
.setTimestamp(System.currentTimeMillis());
}
public R setCode(int code) {
this.code = code;
return this;
}
public R setSuccess(boolean success) {
this.success = success;
return this;
}
public R setMessage(String msg) {
this.msg = msg;
return this;
}
public R setData(Object data) {
this.data = data;
return this;
}
public R setTimestamp(long timestamp) {
this.timestamp = timestamp;
return this;
}
}

View File

@@ -0,0 +1,26 @@
package cn.datax.common.core;
public interface RedisConstant {
String MARKET_API_KEY = "data:market:apis";
String MARKET_API_MASK_KEY = "data:market:api:masks";
String SYSTEM_DICT_KEY = "data:system:dicts";
String SYSTEM_CONFIG_KEY = "data:system:configs";
String METADATA_SOURCE_KEY = "data:metadata:sources";
String METADATA_TABLE_KEY = "data:metadata:tables";
String METADATA_COLUMN_KEY = "data:metadata:columns";
String METADATA_AUTHORIZE_KEY = "data:metadata:authorizes";
String STANDARD_DICT_KEY = "data:standard:dicts";
String WORKFLOW_BUSINESS_KEY = "data:workflow:business";
String VISUAL_SET_KEY = "data:visual:sets";
}

View File

@@ -0,0 +1,27 @@
package cn.datax.common.exception;
import lombok.Getter;
import org.springframework.http.HttpStatus;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
/**
* @author AllDataDC
* @date 2023-01-27
* 统一异常处理
*/
@Getter
public class BadRequestException extends RuntimeException{
private Integer status = BAD_REQUEST.value();
public BadRequestException(String msg){
super(msg);
}
public BadRequestException(HttpStatus status, String msg){
super(msg);
this.status = status.value();
}
}

View File

@@ -0,0 +1,27 @@
package cn.datax.common.exception;
public class DataException extends RuntimeException {
private static final long serialVersionUID = 1L;
public DataException() {
super();
}
public DataException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public DataException(String message, Throwable cause) {
super(message, cause);
}
public DataException(String message) {
super(message);
}
public DataException(Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,64 @@
package cn.datax.common.exception;
import cn.datax.common.core.R;
import cn.datax.common.utils.ThrowableUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理自定义异常
*/
@ExceptionHandler(DataException.class)
public R handleWithException(DataException e) {
log.error("自定义异常信息 ex={},StackTrace={}", e.getMessage(), ThrowableUtil.getStackTrace(e));
return R.error(e.getMessage());
}
/**
* 请求的 JSON 参数在请求体内的参数校验
*/
@ExceptionHandler({MethodArgumentNotValidException.class, BindException.class})
public R handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
String message = StringUtils.collectionToCommaDelimitedString(
e.getBindingResult().getFieldErrors()
.stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.toList()));
log.error("参数校验异常信息 ex={},StackTrace={}", e.getMessage(), ThrowableUtil.getStackTrace(e));
return R.error(message);
}
/**
* 请求的 URL 参数检验
*/
@ExceptionHandler(ConstraintViolationException.class)
public R handleConstraintViolationException(ConstraintViolationException e) {
String message = StringUtils.collectionToCommaDelimitedString(
e.getConstraintViolations()
.stream()
.map(ConstraintViolation::getMessage)
.collect(Collectors.toList()));
log.error("参数校验异常信息 ex={},StackTrace={}", e.getMessage(), ThrowableUtil.getStackTrace(e));
return R.error(message);
}
@ExceptionHandler(Exception.class)
public R handleException(Exception e) {
log.error("全局异常信息ex={},StackTrace={}", e.getMessage(), ThrowableUtil.getStackTrace(e));
return R.error(e.getMessage());
}
}

View File

@@ -0,0 +1,56 @@
package cn.datax.common.mapstruct;
import java.util.List;
/**
*
* Mapper文件基类
* 更多的用法需自行实现
* @param <D> 目标对象一般为DTO对象
* @param <E> 源对象,一般为需要转换的对象
* @param <V> 目标对象一般为VO对象
*/
public interface EntityMapper<D, E, V> {
/**
* 将源对象转换为DTO对象
* @param e
* @return D
*/
D toDTO(E e);
/**
* 将源对象集合转换为DTO对象集合
* @param es
* @return List<D>
*/
List<D> toDTO(List<E> es);
/**
* 将源对象转换为VO对象
* @param e
* @return D
*/
V toVO(E e);
/**
* 将源对象集合转换为VO对象集合
* @param es
* @return List<D>
*/
List<V> toVO(List<E> es);
/**
* 将目标对象转换为源对象
* @param d
* @return E
*/
E toEntity(D d);
/**
* 将目标对象集合转换为源对象集合
* @param ds
* @return List<E>
*/
List<E> toEntity(List<D> ds);
}

View File

@@ -0,0 +1,69 @@
package cn.datax.common.utils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class HttpUtil {
public static final String METHOD_POST = "POST";
public static final String METHOD_GET = "GET";
public static String getBodyString(HttpServletRequest request) {
String method = request.getMethod();
String bodyString;
if (METHOD_GET.equals(method)) {
bodyString = doGet(request);
} else if (METHOD_POST.equals(method)) {
bodyString = doPost(request);
} else {
// 其他请求方式暂不处理
return null;
}
return bodyString;
}
private static String doPost(HttpServletRequest request) {
StringBuffer sb = new StringBuffer();
InputStream inputStream;
BufferedReader bufferedReader;
try {
//将数据保存到数组中,每次读取的时候,都读取一遍
inputStream = request.getInputStream();
//将字节数组当做输出的目的地
//字节流转换为字符流(处理流)
bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
String line = "";
while ((line = bufferedReader.readLine()) != null) {
sb.append(line);
}
} catch (Exception e) {
log.error("数据读取异常", e);
}
return sb.toString();
}
private static String doGet(HttpServletRequest request) {
Map<String, Object> map = new HashMap<>();
Enumeration<String> parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()) {
String nextElement = parameterNames.nextElement();
String parameter = request.getParameter(nextElement);
map.put(nextElement, parameter);
}
try {
return new ObjectMapper().writeValueAsString(map);
} catch (JsonProcessingException e) {
}
return null;
}
}

View File

@@ -0,0 +1,63 @@
package cn.datax.common.utils;
import javax.servlet.http.HttpServletRequest;
import java.net.*;
import java.util.Enumeration;
public class IPUtil {
public static String getLocalIP() throws SocketException {
String localIP = null;
Enumeration allNetInterfaces = NetworkInterface.getNetworkInterfaces();
InetAddress ip = null;
while (allNetInterfaces.hasMoreElements()) {
NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();
Enumeration addresses = netInterface.getInetAddresses();
while (addresses.hasMoreElements()) {
ip = (InetAddress) addresses.nextElement();
if (ip != null && ip instanceof Inet4Address) {
localIP = ip.getHostAddress();
if (!"127.0.0.1".equalsIgnoreCase(localIP)) {
return localIP;
}
}
}
}
return localIP;
}
/**
* 获取当前网络ip
* @param request
* @return
*/
public static String getIpAddr(HttpServletRequest request) {
String ipAddress = request.getHeader("x-forwarded-for");
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getRemoteAddr();
if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) {
//根据网卡取本机配置的IP
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
ipAddress = inet.getHostAddress();
}
}
//对于通过多个代理的情况第一个IP为客户端真实IP,多个IP按照','分割
if (ipAddress != null && ipAddress.length() > 15) { //"***.***.***.***".length() = 15
if (ipAddress.indexOf(",") > 0) {
ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
}
}
return ipAddress;
}
}

View File

@@ -0,0 +1,130 @@
package cn.datax.common.utils;
import cn.datax.service.system.api.dto.JwtUserDto;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
@Slf4j
public class JwtUtil {
/**
* 获取凭证信息
*
* @param token jwt token串
* @return Claims
*/
public static Claims getClaimByToken(String token) {
try {
if (StringUtils.startsWithIgnoreCase(token, "Bearer ")) {
token = token.split(" ")[1];
}
return Jwts.parser()
.setSigningKey("ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI=")
.parseClaimsJws(token)
.getBody();
}catch (Exception e){
HttpServletRequest request =((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String authorization = request.getHeader("Authorization");
String url = request.getRequestURL().toString();
String uri = request.getRequestURI();
return null;
}
}
/**
* 获取过期时间
*
* @param token jwt token 串
* @return Date
*/
public Date getExpiration(String token) {
return getClaimByToken(token).getExpiration();
}
/**
* 验证token是否失效
*
* @param token token
* @return true:过期 false:没过期
*/
public boolean isExpired(String token) {
try {
final Date expiration = getExpiration(token);
return expiration.before(new Date());
} catch (Exception e) {
log.error("[JwtUtils --> isExpired]: {}", e.getMessage());
return true;
}
}
// /**
// * 检验是否为 jwt 格式的字符串
// *
// * 说明: jwt 字符串由三部分组成, 分别用 . 分隔开, 所以认为有两个 . 的字符串就是jwt形式的字符串
// * @param token jwt token串
// * @return boolean
// */
// public boolean isJwtStr(String token){
// return StringUtils.countOccurrencesOf(token, ".") == 2;
// }
/**
* 获取 jwt 中的账户名
*
* @param token jwt token 串
* @return String
*/
public String getAccountName(String token){
String subject = getClaimByToken(token).getSubject();
JwtUserDto jwtContent = JSONObject.parseObject(subject, JwtUserDto.class);
jwtContent.getUsername();
return jwtContent.getUsername();
}
/**
* 获取 jwt 的账户对象
* @param token
* @return
*/
public static String getTokenSubjectObject(String token){
Claims claimByToken = getClaimByToken(token);
String subject = claimByToken.getSubject();
String body = JSONObject.toJSONString(subject);
Object parse = JSON.parse(body);
String s = parse.toString();
return s;
}
/**
* 获取 jwt 账户信息的json字符串
* @param token
* @return
*/
public String getTokenSubjectStr(String token){
String body = JSONObject.toJSONString(getClaimByToken(token).getSubject());
Object parse = JSON.parse(body);
return parse.toString();
}
}

View File

@@ -0,0 +1,123 @@
package cn.datax.common.utils;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Base64;
public class MD5Util {
/** 向量(同时拥有向量和密匙才能解密)此向量必须是8byte多少都报错 */
private final byte[] DESIV = new byte[] { 0x22, 0x54, 0x36, 110, 0x40, (byte) 0xac, (byte) 0xad, (byte) 0xdf };
/** 自定义密钥,个数不能太短太短报错过长它默认只取前N位N的具体值大家另行查找资料 */
private final String deSkey = "cloudcloud";
/** 加密算法的参数接口 */
private AlgorithmParameterSpec iv = null;
private Key key = null;
private String charset = "UTF-8";
private static volatile MD5Util instance;
/**
* 构造函数
* @throws Exception
*/
private MD5Util() throws Exception {
// 设置密钥参数
DESKeySpec keySpec = new DESKeySpec(deSkey.getBytes(this.charset));
// 设置向量
iv = new IvParameterSpec(DESIV);
// 获得密钥工厂
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
// 得到密钥对象
key = keyFactory.generateSecret(keySpec);
}
public static MD5Util getInstance() throws Exception {
if(instance == null) {
synchronized (MD5Util.class) {
if(instance == null) {
instance = new MD5Util();
}
}
}
return instance;
}
public static void main(String[] args) {
try {
String value = "1246656415670484994";
MD5Util mt = new MD5Util();
System.out.println("加密前的字符:" + value);
System.out.println("加密后的字符:" + mt.encode(value));
System.out.println("解密后的字符:" + mt.decode(mt.encode(value)));
System.out.println("字符串的MD5值"+ getMD5Value(value));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 加密
* @param data
* @return
* @throws Exception
*/
public String encode(String data) throws Exception {
// 得到加密对象Cipher
Cipher enCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
// 设置工作模式为加密模式,给出密钥和向量
enCipher.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] pasByte = enCipher.doFinal(data.getBytes(this.charset));
return Base64.getEncoder().encodeToString(pasByte);
}
/**
* 解密
* @param data
* @return
* @throws Exception
*/
public String decode(String data) throws Exception {
Cipher deCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
deCipher.init(Cipher.DECRYPT_MODE, key, iv);
//此处注意doFinal()的参数的位数必须是8的倍数否则会报错通过encode加密的字符串读出来都是8的倍数位但写入文件再读出来就可能因为读取的方式的问题导致最后此处的doFinal()的参数的位数不是8的倍数
//此处必须用base64Decoder若用data。getBytes()则获取的字符串的byte数组的个数极可能不是8的倍数而且不与上面的BASE64Encoder对应即使解密不报错也不会得到正确结果
byte[] pasByte = deCipher.doFinal(Base64.getDecoder().decode(data));
return new String(pasByte, this.charset);
}
/**
* 获取MD5的值可用于对比校验
* @param sourceStr
* @return
*/
private static String getMD5Value(String sourceStr) {
String result = "";
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(sourceStr.getBytes());
byte b[] = md.digest();
int i;
StringBuffer buf = new StringBuffer("");
for (int offset = 0; offset < b.length; offset++) {
i = b[offset];
if (i < 0) {
i += 256;
}
if (i < 16) {
buf.append("0");
}
buf.append(Integer.toHexString(i));
}
result = buf.toString();
} catch (NoSuchAlgorithmException e) {
}
return result;
}
}

View File

@@ -0,0 +1,55 @@
package cn.datax.common.utils;
import cn.hutool.core.util.StrUtil;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 消息模板格式化
*/
public class MsgFormatUtil {
private static String REGEX = "(\\{([a-zA-Z]+)\\})";
public static String TEMPALTE_NICKNAME = "nickname";
public static String TEMPALTE_DATETIME = "datetime";
public static String TEMPALTE_BUSINESS_NAME = "businessName";
public static String TEMPALTE_BUSINESS_KEY = "businessKey";
/**
* 根据模板及参数获得内容
* @param tempalte
* @param parameters
* @return
*/
public static String getContent(String tempalte, Map<String, String> parameters) {
if (StrUtil.isBlank(tempalte)) {
tempalte = "业务名称:{businessName},发起人:{nickname},业务编号:{businessKey}";
}
Pattern p = Pattern.compile(REGEX);
Matcher m = p.matcher(tempalte);
StringBuffer stringBuffer = new StringBuffer();
while (m.find()){
String key = m.group(2);
String value = null;
if (parameters.containsKey(key)){
value = parameters.get(key);
}
value = (value == null) ? "" : value;
m.appendReplacement(stringBuffer, value);
}
m.appendTail(stringBuffer);
return stringBuffer.toString();
}
public static void main(String[] args) {
String tempalte = "{name}你好,今年{age}岁";
Map<String,String> parameters = new HashMap<>();
parameters.put("name", "chris");
parameters.put("age", "22");
System.out.println(getContent(tempalte, parameters));
}
}

View File

@@ -0,0 +1,53 @@
package cn.datax.common.utils;
import java.io.Serializable;
public class PageUtil implements Serializable {
private static final long serialVersionUID = 1L;
private static Integer DEFAULT_MAX_COUNT = 5000;
// 当前页码
private Integer pageNum = 1;
// 分页条数
private Integer pageSize = 20;
public Integer getPageNum() {
return pageNum;
}
public void setPageNum(Integer pageNum) {
this.pageNum = pageNum;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
if (this.pageSize > 0) {
this.pageSize = this.pageSize > DEFAULT_MAX_COUNT ? DEFAULT_MAX_COUNT : this.pageSize;
} else {
this.pageSize = 20;
}
}
public PageUtil(Integer pageNum, Integer pageSize) {
this.pageNum = pageNum;
this.pageSize = pageSize;
if (this.pageSize > 0) {
this.pageSize = this.pageSize > DEFAULT_MAX_COUNT ? DEFAULT_MAX_COUNT : this.pageSize;
} else {
this.pageSize = 20;
}
}
public Integer getOffset() {
pageSize = pageSize == null ? 20 : pageSize;
pageNum = pageNum == null ? 1 : pageNum;
int offset = pageNum > 0 ? (pageNum - 1) * pageSize : 0;
return offset;
}
}

View File

@@ -0,0 +1,22 @@
package cn.datax.common.utils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 获取 HttpServletRequest
*
*/
public class RequestHolder {
public static HttpServletRequest getHttpServletRequest() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
}
public static HttpServletResponse getHttpServletResponse() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
}
}

View File

@@ -0,0 +1,27 @@
package cn.datax.common.utils;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ResponseUtil {
/**
* 设置响应
*
* @param response HttpServletResponse
* @param contentType content-type
* @param status http状态码
* @param value 响应内容
* @throws IOException IOException
*/
public static void makeResponse(HttpServletResponse response, String contentType,
int status, Object value) throws IOException {
response.setContentType(contentType);
response.setStatus(status);
ObjectMapper objectMapper = new ObjectMapper();
response.getOutputStream().write(objectMapper.writeValueAsBytes(value));
}
}

View File

@@ -0,0 +1,129 @@
package cn.datax.common.utils;
import com.platform.exception.BadRequestException;
import cn.datax.service.system.api.dto.JwtUserDto;
import cn.datax.service.system.api.feign.UserServiceFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
@Component
public class SecurityUtil {
@Autowired
private UserServiceFeign userServiceFeign;
@Autowired
private JwtUtil jwtUtil;
/**
* 获取用户
*
* @return user
*/
public static JwtUserDto getDataUser() {
UserServiceFeign userServiceFeign = SpringContextHolder.getBean(UserServiceFeign.class);
return userServiceFeign.loginByUsername(getCurrentUsername());
}
public static String getCurrentUsername() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String authorization = request.getHeader("Authorization");
if (null == authorization) {
authorization = RequestContextHolder.getRequestAttributes().getAttribute("token", 1).toString();
}
String tokenSubjectObject = JwtUtil.getTokenSubjectObject(authorization);
if (tokenSubjectObject == null) {
throw new BadRequestException(HttpStatus.UNAUTHORIZED, "当前登录状态过期");
}
return tokenSubjectObject;
}
/**
* 获取用户ID
*
* @return id
*/
public static String getUserId() {
JwtUserDto user = getDataUser();
if (user != null) {
return user.getUser().getId() + "";
}
return "";
}
/**
* 获取用户部门
*
* @return id
*/
public static String getUserDeptId() {
JwtUserDto user = getDataUser();
if (user != null) {
return user.getUser().getDeptId() + "";
}
return "";
}
/**
* 获取用户名称
*
* @return username
*/
public static String getUserName() {
JwtUserDto user = getDataUser();
if (user != null) {
return user.getUsername();
}
return "";
}
/**
* 获取用户昵称
*
* @return nickname
*/
public static String getNickname() {
JwtUserDto user = getDataUser();
if (user != null) {
return user.getUser().getNickName();
}
return "";
}
/**
* 获取用户角色
*
* @return username
*/
public static List<String> getUserRoleIds() {
JwtUserDto user = getDataUser();
if (user != null) {
List<String> roles = new ArrayList<>(user.getRoles());
return roles;
}
return null;
}
/**
* 获取用户
*
* @return user
*/
public static boolean isAdmin() {
return true;
}
}

View File

@@ -0,0 +1,82 @@
package cn.datax.common.utils;
import cn.datax.common.exception.BadRequestException;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import java.util.List;
/**
* 获取当前登录的用户
* @author AllDataDC
* @date 2023-01-27
*/
@Slf4j
public class SecurityUtils {
/**
* 获取当前登录的用户
* @return UserDetails
*/
public static UserDetails getCurrentUser() {
UserDetailsService userDetailsService = SpringContextHolder.getBean(UserDetailsService.class);
return userDetailsService.loadUserByUsername(getCurrentUsername());
}
/**
* 获取系统用户名称
*
* @return 系统用户名称
*/
public static String getCurrentUsername() {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
throw new BadRequestException(HttpStatus.UNAUTHORIZED, "当前登录状态过期");
}
if (authentication.getPrincipal() instanceof UserDetails) {
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
return userDetails.getUsername();
}
throw new BadRequestException(HttpStatus.UNAUTHORIZED, "找不到当前登录的信息");
}
/**
* 获取系统用户ID
* @return 系统用户ID
*/
public static Long getCurrentUserId() {
UserDetails userDetails = getCurrentUser();
return new JSONObject(new JSONObject(userDetails).get("user")).get("id", Long.class);
}
/**
* 获取当前用户的数据权限
* @return /
*/
public static List<Long> getCurrentUserDataScope(){
UserDetails userDetails = getCurrentUser();
JSONArray array = JSONUtil.parseArray(new JSONObject(userDetails).get("dataScopes"));
return JSONUtil.toList(array,Long.class);
}
// /**
// * 获取数据权限级别
// * @return 级别
// */
// public static String getDataScopeType() {
// List<Long> dataScopes = getCurrentUserDataScope();
// if(dataScopes.size() != 0){
// return "";
// }
// return DataScopeEnum.ALL.getValue();
// }
}

View File

@@ -0,0 +1,67 @@
package cn.datax.common.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@Component
@Lazy(false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
private static ApplicationContext applicationContext = null;
private static Logger logger = LoggerFactory.getLogger(SpringContextHolder.class);
/**
* 取得存储在静态变量中的ApplicationContext.
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
return (T) applicationContext.getBean(name);
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(Class<T> requiredType) {
return applicationContext.getBean(requiredType);
}
/**
* 清除SpringContextHolder中的ApplicationContext为Null.
*/
public static void clearHolder() {
if (logger.isDebugEnabled()) {
logger.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
}
applicationContext = null;
}
/**
* 实现ApplicationContextAware接口, 注入Context到静态变量中.
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContextHolder.applicationContext = applicationContext;
}
/**
* 实现DisposableBean接口, 在Context关闭时清理静态变量.
*/
@Override
public void destroy() throws Exception {
SpringContextHolder.clearHolder();
}
}

View File

@@ -0,0 +1,26 @@
package cn.datax.common.utils;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* 异常工具
*/
public class ThrowableUtil {
/**
* 获取堆栈信息
* @param throwable
* @return
*/
public static String getStackTrace(Throwable throwable){
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
try {
throwable.printStackTrace(pw);
return sw.toString();
} finally {
pw.close();
}
}
}

View File

@@ -0,0 +1,5 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.datax.common.config.JacksonConfig,\
cn.datax.common.config.RestTemplateConfig,\
cn.datax.common.exception.GlobalExceptionHandler,\
cn.datax.common.utils.SpringContextHolder

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>common</artifactId>
<groupId>com.platform</groupId>
<version>0.4.x</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<version>0.4.x</version>
<artifactId>common-database</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>${mariadb.version}</version>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>${oracle.version}</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>${postgresql.version}</version>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>${sqlserver.version}</version>
</dependency>
<dependency>
<groupId>com.dameng</groupId>
<artifactId>DmJdbcDriver18</artifactId>
<version>${dameng.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,14 @@
package cn.datax.common.database;
import cn.datax.common.database.constants.DbQueryProperty;
public interface DataSourceFactory {
/**
* 创建数据源实例
*
* @param property
* @return
*/
DbQuery createDbQuery(DbQueryProperty property);
}

View File

@@ -0,0 +1,62 @@
package cn.datax.common.database;
import cn.datax.common.database.core.DbColumn;
import cn.datax.common.database.core.DbTable;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.jdbc.core.RowMapper;
/**
* 表数据查询接口
*
* @author AllDataDC
* @date 2022-11-14
*/
public interface DbDialect {
RowMapper<DbTable> tableMapper();
RowMapper<DbColumn> columnMapper();
/**
* 获取指定表的所有列
*
* @param dbName
* @param tableName
* @return
*/
String columns(String dbName, String tableName);
/**
* 获取数据库下的 所有表
*
* @param dbName
* @return
*/
String tables(String dbName);
/**
* 构建 分页 sql
*
* @param sql
* @param offset
* @param count
* @return
*/
String buildPaginationSql(String sql, long offset, long count);
/**
* 包装 count sql
*
* @param sql
* @return
*/
String count(String sql);
/**
* oracl 读取long 类型会流关闭是oracle的bug需要特殊处理
* @return
*/
default RowMapper<DbColumn> columnLongMapper() {
return null;
};
}

View File

@@ -0,0 +1,121 @@
package cn.datax.common.database;
import cn.datax.common.database.core.DbColumn;
import cn.datax.common.database.core.DbTable;
import cn.datax.common.database.core.PageResult;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
/**
* 表数据查询接口
*
* @author AllDataDC
* @date 2022-11-14
*/
public interface DbQuery {
/**
* 获取数据库连接
*/
Connection getConnection();
/**
* 检测连通性
*/
boolean valid();
/**
* 关闭数据源
*/
void close();
/**
* 获取指定表 具有的所有字段列表
* @param dbName
* @param tableName
* @return
*/
List<DbColumn> getTableColumns(String dbName, String tableName);
/**
* 获取指定数据库下 所有的表信息
*
* @param dbName
* @return
*/
List<DbTable> getTables(String dbName);
/**
* 获取总数
*
* @param sql
* @return
*/
int count(String sql);
/**
* 获取总数带查询参数
*
* @param sql
* @return
*/
int count(String sql, Object[] args);
/**
* 获取总数带查询参数 NamedParameterJdbcTemplate
*
* @param sql
* @return
*/
int count(String sql, Map<String, Object> params);
/**
* 查询结果列表
*
* @param sql
* @return
*/
List<Map<String, Object>> queryList(String sql);
/**
* 查询结果列表带查询参数
*
* @param sql
* @param args
* @return
*/
List<Map<String, Object>> queryList(String sql, Object[] args);
/**
* 查询结果分页
*
* @param sql
* @param offset
* @param size
* @return
*/
PageResult<Map<String, Object>> queryByPage(String sql, long offset, long size);
/**
* 查询结果分页带查询参数
* @param sql
* @param args
* @param offset
* @param size
* @return
*/
PageResult<Map<String, Object>> queryByPage(String sql, Object[] args, long offset, long size);
/**
* 查询结果分页带查询参数 NamedParameterJdbcTemplate
* @param sql
* @param params
* @param offset
* @param size
* @return
*/
PageResult<Map<String, Object>> queryByPage(String sql, Map<String, Object> params, long offset, long size);
}

View File

@@ -0,0 +1,19 @@
package cn.datax.common.database;
import cn.datax.common.database.constants.DbType;
import cn.datax.common.database.dialect.DialectRegistry;
/**
* 方言工厂类
*
* @author AllDataDC
* @date 2022-11-14
*/
public class DialectFactory {
private static final DialectRegistry DIALECT_REGISTRY = new DialectRegistry();
public static DbDialect getDialect(DbType dbType) {
return DIALECT_REGISTRY.getDialect(dbType);
}
}

View File

@@ -0,0 +1,123 @@
package cn.datax.common.database.cache;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class DefaultSqlCache extends LinkedHashMap<String, DefaultSqlCache.ExpireNode<Object>> implements SqlCache {
private int capacity;
private long expire;
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public DefaultSqlCache(int capacity, long expire) {
super((int) Math.ceil(capacity / 0.75) + 1, 0.75f, true);
// 容量
this.capacity = capacity;
// 固定过期时间
this.expire = expire;
}
@Override
public void put(String key, Object value, long ttl) {
long expireTime = Long.MAX_VALUE;
if (ttl >= 0) {
expireTime = System.currentTimeMillis() + (ttl == 0 ? this.expire : ttl);
}
lock.writeLock().lock();
try {
// 封装成过期时间节点
put(key, new ExpireNode<>(expireTime, value));
} finally {
lock.writeLock().unlock();
}
}
@Override
public Object get(String key) {
lock.readLock().lock();
ExpireNode<Object> expireNode;
try {
expireNode = super.get(key);
} finally {
lock.readLock().unlock();
}
if (expireNode == null) {
return null;
}
// 惰性删除过期的
if (this.expire > -1L && expireNode.expire < System.currentTimeMillis()) {
try {
lock.writeLock().lock();
super.remove(key);
} finally {
lock.writeLock().unlock();
}
return null;
}
return expireNode.value;
}
@Override
public void delete(String key) {
try {
lock.writeLock().lock();
Iterator<Map.Entry<String, ExpireNode<Object>>> iterator = super.entrySet().iterator();
// 清除key的缓存
while (iterator.hasNext()) {
Map.Entry<String, ExpireNode<Object>> entry = iterator.next();
if (entry.getKey().equals(key)) {
iterator.remove();
}
}
} finally {
lock.writeLock().unlock();
}
}
@Override
protected boolean removeEldestEntry(Map.Entry<String, ExpireNode<Object>> eldest) {
if (this.expire > -1L && size() > capacity) {
clean();
}
// lru淘汰
return size() > this.capacity;
}
/**
* 清理已过期的数据
*/
private void clean() {
try {
lock.writeLock().lock();
Iterator<Map.Entry<String, ExpireNode<Object>>> iterator = super.entrySet().iterator();
long now = System.currentTimeMillis();
while (iterator.hasNext()) {
Map.Entry<String, ExpireNode<Object>> next = iterator.next();
// 判断是否过期
if (next.getValue().expire < now) {
iterator.remove();
}
}
} finally {
lock.writeLock().unlock();
}
}
/**
* 过期时间节点
*/
static class ExpireNode<V> {
long expire;
Object value;
public ExpireNode(long expire, Object value) {
this.expire = expire;
this.value = value;
}
}
}

View File

@@ -0,0 +1,38 @@
package cn.datax.common.database.cache;
import cn.datax.common.database.utils.MD5Util;
import java.util.Arrays;
/**
* SQL缓存接口
*/
public interface SqlCache {
/**
* 计算key
*/
default String buildSqlCacheKey(String sql, Object[] args) {
return MD5Util.encrypt(sql + ":" + Arrays.toString(args));
}
/**
* 存入缓存
* @param key key
* @param value 值
*/
void put(String key, Object value, long ttl);
/**
* 获取缓存
* @param key key
* @return
*/
<T> T get(String key);
/**
* 删除缓存
* @param key key
*/
void delete(String key);
}

View File

@@ -0,0 +1,37 @@
package cn.datax.common.database.constants;
import cn.datax.common.database.exception.DataQueryException;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.util.StringUtils;
import java.io.Serializable;
@Data
@AllArgsConstructor
public class DbQueryProperty implements Serializable {
private static final long serialVersionUID = 1L;
private String dbType;
private String host;
private String username;
private String password;
private Integer port;
private String dbName;
private String sid;
/**
* 参数合法性校验
*/
public void viald() {
if (StringUtils.isEmpty(dbType) || StringUtils.isEmpty(host) ||
StringUtils.isEmpty(username) || StringUtils.isEmpty(password) ||
StringUtils.isEmpty(port)) {
throw new DataQueryException("参数不完整");
}
if (DbType.OTHER.getDb().equals(dbType)) {
throw new DataQueryException("不支持的数据库类型");
}
}
}

View File

@@ -0,0 +1,94 @@
package cn.datax.common.database.constants;
/**
* 数据库类型
*
* @author AllDataDC
* @date 2022-11-14
*/
public enum DbType {
/**
* MYSQL
*/
MYSQL("1", "MySql数据库", "jdbc:mysql://${host}:${port}/${dbName}?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8"),
/**
* MARIADB
*/
MARIADB("2", "MariaDB数据库", "jdbc:mariadb://${host}:${port}/${dbName}"),
/**
* ORACLE
*/
ORACLE("3", "Oracle11g及以下数据库", "jdbc:oracle:thin:@${host}:${port}:${sid}"),
/**
* oracle12c new pagination
*/
ORACLE_12C("4", "Oracle12c+数据库", "jdbc:oracle:thin:@${host}:${port}:${sid}"),
/**
* POSTGRESQL
*/
POSTGRE_SQL("5", "PostgreSql数据库", "jdbc:postgresql://${host}:${port}/${dbName}"),
/**
* SQLSERVER2005
*/
SQL_SERVER2008("6", "SQLServer2008及以下数据库", "jdbc:sqlserver://${host}:${port};DatabaseName=${dbName}"),
/**
* SQLSERVER
*/
SQL_SERVER("7", "SQLServer2012+数据库", "jdbc:sqlserver://${host}:${port};DatabaseName=${dbName}"),
/**
* DMDb
*/
DMDB("9", "DM数据库", "jdbc:dm://${host}:${port}/${dbName}"),
/**
* UNKONWN DB
*/
OTHER("8", "其他数据库", "");
/**
* 数据库名称
*/
private final String db;
/**
* 描述
*/
private final String desc;
/**
* url
*/
private final String url;
public String getDb() {
return this.db;
}
public String getDesc() {
return this.desc;
}
public String getUrl() {
return this.url;
}
DbType(String db, String desc, String url) {
this.db = db;
this.desc = desc;
this.url = url;
}
/**
* 获取数据库类型
*
* @param dbType 数据库类型字符串
*/
public static DbType getDbType(String dbType) {
for (DbType type : DbType.values()) {
if (type.db.equals(dbType)) {
return type;
}
}
return OTHER;
}
}

View File

@@ -0,0 +1,57 @@
package cn.datax.common.database.core;
import lombok.Data;
@Data
public class DbColumn {
/**
* 列名
*/
private String colName;
/**
* 数据类型
*/
private String dataType;
/**
* 数据长度
*/
private String dataLength;
/**
* 数据精度
*/
private String dataPrecision;
/**
* 数据小数位
*/
private String dataScale;
/**
* 是否主键
*/
private Boolean colKey;
/**
* 是否允许为空
*/
private Boolean nullable;
/**
* 列的序号
*/
private Integer colPosition;
/**
* 列默认值
*/
private String dataDefault;
/**
* 列注释
*/
private String colComment;
}

View File

@@ -0,0 +1,17 @@
package cn.datax.common.database.core;
import lombok.Data;
@Data
public class DbTable {
/**
* 表名
*/
private String tableName;
/**
* 表注释
*/
private String tableComment;
}

View File

@@ -0,0 +1,24 @@
package cn.datax.common.database.core;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
@Data
@Accessors(chain = true)
public class PageResult<T> implements Serializable {
private static final long serialVersionUID = 1L;
private Integer pageNum;
private Integer pageSize;
private Integer total;
private List<T> data;
public PageResult(Integer total, List<T> data) {
this.total = total;
this.data = data;
}
}

View File

@@ -0,0 +1,63 @@
package cn.datax.common.database.datasource;
import cn.datax.common.database.*;
import cn.datax.common.database.constants.DbQueryProperty;
import cn.datax.common.database.constants.DbType;
import cn.datax.common.database.exception.DataQueryException;
import cn.datax.common.database.query.AbstractDbQueryFactory;
import cn.datax.common.database.query.CacheDbQueryFactoryBean;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.StringUtils;
import javax.sql.DataSource;
public abstract class AbstractDataSourceFactory implements DataSourceFactory {
@Override
public DbQuery createDbQuery(DbQueryProperty property) {
property.viald();
DbType dbType = DbType.getDbType(property.getDbType());
DataSource dataSource = createDataSource(property);
DbQuery dbQuery = createDbQuery(dataSource, dbType);
return dbQuery;
}
public DbQuery createDbQuery(DataSource dataSource, DbType dbType) {
DbDialect dbDialect = DialectFactory.getDialect(dbType);
if(dbDialect == null){
throw new DataQueryException("该数据库类型正在开发中");
}
AbstractDbQueryFactory dbQuery = new CacheDbQueryFactoryBean();
dbQuery.setDataSource(dataSource);
dbQuery.setJdbcTemplate(new JdbcTemplate(dataSource));
dbQuery.setDbDialect(dbDialect);
return dbQuery;
}
public DataSource createDataSource(DbQueryProperty property) {
HikariDataSource dataSource = new HikariDataSource();
// if (property.getDbType().equals("9")) {
// dataSource.setDriverClassName("dm.jdbc.driver.DmDriver");
// }
dataSource.setJdbcUrl(trainToJdbcUrl(property));
dataSource.setUsername(property.getUsername());
dataSource.setPassword(property.getPassword());
return dataSource;
}
protected String trainToJdbcUrl(DbQueryProperty property) {
String url = DbType.getDbType(property.getDbType()).getUrl();
if (StringUtils.isEmpty(url)) {
throw new DataQueryException("无效数据库类型!");
}
url = url.replace("${host}", property.getHost());
url = url.replace("${port}", String.valueOf(property.getPort()));
if (DbType.ORACLE.getDb().equals(property.getDbType()) || DbType.ORACLE_12C.getDb().equals(property.getDbType())) {
url = url.replace("${sid}", property.getSid());
} else {
url = url.replace("${dbName}", property.getDbName());
}
return url;
}
}

View File

@@ -0,0 +1,64 @@
package cn.datax.common.database.datasource;
import cn.datax.common.database.constants.DbQueryProperty;
import javax.sql.DataSource;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class CacheDataSourceFactoryBean extends AbstractDataSourceFactory {
/**
* 数据源缓存
*/
private static Map<String, DataSource> dataSourceMap = new ConcurrentHashMap<>();
@Override
public DataSource createDataSource(DbQueryProperty property) {
String key = property.getDbType() + ":" + property.getHost()
+ ":" + property.getPort() + ":" + property.getUsername()
+ ":" + property.getPassword() + ":" + property.getDbName()
+ ":" + property.getSid();
String s = compress(key);
DataSource dataSource = dataSourceMap.get(s);
if (null == dataSource) {
synchronized (CacheDataSourceFactoryBean.class) {
dataSource = super.createDataSource(property);
dataSourceMap.put(s, dataSource);
}
}
return dataSource;
}
// 压缩
public static String compress(String str) {
if (str == null || str.length() == 0) {
return str;
}
MessageDigest md = null;
try {
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
md.update(str.getBytes());
byte b[] = md.digest();
int i;
StringBuffer buf = new StringBuffer();
for (int offset = 0; offset < b.length; offset++) {
i = b[offset];
if (i < 0)
i += 256;
if (i < 16)
buf.append("0");
buf.append(Integer.toHexString(i));
}
// System.out.println("MD5(" + str + ",32小写) = " + buf.toString());
// System.out.println("MD5(" + str + ",32大写) = " + buf.toString().toUpperCase());
// System.out.println("MD5(" + str + ",16小写) = " + buf.toString().substring(8, 24));
// System.out.println("MD5(" + str + ",16大写) = " + buf.toString().substring(8, 24).toUpperCase());
return buf.toString().substring(8, 24).toUpperCase();
}
}

View File

@@ -0,0 +1,4 @@
package cn.datax.common.database.datasource;
public class DefaultDataSourceFactoryBean extends AbstractDataSourceFactory {
}

View File

@@ -0,0 +1,37 @@
package cn.datax.common.database.dialect;
import cn.datax.common.database.DbDialect;
/**
* 方言抽象类
*
* @author AllDataDC
* @date 2022-11-14
*/
public abstract class AbstractDbDialect implements DbDialect {
@Override
public String columns(String dbName, String tableName) {
return "select column_name AS COLNAME, ordinal_position AS COLPOSITION, column_default AS DATADEFAULT, is_nullable AS NULLABLE, data_type AS DATATYPE, " +
"character_maximum_length AS DATALENGTH, numeric_precision AS DATAPRECISION, numeric_scale AS DATASCALE, column_key AS COLKEY, column_comment AS COLCOMMENT " +
"from information_schema.columns where table_schema = '" + dbName + "' and table_name = '" + tableName + "' order by ordinal_position ";
}
@Override
public String tables(String dbName) {
return "SELECT table_name AS TABLENAME, table_comment AS TABLECOMMENT FROM information_schema.tables where table_schema = '" + dbName + "' ";
}
@Override
public String buildPaginationSql(String originalSql, long offset, long count) {
// 获取 分页实际条数
StringBuilder sqlBuilder = new StringBuilder(originalSql);
sqlBuilder.append(" LIMIT ").append(offset).append(" , ").append(count);
return sqlBuilder.toString();
}
@Override
public String count(String sql) {
return "SELECT COUNT(*) FROM ( " + sql + " ) TEMP";
}
}

View File

@@ -0,0 +1,28 @@
package cn.datax.common.database.dialect;
import cn.datax.common.database.DbDialect;
import cn.datax.common.database.constants.DbType;
import java.util.EnumMap;
import java.util.Map;
public class DialectRegistry {
private final Map<DbType, DbDialect> dialect_enum_map = new EnumMap<>(DbType.class);
public DialectRegistry() {
dialect_enum_map.put(DbType.MARIADB, new MariaDBDialect());
dialect_enum_map.put(DbType.MYSQL, new MySqlDialect());
dialect_enum_map.put(DbType.ORACLE_12C, new Oracle12cDialect());
dialect_enum_map.put(DbType.ORACLE, new OracleDialect());
dialect_enum_map.put(DbType.POSTGRE_SQL, new PostgreDialect());
dialect_enum_map.put(DbType.SQL_SERVER2008, new SQLServer2008Dialect());
dialect_enum_map.put(DbType.SQL_SERVER, new SQLServerDialect());
dialect_enum_map.put(DbType.DMDB, new DmDBDialect());
dialect_enum_map.put(DbType.OTHER, new UnknownDialect());
}
public DbDialect getDialect(DbType dbType) {
return dialect_enum_map.get(dbType);
}
}

View File

@@ -0,0 +1,61 @@
package cn.datax.common.database.dialect;
import cn.datax.common.database.core.DbColumn;
import cn.datax.common.database.core.DbTable;
import cn.datax.common.database.exception.DataQueryException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.util.StringUtils;
import java.sql.ResultSet;
public class DmDBDialect extends AbstractDbDialect {
@Override
public String columns(String dbName, String tableName) {
return "select columns.column_name AS colName, columns.data_type AS DATATYPE, columns.data_length AS DATALENGTH, columns.data_precision AS DATAPRECISION, " +
"columns.data_scale AS DATASCALE, columns.nullable AS NULLABLE, columns.column_id AS COLPOSITION, columns.data_default AS DATADEFAULT, comments.comments AS COLCOMMENT," +
"case when t.column_name is null then 0 else 1 end as COLKEY " +
"from sys.user_tab_columns columns LEFT JOIN sys.user_col_comments comments ON columns.table_name = comments.table_name AND columns.column_name = comments.column_name " +
"left join ( " +
"select col.column_name as column_name, con.table_name as table_name from user_constraints con, user_cons_columns col " +
"where con.constraint_name = col.constraint_name and con.constraint_type = 'P' " +
") t on t.table_name = columns.table_name and columns.column_name = t.column_name " +
"where columns.table_name = UPPER('" + tableName + "') order by columns.column_id ";
}
@Override
public String tables(String dbName) {
return "select a.table_name as TABLENAME,b.comments AS TABLECOMMENT from dba_tables a join user_tab_comments b " +
"on a.table_name = b.table_name where a.owner='" + dbName + "'";
}
@Override
public RowMapper<DbColumn> columnMapper() {
return (ResultSet rs, int rowNum) -> {
DbColumn entity = new DbColumn();
entity.setColName(rs.getString("COLNAME"));
entity.setDataType(rs.getString("DATATYPE"));
entity.setDataLength(rs.getString("DATALENGTH"));
entity.setDataPrecision(rs.getString("DATAPRECISION"));
entity.setDataScale(rs.getString("DATASCALE"));
entity.setColKey("1".equals(rs.getString("COLKEY")) ? true : false);
entity.setNullable("1".equals(rs.getString("NULLABLE")) ? true : false);
entity.setColPosition(rs.getInt("COLPOSITION"));
entity.setDataDefault(rs.getString("DATADEFAULT"));
entity.setColComment(rs.getString("COLCOMMENT"));
return entity;
};
}
@Override
public RowMapper<DbTable> tableMapper() {
return (ResultSet rs, int rowNum) -> {
DbTable entity = new DbTable();
entity.setTableName(rs.getString("TABLENAME"));
entity.setTableComment(rs.getString("TABLECOMMENT"));
return entity;
};
}
}

View File

@@ -0,0 +1,10 @@
package cn.datax.common.database.dialect;
/**
* MariaDB 数据库方言
*
* @author AllDataDC
* @date 2022-11-14
*/
public class MariaDBDialect extends MySqlDialect {
}

View File

@@ -0,0 +1,44 @@
package cn.datax.common.database.dialect;
import cn.datax.common.database.core.DbColumn;
import cn.datax.common.database.core.DbTable;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
/**
* MySql 数据库方言
*
* @author AllDataDC
* @date 2022-11-14
*/
public class MySqlDialect extends AbstractDbDialect {
@Override
public RowMapper<DbColumn> columnMapper() {
return (ResultSet rs, int rowNum) -> {
DbColumn entity = new DbColumn();
entity.setColName(rs.getString("COLNAME"));
entity.setDataType(rs.getString("DATATYPE"));
entity.setDataLength(rs.getString("DATALENGTH"));
entity.setDataPrecision(rs.getString("DATAPRECISION"));
entity.setDataScale(rs.getString("DATASCALE"));
entity.setColKey("PRI".equals(rs.getString("COLKEY")));
entity.setNullable("YES".equals(rs.getString("NULLABLE")));
entity.setColPosition(rs.getInt("COLPOSITION"));
entity.setDataDefault(rs.getString("DATADEFAULT"));
entity.setColComment(rs.getString("COLCOMMENT"));
return entity;
};
}
@Override
public RowMapper<DbTable> tableMapper() {
return (ResultSet rs, int rowNum) -> {
DbTable entity = new DbTable();
entity.setTableName(rs.getString("TABLENAME"));
entity.setTableComment(rs.getString("TABLECOMMENT"));
return entity;
};
}
}

View File

@@ -0,0 +1,17 @@
package cn.datax.common.database.dialect;
/**
* ORACLE Oracle12c+数据库方言
*
* @author AllDataDC
* @date 2022-11-14
*/
public class Oracle12cDialect extends OracleDialect {
@Override
public String buildPaginationSql(String originalSql, long offset, long count) {
StringBuilder sqlBuilder = new StringBuilder(originalSql);
sqlBuilder.append(" OFFSET ").append(offset).append(" ROWS FETCH NEXT ").append(count).append(" ROWS ONLY ");
return sqlBuilder.toString();
}
}

View File

@@ -0,0 +1,85 @@
package cn.datax.common.database.dialect;
import cn.datax.common.database.core.DbColumn;
import cn.datax.common.database.core.DbTable;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;
/**
* Oracle Oracle11g及以下数据库方言
*
* @author AllDataDC
* @date 2022-11-14
*/
public class OracleDialect extends AbstractDbDialect {
@Override
public String columns(String dbName, String tableName) {
return "select columns.column_name AS colName, columns.data_type AS DATATYPE, columns.data_length AS DATALENGTH, columns.data_precision AS DATAPRECISION, " +
"columns.data_scale AS DATASCALE, columns.nullable AS NULLABLE, columns.column_id AS COLPOSITION, columns.data_default AS DATADEFAULT, comments.comments AS COLCOMMENT," +
"case when t.column_name is null then 0 else 1 end as COLKEY " +
"from sys.user_tab_columns columns LEFT JOIN sys.user_col_comments comments ON columns.table_name = comments.table_name AND columns.column_name = comments.column_name " +
"left join ( " +
"select col.column_name as column_name, con.table_name as table_name from user_constraints con, user_cons_columns col " +
"where con.constraint_name = col.constraint_name and con.constraint_type = 'P' " +
") t on t.table_name = columns.table_name and columns.column_name = t.column_name " +
"where columns.table_name = UPPER('" + tableName + "') order by columns.column_id ";
}
@Override
public String tables(String dbName) {
return "select tables.table_name AS TABLENAME, comments.comments AS TABLECOMMENT from sys.user_tables tables " +
"LEFT JOIN sys.user_tab_comments comments ON tables.table_name = comments.table_name ";
}
@Override
public String buildPaginationSql(String originalSql, long offset, long count) {
StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.append("SELECT * FROM ( SELECT TMP.*, ROWNUM ROW_ID FROM ( ");
sqlBuilder.append(originalSql).append(" ) TMP WHERE ROWNUM <=").append((offset >= 1) ? (offset + count) : count);
sqlBuilder.append(") WHERE ROW_ID > ").append(offset);
return sqlBuilder.toString();
}
@Override
public RowMapper<DbColumn> columnLongMapper() {
return (ResultSet rs, int rowNum) -> {
DbColumn entity = new DbColumn();
entity.setDataDefault(rs.getString("DATADEFAULT"));
return entity;
};
}
@Override
public RowMapper<DbColumn> columnMapper() {
return (ResultSet rs, int rowNum) -> {
DbColumn entity = new DbColumn();
entity.setColName(rs.getString("COLNAME"));
entity.setDataType(rs.getString("DATATYPE"));
entity.setDataLength(rs.getString("DATALENGTH"));
entity.setDataPrecision(rs.getString("DATAPRECISION"));
entity.setDataScale(rs.getString("DATASCALE"));
entity.setColKey("1".equals(rs.getString("COLKEY")));
entity.setNullable("Y".equals(rs.getString("NULLABLE")));
//long类型单独处理
//entity.setDataDefault(rs.getString("DATADEFAULT"));
entity.setColPosition(rs.getInt("COLPOSITION"));
entity.setColComment(rs.getString("COLCOMMENT"));
return entity;
};
}
@Override
public RowMapper<DbTable> tableMapper() {
return (ResultSet rs, int rowNum) -> {
DbTable entity = new DbTable();
entity.setTableName(rs.getString("TABLENAME"));
entity.setTableComment(rs.getString("TABLECOMMENT"));
return entity;
};
}
}

View File

@@ -0,0 +1,71 @@
package cn.datax.common.database.dialect;
import cn.datax.common.database.core.DbColumn;
import cn.datax.common.database.core.DbTable;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
/**
* Postgre 数据库方言
*
* @author AllDataDC
* @date 2022-11-14
*/
public class PostgreDialect extends AbstractDbDialect {
@Override
public String columns(String dbName, String tableName) {
return "select col.column_name AS COLNAME, col.ordinal_position AS COLPOSITION, col.column_default AS DATADEFAULT, col.is_nullable AS NULLABLE, col.udt_name AS DATATYPE, " +
"col.character_maximum_length AS DATALENGTH, col.numeric_precision AS DATAPRECISION, col.numeric_scale AS DATASCALE, des.description AS COLCOMMENT, " +
"case when t.colname is null then 0 else 1 end as COLKEY " +
"from information_schema.columns col left join pg_description des on col.table_name::regclass = des.objoid and col.ordinal_position = des.objsubid " +
"left join ( " +
"select pg_attribute.attname as colname from pg_constraint inner join pg_class on pg_constraint.conrelid = pg_class.oid " +
"inner join pg_attribute on pg_attribute.attrelid = pg_class.oid and pg_attribute.attnum = any(pg_constraint.conkey) " +
"where pg_class.relname = '" + tableName + "' and pg_constraint.contype = 'p' " +
") t on t.colname = col.column_name " +
"where col.table_catalog = '" + dbName + "' and col.table_schema = 'public' and col.table_name = '" + tableName + "' order by col.ordinal_position ";
}
@Override
public String tables(String dbName) {
return "select relname AS TABLENAME, cast(obj_description(relfilenode, 'pg_class') as varchar) AS TABLECOMMENT from pg_class " +
"where relname in (select tablename from pg_tables where schemaname = 'public' and tableowner = '" + dbName + "' and position('_2' in tablename) = 0) ";
}
@Override
public String buildPaginationSql(String originalSql, long offset, long count) {
StringBuilder sqlBuilder = new StringBuilder(originalSql);
sqlBuilder.append(" LIMIT ").append(count).append(" offset ").append(offset);
return sqlBuilder.toString();
}
@Override
public RowMapper<DbColumn> columnMapper() {
return (ResultSet rs, int rowNum) -> {
DbColumn entity = new DbColumn();
entity.setColName(rs.getString("COLNAME"));
entity.setDataType(rs.getString("DATATYPE"));
entity.setDataLength(rs.getString("DATALENGTH"));
entity.setDataPrecision(rs.getString("DATAPRECISION"));
entity.setDataScale(rs.getString("DATASCALE"));
entity.setColKey("1".equals(rs.getString("COLKEY")) ? true : false);
entity.setNullable("YES".equals(rs.getString("NULLABLE")) ? true : false);
entity.setColPosition(rs.getInt("COLPOSITION"));
entity.setDataDefault(rs.getString("DATADEFAULT"));
entity.setColComment(rs.getString("COLCOMMENT"));
return entity;
};
}
@Override
public RowMapper<DbTable> tableMapper() {
return (ResultSet rs, int rowNum) -> {
DbTable entity = new DbTable();
entity.setTableName(rs.getString("TABLENAME"));
entity.setTableComment(rs.getString("TABLECOMMENT"));
return entity;
};
}
}

View File

@@ -0,0 +1,106 @@
package cn.datax.common.database.dialect;
import cn.datax.common.database.core.DbColumn;
import cn.datax.common.database.core.DbTable;
import cn.datax.common.database.exception.DataQueryException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.util.StringUtils;
import java.sql.ResultSet;
/**
* SQLServer 2005 数据库方言
*
* @author AllDataDC
* @date 2022-11-14
*/
public class SQLServer2008Dialect extends AbstractDbDialect {
@Override
public String columns(String dbName, String tableName) {
return "select columns.name AS colName, columns.column_id AS COLPOSITION, columns.max_length AS DATALENGTH, columns.precision AS DATAPRECISION, columns.scale AS DATASCALE, " +
"columns.is_nullable AS NULLABLE, types.name AS DATATYPE, CAST(ep.value AS NVARCHAR(128)) AS COLCOMMENT, e.text AS DATADEFAULT, " +
"(select top 1 ind.is_primary_key from sys.index_columns ic left join sys.indexes ind on ic.object_id = ind.object_id and ic.index_id = ind.index_id and ind.name like 'PK_%' where ic.object_id=columns.object_id and ic.column_id=columns.column_id) AS COLKEY " +
"from sys.columns columns LEFT JOIN sys.types types ON columns.system_type_id = types.system_type_id " +
"LEFT JOIN syscomments e ON columns.default_object_id= e.id " +
"LEFT JOIN sys.extended_properties ep ON ep.major_id = columns.object_id AND ep.minor_id = columns.column_id AND ep.name = 'MS_Description' " +
"where columns.object_id = object_id('" + tableName + "') order by columns.column_id ";
}
@Override
public String tables(String dbName) {
return "select tables.name AS TABLENAME, CAST(ep.value AS NVARCHAR(128)) AS TABLECOMMENT " +
"from sys.tables tables LEFT JOIN sys.extended_properties ep ON ep.major_id = tables.object_id AND ep.minor_id = 0";
}
private static String getOrderByPart(String sql) {
String loweredString = sql.toLowerCase();
int orderByIndex = loweredString.indexOf("order by");
if (orderByIndex != -1) {
return sql.substring(orderByIndex);
} else {
return "";
}
}
@Override
public String buildPaginationSql(String originalSql, long offset, long count) {
StringBuilder pagingBuilder = new StringBuilder();
String orderby = getOrderByPart(originalSql);
String distinctStr = "";
String loweredString = originalSql.toLowerCase();
String sqlPartString = originalSql;
if (loweredString.trim().startsWith("select")) {
int index = 6;
if (loweredString.startsWith("select distinct")) {
distinctStr = "DISTINCT ";
index = 15;
}
sqlPartString = sqlPartString.substring(index);
}
pagingBuilder.append(sqlPartString);
// if no ORDER BY is specified use fake ORDER BY field to avoid errors
if (StringUtils.isEmpty(orderby)) {
orderby = "ORDER BY CURRENT_TIMESTAMP";
}
StringBuilder sql = new StringBuilder();
sql.append("WITH selectTemp AS (SELECT ").append(distinctStr).append("TOP 100 PERCENT ")
.append(" ROW_NUMBER() OVER (").append(orderby).append(") as __row_number__, ").append(pagingBuilder)
.append(") SELECT * FROM selectTemp WHERE __row_number__ BETWEEN ")
//FIX#299原因mysql中limit 10(offset,size) 是从第10开始不包含10,而这里用的BETWEEN是两边都包含所以改为offset+1
.append(offset + 1)
.append(" AND ")
.append(offset + count).append(" ORDER BY __row_number__");
return sql.toString();
}
@Override
public RowMapper<DbColumn> columnMapper() {
return (ResultSet rs, int rowNum) -> {
DbColumn entity = new DbColumn();
entity.setColName(rs.getString("COLNAME"));
entity.setDataType(rs.getString("DATATYPE"));
entity.setDataLength(rs.getString("DATALENGTH"));
entity.setDataPrecision(rs.getString("DATAPRECISION"));
entity.setDataScale(rs.getString("DATASCALE"));
entity.setColKey("1".equals(rs.getString("COLKEY")) ? true : false);
entity.setNullable("1".equals(rs.getString("NULLABLE")) ? true : false);
entity.setColPosition(rs.getInt("COLPOSITION"));
entity.setDataDefault(rs.getString("DATADEFAULT"));
entity.setColComment(rs.getString("COLCOMMENT"));
return entity;
};
}
@Override
public RowMapper<DbTable> tableMapper() {
return (ResultSet rs, int rowNum) -> {
DbTable entity = new DbTable();
entity.setTableName(rs.getString("TABLENAME"));
entity.setTableComment(rs.getString("TABLECOMMENT"));
return entity;
};
}
}

View File

@@ -0,0 +1,17 @@
package cn.datax.common.database.dialect;
/**
* SQLServer 数据库方言
*
* @author AllDataDC
* @date 2022-11-14
*/
public class SQLServerDialect extends SQLServer2008Dialect {
@Override
public String buildPaginationSql(String originalSql, long offset, long count) {
StringBuilder sqlBuilder = new StringBuilder(originalSql);
sqlBuilder.append(" OFFSET ").append(offset).append(" ROWS FETCH NEXT ").append(count).append(" ROWS ONLY ");
return sqlBuilder.toString();
}
}

View File

@@ -0,0 +1,45 @@
package cn.datax.common.database.dialect;
import cn.datax.common.database.core.DbColumn;
import cn.datax.common.database.core.DbTable;
import cn.datax.common.database.exception.DataQueryException;
import org.springframework.jdbc.core.RowMapper;
/**
* 未知 数据库方言
*
* @author AllDataDC
* @date 2022-11-14
*/
public class UnknownDialect extends AbstractDbDialect {
@Override
public String columns(String dbName, String tableName) {
throw new DataQueryException("不支持的数据库类型");
}
@Override
public String tables(String dbName) {
throw new DataQueryException("不支持的数据库类型");
}
@Override
public String buildPaginationSql(String sql, long offset, long count) {
throw new DataQueryException("不支持的数据库类型");
}
@Override
public String count(String sql) {
throw new DataQueryException("不支持的数据库类型");
}
@Override
public RowMapper<DbColumn> columnMapper() {
throw new DataQueryException("不支持的数据库类型");
}
@Override
public RowMapper<DbTable> tableMapper() {
throw new DataQueryException("不支持的数据库类型");
}
}

View File

@@ -0,0 +1,8 @@
package cn.datax.common.database.exception;
public class DataQueryException extends RuntimeException {
public DataQueryException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,150 @@
package cn.datax.common.database.query;
import cn.datax.common.database.DbDialect;
import cn.datax.common.database.DbQuery;
import cn.datax.common.database.core.DbColumn;
import cn.datax.common.database.core.DbTable;
import cn.datax.common.database.core.PageResult;
import cn.datax.common.database.dialect.OracleDialect;
import cn.datax.common.database.dialect.PostgreDialect;
import cn.datax.common.database.dialect.DmDBDialect;
import cn.datax.common.database.exception.DataQueryException;
import com.zaxxer.hikari.HikariDataSource;
import lombok.Setter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
@Setter
public abstract class AbstractDbQueryFactory implements DbQuery {
protected DataSource dataSource;
protected JdbcTemplate jdbcTemplate;
protected DbDialect dbDialect;
@Override
public Connection getConnection() {
try {
return dataSource.getConnection();
} catch (SQLException e) {
throw new DataQueryException("获取数据库连接出错");
}
}
@Override
public boolean valid() {
Connection conn = null;
try {
conn = dataSource.getConnection();
return conn.isValid(0);
} catch (SQLException e) {
throw new DataQueryException("检测连通性出错:"+e.getMessage());
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
throw new DataQueryException("关闭数据库连接出错");
}
}
}
}
@Override
public void close() {
if (dataSource instanceof HikariDataSource) {
((HikariDataSource) dataSource).close();
} else {
throw new DataQueryException("不合法数据源类型");
}
}
@Override
public List<DbColumn> getTableColumns(String dbName, String tableName) {
String sql = dbDialect.columns(dbName, tableName);
if (dbDialect instanceof OracleDialect) {
List<DbColumn> longColumns = jdbcTemplate.query(sql, dbDialect.columnLongMapper());
List<DbColumn> queryColumns = jdbcTemplate.query(sql, dbDialect.columnMapper());
for (int i = 0; i < longColumns.size(); i++) {
DbColumn longColumn = longColumns.get(i);
DbColumn otherColumn = queryColumns.get(i);
otherColumn.setDataDefault(longColumn.getDataDefault());
}
return queryColumns;
}
return jdbcTemplate.query(sql, dbDialect.columnMapper());
}
@Override
public List<DbTable> getTables(String dbName) {
String sql = null;
if (dbDialect instanceof PostgreDialect) {
//如果数据源为PostgreSql,同步元数据时默认owner为登录账号userName故不能传递dbName需传递userName
HikariDataSource hikariDataSource = (HikariDataSource) dataSource;
String username = hikariDataSource.getUsername();
sql = dbDialect.tables(username);
} else {
sql = dbDialect.tables(dbName);
}
return jdbcTemplate.query(sql, dbDialect.tableMapper());
}
@Override
public int count(String sql) {
return jdbcTemplate.queryForObject(dbDialect.count(sql), Integer.class);
}
@Override
public int count(String sql, Object[] args) {
return jdbcTemplate.queryForObject(dbDialect.count(sql), args, Integer.class);
}
@Override
public int count(String sql, Map<String, Object> params) {
NamedParameterJdbcTemplate namedJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate);
return namedJdbcTemplate.queryForObject(dbDialect.count(sql), params, Integer.class);
}
@Override
public List<Map<String, Object>> queryList(String sql) {
return jdbcTemplate.queryForList(sql);
}
@Override
public List<Map<String, Object>> queryList(String sql, Object[] args) {
return jdbcTemplate.queryForList(sql, args);
}
@Override
public PageResult<Map<String, Object>> queryByPage(String sql, long offset, long size) {
int total = count(sql);
String pageSql = dbDialect.buildPaginationSql(sql, offset, size);
List<Map<String, Object>> records = jdbcTemplate.queryForList(pageSql);
return new PageResult<>(total, records);
}
@Override
public PageResult<Map<String, Object>> queryByPage(String sql, Object[] args, long offset, long size) {
int total = count(sql, args);
String pageSql = dbDialect.buildPaginationSql(sql, offset, size);
List<Map<String, Object>> records = jdbcTemplate.queryForList(pageSql, args);
return new PageResult<>(total, records);
}
@Override
public PageResult<Map<String, Object>> queryByPage(String sql, Map<String, Object> params, long offset, long size) {
int total = count(sql, params);
String pageSql = dbDialect.buildPaginationSql(sql, offset, size);
NamedParameterJdbcTemplate namedJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate);
List<Map<String, Object>> records = namedJdbcTemplate.queryForList(pageSql, params);
return new PageResult<>(total, records);
}
}

Some files were not shown because too many files have changed in this diff Show More