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

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);
}
}

View File

@@ -0,0 +1,104 @@
package cn.datax.common.database.query;
import cn.datax.common.database.cache.DefaultSqlCache;
import cn.datax.common.database.core.DbColumn;
import cn.datax.common.database.core.DbTable;
import cn.datax.common.database.core.PageResult;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class CacheDbQueryFactoryBean extends AbstractDbQueryFactory {
/**
* 默认缓存5分钟
*/
private static long DEFAULT_EXPIRE = 5 * 60 * 1000;
private static DefaultSqlCache sqlCache = new DefaultSqlCache(100, DEFAULT_EXPIRE);
private <T> T putCacheValue(String key, T value, long ttl) {
sqlCache.put(key, value, ttl);
return value;
}
@Override
public List<DbColumn> getTableColumns(String dbName, String tableName) {
Object[] args = new Object[]{dbName, tableName};
Optional.ofNullable(sqlCache.get(sqlCache.buildSqlCacheKey(super.dataSource.toString() + ":getTableColumns", args)));
return super.getTableColumns(dbName, tableName);
}
@Override
public List<DbTable> getTables(String dbName) {
Object[] args = new Object[]{dbName};
String cacheKey = sqlCache.buildSqlCacheKey(super.dataSource.toString() + ":getTables", args);
return (List<DbTable>) Optional.ofNullable(sqlCache.get(cacheKey))
.orElse(putCacheValue(cacheKey, super.getTables(dbName), DEFAULT_EXPIRE));
}
@Override
public int count(String sql) {
String cacheKey = sqlCache.buildSqlCacheKey(super.dataSource.toString() + ":" + sql, null);
return (int) Optional.ofNullable(sqlCache.get(cacheKey))
.orElse(putCacheValue(cacheKey, super.count(sql), DEFAULT_EXPIRE));
}
@Override
public int count(String sql, Object[] args) {
String cacheKey = sqlCache.buildSqlCacheKey(super.dataSource.toString() + ":" + sql, args);
return (int) Optional.ofNullable(sqlCache.get(cacheKey))
.orElse(putCacheValue(cacheKey, super.count(sql, args), DEFAULT_EXPIRE));
}
@Override
public int count(String sql, Map<String, Object> params) {
String cacheKey = sqlCache.buildSqlCacheKey(super.dataSource.toString() + ":" + sql, params.values().toArray());
return (int) Optional.ofNullable(sqlCache.get(cacheKey))
.orElse(putCacheValue(cacheKey, super.count(sql, params), DEFAULT_EXPIRE));
}
@Override
public List<Map<String, Object>> queryList(String sql) {
String cacheKey = sqlCache.buildSqlCacheKey(super.dataSource.toString() + ":" + sql, null);
return (List<Map<String, Object>>) Optional.ofNullable(sqlCache.get(cacheKey))
.orElse(putCacheValue(cacheKey, super.queryList(sql), DEFAULT_EXPIRE));
}
@Override
public List<Map<String, Object>> queryList(String sql, Object[] args) {
String cacheKey = sqlCache.buildSqlCacheKey(super.dataSource.toString() + ":" + sql, args);
return (List<Map<String, Object>>) Optional.ofNullable(sqlCache.get(cacheKey))
.orElse(putCacheValue(cacheKey, super.queryList(sql, args), DEFAULT_EXPIRE));
}
@Override
public PageResult<Map<String, Object>> queryByPage(String sql, long offset, long size) {
Object[] args = new Object[]{offset, size};
String cacheKey = sqlCache.buildSqlCacheKey(super.dataSource.toString() + ":" + sql, args);
return (PageResult<Map<String, Object>>) Optional.ofNullable(sqlCache.get(cacheKey))
.orElse(putCacheValue(cacheKey, super.queryByPage(sql, offset, size), DEFAULT_EXPIRE));
}
@Override
public PageResult<Map<String, Object>> queryByPage(String sql, Object[] args, long offset, long size) {
Object[] objects = Arrays.copyOf(args, args.length + 2);
objects[args.length] = offset;
objects[args.length + 1] = size;
String cacheKey = sqlCache.buildSqlCacheKey(super.dataSource.toString() + ":" + sql, objects);
return (PageResult<Map<String, Object>>) Optional.ofNullable(sqlCache.get(cacheKey))
.orElse(putCacheValue(cacheKey, super.queryByPage(sql, args, offset, size), DEFAULT_EXPIRE));
}
@Override
public PageResult<Map<String, Object>> queryByPage(String sql, Map<String, Object> params, long offset, long size) {
Object[] args = params.values().toArray();
Object[] objects = Arrays.copyOf(args, args.length + 2);
objects[args.length] = offset;
objects[args.length + 1] = size;
String cacheKey = sqlCache.buildSqlCacheKey(super.dataSource.toString() + ":" + sql, objects);
return (PageResult<Map<String, Object>>) Optional.ofNullable(sqlCache.get(cacheKey))
.orElse(putCacheValue(cacheKey, super.queryByPage(sql, params, offset, size), DEFAULT_EXPIRE));
}
}

View File

@@ -0,0 +1,5 @@
package cn.datax.common.database.query;
public class DefaultDbQueryFactoryBean extends AbstractDbQueryFactory {
}

View File

@@ -0,0 +1,46 @@
package cn.datax.common.database.utils;
import java.security.MessageDigest;
import java.util.Arrays;
public class MD5Util {
public static void main(String[] args) throws InterruptedException {
Object[] arr = new Object[]{"dbName"};
Object[] objects = Arrays.copyOf(arr, arr.length + 2);
System.out.println(objects.length);
int length = arr.length;
objects[length] = 1;
objects[length+1] = 2;
System.out.println(Arrays.toString(objects));
// String encrypt = MD5Util.encrypt("sql" + ":" + Arrays.toString(arr));
// System.out.println(encrypt);
}
private static final char[] HEX_CHARS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
/**
* MD5加密
*/
public static String encrypt(String value){
return encrypt(value.getBytes());
}
/**
* MD5加密
*/
public static String encrypt(byte[] value){
try {
byte[] bytes = MessageDigest.getInstance("MD5").digest(value);
char[] chars = new char[32];
for (int i = 0; i < chars.length; i = i + 2) {
byte b = bytes[i / 2];
chars[i] = HEX_CHARS[(b >>> 0x4) & 0xf];
chars[i + 1] = HEX_CHARS[b & 0xf];
}
return new String(chars);
} catch (Exception e) {
throw new RuntimeException("md5 encrypt error", e);
}
}
}

View File

@@ -0,0 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.datax.common.database.datasource.CacheDataSourceFactoryBean

View File

@@ -0,0 +1,42 @@
<?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-dictionary</artifactId>
<dependencies>
<!-- SpringWeb模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.platform</groupId>
<artifactId>common-core</artifactId>
<version>0.4.x</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.platform</groupId>
<artifactId>common-redis</artifactId>
<version>0.4.x</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,12 @@
package cn.datax.common.dictionary.annotation;
import java.lang.annotation.*;
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DictAop {
/** 字典编码 */
String code() default "";
}

View File

@@ -0,0 +1,59 @@
package cn.datax.common.dictionary.config;
import cn.datax.common.core.JsonPage;
import cn.datax.common.core.R;
import cn.datax.common.dictionary.annotation.DictAop;
import cn.datax.common.dictionary.utils.DictUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
@ControllerAdvice
public class DictAnalysis implements ResponseBodyAdvice {
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
if (o instanceof R) {
if (((R) o).getData() instanceof JsonPage) {
List list = ((JsonPage) ((R) o).getData()).getData();
List<JSONObject> items = new ArrayList<>();
for (Object record : list) {
JSONObject item = JSONObject.parseObject(JSON.toJSONString(record));
for (Field field : record.getClass().getDeclaredFields()) {
// 获取自定义注解
DictAop dictAop = field.getAnnotation(DictAop.class);
if (null != dictAop) {
String code = dictAop.code();
String text = field.getName();
Object object = item.get(field.getName());
if (null != object) {
// 字典翻译
Object dictValue = DictUtil.getInstance().getDictItemValue(code, object.toString());
if (null != dictValue) {
item.put(field.getName() + "_dictText", dictValue);
}
}
}
}
items.add(item);
}
((JsonPage) ((R) o).getData()).setData(items);
}
}
return o;
}
@Override
public boolean supports(MethodParameter methodParameter, Class aClass) {
return true;
}
}

View File

@@ -0,0 +1,39 @@
package cn.datax.common.dictionary.utils;
import cn.datax.common.core.RedisConstant;
import cn.datax.common.redis.service.RedisService;
import cn.datax.common.utils.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;
import java.util.Optional;
@Slf4j
public class ConfigUtil {
private ConfigUtil() {}
private static volatile ConfigUtil instance;
public static ConfigUtil getInstance() {
if(instance == null) {
synchronized (ConfigUtil.class) {
if(instance == null) {
instance = new ConfigUtil();
}
}
}
return instance;
}
private RedisService redisService = SpringContextHolder.getBean(RedisService.class);
/**
* 获取参数
* @param code
*/
public Object getConfig(String code) {
String key = RedisConstant.SYSTEM_CONFIG_KEY;
Object o = redisService.hget(key, code);
return Optional.ofNullable(o).orElse(null);
}
}

View File

@@ -0,0 +1,69 @@
package cn.datax.common.dictionary.utils;
import cn.datax.common.core.RedisConstant;
import cn.datax.common.redis.service.RedisService;
import cn.datax.common.utils.SpringContextHolder;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
public class DictUtil {
private DictUtil() {}
private static volatile DictUtil instance;
public static DictUtil getInstance() {
if(instance == null) {
synchronized (DictUtil.class) {
if(instance == null) {
instance = new DictUtil();
}
}
}
return instance;
}
private RedisService redisService = SpringContextHolder.getBean(RedisService.class);
/**
* 获取字典项
* @param code
*/
public Object getDictItemList(String code) {
String key = RedisConstant.SYSTEM_DICT_KEY;
Object object = redisService.get(key);
if (null == object) {
return null;
}
JSONArray jsonArray = JSONArray.parseArray(JSON.toJSONString(object));
List<Object> list = jsonArray.stream().filter(obj -> ((JSONObject) obj).get("dictCode").equals(code))
.flatMap(obj -> ((JSONObject) obj).getJSONArray("items").stream()).collect(Collectors.toList());
return list;
}
/**
* 获取字典项值
* @param code
* @param text
* @return
*/
public Object getDictItemValue(String code, String text) {
String key = RedisConstant.SYSTEM_DICT_KEY;
Object object = redisService.get(key);
if (null == object) {
return null;
}
JSONArray jsonArray = JSONArray.parseArray(JSON.toJSONString(object));
Object o = jsonArray.stream().filter(obj -> ((JSONObject) obj).get("dictCode").equals(code))
.flatMap(obj -> ((JSONObject) obj).getJSONArray("items").stream())
.filter(obj -> ((JSONObject) obj).get("itemText").equals(text))
.map(obj -> ((JSONObject) obj).get("itemValue")).findFirst().orElse(null);
return o;
}
}

View File

@@ -0,0 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.datax.common.dictionary.config.DictAnalysis

View File

@@ -0,0 +1,36 @@
<?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-jasperreport</artifactId>
<dependencies>
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>${jasperreports.version}</version>
<exclusions>
<exclusion>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>2.1.7</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,126 @@
package cn.datax.common.jasperreport.utils;
import lombok.extern.slf4j.Slf4j;
import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.export.HtmlExporter;
import net.sf.jasperreports.export.HtmlExporterOutput;
import net.sf.jasperreports.export.SimpleExporterInput;
import net.sf.jasperreports.export.SimpleHtmlExporterOutput;
import net.sf.jasperreports.export.SimpleHtmlReportConfiguration;
import org.springframework.core.io.ClassPathResource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.List;
import java.util.Map;
@Slf4j
public class JasperReportUtil {
final static String jasperDir = "jaspers";
public static String getJasperFileDir(String fileName) {
return jasperDir + File.separator + fileName + ".jasper";
}
private static String getContentType(ReportType type) {
String contentType;
switch (type) {
case HTML:
contentType = "text/html;charset=utf-8";
break;
case PDF:
contentType = "application/pdf";
break;
case XLS:
contentType = "application/vnd.ms-excel";
break;
case XLSX:
contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
break;
case XML:
contentType = "text/xml";
break;
case RTF:
contentType = "application/rtf";
break;
case CSV:
contentType = "text/plain";
break;
case DOC:
contentType = "application/msword";
break;
default:
contentType = "text/html;charset=utf-8";
}
return contentType;
}
static JasperPrint getJasperPrint(InputStream jasperStream, Map parameters, List<?> list) throws JRException {
JRDataSource dataSource;
if (null == list || list.size() == 0) {
dataSource = new JREmptyDataSource();
} else {
dataSource = new JRBeanCollectionDataSource(list);
}
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperStream, parameters, dataSource);
return jasperPrint;
}
public static void exportToPdf(String jasperPath, Map parameters, List<?> list, HttpServletResponse response) throws Exception {
OutputStream outputStream = response.getOutputStream();
try {
ClassPathResource resource = new ClassPathResource(jasperPath);
response.setContentType(getContentType(ReportType.PDF));
InputStream jasperStream = resource.getInputStream();
JasperPrint jasperPrint = getJasperPrint(jasperStream, parameters, list);
JasperExportManager.exportReportToPdfStream(jasperPrint, outputStream);
} catch (Exception e) {
log.error("读取报表异常", e);
outputStream.write("读取报表异常".getBytes());
} finally {
outputStream.flush();
outputStream.close();
}
}
public static void exportToHtml(String jasperPath, Map parameters, List<?> list, HttpServletResponse response) throws Exception {
response.setHeader("Content-type", "text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType(getContentType(ReportType.HTML));
PrintWriter out = response.getWriter();
HtmlExporter exporter = new HtmlExporter();
try {
ClassPathResource resource = new ClassPathResource(jasperPath);
InputStream jasperStream = resource.getInputStream();
JasperPrint jasperPrint = getJasperPrint(jasperStream, parameters, list);
exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
SimpleHtmlReportConfiguration configuration = new SimpleHtmlReportConfiguration();
exporter.setConfiguration(configuration);
HtmlExporterOutput outPut = new SimpleHtmlExporterOutput(out);
exporter.setExporterOutput(outPut);
exporter.exportReport();
} catch (Exception e) {
log.error("读取报表异常", e);
out.write("读取报表异常");
} finally {
out.flush();
out.close();
}
}
public enum ReportType {
HTML,
PDF,
XLS,
XLSX,
XML,
RTF,
CSV,
DOC
}
}

View File

@@ -0,0 +1,2 @@
net.sf.jasperreports.extension.registry.factory.simple.font.families=net.sf.jasperreports.engine.fonts.SimpleFontExtensionsRegistryFactory
net.sf.jasperreports.extension.simple.font.families.dejavu=jaspers/fonts/fonts.xml

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<fontFamilies>
<fontFamily name="微软雅黑">
<normal>jaspers/fonts/msyh.ttf</normal>
<bold>jaspers/fonts/msyh.ttf</bold>
<italic>jaspers/fonts/msyh.ttf</italic>
<boldItalic>jaspers/fonts/msyh.ttf</boldItalic>
<pdfEncoding>Identity-H</pdfEncoding>
<pdfEmbedded>true</pdfEmbedded>
<exportFonts>
<export key="net.sf.jasperreports.html">'微软雅黑', Arial, Helvetica, sans-serif</export>
<export key="net.sf.jasperreports.xhtml">'微软雅黑', Arial, Helvetica, sans-serif</export>
</exportFonts>
</fontFamily>
</fontFamilies>

View File

@@ -0,0 +1,37 @@
<?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-log</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.platform</groupId>
<artifactId>common-service-api</artifactId>
<version>0.4.x</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>com.platform</groupId>
<artifactId>generic</artifactId>
<version>0.4.x</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,20 @@
package cn.datax.common.log.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAop {
/** 模块 */
String module() default "";
/** 描述 */
String value() default "";
}

View File

@@ -0,0 +1,134 @@
package cn.datax.common.log.annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import com.platform.utils.RequestHolder;
import cn.datax.service.system.api.dto.LogDto;
import cn.hutool.core.util.URLUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.platform.utils.SecurityUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
@Slf4j
@Aspect
public class LogAspect {
// @Autowired
// private LogServiceFeign logServiceFeign;
@Autowired
private ObjectMapper objectMapper;
// 配置织入点
@Pointcut("@annotation(cn.datax.common.log.annotation.LogAop)")
public void logPointCut() {}
/**
* 通知方法会将目标方法封装起来
*
* @param joinPoint 切点
*/
@Around(value = "logPointCut()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = joinPoint.proceed();
long endTime = System.currentTimeMillis();
LogDto logDto = getLog();
logDto.setTime(String.valueOf(endTime - startTime));
handleLog(joinPoint, logDto);
return result;
}
/**
* 通知方法会在目标方法抛出异常后执行
*
* @param joinPoint
* @param e
*/
@AfterThrowing(value = "logPointCut()", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
LogDto logDto = getLog();
logDto.setExCode(e.getClass().getSimpleName()).setExMsg(e.getMessage());
handleLog(joinPoint, logDto);
}
private LogDto getLog(){
LogDto log = new LogDto();
HttpServletRequest request = RequestHolder.getHttpServletRequest();
log.setUserId(SecurityUtil.getUserId());
log.setUserName(SecurityUtil.getUserName());
log.setRemoteAddr(ServletUtil.getClientIP(request));
log.setRequestUri(URLUtil.getPath(request.getRequestURI()));
UserAgent ua = UserAgentUtil.parse(request.getHeader("User-Agent"));
log.setBrowser(ua.getBrowser().toString());
log.setOs(ua.getOs().toString());
return log;
}
protected void handleLog(final JoinPoint joinPoint, LogDto logDto) {
// 获得注解
LogAop logAop = getAnnotationLog(joinPoint);
if(null == logAop) {
return;
}
// 设置方法名称
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
logDto.setModule(logAop.module()).setTitle(logAop.value())
.setClassName(className).setMethodName(methodName);
try {
logDto.setParams(objectMapper.writeValueAsString(getRequestParams(joinPoint)));
} catch (JsonProcessingException e) {}
// 保存数据库
// logServiceFeign.saveLog(logDto);
}
/**
* 是否存在注解,如果存在就获取
*/
private LogAop getAnnotationLog(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
return null;
}
/**
* 获取入参
* */
private Map<String, Object> getRequestParams(JoinPoint joinPoint) {
Map<String, Object> requestParams = new HashMap<>();
// 参数名
String[] paramNames = ((MethodSignature)joinPoint.getSignature()).getParameterNames();
// 参数值
Object[] paramValues = joinPoint.getArgs();
for (int i = 0; i < paramNames.length; i++) {
Object value = paramValues[i];
// 如果是文件对象
if (value instanceof MultipartFile) {
MultipartFile file = (MultipartFile) value;
// 获取文件名
value = file.getOriginalFilename();
}
requestParams.put(paramNames[i], value);
}
return requestParams;
}
}

View File

@@ -0,0 +1,26 @@
package com.platform.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,19 @@
package com.platform.utils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
/**
* 获取 HttpServletRequest
* @author AllDataDC
* @date 2023-01-27
*/
public class RequestHolder {
public static HttpServletRequest getHttpServletRequest() {
return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
}
}

View File

@@ -0,0 +1,125 @@
package com.platform.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.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");
String tokenSubjectObject = String.valueOf(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() {
JwtUserDto user = getDataUser();
if (user != null){
return user.getUser().getIsAdmin();
}
return false;
}
}

View File

@@ -0,0 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.datax.common.log.annotation.LogAspect

View File

@@ -0,0 +1,56 @@
<?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-mybatis</artifactId>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>${oracle.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>${dynamic-datasource.version}</version>
</dependency>
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>${p6spy.version}</version>
</dependency>
<dependency>
<groupId>com.platform</groupId>
<artifactId>common-core</artifactId>
<version>0.4.x</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,27 @@
package cn.datax.common.mybatis.annotation;
import java.lang.annotation.*;
/**
* 数据权限过滤注解
* 参考 https://gitee.com/cancerGit/Crown
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface DataScopeAop {
/**
* 表的别名
*/
String alias() default "sys_user";
/**
* 表的部门字段
*/
String deptScopeName() default "create_dept";
/**
* 表的用户字段
*/
String userScopeName() default "create_by";
}

View File

@@ -0,0 +1,125 @@
package cn.datax.common.mybatis.aspectj;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;
import cn.datax.common.base.BaseQueryParams;
import cn.datax.common.core.DataConstant;
import cn.datax.common.core.DataRole;
import cn.datax.common.core.DataUser;
import cn.datax.common.mybatis.annotation.DataScopeAop;
import cn.datax.common.utils.SecurityUtil;
import cn.datax.service.system.api.dto.JwtUserDto;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
/**
* 数据过滤处理(基于注解式,用于自定义sql
*/
@Slf4j
@Aspect
public class DataScopeAspect {
// 配置织入点
@Pointcut("@annotation(cn.datax.common.mybatis.annotation.DataScopeAop)")
public void dataScopePointCut() {
}
@Before("dataScopePointCut()")
public void doBefore(JoinPoint point) {
handleDataScope(point);
}
protected void handleDataScope(final JoinPoint joinPoint) {
// 获得注解
DataScopeAop dataScope = getAnnotationLog(joinPoint);
if (dataScope == null) {
return;
}
JwtUserDto currentUser = SecurityUtil.getDataUser();
if (null != currentUser) {
// 如果是超级管理员,则不过滤数据
// if (!currentUser.getUser().isAdmin) {
// dataScopeFilter(joinPoint, currentUser, dataScope);
// }
}
}
// /**
// * 数据范围过滤
// *
// * @param user
// * @param dataScope
// */
// private void dataScopeFilter(JoinPoint joinPoint, JwtUserDto user, DataScopeAop dataScope) {
// StringBuilder sqlString = new StringBuilder();
// Set<String> roles = user.getRoles();
// if (CollUtil.isNotEmpty(roles)){
// for (String role : roles){
// String roleDataScope = role.getDataScope();
// if (DataConstant.DataScope.ALL.getKey().equals(roleDataScope)) {
// sqlString = new StringBuilder();
// break;
// } else if (DataConstant.DataScope.CUSTOM.getKey().equals(roleDataScope)) {
// sqlString.append(StrUtil.format(
// " OR {}.{} IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) "
// ,dataScope.alias()
// ,dataScope.deptScopeName()
// ,"'" + role.getId() + "'"
// ));
// } else if (DataConstant.DataScope.DEPT.getKey().equals(roleDataScope)) {
// sqlString.append(StrUtil.format(
// " OR {}.{} = {} "
// ,dataScope.alias()
// ,dataScope.deptScopeName()
// ,"'" + user.getDept() + "'"
// ));
// } else if (DataConstant.DataScope.DEPTANDCHILD.getKey().equals(roleDataScope)) {
// sqlString.append(StrUtil.format(
// " OR {}.{} IN ( SELECT descendant FROM sys_dept_relation WHERE ancestor = {} )"
// ,dataScope.alias()
// ,dataScope.deptScopeName()
// ,"'" + user.getDept() + "'"
// ));
// } else if (DataConstant.DataScope.SELF.getKey().equals(roleDataScope)) {
// if (StrUtil.isNotBlank(dataScope.alias())) {
// sqlString.append(StrUtil.format(" OR {}.{} = {} "
// ,dataScope.alias()
// ,dataScope.userScopeName()
// ,user.getId()));
// } else {
// // 数据权限为仅本人且没有alias别名不查询任何数据
// sqlString.append(" OR 1=0 ");
// }
// }
// }
// }
// if (StrUtil.isNotBlank(sqlString.toString())) {
// BaseQueryParams baseQueryParams = (BaseQueryParams) joinPoint.getArgs()[0];
// baseQueryParams.setDataScope(" AND (" + sqlString.substring(4) + ")");
// }
// log.info("数据范围过滤:{}", sqlString);
// }
/**
* 是否存在注解,如果存在就获取
*/
private DataScopeAop getAnnotationLog(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null) {
return method.getAnnotation(DataScopeAop.class);
}
return null;
}
}

View File

@@ -0,0 +1,58 @@
package cn.datax.common.mybatis.config;
import cn.datax.common.mybatis.aspectj.DataScopeAspect;
import cn.datax.common.mybatis.injector.DataLogicSqlInjector;
import cn.datax.common.mybatis.interceptor.DataScopeInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@MapperScan({"cn.datax.service.**.dao","com.platform.dts.mapper"})
@EnableTransactionManagement
public class DataBatisPlusConfig {
/**
* 分页插件
*
* @return PaginationInterceptor
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
/**
* 数据权限插件
*
* @return DataScopeInterceptor
*/
@Bean
public DataScopeInterceptor dataScopeInterceptor() {
return new DataScopeInterceptor();
}
/**
* 数据过滤处理(基于注解式)
*
* @return dataScopeAspect
*/
@Bean
public DataScopeAspect dataScopeAspect() {
return new DataScopeAspect();
}
/**
* 自定义 SqlInjector
* 里面包含自定义的全局方法
*/
@Bean
public DataLogicSqlInjector myLogicSqlInjector() {
return new DataLogicSqlInjector();
}
@Bean
public DataMetaObjectHandler dataMetaObjectHandler() {
return new DataMetaObjectHandler();
}
}

View File

@@ -0,0 +1,34 @@
package cn.datax.common.mybatis.config;
import cn.datax.common.core.DataConstant;
import cn.datax.common.utils.SecurityUtil;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import java.time.LocalDateTime;
public class DataMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "status", String.class, DataConstant.EnableState.ENABLE.getKey());
this.strictInsertFill(metaObject, "createBy", String.class, SecurityUtil.getUserId());
this.strictInsertFill(metaObject, "updateBy", String.class, SecurityUtil.getUserId());
boolean bolCreateDept = metaObject.hasSetter("createDept");
if (bolCreateDept) {
this.strictInsertFill(metaObject, "createDept", String.class, SecurityUtil.getUserDeptId());
}
boolean bolFlowStatus = metaObject.hasSetter("flowStatus");
if (bolFlowStatus) {
this.strictInsertFill(metaObject, "flowStatus", String.class, DataConstant.AuditState.WAIT.getKey());
}
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
this.strictUpdateFill(metaObject, "updateBy", String.class, SecurityUtil.getUserId());
}
}

View File

@@ -0,0 +1,27 @@
package cn.datax.common.mybatis.injector;
import cn.datax.common.mybatis.injector.methods.SelectListDataScope;
import cn.datax.common.mybatis.injector.methods.SelectPageDataScope;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import java.util.List;
/**
* 自定义 SqlInjector
*/
public class DataLogicSqlInjector extends DefaultSqlInjector {
/**
* 如果只需增加方法保留MP自带方法
* 可以super.getMethodList() 再add
* @return
*/
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass);
methodList.add(new SelectListDataScope());
methodList.add(new SelectPageDataScope());
return methodList;
}
}

View File

@@ -0,0 +1,21 @@
package cn.datax.common.mybatis.injector.methods;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
public class SelectListDataScope extends AbstractMethod {
public SelectListDataScope() {
}
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
SqlMethod sqlMethod = SqlMethod.SELECT_LIST;
String sql = String.format(sqlMethod.getSql(), this.sqlFirst(), this.sqlSelectColumns(tableInfo, true), tableInfo.getTableName(), this.sqlWhereEntityWrapper(true, tableInfo), this.sqlComment());
SqlSource sqlSource = this.languageDriver.createSqlSource(this.configuration, sql, modelClass);
return this.addSelectMappedStatementForTable(mapperClass, "selectListDataScope", sqlSource, tableInfo);
}
}

View File

@@ -0,0 +1,21 @@
package cn.datax.common.mybatis.injector.methods;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
public class SelectPageDataScope extends AbstractMethod {
public SelectPageDataScope() {
}
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
SqlMethod sqlMethod = SqlMethod.SELECT_PAGE;
String sql = String.format(sqlMethod.getSql(), this.sqlFirst(), this.sqlSelectColumns(tableInfo, true), tableInfo.getTableName(), this.sqlWhereEntityWrapper(true, tableInfo), this.sqlComment());
SqlSource sqlSource = this.languageDriver.createSqlSource(this.configuration, sql, modelClass);
return this.addSelectMappedStatementForTable(mapperClass, "selectPageDataScope", sqlSource, tableInfo);
}
}

View File

@@ -0,0 +1,162 @@
package cn.datax.common.mybatis.interceptor;
import cn.datax.common.base.DataScope;
import cn.datax.common.core.DataConstant;
import cn.datax.common.core.DataRole;
import cn.datax.common.core.DataUser;
import cn.datax.common.utils.SecurityUtil;
import cn.datax.service.system.api.dto.JwtUserDto;
import cn.datax.service.system.api.dto.UserLoginDto;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.handlers.AbstractSqlParserHandler;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import java.sql.Connection;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
* mybatis 数据权限拦截器
*/
@Slf4j
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class DataScopeInterceptor extends AbstractSqlParserHandler implements Interceptor {
@Override
@SneakyThrows
public Object intercept(Invocation invocation) {
StatementHandler statementHandler = (StatementHandler) PluginUtils.realTarget(invocation.getTarget());
MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
this.sqlParser(metaObject);
// 先判断是不是SELECT操作
MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) {
return invocation.proceed();
}
BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
String originalSql = boundSql.getSql();
Object parameterObject = boundSql.getParameterObject();
//查找参数中包含DataScope类型的参数
DataScope dataScope = findDataScopeObject(parameterObject);
if (dataScope != null) {
// 获取当前的用户
JwtUserDto currentUser = SecurityUtil.getDataUser();
if (null != currentUser) {
UserLoginDto user = currentUser.getUser();
// 如果是超级管理员,则不过滤数据
// if (!user.isAdmin) {
// String sqlString = dataScopeFilter(currentUser, dataScope);
// if (StrUtil.isNotBlank(sqlString)) {
// originalSql = "SELECT * FROM (" + originalSql + ") TEMP_DATA_SCOPE WHERE 1=1 AND (" + sqlString.substring(4) + ")";
// metaObject.setValue("delegate.boundSql.sql", originalSql);
// }
// }
}
}
return invocation.proceed();
}
// /**
// * 数据范围过滤
// *
// * @param user
// * @param dataScope
// */
// private String dataScopeFilter(JwtUserDto user, DataScope dataScope) {
// StringBuilder sqlString = new StringBuilder();
// Set<String> roles = user.getRoles();
// if (CollUtil.isNotEmpty(roles)){
// for (String role : roles){
//// String roleDataScope = role.getDataScope();
// if (DataConstant.DataScope.ALL.getKey().equals(roleDataScope)) {
// sqlString = new StringBuilder();
// break;
// } else if (DataConstant.DataScope.CUSTOM.getKey().equals(roleDataScope)) {
// sqlString.append(StrUtil.format(
// " OR {} IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) "
// ,dataScope.getDeptScopeName()
// ,"'" + role + "'"
// ));
// } else if (DataConstant.DataScope.DEPT.getKey().equals(roleDataScope)) {
// sqlString.append(StrUtil.format(
// " OR {} = {} "
// ,dataScope.getDeptScopeName()
// ,"'" + user.getUser().getDept() + "'"
// ));
// } else if (DataConstant.DataScope.DEPTANDCHILD.getKey().equals(roleDataScope)) {
// sqlString.append(StrUtil.format(
// " OR {} IN ( SELECT descendant FROM sys_dept_relation WHERE ancestor = {} )"
// ,dataScope.getDeptScopeName()
// ,"'" + user.getUser().getDept() + "'"
// ));
// } else if (DataConstant.DataScope.SELF.getKey().equals(roleDataScope)) {
// sqlString.append(StrUtil.format(" OR {} = {} "
// ,dataScope.getUserScopeName()
// ,"'" + user.getUser().getId() + "'"
// ));
// }
// }
// }
// log.info("数据范围过滤:{}", sqlString);
// return sqlString.toString();
// }
/**
* 生成拦截对象的代理
*
* @param target 目标对象
* @return 代理对象
*/
@Override
public Object plugin(Object target) {
if (target instanceof StatementHandler) {
return Plugin.wrap(target, this);
}
return target;
}
/**
* mybatis配置的属性
*
* @param properties mybatis配置的属性
*/
@Override
public void setProperties(Properties properties) {
}
/**
* 查找参数是否包括DataScope对象
*
* @param parameterObj 参数列表
* @return DataScope
*/
private DataScope findDataScopeObject(Object parameterObj) {
if (parameterObj instanceof DataScope) {
return (DataScope) parameterObj;
} else if (parameterObj instanceof Map) {
for (Object val : ((Map<?, ?>) parameterObj).values()) {
if (val instanceof DataScope) {
return (DataScope) val;
}
}
}
return null;
}
}

View File

@@ -0,0 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.datax.common.mybatis.config.DataBatisPlusConfig

Binary file not shown.

View File

@@ -0,0 +1,23 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<version>0.4.x</version>
<groupId>com.platform</groupId>
<artifactId>common</artifactId>
</parent>
<version>0.4.x</version>
<artifactId>common-office</artifactId>
<dependencies>
<dependency>
<groupId>com.aspose</groupId>
<artifactId>aspose-words</artifactId>
<version>${aspose.version}</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/aspose-words-20.3.jar</systemPath>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,96 @@
package cn.datax.commo.office.word;
import com.aspose.words.IMailMergeDataSource;
import com.aspose.words.ref.Ref;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class MapMailMergeDataSource implements IMailMergeDataSource {
private List<Map<String, Object>> dataList;
private int index;
/**
* word模板中的«TableStart:tableName»«TableEnd:tableName»对应
*/
private String tableName = null;
/**
* @param dataList 数据集
* @param tableName 与模板中的Name对应
*/
public MapMailMergeDataSource(List<Map<String, Object>> dataList, String tableName) {
this.dataList = dataList;
this.tableName = tableName;
index = -1;
}
/**
* @param data 单个数据集
* @param tableName 与模板中的Name对应
*/
public MapMailMergeDataSource(Map<String, Object> data, String tableName) {
if (this.dataList == null) {
this.dataList = new ArrayList<Map<String, Object>>();
this.dataList.add(data);
}
this.tableName = tableName;
index = -1;
}
/**
* 获取结果集总数
*
* @return
*/
private int getCount() {
return this.dataList.size();
}
@Override
public IMailMergeDataSource getChildDataSource(String arg0)
throws Exception {
return null;
}
@Override
public String getTableName() throws Exception {
return this.tableName;
}
/**
* 实现接口
* 获取当前index指向数据行的数据
* 将数据存入args数组中即可
*
* @return ***返回false则不绑定数据***
*/
@Override
public boolean getValue(String key, Ref<Object> args) throws Exception {
if (index < 0 || index >= this.getCount()) {
return false;
}
if (args != null) {
args.set(this.dataList.get(index).get(key));
return true;
} else {
return false;
}
}
/**
* 实现接口
* 判断是否还有下一条记录
*/
@Override
public boolean moveNext() throws Exception {
index += 1;
if (index >= this.getCount()) {
return false;
}
return true;
}
}

View File

@@ -0,0 +1,47 @@
package cn.datax.commo.office.word;
import com.aspose.words.Document;
import com.aspose.words.MailMerge;
import java.util.List;
import java.util.Map;
public class MergeDataSource {
/**
* word模板普通数据填充
* @param name
* @param value
* @param modelPath
* @return
* @throws Exception
*/
public Document load(String[] name, Object[] value, String modelPath) throws Exception {
Document doc = new Document(modelPath);
// 这里可以做特殊字段处理(如:图片插入、字符对应的特殊符号[https://wenku.baidu.com/view/81b41244336c1eb91a375dcb.html]
// DocumentBuilder builder = new DocumentBuilder(doc);
// builder.moveToMergeField(key);
// builder.insertImage((BufferedImage) value);
MailMerge merge = doc.getMailMerge();
merge.execute(name, value);
return doc;
}
/**
* word模板里有集合的表格填充
* @param name
* @param value
* @param modelPath
* @param dataList
* @return
* @throws Exception
*/
public Document load(String[] name, Object[] value, String modelPath, List<Map<String, Object>> dataList, String tableName) throws Exception {
Document doc = new Document(modelPath);
MailMerge merge = doc.getMailMerge();
merge.execute(name, value);
merge.executeWithRegions(new MapMailMergeDataSource(dataList, tableName));
return doc;
}
}

View File

@@ -0,0 +1,280 @@
package cn.datax.commo.office.word;
import com.aspose.words.*;
import com.aspose.words.Shape;
import java.awt.*;
import java.io.*;
import java.util.*;
import java.util.List;
public class WordUtil {
private WordUtil() {}
private static volatile WordUtil instance;
public static WordUtil getInstance() {
if(instance == null) {
synchronized (WordUtil.class) {
if(instance == null) {
instance = new WordUtil();
}
}
}
return instance;
}
/**
* 去除水印
*/
static {
String license =
"<License>\n" +
" <Data>\n" +
" <Products>\n" +
" <Product>Aspose.Cells for Java</Product>\n" +
" <Product>Aspose.Words for Java</Product>\n" +
" <Product>Aspose.Slides for Java</Product>\n" +
" </Products>\n" +
" <EditionType>Enterprise</EditionType>\n" +
" <SubscriptionExpiry>20991231</SubscriptionExpiry>\n" +
" <LicenseExpiry>20991231</LicenseExpiry>\n" +
" <SerialNumber>8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7</SerialNumber>\n" +
" </Data>\n" +
" <Signature>datax</Signature>\n" +
"</License>";
try {
new License().setLicense(new ByteArrayInputStream(license.getBytes("UTF-8")));
} catch (Exception e) {}
}
/**
* 获取文档
*
* @param fileName 模板文件 F:\模板.docx
* @return
* @throws Exception
*/
public Document getDocument(String fileName) throws Exception {
return new Document(fileName);
}
/**
* 获取文档
*
* @param inputStream 模板文件输入流
* @return
* @throws Exception
*/
public Document getDocument(InputStream inputStream) throws Exception {
return new Document(inputStream);
}
/**
* 普通数据模板 返回缓冲输入流
*
* @param name
* @param value
* @param modelPath 模板文件 F:\模板.docx
* @return 缓冲输入流 供controller层下载
* @throws Exception
*/
public ByteArrayInputStream fillWordData(String[] name, Object[] value, String modelPath) throws Exception {
Document doc = new MergeDataSource().load(name, value, modelPath);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
doc.save(bos, SaveOptions.createSaveOptions(SaveFormat.DOCX));
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
return bis;
}
/**
* 普通数据模板 直接保存到指定位置
*
* @param name
* @param value
* @param modelPath 模板文件 F:\模板.docx
* @param destPath 保存文件 F:\测试.docx
* @throws Exception
*/
public void fillWordData(String[] name, Object[] value, String modelPath, String destPath) throws Exception {
Document doc = new MergeDataSource().load(name, value, modelPath);
doc.save(destPath, SaveOptions.createSaveOptions(SaveFormat.DOCX));
}
/**
* 带集合的数据模板 返回缓冲输入流
*
* @param name
* @param value
* @param modelPath 模板文件 F:\模板.docx
* @param dataList 集合数据
* @param tableName 集合名称
* @throws Exception
*/
public ByteArrayInputStream fillWordListData(String[] name, Object[] value, String modelPath, List<Map<String, Object>> dataList, String tableName) throws Exception {
Document doc = new MergeDataSource().load(name, value, modelPath, dataList, tableName);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
doc.save(bos, SaveOptions.createSaveOptions(SaveFormat.DOCX));
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
return bis;
}
/**
* 带集合的数据模板 直接保存到指定位置
*
* @param name
* @param value
* @param modelPath 模板文件 F:\模板.docx
* @param destPath 保存文件 F:\测试.docx
* @param dataList 集合数据
* @param tableName 集合名称
* @throws Exception
*/
public void fillWordListData(String[] name, Object[] value, String modelPath, String destPath, List<Map<String, Object>> dataList, String tableName) throws Exception {
Document doc = new MergeDataSource().load(name, value, modelPath, dataList, tableName);
doc.save(destPath, SaveOptions.createSaveOptions(SaveFormat.DOCX));
}
/**
* word转pdf
* @param srcPath 文件路径 F:\\test\\审批流提交.docx
* @param destPath 目标路径 F:\\test\\20200420.pdf
* @throws Exception
*/
public void word2pdf(String srcPath, String destPath) throws Exception {
// 转换开始前时间
long old = System.currentTimeMillis();
// 要转换的word文档的路径
Document doc = new Document(srcPath);
// 全面支持DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF, EPUB, XPS, SWF 相互转换
doc.save(destPath, SaveOptions.createSaveOptions(SaveFormat.PDF));
// 转换结束后时间
long now = System.currentTimeMillis();
System.out.println("共耗时:" + ((now - old) / 1000.0) + "");
}
/**
* 创建空文档
*
* @param destPath 文件路径 F:\\test\\审批流提交.docx
* @return
*/
public void createWord(String destPath) throws Exception {
Document doc = new Document();
doc.save(destPath, SaveOptions.createSaveOptions(SaveFormat.DOCX));
}
/**
* 加水印方法
*
* @param doc word文件流
* @param watermarkText 水印内容
*/
public void insertWatermarkText(Document doc, String watermarkText) throws Exception {
Shape watermark = new Shape(doc, ShapeType.TEXT_PLAIN_TEXT);
watermark.setName("WaterMark");
watermark.getTextPath().setText(watermarkText);
watermark.getTextPath().setFontFamily("Arial");
watermark.setWidth(500);
watermark.setHeight(100);
watermark.setRotation(-40);
watermark.getFill().setColor(Color.GRAY);
watermark.setStrokeColor(Color.GRAY);
watermark.setRelativeHorizontalPosition(RelativeHorizontalPosition.PAGE);
watermark.setRelativeVerticalPosition(RelativeVerticalPosition.PAGE);
watermark.setWrapType(WrapType.NONE);
watermark.setVerticalAlignment(VerticalAlignment.CENTER);
watermark.setHorizontalAlignment(HorizontalAlignment.CENTER);
Paragraph watermarkPara = new Paragraph(doc);
watermarkPara.appendChild(watermark);
for (Section sect : doc.getSections()) {
insertWatermarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_PRIMARY);
insertWatermarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_FIRST);
insertWatermarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_EVEN);
}
}
private void insertWatermarkIntoHeader(Paragraph watermarkPara, Section sect, int headerType) throws Exception {
HeaderFooter header = sect.getHeadersFooters().getByHeaderFooterType(headerType);
if (header == null) {
header = new HeaderFooter(sect.getDocument(), headerType);
sect.getHeadersFooters().add(header);
}
header.appendChild(watermarkPara.deepClone(true));
}
public static void main(String[] args) throws Exception {
// Map<String, Object> map = new HashMap<>();
// map.put("companyName", "测试");
// map.put("totalSalary", new BigDecimal("12.34"));
// List<Map<String, Object>> list = new ArrayList<>();
// Map<String, Object> map1 = new HashMap<>();
// map1.put("id", "1");
// map1.put("name", "测试1");
// map1.put("age", 12);
// map1.put("sex", "男");
// map1.put("salary", new BigDecimal("5.0"));
// list.add(map1);
// Map<String, Object> map2 = new HashMap<>();
// map2.put("id", "2");
// map2.put("name", "测试2");
// map2.put("age", 14);
// map2.put("sex", "女");
// map2.put("salary", new BigDecimal("7.34"));
// list.add(map2);
// List<String> objects1 = new ArrayList<>();
// List<Object> objects2 = new ArrayList<>();
// for(Map.Entry<String, Object> entry : map.entrySet()){
// objects1.add(entry.getKey());
// objects2.add(entry.getValue());
// }
// WordUtil.getInstance().fillWordListData(objects1.toArray(new String[objects1.size()]), objects2.toArray(new Object[objects2.size()]), "F:\\test\\模板.docx", "F:\\test\\123.docx", list, "workerList");
// WordUtil.getInstance().word2pdf("F:\\test.docx", "F:\\20200420.pdf");
//
// // 用户表(子表) TableStart:UserList TableEnd:UserList
// DataTable userTable = new DataTable("UserList");
// userTable.getColumns().add("id");
// userTable.getColumns().add("name");
// userTable.getColumns().add("age");
// userTable.getColumns().add("sex");
// userTable.getColumns().add("salary");
// for (int i = 1; i < 3; i++) {
// DataRow row = userTable.newRow();
// row.set(0, i);
// row.set(1, "name" + i);
// row.set(2, "age" + i);
// row.set(3, "sex" + i);
// row.set(4, "salary" + i);
// userTable.getRows().add(row);
// }
// // 分数表(子表) TableStart:ScoreList TableEnd:ScoreList
// DataTable scoreTable = new DataTable("ScoreList");
// scoreTable.getColumns().add("id");
// scoreTable.getColumns().add("uid");
// scoreTable.getColumns().add("score");
// for (int i = 1; i < 3; i++) {
// DataRow row = scoreTable.newRow();
// row.set(0, i);
// row.set(1, i);
// row.set(2, 10*i);
// scoreTable.getRows().add(row);
// }
// // 提供数据源
// DataSet dataSet = new DataSet();
// dataSet.getTables().add(userTable);
// dataSet.getTables().add(scoreTable);
// DataRelation dataRelation = new DataRelation("UserScoreRelation", userTable.getColumns().get("id"), scoreTable.getColumns().get("uid"));
// dataSet.getRelations().add(dataRelation);
// // 合并模版
// Document doc = new Document("F:\\test.docx");
// //提供数据源
// String[] fieldNames = new String[] {"name", "address"};
// Object[] fieldValues = new Object[] {"张三", "陕西咸阳"};
// //合并模版,相当于页面的渲染
// MailMerge mailMerge = doc.getMailMerge();
// mailMerge.execute(fieldNames, fieldValues);
// mailMerge.executeWithRegions(dataSet);
// doc.save("F:\\test_r.docx", SaveOptions.createSaveOptions(SaveFormat.DOCX));
}
}

View File

@@ -0,0 +1,26 @@
<?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-qrcode</artifactId>
<dependencies>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>${zxing.version}</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>${zxing.version}</version>
</dependency>
</dependencies>
</project>

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