first commit
This commit is contained in:
16
renren-dynamic-datasource/pom.xml
Normal file
16
renren-dynamic-datasource/pom.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<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>
|
||||
<groupId>io.renren</groupId>
|
||||
<artifactId>renren-security</artifactId>
|
||||
<version>5.2.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>renren-dynamic-datasource</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<description>多数据源</description>
|
||||
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.commons.dynamic.datasource.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 多数据源注解
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface DataSource {
|
||||
String value() default "";
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.commons.dynamic.datasource.aspect;
|
||||
|
||||
import io.renren.commons.dynamic.datasource.annotation.DataSource;
|
||||
import io.renren.commons.dynamic.datasource.config.DynamicContextHolder;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 多数据源,切面处理类
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Aspect
|
||||
@Component
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public class DataSourceAspect {
|
||||
protected Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@Pointcut("@annotation(io.renren.commons.dynamic.datasource.annotation.DataSource) " +
|
||||
"|| @within(io.renren.commons.dynamic.datasource.annotation.DataSource)")
|
||||
public void dataSourcePointCut() {
|
||||
|
||||
}
|
||||
|
||||
@Around("dataSourcePointCut()")
|
||||
public Object around(ProceedingJoinPoint point) throws Throwable {
|
||||
MethodSignature signature = (MethodSignature) point.getSignature();
|
||||
Class targetClass = point.getTarget().getClass();
|
||||
Method method = signature.getMethod();
|
||||
|
||||
DataSource targetDataSource = (DataSource)targetClass.getAnnotation(DataSource.class);
|
||||
DataSource methodDataSource = method.getAnnotation(DataSource.class);
|
||||
if(targetDataSource != null || methodDataSource != null){
|
||||
String value;
|
||||
if(methodDataSource != null){
|
||||
value = methodDataSource.value();
|
||||
}else {
|
||||
value = targetDataSource.value();
|
||||
}
|
||||
|
||||
DynamicContextHolder.push(value);
|
||||
logger.debug("set datasource is {}", value);
|
||||
}
|
||||
|
||||
try {
|
||||
return point.proceed();
|
||||
} finally {
|
||||
DynamicContextHolder.poll();
|
||||
logger.debug("clean datasource");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.commons.dynamic.datasource.config;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
|
||||
/**
|
||||
* 多数据源上下文
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
*/
|
||||
public class DynamicContextHolder {
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final ThreadLocal<Deque<String>> CONTEXT_HOLDER = new ThreadLocal() {
|
||||
@Override
|
||||
protected Object initialValue() {
|
||||
return new ArrayDeque();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获得当前线程数据源
|
||||
*
|
||||
* @return 数据源名称
|
||||
*/
|
||||
public static String peek() {
|
||||
return CONTEXT_HOLDER.get().peek();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前线程数据源
|
||||
*
|
||||
* @param dataSource 数据源名称
|
||||
*/
|
||||
public static void push(String dataSource) {
|
||||
CONTEXT_HOLDER.get().push(dataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空当前线程数据源
|
||||
*/
|
||||
public static void poll() {
|
||||
Deque<String> deque = CONTEXT_HOLDER.get();
|
||||
deque.poll();
|
||||
if (deque.isEmpty()) {
|
||||
CONTEXT_HOLDER.remove();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.commons.dynamic.datasource.config;
|
||||
|
||||
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
|
||||
|
||||
/**
|
||||
* 多数据源
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class DynamicDataSource extends AbstractRoutingDataSource {
|
||||
|
||||
@Override
|
||||
protected Object determineCurrentLookupKey() {
|
||||
return DynamicContextHolder.peek();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.commons.dynamic.datasource.config;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import io.renren.commons.dynamic.datasource.properties.DataSourceProperties;
|
||||
import io.renren.commons.dynamic.datasource.properties.DynamicDataSourceProperties;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 配置多数据源
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(DynamicDataSourceProperties.class)
|
||||
public class DynamicDataSourceConfig {
|
||||
@Autowired
|
||||
private DynamicDataSourceProperties properties;
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties(prefix = "spring.datasource.druid")
|
||||
public DataSourceProperties dataSourceProperties() {
|
||||
return new DataSourceProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DynamicDataSource dynamicDataSource(DataSourceProperties dataSourceProperties) {
|
||||
DynamicDataSource dynamicDataSource = new DynamicDataSource();
|
||||
dynamicDataSource.setTargetDataSources(getDynamicDataSource());
|
||||
|
||||
//默认数据源
|
||||
DruidDataSource defaultDataSource = DynamicDataSourceFactory.buildDruidDataSource(dataSourceProperties);
|
||||
dynamicDataSource.setDefaultTargetDataSource(defaultDataSource);
|
||||
|
||||
return dynamicDataSource;
|
||||
}
|
||||
|
||||
private Map<Object, Object> getDynamicDataSource(){
|
||||
Map<String, DataSourceProperties> dataSourcePropertiesMap = properties.getDatasource();
|
||||
Map<Object, Object> targetDataSources = new HashMap<>(dataSourcePropertiesMap.size());
|
||||
dataSourcePropertiesMap.forEach((k, v) -> {
|
||||
DruidDataSource druidDataSource = DynamicDataSourceFactory.buildDruidDataSource(v);
|
||||
targetDataSources.put(k, druidDataSource);
|
||||
});
|
||||
|
||||
return targetDataSources;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.commons.dynamic.datasource.config;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import io.renren.commons.dynamic.datasource.properties.DataSourceProperties;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* DruidDataSource
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class DynamicDataSourceFactory {
|
||||
|
||||
public static DruidDataSource buildDruidDataSource(DataSourceProperties properties) {
|
||||
DruidDataSource druidDataSource = new DruidDataSource();
|
||||
druidDataSource.setDriverClassName(properties.getDriverClassName());
|
||||
druidDataSource.setUrl(properties.getUrl());
|
||||
druidDataSource.setUsername(properties.getUsername());
|
||||
druidDataSource.setPassword(properties.getPassword());
|
||||
|
||||
druidDataSource.setInitialSize(properties.getInitialSize());
|
||||
druidDataSource.setMaxActive(properties.getMaxActive());
|
||||
druidDataSource.setMinIdle(properties.getMinIdle());
|
||||
druidDataSource.setMaxWait(properties.getMaxWait());
|
||||
druidDataSource.setTimeBetweenEvictionRunsMillis(properties.getTimeBetweenEvictionRunsMillis());
|
||||
druidDataSource.setMinEvictableIdleTimeMillis(properties.getMinEvictableIdleTimeMillis());
|
||||
druidDataSource.setMaxEvictableIdleTimeMillis(properties.getMaxEvictableIdleTimeMillis());
|
||||
druidDataSource.setValidationQuery(properties.getValidationQuery());
|
||||
druidDataSource.setValidationQueryTimeout(properties.getValidationQueryTimeout());
|
||||
druidDataSource.setTestOnBorrow(properties.isTestOnBorrow());
|
||||
druidDataSource.setTestOnReturn(properties.isTestOnReturn());
|
||||
druidDataSource.setPoolPreparedStatements(properties.isPoolPreparedStatements());
|
||||
druidDataSource.setMaxOpenPreparedStatements(properties.getMaxOpenPreparedStatements());
|
||||
druidDataSource.setSharePreparedStatements(properties.isSharePreparedStatements());
|
||||
|
||||
try {
|
||||
// druidDataSource.setFilters(properties.getFilters());
|
||||
druidDataSource.init();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return druidDataSource;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.commons.dynamic.datasource.properties;
|
||||
|
||||
/**
|
||||
* 多数据源属性
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class DataSourceProperties {
|
||||
private String driverClassName;
|
||||
private String url;
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* Druid默认参数
|
||||
*/
|
||||
private int initialSize = 2;
|
||||
private int maxActive = 10;
|
||||
private int minIdle = -1;
|
||||
private long maxWait = 60 * 1000L;
|
||||
private long timeBetweenEvictionRunsMillis = 60 * 1000L;
|
||||
private long minEvictableIdleTimeMillis = 1000L * 60L * 30L;
|
||||
private long maxEvictableIdleTimeMillis = 1000L * 60L * 60L * 7;
|
||||
private String validationQuery = "select 1";
|
||||
private int validationQueryTimeout = -1;
|
||||
private boolean testOnBorrow = false;
|
||||
private boolean testOnReturn = false;
|
||||
private boolean testWhileIdle = true;
|
||||
private boolean poolPreparedStatements = false;
|
||||
private int maxOpenPreparedStatements = -1;
|
||||
private boolean sharePreparedStatements = false;
|
||||
private String filters = "stat,wall";
|
||||
|
||||
public String getDriverClassName() {
|
||||
return driverClassName;
|
||||
}
|
||||
|
||||
public void setDriverClassName(String driverClassName) {
|
||||
this.driverClassName = driverClassName;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public int getInitialSize() {
|
||||
return initialSize;
|
||||
}
|
||||
|
||||
public void setInitialSize(int initialSize) {
|
||||
this.initialSize = initialSize;
|
||||
}
|
||||
|
||||
public int getMaxActive() {
|
||||
return maxActive;
|
||||
}
|
||||
|
||||
public void setMaxActive(int maxActive) {
|
||||
this.maxActive = maxActive;
|
||||
}
|
||||
|
||||
public int getMinIdle() {
|
||||
return minIdle;
|
||||
}
|
||||
|
||||
public void setMinIdle(int minIdle) {
|
||||
this.minIdle = minIdle;
|
||||
}
|
||||
|
||||
public long getMaxWait() {
|
||||
return maxWait;
|
||||
}
|
||||
|
||||
public void setMaxWait(long maxWait) {
|
||||
this.maxWait = maxWait;
|
||||
}
|
||||
|
||||
public long getTimeBetweenEvictionRunsMillis() {
|
||||
return timeBetweenEvictionRunsMillis;
|
||||
}
|
||||
|
||||
public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
|
||||
this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
|
||||
}
|
||||
|
||||
public long getMinEvictableIdleTimeMillis() {
|
||||
return minEvictableIdleTimeMillis;
|
||||
}
|
||||
|
||||
public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
|
||||
this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
|
||||
}
|
||||
|
||||
public long getMaxEvictableIdleTimeMillis() {
|
||||
return maxEvictableIdleTimeMillis;
|
||||
}
|
||||
|
||||
public void setMaxEvictableIdleTimeMillis(long maxEvictableIdleTimeMillis) {
|
||||
this.maxEvictableIdleTimeMillis = maxEvictableIdleTimeMillis;
|
||||
}
|
||||
|
||||
public String getValidationQuery() {
|
||||
return validationQuery;
|
||||
}
|
||||
|
||||
public void setValidationQuery(String validationQuery) {
|
||||
this.validationQuery = validationQuery;
|
||||
}
|
||||
|
||||
public int getValidationQueryTimeout() {
|
||||
return validationQueryTimeout;
|
||||
}
|
||||
|
||||
public void setValidationQueryTimeout(int validationQueryTimeout) {
|
||||
this.validationQueryTimeout = validationQueryTimeout;
|
||||
}
|
||||
|
||||
public boolean isTestOnBorrow() {
|
||||
return testOnBorrow;
|
||||
}
|
||||
|
||||
public void setTestOnBorrow(boolean testOnBorrow) {
|
||||
this.testOnBorrow = testOnBorrow;
|
||||
}
|
||||
|
||||
public boolean isTestOnReturn() {
|
||||
return testOnReturn;
|
||||
}
|
||||
|
||||
public void setTestOnReturn(boolean testOnReturn) {
|
||||
this.testOnReturn = testOnReturn;
|
||||
}
|
||||
|
||||
public boolean isTestWhileIdle() {
|
||||
return testWhileIdle;
|
||||
}
|
||||
|
||||
public void setTestWhileIdle(boolean testWhileIdle) {
|
||||
this.testWhileIdle = testWhileIdle;
|
||||
}
|
||||
|
||||
public boolean isPoolPreparedStatements() {
|
||||
return poolPreparedStatements;
|
||||
}
|
||||
|
||||
public void setPoolPreparedStatements(boolean poolPreparedStatements) {
|
||||
this.poolPreparedStatements = poolPreparedStatements;
|
||||
}
|
||||
|
||||
public int getMaxOpenPreparedStatements() {
|
||||
return maxOpenPreparedStatements;
|
||||
}
|
||||
|
||||
public void setMaxOpenPreparedStatements(int maxOpenPreparedStatements) {
|
||||
this.maxOpenPreparedStatements = maxOpenPreparedStatements;
|
||||
}
|
||||
|
||||
public boolean isSharePreparedStatements() {
|
||||
return sharePreparedStatements;
|
||||
}
|
||||
|
||||
public void setSharePreparedStatements(boolean sharePreparedStatements) {
|
||||
this.sharePreparedStatements = sharePreparedStatements;
|
||||
}
|
||||
|
||||
public String getFilters() {
|
||||
return filters;
|
||||
}
|
||||
|
||||
public void setFilters(String filters) {
|
||||
this.filters = filters;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.commons.dynamic.datasource.properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 多数据源属性
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "dynamic")
|
||||
public class DynamicDataSourceProperties {
|
||||
private Map<String, DataSourceProperties> datasource = new LinkedHashMap<>();
|
||||
|
||||
public Map<String, DataSourceProperties> getDatasource() {
|
||||
return datasource;
|
||||
}
|
||||
|
||||
public void setDatasource(Map<String, DataSourceProperties> datasource) {
|
||||
this.datasource = datasource;
|
||||
}
|
||||
}
|
||||
135
renren-generator/pom.xml
Normal file
135
renren-generator/pom.xml
Normal file
@@ -0,0 +1,135 @@
|
||||
<?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>
|
||||
<groupId>io.renren</groupId>
|
||||
<artifactId>renren-generator</artifactId>
|
||||
<version>5.2.0</version>
|
||||
<packaging>jar</packaging>
|
||||
<description>renren-generator</description>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.7.5</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
<mybatis.spring.boot.version>2.2.2</mybatis.spring.boot.version>
|
||||
<pagehelper.spring.boot.version>1.4.2</pagehelper.spring.boot.version>
|
||||
<druid.version>1.2.14</druid.version>
|
||||
<commons.lang.version>2.6</commons.lang.version>
|
||||
<commons.io.version>2.11.0</commons.io.version>
|
||||
<commons.configuration.version>1.10</commons.configuration.version>
|
||||
<velocity.version>1.7</velocity.version>
|
||||
<mssql.version>4.0</mssql.version>
|
||||
<oracle.version>11.2.0.3</oracle.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>${mybatis.spring.boot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.pagehelper</groupId>
|
||||
<artifactId>pagehelper-spring-boot-starter</artifactId>
|
||||
<version>${pagehelper.spring.boot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid</artifactId>
|
||||
<version>${druid.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<version>${commons.lang.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>${commons.io.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-configuration</groupId>
|
||||
<artifactId>commons-configuration</artifactId>
|
||||
<version>${commons.configuration.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>velocity</artifactId>
|
||||
<groupId>org.apache.velocity</groupId>
|
||||
<version>${velocity.version}</version>
|
||||
</dependency>
|
||||
<!-- mysql驱动 -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
<!-- oracle驱动 -->
|
||||
<dependency>
|
||||
<groupId>com.oracle</groupId>
|
||||
<artifactId>ojdbc6</artifactId>
|
||||
<version>${oracle.version}</version>
|
||||
</dependency>
|
||||
<!-- sqlserver驱动 -->
|
||||
<dependency>
|
||||
<groupId>com.microsoft.sqlserver</groupId>
|
||||
<artifactId>sqljdbc4</artifactId>
|
||||
<version>${mssql.version}</version>
|
||||
</dependency>
|
||||
<!-- postgresql驱动 -->
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<!-- 阿里云maven仓库 -->
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>public</id>
|
||||
<name>aliyun nexus</name>
|
||||
<url>https://maven.aliyun.com/repository/public/</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>public</id>
|
||||
<name>aliyun nexus</name>
|
||||
<url>https://maven.aliyun.com/repository/public/</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* renren-generator
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class GeneratorApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(GeneratorApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.config;
|
||||
|
||||
import io.renren.dao.*;
|
||||
import io.renren.utils.RenException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
/**
|
||||
* 数据库配置
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
*/
|
||||
@Configuration
|
||||
public class DbConfig {
|
||||
@Value("${renren.database: mysql}")
|
||||
private String database;
|
||||
@Autowired
|
||||
private MySQLGeneratorDao mySQLGeneratorDao;
|
||||
@Autowired
|
||||
private OracleGeneratorDao oracleGeneratorDao;
|
||||
@Autowired
|
||||
private SQLServerGeneratorDao sqlServerGeneratorDao;
|
||||
@Autowired
|
||||
private PostgreSQLGeneratorDao postgreSQLGeneratorDao;
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public GeneratorDao getGeneratorDao(){
|
||||
if("mysql".equalsIgnoreCase(database)){
|
||||
return mySQLGeneratorDao;
|
||||
}else if("oracle".equalsIgnoreCase(database)){
|
||||
return oracleGeneratorDao;
|
||||
}else if("sqlserver".equalsIgnoreCase(database)){
|
||||
return sqlServerGeneratorDao;
|
||||
}else if("postgresql".equalsIgnoreCase(database)){
|
||||
return postgreSQLGeneratorDao;
|
||||
}else {
|
||||
throw new RenException("不支持当前数据库:" + database);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.controller;
|
||||
|
||||
import io.renren.service.SysGeneratorService;
|
||||
import io.renren.utils.PageUtils;
|
||||
import io.renren.utils.Query;
|
||||
import io.renren.utils.R;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 代码生成器
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/sys/generator")
|
||||
public class SysGeneratorController {
|
||||
@Autowired
|
||||
private SysGeneratorService sysGeneratorService;
|
||||
|
||||
/**
|
||||
* 列表
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping("/list")
|
||||
public R list(@RequestParam Map<String, Object> params){
|
||||
PageUtils pageUtil = sysGeneratorService.queryList(new Query(params));
|
||||
|
||||
return R.ok().put("page", pageUtil);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成代码
|
||||
*/
|
||||
@RequestMapping("/code")
|
||||
public void code(String tables, HttpServletResponse response) throws IOException{
|
||||
byte[] data = sysGeneratorService.generatorCode(tables.split(","));
|
||||
|
||||
response.reset();
|
||||
response.setHeader("Content-Disposition", "attachment; filename=\"renren.zip\"");
|
||||
response.addHeader("Content-Length", "" + data.length);
|
||||
response.setContentType("application/octet-stream; charset=UTF-8");
|
||||
|
||||
IOUtils.write(data, response.getOutputStream());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.dao;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 数据库接口
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
*/
|
||||
public interface GeneratorDao {
|
||||
List<Map<String, Object>> queryList(Map<String, Object> map);
|
||||
|
||||
Map<String, String> queryTable(String tableName);
|
||||
|
||||
List<Map<String, String>> queryColumns(String tableName);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.dao;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
|
||||
/**
|
||||
* MySQL代码生成器
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
*/
|
||||
@Mapper
|
||||
public interface MySQLGeneratorDao extends GeneratorDao {
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.dao;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* Oracle代码生成器
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
*/
|
||||
@Mapper
|
||||
public interface OracleGeneratorDao extends GeneratorDao {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.dao;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* PostgreSQL代码生成器
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
*/
|
||||
@Mapper
|
||||
public interface PostgreSQLGeneratorDao extends GeneratorDao {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.dao;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* SQLServer代码生成器
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
*/
|
||||
@Mapper
|
||||
public interface SQLServerGeneratorDao extends GeneratorDao {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.entity;
|
||||
|
||||
/**
|
||||
* 列的属性
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
*/
|
||||
public class ColumnEntity {
|
||||
//列名
|
||||
private String columnName;
|
||||
//列名类型
|
||||
private String dataType;
|
||||
//列名备注
|
||||
private String comments;
|
||||
|
||||
//属性名称(第一个字母大写),如:user_name => UserName
|
||||
private String attrName;
|
||||
//属性名称(第一个字母小写),如:user_name => userName
|
||||
private String attrname;
|
||||
//属性类型
|
||||
private String attrType;
|
||||
//auto_increment
|
||||
private String extra;
|
||||
|
||||
public String getColumnName() {
|
||||
return columnName;
|
||||
}
|
||||
public void setColumnName(String columnName) {
|
||||
this.columnName = columnName;
|
||||
}
|
||||
public String getDataType() {
|
||||
return dataType;
|
||||
}
|
||||
public void setDataType(String dataType) {
|
||||
this.dataType = dataType;
|
||||
}
|
||||
public String getComments() {
|
||||
return comments;
|
||||
}
|
||||
public void setComments(String comments) {
|
||||
this.comments = comments;
|
||||
}
|
||||
public String getAttrname() {
|
||||
return attrname;
|
||||
}
|
||||
public void setAttrname(String attrname) {
|
||||
this.attrname = attrname;
|
||||
}
|
||||
public String getAttrName() {
|
||||
return attrName;
|
||||
}
|
||||
public void setAttrName(String attrName) {
|
||||
this.attrName = attrName;
|
||||
}
|
||||
public String getAttrType() {
|
||||
return attrType;
|
||||
}
|
||||
public void setAttrType(String attrType) {
|
||||
this.attrType = attrType;
|
||||
}
|
||||
public String getExtra() {
|
||||
return extra;
|
||||
}
|
||||
public void setExtra(String extra) {
|
||||
this.extra = extra;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.entity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 表数据
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
*/
|
||||
public class TableEntity {
|
||||
//表的名称
|
||||
private String tableName;
|
||||
//表的备注
|
||||
private String comments;
|
||||
//表的主键
|
||||
private ColumnEntity pk;
|
||||
//表的列名(不包含主键)
|
||||
private List<ColumnEntity> columns;
|
||||
|
||||
//类名(第一个字母大写),如:sys_user => SysUser
|
||||
private String className;
|
||||
//类名(第一个字母小写),如:sys_user => sysUser
|
||||
private String classname;
|
||||
|
||||
public String getTableName() {
|
||||
return tableName;
|
||||
}
|
||||
public void setTableName(String tableName) {
|
||||
this.tableName = tableName;
|
||||
}
|
||||
public String getComments() {
|
||||
return comments;
|
||||
}
|
||||
public void setComments(String comments) {
|
||||
this.comments = comments;
|
||||
}
|
||||
public ColumnEntity getPk() {
|
||||
return pk;
|
||||
}
|
||||
public void setPk(ColumnEntity pk) {
|
||||
this.pk = pk;
|
||||
}
|
||||
public List<ColumnEntity> getColumns() {
|
||||
return columns;
|
||||
}
|
||||
public void setColumns(List<ColumnEntity> columns) {
|
||||
this.columns = columns;
|
||||
}
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
public void setClassName(String className) {
|
||||
this.className = className;
|
||||
}
|
||||
public String getClassname() {
|
||||
return classname;
|
||||
}
|
||||
public void setClassname(String classname) {
|
||||
this.classname = classname;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.service;
|
||||
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import io.renren.dao.GeneratorDao;
|
||||
import io.renren.utils.GenUtils;
|
||||
import io.renren.utils.PageUtils;
|
||||
import io.renren.utils.Query;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/**
|
||||
* 代码生成器
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
*/
|
||||
@Service
|
||||
public class SysGeneratorService {
|
||||
@Autowired
|
||||
private GeneratorDao generatorDao;
|
||||
|
||||
public PageUtils queryList(Query query) {
|
||||
Page<?> page = PageHelper.startPage(query.getPage(), query.getLimit());
|
||||
List<Map<String, Object>> list = generatorDao.queryList(query);
|
||||
|
||||
return new PageUtils(list, (int)page.getTotal(), query.getLimit(), query.getPage());
|
||||
}
|
||||
|
||||
public Map<String, String> queryTable(String tableName) {
|
||||
return generatorDao.queryTable(tableName);
|
||||
}
|
||||
|
||||
public List<Map<String, String>> queryColumns(String tableName) {
|
||||
return generatorDao.queryColumns(tableName);
|
||||
}
|
||||
|
||||
public byte[] generatorCode(String[] tableNames) {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
ZipOutputStream zip = new ZipOutputStream(outputStream);
|
||||
|
||||
for(String tableName : tableNames){
|
||||
//查询表信息
|
||||
Map<String, String> table = queryTable(tableName);
|
||||
//查询列信息
|
||||
List<Map<String, String>> columns = queryColumns(tableName);
|
||||
//生成代码
|
||||
GenUtils.generatorCode(table, columns, zip);
|
||||
}
|
||||
IOUtils.closeQuietly(zip);
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
}
|
||||
77
renren-generator/src/main/java/io/renren/utils/Assert.java
Normal file
77
renren-generator/src/main/java/io/renren/utils/Assert.java
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.renren.utils;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 断言类
|
||||
* </p>
|
||||
*
|
||||
* @author miemie
|
||||
* @since 2018-07-24
|
||||
*/
|
||||
public final class Assert {
|
||||
|
||||
/**
|
||||
* 断言这个 boolean 为 true
|
||||
* 为 false 则抛出异常
|
||||
*
|
||||
* @param expression boolean 值
|
||||
* @param message 消息
|
||||
*/
|
||||
public static void isTrue(boolean expression, String message, Object... params) {
|
||||
if (!expression) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 断言这个 boolean 为 false
|
||||
* 为 true 则抛出异常
|
||||
*
|
||||
* @param expression boolean 值
|
||||
* @param message 消息
|
||||
*/
|
||||
public static void isFalse(boolean expression, String message, Object... params) {
|
||||
isTrue(!expression, message, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 断言这个 object 为 null
|
||||
* 不为 null 则抛异常
|
||||
*
|
||||
* @param object 对象
|
||||
* @param message 消息
|
||||
*/
|
||||
public static void isNull(Object object, String message, Object... params) {
|
||||
isTrue(object == null, message, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 断言这个 object 不为 null
|
||||
* 为 null 则抛异常
|
||||
*
|
||||
* @param object 对象
|
||||
* @param message 消息
|
||||
*/
|
||||
public static void notNull(Object object, String message, Object... params) {
|
||||
isTrue(object != null, message, params);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.utils;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 日期处理
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
*/
|
||||
public class DateUtils {
|
||||
/** 时间格式(yyyy-MM-dd) */
|
||||
public final static String DATE_PATTERN = "yyyy-MM-dd";
|
||||
/** 时间格式(yyyy-MM-dd HH:mm:ss) */
|
||||
public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
public static String format(Date date) {
|
||||
return format(date, DATE_PATTERN);
|
||||
}
|
||||
|
||||
public static String format(Date date, String pattern) {
|
||||
if(date != null){
|
||||
SimpleDateFormat df = new SimpleDateFormat(pattern);
|
||||
return df.format(date);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
254
renren-generator/src/main/java/io/renren/utils/GenUtils.java
Normal file
254
renren-generator/src/main/java/io/renren/utils/GenUtils.java
Normal file
@@ -0,0 +1,254 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.utils;
|
||||
|
||||
import io.renren.entity.ColumnEntity;
|
||||
import io.renren.entity.TableEntity;
|
||||
import org.apache.commons.configuration.Configuration;
|
||||
import org.apache.commons.configuration.ConfigurationException;
|
||||
import org.apache.commons.configuration.PropertiesConfiguration;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.WordUtils;
|
||||
import org.apache.velocity.Template;
|
||||
import org.apache.velocity.VelocityContext;
|
||||
import org.apache.velocity.app.Velocity;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.*;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/**
|
||||
* 代码生成器 工具类
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
*/
|
||||
public class GenUtils {
|
||||
|
||||
public static List<String> getTemplates(){
|
||||
List<String> templates = new ArrayList<String>();
|
||||
templates.add("template/DTO.java.vm");
|
||||
templates.add("template/Entity.java.vm");
|
||||
templates.add("template/Dao.java.vm");
|
||||
templates.add("template/Dao.xml.vm");
|
||||
templates.add("template/Service.java.vm");
|
||||
templates.add("template/ServiceImpl.java.vm");
|
||||
templates.add("template/Controller.java.vm");
|
||||
templates.add("template/Excel.java.vm");
|
||||
templates.add("template/index.vue.vm");
|
||||
templates.add("template/add-or-update.vue.vm");
|
||||
templates.add("template/mysql.vm");
|
||||
templates.add("template/sqlserver.vm");
|
||||
templates.add("template/oracle.vm");
|
||||
templates.add("template/postgresql.vm");
|
||||
return templates;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成代码
|
||||
*/
|
||||
public static void generatorCode(Map<String, String> table,
|
||||
List<Map<String, String>> columns, ZipOutputStream zip){
|
||||
//配置信息
|
||||
Configuration config = getConfig();
|
||||
boolean hasBigDecimal = false;
|
||||
//表信息
|
||||
TableEntity tableEntity = new TableEntity();
|
||||
tableEntity.setTableName(table.get("tableName"));
|
||||
tableEntity.setComments(table.get("tableComment"));
|
||||
//表名转换成Java类名
|
||||
String className = tableToJava(tableEntity.getTableName(), config.getString("tablePrefix"));
|
||||
tableEntity.setClassName(className);
|
||||
tableEntity.setClassname(StringUtils.uncapitalize(className));
|
||||
|
||||
//列信息
|
||||
List<ColumnEntity> columnsList = new ArrayList<>();
|
||||
for(Map<String, String> column : columns){
|
||||
ColumnEntity columnEntity = new ColumnEntity();
|
||||
columnEntity.setColumnName(column.get("columnName"));
|
||||
columnEntity.setDataType(column.get("dataType"));
|
||||
columnEntity.setComments(column.get("columnComment"));
|
||||
columnEntity.setExtra(column.get("extra"));
|
||||
|
||||
//列名转换成Java属性名
|
||||
String attrName = columnToJava(columnEntity.getColumnName());
|
||||
columnEntity.setAttrName(attrName);
|
||||
columnEntity.setAttrname(StringUtils.uncapitalize(attrName));
|
||||
|
||||
//列的数据类型,转换成Java类型
|
||||
String attrType = config.getString(columnEntity.getDataType(), "unknowType");
|
||||
columnEntity.setAttrType(attrType);
|
||||
if (!hasBigDecimal && attrType.equals("BigDecimal" )) {
|
||||
hasBigDecimal = true;
|
||||
}
|
||||
//是否主键
|
||||
if("PRI".equalsIgnoreCase(column.get("columnKey")) && tableEntity.getPk() == null){
|
||||
tableEntity.setPk(columnEntity);
|
||||
}
|
||||
|
||||
columnsList.add(columnEntity);
|
||||
}
|
||||
tableEntity.setColumns(columnsList);
|
||||
|
||||
//没主键,则第一个字段为主键
|
||||
if(tableEntity.getPk() == null){
|
||||
tableEntity.setPk(tableEntity.getColumns().get(0));
|
||||
}
|
||||
|
||||
//设置velocity资源加载器
|
||||
Properties prop = new Properties();
|
||||
prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
|
||||
Velocity.init(prop);
|
||||
|
||||
//封装模板数据
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("tableName", tableEntity.getTableName());
|
||||
map.put("comments", tableEntity.getComments());
|
||||
map.put("pk", tableEntity.getPk());
|
||||
map.put("className", tableEntity.getClassName());
|
||||
map.put("classname", tableEntity.getClassname());
|
||||
map.put("pathName", tableEntity.getClassname().toLowerCase());
|
||||
map.put("columns", tableEntity.getColumns());
|
||||
map.put("hasBigDecimal", hasBigDecimal);
|
||||
map.put("version", config.getString("version" ));
|
||||
map.put("package", config.getString("package" ));
|
||||
map.put("moduleName", config.getString("moduleName" ));
|
||||
map.put("author", config.getString("author"));
|
||||
map.put("email", config.getString("email"));
|
||||
map.put("datetime", DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN));
|
||||
map.put("date", DateUtils.format(new Date(), DateUtils.DATE_PATTERN));
|
||||
|
||||
for(int i=0; i<=10; i++){
|
||||
map.put("id"+i, IdWorker.getId());
|
||||
}
|
||||
|
||||
VelocityContext context = new VelocityContext(map);
|
||||
|
||||
//获取模板列表
|
||||
List<String> templates = getTemplates();
|
||||
for(String template : templates){
|
||||
//渲染模板
|
||||
StringWriter sw = new StringWriter();
|
||||
Template tpl = Velocity.getTemplate(template, "UTF-8");
|
||||
tpl.merge(context, sw);
|
||||
|
||||
try {
|
||||
//添加到zip
|
||||
zip.putNextEntry(new ZipEntry(getFileName(template, tableEntity.getClassName(), config.getString("package"), config.getString("moduleName"))));
|
||||
IOUtils.write(sw.toString(), zip, "UTF-8");
|
||||
IOUtils.closeQuietly(sw);
|
||||
zip.closeEntry();
|
||||
} catch (IOException e) {
|
||||
throw new RenException("渲染模板失败,表名:" + tableEntity.getTableName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 列名转换成Java属性名
|
||||
*/
|
||||
public static String columnToJava(String columnName) {
|
||||
return WordUtils.capitalizeFully(columnName, new char[]{'_'}).replace("_", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 表名转换成Java类名
|
||||
*/
|
||||
public static String tableToJava(String tableName, String tablePrefix) {
|
||||
if(StringUtils.isNotBlank(tablePrefix)){
|
||||
tableName = tableName.startsWith(tablePrefix) ? tableName.replaceFirst(tablePrefix, "") : tableName;
|
||||
}
|
||||
return columnToJava(tableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置信息
|
||||
*/
|
||||
public static Configuration getConfig(){
|
||||
try {
|
||||
return new PropertiesConfiguration("generator.properties");
|
||||
} catch (ConfigurationException e) {
|
||||
throw new RenException("获取配置文件失败,", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件名
|
||||
*/
|
||||
public static String getFileName(String template, String className, String packageName, String moduleName) {
|
||||
String packagePath = "main" + File.separator + "java" + File.separator;
|
||||
if (StringUtils.isNotBlank(packageName)) {
|
||||
packagePath += packageName.replace(".", File.separator) + File.separator + "modules" + File.separator + moduleName + File.separator;
|
||||
}
|
||||
|
||||
if (template.contains("Entity.java.vm" )) {
|
||||
return packagePath + "entity" + File.separator + className + "Entity.java";
|
||||
}
|
||||
|
||||
if (template.contains("Excel.java.vm" )) {
|
||||
return packagePath + "excel" + File.separator + className + "Excel.java";
|
||||
}
|
||||
|
||||
if (template.contains("Dao.java.vm" )) {
|
||||
return packagePath + "dao" + File.separator + className + "Dao.java";
|
||||
}
|
||||
|
||||
if (template.contains("Service.java.vm" )) {
|
||||
return packagePath + "service" + File.separator + className + "Service.java";
|
||||
}
|
||||
|
||||
if (template.contains("ServiceImpl.java.vm" )) {
|
||||
return packagePath + "service" + File.separator + "impl" + File.separator + className + "ServiceImpl.java";
|
||||
}
|
||||
|
||||
if (template.contains("Controller.java.vm" )) {
|
||||
return packagePath + "controller" + File.separator + className + "Controller.java";
|
||||
}
|
||||
|
||||
if (template.contains("Dao.xml.vm" )) {
|
||||
return "main" + File.separator + "resources" + File.separator + "mapper" + File.separator + moduleName + File.separator + className + "Dao.xml";
|
||||
}
|
||||
|
||||
if (template.contains("DTO.java.vm" )) {
|
||||
return packagePath + "dto" + File.separator + className + "DTO.java";
|
||||
}
|
||||
|
||||
if (template.contains("index.vue.vm" )) {
|
||||
return "vue" + File.separator + "views" + File.separator + "modules" +
|
||||
File.separator + moduleName + File.separator + className.toLowerCase() + ".vue";
|
||||
}
|
||||
|
||||
if (template.contains("add-or-update.vue.vm" )) {
|
||||
return "vue" + File.separator + "views" + File.separator + "modules" +
|
||||
File.separator + moduleName + File.separator + className.toLowerCase() + "-add-or-update.vue";
|
||||
}
|
||||
|
||||
if (template.contains("mysql.vm" )) {
|
||||
return className.toLowerCase() + ".mysql.sql";
|
||||
}
|
||||
|
||||
if (template.contains("oracle.vm" )) {
|
||||
return className.toLowerCase() + ".oracle.sql";
|
||||
}
|
||||
|
||||
if (template.contains("sqlserver.vm" )) {
|
||||
return className.toLowerCase() + ".sqlserver.sql";
|
||||
}
|
||||
|
||||
if (template.contains("postgresql.vm" )) {
|
||||
return className.toLowerCase() + ".postgresql.sql";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
67
renren-generator/src/main/java/io/renren/utils/IdWorker.java
Normal file
67
renren-generator/src/main/java/io/renren/utils/IdWorker.java
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2020, hubin (jobob@qq.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package io.renren.utils;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 高效GUID产生算法(sequence),基于Snowflake实现64位自增ID算法。 <br>
|
||||
* 优化开源项目 http://git.oschina.net/yu120/sequence
|
||||
* </p>
|
||||
*
|
||||
* @author hubin
|
||||
* @since 2016-08-01
|
||||
*/
|
||||
public class IdWorker {
|
||||
|
||||
/**
|
||||
* 主机和进程的机器码
|
||||
*/
|
||||
private static Sequence WORKER = new Sequence();
|
||||
|
||||
public static long getId() {
|
||||
return WORKER.nextId();
|
||||
}
|
||||
|
||||
public static String getIdStr() {
|
||||
return String.valueOf(WORKER.nextId());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 有参构造器
|
||||
* </p>
|
||||
*
|
||||
* @param workerId 工作机器 ID
|
||||
* @param datacenterId 序列号
|
||||
*/
|
||||
public static void initSequence(long workerId, long datacenterId) {
|
||||
WORKER = new Sequence(workerId, datacenterId);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 使用ThreadLocalRandom获取UUID获取更优的效果 去掉"-"
|
||||
* </p>
|
||||
*/
|
||||
public static String get32UUID() {
|
||||
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||
return new UUID(random.nextLong(), random.nextLong()).toString().replace(StringPool.DASH, StringPool.EMPTY);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.utils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 分页工具类
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
*/
|
||||
public class PageUtils implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
//总记录数
|
||||
private int totalCount;
|
||||
//每页记录数
|
||||
private int pageSize;
|
||||
//总页数
|
||||
private int totalPage;
|
||||
//当前页数
|
||||
private int currPage;
|
||||
//列表数据
|
||||
private List<?> list;
|
||||
|
||||
/**
|
||||
* 分页
|
||||
* @param list 列表数据
|
||||
* @param totalCount 总记录数
|
||||
* @param pageSize 每页记录数
|
||||
* @param currPage 当前页数
|
||||
*/
|
||||
public PageUtils(List<?> list, int totalCount, int pageSize, int currPage) {
|
||||
this.list = list;
|
||||
this.totalCount = totalCount;
|
||||
this.pageSize = pageSize;
|
||||
this.currPage = currPage;
|
||||
this.totalPage = (int)Math.ceil((double)totalCount/pageSize);
|
||||
}
|
||||
|
||||
public int getTotalCount() {
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
public void setTotalCount(int totalCount) {
|
||||
this.totalCount = totalCount;
|
||||
}
|
||||
|
||||
public int getPageSize() {
|
||||
return pageSize;
|
||||
}
|
||||
|
||||
public void setPageSize(int pageSize) {
|
||||
this.pageSize = pageSize;
|
||||
}
|
||||
|
||||
public int getTotalPage() {
|
||||
return totalPage;
|
||||
}
|
||||
|
||||
public void setTotalPage(int totalPage) {
|
||||
this.totalPage = totalPage;
|
||||
}
|
||||
|
||||
public int getCurrPage() {
|
||||
return currPage;
|
||||
}
|
||||
|
||||
public void setCurrPage(int currPage) {
|
||||
this.currPage = currPage;
|
||||
}
|
||||
|
||||
public List<?> getList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
public void setList(List<?> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
}
|
||||
53
renren-generator/src/main/java/io/renren/utils/Query.java
Normal file
53
renren-generator/src/main/java/io/renren/utils/Query.java
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.utils;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 查询参数
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
*/
|
||||
public class Query extends LinkedHashMap<String, Object> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
//当前页码
|
||||
private int page;
|
||||
//每页条数
|
||||
private int limit;
|
||||
|
||||
public Query(Map<String, Object> params){
|
||||
this.putAll(params);
|
||||
|
||||
//分页参数
|
||||
this.page = Integer.parseInt(params.get("page").toString());
|
||||
this.limit = Integer.parseInt(params.get("limit").toString());
|
||||
this.put("offset", (page - 1) * limit);
|
||||
this.put("page", page);
|
||||
this.put("limit", limit);
|
||||
}
|
||||
|
||||
|
||||
public int getPage() {
|
||||
return page;
|
||||
}
|
||||
|
||||
public void setPage(int page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
public int getLimit() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
public void setLimit(int limit) {
|
||||
this.limit = limit;
|
||||
}
|
||||
}
|
||||
62
renren-generator/src/main/java/io/renren/utils/R.java
Normal file
62
renren-generator/src/main/java/io/renren/utils/R.java
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.utils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 返回数据
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
*/
|
||||
public class R extends HashMap<String, Object> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public R() {
|
||||
put("code", 0);
|
||||
}
|
||||
|
||||
public static R error() {
|
||||
return error(500, "未知异常,请联系管理员");
|
||||
}
|
||||
|
||||
public static R error(String msg) {
|
||||
return error(500, msg);
|
||||
}
|
||||
|
||||
public static R error(int code, String msg) {
|
||||
R r = new R();
|
||||
r.put("code", code);
|
||||
r.put("msg", msg);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static R ok(String msg) {
|
||||
R r = new R();
|
||||
r.put("msg", msg);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static R ok(Map<String, Object> map) {
|
||||
R r = new R();
|
||||
r.putAll(map);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static R ok() {
|
||||
return new R();
|
||||
}
|
||||
|
||||
@Override
|
||||
public R put(String key, Object value) {
|
||||
super.put(key, value);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.utils;
|
||||
|
||||
/**
|
||||
* 自定义异常
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
*/
|
||||
public class RenException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String msg;
|
||||
private int code = 500;
|
||||
|
||||
public RenException(String msg) {
|
||||
super(msg);
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public RenException(String msg, Throwable e) {
|
||||
super(msg, e);
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public RenException(String msg, int code) {
|
||||
super(msg);
|
||||
this.msg = msg;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public RenException(String msg, int code, Throwable e) {
|
||||
super(msg, e);
|
||||
this.msg = msg;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2018 人人开源 All rights reserved.
|
||||
*
|
||||
* https://www.renren.io
|
||||
*
|
||||
* 版权所有,侵权必究!
|
||||
*/
|
||||
|
||||
package io.renren.utils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
/**
|
||||
* 异常处理器
|
||||
*
|
||||
* @author Mark sunlightcs@gmail.com
|
||||
*/
|
||||
@RestControllerAdvice
|
||||
public class RenExceptionHandler {
|
||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
/**
|
||||
* 处理自定义异常
|
||||
*/
|
||||
@ExceptionHandler(RenException.class)
|
||||
public R handleRenException(RenException e){
|
||||
R r = new R();
|
||||
r.put("code", e.getCode());
|
||||
r.put("msg", e.getMessage());
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public R handleException(Exception e){
|
||||
logger.error(e.getMessage(), e);
|
||||
return R.error();
|
||||
}
|
||||
}
|
||||
203
renren-generator/src/main/java/io/renren/utils/Sequence.java
Normal file
203
renren-generator/src/main/java/io/renren/utils/Sequence.java
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2020, hubin (jobob@qq.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package io.renren.utils;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.ibatis.logging.Log;
|
||||
import org.apache.ibatis.logging.LogFactory;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 分布式高效有序ID生产黑科技(sequence) <br>
|
||||
* 优化开源项目:http://git.oschina.net/yu120/sequence
|
||||
* </p>
|
||||
*
|
||||
* @author hubin
|
||||
* @since 2016-08-18
|
||||
*/
|
||||
public class Sequence {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(Sequence.class);
|
||||
/**
|
||||
* 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
|
||||
*/
|
||||
private final long twepoch = 1288834974657L;
|
||||
/**
|
||||
* 机器标识位数
|
||||
*/
|
||||
private final long workerIdBits = 5L;
|
||||
private final long datacenterIdBits = 5L;
|
||||
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
|
||||
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
|
||||
/**
|
||||
* 毫秒内自增位
|
||||
*/
|
||||
private final long sequenceBits = 12L;
|
||||
private final long workerIdShift = sequenceBits;
|
||||
private final long datacenterIdShift = sequenceBits + workerIdBits;
|
||||
/**
|
||||
* 时间戳左移动位
|
||||
*/
|
||||
private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
|
||||
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
|
||||
|
||||
private final long workerId;
|
||||
|
||||
/**
|
||||
* 数据标识 ID 部分
|
||||
*/
|
||||
private final long datacenterId;
|
||||
/**
|
||||
* 并发控制
|
||||
*/
|
||||
private long sequence = 0L;
|
||||
/**
|
||||
* 上次生产 ID 时间戳
|
||||
*/
|
||||
private long lastTimestamp = -1L;
|
||||
|
||||
public Sequence() {
|
||||
this.datacenterId = getDatacenterId(maxDatacenterId);
|
||||
this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 有参构造器
|
||||
* </p>
|
||||
*
|
||||
* @param workerId 工作机器 ID
|
||||
* @param datacenterId 序列号
|
||||
*/
|
||||
public Sequence(long workerId, long datacenterId) {
|
||||
Assert.isFalse(workerId > maxWorkerId || workerId < 0,
|
||||
String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
|
||||
Assert.isFalse(datacenterId > maxDatacenterId || datacenterId < 0,
|
||||
String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
|
||||
this.workerId = workerId;
|
||||
this.datacenterId = datacenterId;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 获取 maxWorkerId
|
||||
* </p>
|
||||
*/
|
||||
protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
|
||||
StringBuilder mpid = new StringBuilder();
|
||||
mpid.append(datacenterId);
|
||||
String name = ManagementFactory.getRuntimeMXBean().getName();
|
||||
if (StringUtils.isNotEmpty(name)) {
|
||||
/*
|
||||
* GET jvmPid
|
||||
*/
|
||||
mpid.append(name.split(StringPool.AT)[0]);
|
||||
}
|
||||
/*
|
||||
* MAC + PID 的 hashcode 获取16个低位
|
||||
*/
|
||||
return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 数据标识id部分
|
||||
* </p>
|
||||
*/
|
||||
protected static long getDatacenterId(long maxDatacenterId) {
|
||||
long id = 0L;
|
||||
try {
|
||||
InetAddress ip = InetAddress.getLocalHost();
|
||||
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
|
||||
if (network == null) {
|
||||
id = 1L;
|
||||
} else {
|
||||
byte[] mac = network.getHardwareAddress();
|
||||
if (null != mac) {
|
||||
id = ((0x000000FF & (long) mac[mac.length - 1]) | (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
|
||||
id = id % (maxDatacenterId + 1);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn(" getDatacenterId: " + e.getMessage());
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下一个ID
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public synchronized long nextId() {
|
||||
long timestamp = timeGen();
|
||||
//闰秒
|
||||
if (timestamp < lastTimestamp) {
|
||||
long offset = lastTimestamp - timestamp;
|
||||
if (offset <= 5) {
|
||||
try {
|
||||
wait(offset << 1);
|
||||
timestamp = timeGen();
|
||||
if (timestamp < lastTimestamp) {
|
||||
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", offset));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", offset));
|
||||
}
|
||||
}
|
||||
|
||||
if (lastTimestamp == timestamp) {
|
||||
// 相同毫秒内,序列号自增
|
||||
sequence = (sequence + 1) & sequenceMask;
|
||||
if (sequence == 0) {
|
||||
// 同一毫秒的序列数已经达到最大
|
||||
timestamp = tilNextMillis(lastTimestamp);
|
||||
}
|
||||
} else {
|
||||
// 不同毫秒内,序列号置为 1 - 3 随机数
|
||||
sequence = ThreadLocalRandom.current().nextLong(1, 3);
|
||||
}
|
||||
|
||||
lastTimestamp = timestamp;
|
||||
|
||||
// 时间戳部分 | 数据中心部分 | 机器标识部分 | 序列号部分
|
||||
return ((timestamp - twepoch) << timestampLeftShift)
|
||||
| (datacenterId << datacenterIdShift)
|
||||
| (workerId << workerIdShift)
|
||||
| sequence;
|
||||
}
|
||||
|
||||
protected long tilNextMillis(long lastTimestamp) {
|
||||
long timestamp = timeGen();
|
||||
while (timestamp <= lastTimestamp) {
|
||||
timestamp = timeGen();
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
protected long timeGen() {
|
||||
return SystemClock.now();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package io.renren.utils;
|
||||
|
||||
/**
|
||||
* Copy to jodd.util
|
||||
* <p>
|
||||
* Pool of <code>String</code> constants to prevent repeating of
|
||||
* hard-coded <code>String</code> literals in the code.
|
||||
* Due to fact that these are <code>public static final</code>
|
||||
* they will be inlined by java compiler and
|
||||
* reference to this class will be dropped.
|
||||
* There is <b>no</b> performance gain of using this pool.
|
||||
* Read: http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#3.10.5
|
||||
* <ul>
|
||||
* <li>Literal strings within the same class in the same package represent references to the same <code>String</code> object.</li>
|
||||
* <li>Literal strings within different classes in the same package represent references to the same <code>String</code> object.</li>
|
||||
* <li>Literal strings within different classes in different packages likewise represent references to the same <code>String</code> object.</li>
|
||||
* <li>Strings computed by constant expressions are computed at compile time and then treated as if they were literals.</li>
|
||||
* <li>Strings computed by concatenation at run time are newly created and therefore distinct.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public interface StringPool {
|
||||
|
||||
String AMPERSAND = "&";
|
||||
String AND = "and";
|
||||
String AT = "@";
|
||||
String ASTERISK = "*";
|
||||
String STAR = ASTERISK;
|
||||
String BACK_SLASH = "\\";
|
||||
String COLON = ":";
|
||||
String COMMA = ",";
|
||||
String DASH = "-";
|
||||
String DOLLAR = "$";
|
||||
String DOT = ".";
|
||||
String DOTDOT = "..";
|
||||
String DOT_CLASS = ".class";
|
||||
String DOT_JAVA = ".java";
|
||||
String DOT_XML = ".xml";
|
||||
String EMPTY = "";
|
||||
String EQUALS = "=";
|
||||
String FALSE = "false";
|
||||
String SLASH = "/";
|
||||
String HASH = "#";
|
||||
String HAT = "^";
|
||||
String LEFT_BRACE = "{";
|
||||
String LEFT_BRACKET = "(";
|
||||
String LEFT_CHEV = "<";
|
||||
String NEWLINE = "\n";
|
||||
String N = "n";
|
||||
String NO = "no";
|
||||
String NULL = "null";
|
||||
String OFF = "off";
|
||||
String ON = "on";
|
||||
String PERCENT = "%";
|
||||
String PIPE = "|";
|
||||
String PLUS = "+";
|
||||
String QUESTION_MARK = "?";
|
||||
String EXCLAMATION_MARK = "!";
|
||||
String QUOTE = "\"";
|
||||
String RETURN = "\r";
|
||||
String TAB = "\t";
|
||||
String RIGHT_BRACE = "}";
|
||||
String RIGHT_BRACKET = ")";
|
||||
String RIGHT_CHEV = ">";
|
||||
String SEMICOLON = ";";
|
||||
String SINGLE_QUOTE = "'";
|
||||
String BACKTICK = "`";
|
||||
String SPACE = " ";
|
||||
String TILDA = "~";
|
||||
String LEFT_SQ_BRACKET = "[";
|
||||
String RIGHT_SQ_BRACKET = "]";
|
||||
String TRUE = "true";
|
||||
String UNDERSCORE = "_";
|
||||
String UTF_8 = "UTF-8";
|
||||
String US_ASCII = "US-ASCII";
|
||||
String ISO_8859_1 = "ISO-8859-1";
|
||||
String Y = "y";
|
||||
String YES = "yes";
|
||||
String ONE = "1";
|
||||
String ZERO = "0";
|
||||
String DOLLAR_LEFT_BRACE = "${";
|
||||
String HASH_LEFT_BRACE = "#{";
|
||||
String CRLF = "\r\n";
|
||||
|
||||
String HTML_NBSP = " ";
|
||||
String HTML_AMP = "&";
|
||||
String HTML_QUOTE = """;
|
||||
String HTML_LT = "<";
|
||||
String HTML_GT = ">";
|
||||
|
||||
// ---------------------------------------------------------------- array
|
||||
|
||||
String[] EMPTY_ARRAY = new String[0];
|
||||
|
||||
byte[] BYTES_NEW_LINE = StringPool.NEWLINE.getBytes();
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2020, hubin (jobob@qq.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package io.renren.utils;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 高并发场景下System.currentTimeMillis()的性能问题的优化
|
||||
* </p>
|
||||
* <p>
|
||||
* System.currentTimeMillis()的调用比new一个普通对象要耗时的多(具体耗时高出多少我还没测试过,有人说是100倍左右)<br>
|
||||
* System.currentTimeMillis()之所以慢是因为去跟系统打了一次交道<br>
|
||||
* 后台定时更新时钟,JVM退出时,线程自动回收<br>
|
||||
* 10亿:43410,206,210.72815533980582%<br>
|
||||
* 1亿:4699,29,162.0344827586207%<br>
|
||||
* 1000万:480,12,40.0%<br>
|
||||
* 100万:50,10,5.0%<br>
|
||||
* </p>
|
||||
*
|
||||
* @author hubin
|
||||
* @since 2016-08-01
|
||||
*/
|
||||
public class SystemClock {
|
||||
|
||||
private final long period;
|
||||
private final AtomicLong now;
|
||||
|
||||
private SystemClock(long period) {
|
||||
this.period = period;
|
||||
this.now = new AtomicLong(System.currentTimeMillis());
|
||||
scheduleClockUpdating();
|
||||
}
|
||||
|
||||
private static SystemClock instance() {
|
||||
return InstanceHolder.INSTANCE;
|
||||
}
|
||||
|
||||
public static long now() {
|
||||
return instance().currentTimeMillis();
|
||||
}
|
||||
|
||||
public static String nowDate() {
|
||||
return new Timestamp(instance().currentTimeMillis()).toString();
|
||||
}
|
||||
|
||||
private void scheduleClockUpdating() {
|
||||
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(runnable -> {
|
||||
Thread thread = new Thread(runnable, "System Clock");
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
});
|
||||
scheduler.scheduleAtFixedRate(() -> now.set(System.currentTimeMillis()), period, period, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private long currentTimeMillis() {
|
||||
return now.get();
|
||||
}
|
||||
|
||||
private static class InstanceHolder {
|
||||
public static final SystemClock INSTANCE = new SystemClock(1);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user