feat: productionize raw history ingestion

This commit is contained in:
lingniu
2026-06-30 23:21:58 +08:00
parent 3cc7ac9669
commit cbba617801
100 changed files with 2995 additions and 1697 deletions

View File

@@ -1,70 +1,64 @@
package com.lingniu.ingest.identity;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lingniu.ingest.api.ProtocolId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.lingniu.ingest.identity.config.VehicleIdentityProperties;
import org.springframework.jdbc.core.ConnectionCallback;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
import java.time.Duration;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.Map;
public final class MySqlVehicleIdentityService implements VehicleIdentityResolver, VehicleIdentityRegistry, AutoCloseable {
public final class MySqlVehicleIdentityService implements VehicleIdentityResolver, VehicleIdentityRegistry {
private static final Logger log = LoggerFactory.getLogger(MySqlVehicleIdentityService.class);
private final JdbcTemplate jdbc;
private final ObjectMapper mapper;
private final String tableName;
private final DataSource dataSource;
private final String table;
private final String registrationTable;
private final ScheduledExecutorService refresher;
private volatile InMemoryVehicleIdentityService index;
public MySqlVehicleIdentityService(DataSource dataSource, String table) {
this(dataSource, table, Duration.ZERO);
}
public MySqlVehicleIdentityService(DataSource dataSource, String table, Duration refreshInterval) {
if (dataSource == null) {
throw new IllegalArgumentException("dataSource must not be null");
public MySqlVehicleIdentityService(DataSource dataSource,
VehicleIdentityProperties.Mysql properties,
ObjectMapper mapper) {
this.jdbc = new JdbcTemplate(dataSource);
this.mapper = mapper == null ? new ObjectMapper() : mapper;
VehicleIdentityProperties.Mysql mysql = properties == null ? new VehicleIdentityProperties.Mysql() : properties;
this.tableName = safeTableName(mysql.getTableName());
if (mysql.isInitializeSchema()) {
initializeSchema();
}
this.dataSource = dataSource;
this.table = sanitizeTable(table);
this.registrationTable = this.table + "_registration";
initializeSchema();
this.index = loadIndex();
this.refresher = startRefresher(refreshInterval);
}
@Override
public void bind(VehicleIdentityBinding binding) {
if (binding == null || !binding.hasResolvedVin()) {
return;
}
upsert(binding.plate(), binding.vin());
index.bind(binding);
}
@Override
public void register(VehicleRegistrationBinding registration) {
if (registration == null) {
return;
}
upsertRegistration(registration);
if (registration.hasResolvedVin()) {
bind(new VehicleIdentityBinding(
registration.protocol(),
registration.vin(),
registration.phone(),
registration.deviceId(),
registration.plate()));
}
String metadataJson = metadataJson(binding.metadata());
jdbc.update("""
INSERT INTO %s
(protocol, vin, phone, device_id, plate, province, city, maker, device_type, plate_color, metadata_json,
created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
ON DUPLICATE KEY UPDATE
vin = VALUES(vin),
device_id = VALUES(device_id),
province = VALUES(province),
city = VALUES(city),
maker = VALUES(maker),
device_type = VALUES(device_type),
plate_color = VALUES(plate_color),
metadata_json = VALUES(metadata_json),
updated_at = CURRENT_TIMESTAMP
""".formatted(tableName),
protocol(binding.protocol()), binding.vin(), binding.phone(), binding.deviceId(), binding.plate(),
binding.metadata().getOrDefault("province", ""),
binding.metadata().getOrDefault("city", ""),
binding.metadata().getOrDefault("maker", ""),
binding.metadata().getOrDefault("deviceType", ""),
binding.metadata().getOrDefault("plateColor", ""),
metadataJson);
}
@Override
@@ -72,223 +66,167 @@ public final class MySqlVehicleIdentityService implements VehicleIdentityResolve
if (lookup == null) {
return new VehicleIdentity("unknown", false, VehicleIdentitySource.UNKNOWN);
}
return index.resolve(lookup);
}
public void refresh() {
index = loadIndex();
}
@Override
public void close() {
if (refresher != null) {
refresher.shutdownNow();
if (!lookup.vin().isBlank()) {
return new VehicleIdentity(lookup.vin(), true, VehicleIdentitySource.EXPLICIT_VIN);
}
VehicleIdentity byPhone = resolveBy("phone", lookup.protocol(), lookup.phone(), VehicleIdentitySource.BOUND_PHONE);
if (byPhone != null) {
return byPhone;
}
VehicleIdentity byDevice = resolveBy("device_id", lookup.protocol(), lookup.deviceId(), VehicleIdentitySource.BOUND_DEVICE_ID);
if (byDevice != null) {
return byDevice;
}
VehicleIdentity byPlate = resolveBy("plate", lookup.protocol(), lookup.plate(), VehicleIdentitySource.BOUND_PLATE);
if (byPlate != null) {
return byPlate;
}
if (!lookup.deviceId().isBlank()) {
return new VehicleIdentity(lookup.deviceId(), false, VehicleIdentitySource.FALLBACK_DEVICE_ID);
}
if (!lookup.phone().isBlank()) {
return new VehicleIdentity(lookup.phone(), false, VehicleIdentitySource.FALLBACK_PHONE);
}
if (!lookup.plate().isBlank()) {
return new VehicleIdentity(lookup.plate(), false, VehicleIdentitySource.FALLBACK_PLATE);
}
return new VehicleIdentity("unknown", false, VehicleIdentitySource.UNKNOWN);
}
private VehicleIdentity resolveBy(String column, ProtocolId protocol, String externalId, VehicleIdentitySource source) {
if (externalId == null || externalId.isBlank()) {
return null;
}
String safeColumn = switch (column) {
case "phone", "device_id", "plate" -> column;
default -> throw new IllegalArgumentException("unsupported identity lookup column: " + column);
};
List<VehicleIdentity> matches = jdbc.query("""
SELECT vin
FROM %s
WHERE protocol = ? AND %s = ?
ORDER BY updated_at DESC
LIMIT 1
""".formatted(tableName, safeColumn),
(rs, rowNum) -> identity(rs, source),
protocol(protocol), externalId.trim());
return matches.isEmpty() ? null : matches.getFirst();
}
private VehicleIdentity identity(ResultSet rs, VehicleIdentitySource source) throws SQLException {
return new VehicleIdentity(rs.getString("vin"), true, source);
}
private void initializeSchema() {
String sql = """
jdbc.execute("""
CREATE TABLE IF NOT EXISTS %s (
plate VARCHAR(128) NOT NULL,
vin VARCHAR(64) NOT NULL,
PRIMARY KEY (plate),
KEY idx_vehicle_identity_vin (vin)
id BIGINT AUTO_INCREMENT PRIMARY KEY,
protocol VARCHAR(32) NOT NULL,
vin VARCHAR(32) NOT NULL,
phone VARCHAR(64) NOT NULL DEFAULT '',
device_id VARCHAR(64) NOT NULL DEFAULT '',
plate VARCHAR(64) NOT NULL DEFAULT '',
province VARCHAR(32) NOT NULL DEFAULT '',
city VARCHAR(32) NOT NULL DEFAULT '',
maker VARCHAR(64) NOT NULL DEFAULT '',
device_type VARCHAR(128) NOT NULL DEFAULT '',
plate_color VARCHAR(32) NOT NULL DEFAULT '',
metadata_json TEXT,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uk_vehicle_identity_protocol_phone (protocol, phone),
KEY idx_vehicle_identity_protocol_device (protocol, device_id),
KEY idx_vehicle_identity_protocol_plate (protocol, plate)
)
""".formatted(table);
String registrationSql = """
CREATE TABLE IF NOT EXISTS %s (
protocol VARCHAR(32) NOT NULL,
phone VARCHAR(64) NOT NULL,
vin VARCHAR(64) NOT NULL DEFAULT 'unknown',
device_id VARCHAR(128) NOT NULL DEFAULT '',
plate VARCHAR(128) NOT NULL DEFAULT '',
province INT NULL,
city INT NULL,
maker VARCHAR(64) NOT NULL DEFAULT '',
device_type VARCHAR(128) NOT NULL DEFAULT '',
plate_color INT NULL,
last_registered_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (protocol, phone),
KEY idx_vehicle_registration_vin (vin),
KEY idx_vehicle_registration_device (protocol, device_id),
KEY idx_vehicle_registration_plate (protocol, plate)
)
""".formatted(registrationTable);
try (Connection connection = dataSource.getConnection();
Statement statement = connection.createStatement()) {
statement.execute(sql);
statement.execute(registrationSql);
} catch (SQLException e) {
throw new IllegalStateException("vehicle identity mysql schema initialize failed: " + table, e);
""".formatted(tableName));
ensureColumn("phone", "phone VARCHAR(64) NOT NULL DEFAULT ''");
ensureColumn("device_id", "device_id VARCHAR(64) NOT NULL DEFAULT ''");
ensureColumn("plate", "plate VARCHAR(64) NOT NULL DEFAULT ''");
ensureColumn("province", "province VARCHAR(32) NOT NULL DEFAULT ''");
ensureColumn("city", "city VARCHAR(32) NOT NULL DEFAULT ''");
ensureColumn("maker", "maker VARCHAR(64) NOT NULL DEFAULT ''");
ensureColumn("device_type", "device_type VARCHAR(128) NOT NULL DEFAULT ''");
ensureColumn("plate_color", "plate_color VARCHAR(32) NOT NULL DEFAULT ''");
ensureColumn("metadata_json", "metadata_json TEXT");
ensureColumn("created_at", "created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP");
ensureColumn("updated_at", "updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP");
ensureIndex("idx_vehicle_identity_protocol_device", "CREATE INDEX idx_vehicle_identity_protocol_device ON %s (protocol, device_id)");
ensureIndex("idx_vehicle_identity_protocol_plate", "CREATE INDEX idx_vehicle_identity_protocol_plate ON %s (protocol, plate)");
}
private void ensureColumn(String columnName, String definition) {
if (!columnExists(columnName)) {
jdbc.execute("ALTER TABLE " + tableName + " ADD COLUMN " + definition);
}
}
private InMemoryVehicleIdentityService loadIndex() {
InMemoryVehicleIdentityService loaded = new InMemoryVehicleIdentityService();
String sql = "SELECT plate, vin FROM " + table;
try (Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement(sql);
ResultSet resultSet = statement.executeQuery()) {
while (resultSet.next()) {
bindGlobalPlate(loaded, resultSet.getString("vin"), resultSet.getString("plate"));
private boolean columnExists(String columnName) {
return Boolean.TRUE.equals(jdbc.execute((ConnectionCallback<Boolean>) connection -> {
DatabaseMetaData metaData = connection.getMetaData();
for (String table : nameVariants(tableName)) {
for (String column : nameVariants(columnName)) {
try (ResultSet rs = metaData.getColumns(null, null, table, column)) {
if (rs.next()) {
return true;
}
}
}
}
loadRegistrationIndex(loaded, connection);
return loaded;
} catch (SQLException e) {
throw new IllegalStateException("vehicle identity mysql index load failed: " + table, e);
return false;
}));
}
private void ensureIndex(String indexName, String ddlTemplate) {
if (!indexExists(indexName)) {
jdbc.execute(ddlTemplate.formatted(tableName));
}
}
private static void bindGlobalPlate(InMemoryVehicleIdentityService loaded, String vin, String plate) {
for (ProtocolId protocol : new ProtocolId[]{
ProtocolId.GB32960,
ProtocolId.JT808,
ProtocolId.MQTT_YUTONG,
ProtocolId.XINDA_PUSH
}) {
loaded.bind(new VehicleIdentityBinding(protocol, vin, "", "", plate));
}
}
private void loadRegistrationIndex(InMemoryVehicleIdentityService loaded, Connection connection) throws SQLException {
String sql = "SELECT r.protocol, r.phone, r.device_id, r.plate, b.vin FROM " + registrationTable + " r "
+ "JOIN " + table + " b ON b.plate = r.plate "
+ "WHERE b.vin IS NOT NULL AND b.vin <> '' AND LOWER(b.vin) <> 'unknown'";
try (PreparedStatement statement = connection.prepareStatement(sql);
ResultSet resultSet = statement.executeQuery()) {
while (resultSet.next()) {
loaded.bind(new VehicleIdentityBinding(
protocol(resultSet.getString("protocol")),
resultSet.getString("vin"),
resultSet.getString("phone"),
resultSet.getString("device_id"),
resultSet.getString("plate")));
private boolean indexExists(String indexName) {
return Boolean.TRUE.equals(jdbc.execute((ConnectionCallback<Boolean>) connection -> {
DatabaseMetaData metaData = connection.getMetaData();
for (String table : nameVariants(tableName)) {
try (ResultSet rs = metaData.getIndexInfo(null, null, table, false, false)) {
while (rs.next()) {
String existing = rs.getString("INDEX_NAME");
if (existing != null && existing.equalsIgnoreCase(indexName)) {
return true;
}
}
}
}
}
loadLegacyRegistrationVinIndex(loaded, connection);
return false;
}));
}
private void loadLegacyRegistrationVinIndex(InMemoryVehicleIdentityService loaded, Connection connection) throws SQLException {
String sql = "SELECT protocol, phone, device_id, plate, vin FROM " + registrationTable
+ " WHERE vin IS NOT NULL AND vin <> '' AND LOWER(vin) <> 'unknown'";
try (PreparedStatement statement = connection.prepareStatement(sql);
ResultSet resultSet = statement.executeQuery()) {
while (resultSet.next()) {
loaded.bind(new VehicleIdentityBinding(
protocol(resultSet.getString("protocol")),
resultSet.getString("vin"),
resultSet.getString("phone"),
resultSet.getString("device_id"),
resultSet.getString("plate")));
}
}
private static String[] nameVariants(String name) {
return new String[]{
name,
name.toLowerCase(Locale.ROOT),
name.toUpperCase(Locale.ROOT)
};
}
private ScheduledExecutorService startRefresher(Duration refreshInterval) {
if (refreshInterval == null || refreshInterval.isZero() || refreshInterval.isNegative()) {
return null;
private String metadataJson(Map<String, String> metadata) {
if (metadata == null || metadata.isEmpty()) {
return "{}";
}
long delayMillis = Math.max(refreshInterval.toMillis(), 1000L);
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(r -> {
Thread t = new Thread(r, "vehicle-identity-mysql-refresh");
t.setDaemon(true);
return t;
});
executor.scheduleWithFixedDelay(this::safeRefresh, delayMillis, delayMillis, TimeUnit.MILLISECONDS);
return executor;
}
private void safeRefresh() {
try {
refresh();
} catch (RuntimeException e) {
log.warn("vehicle identity mysql refresh failed table={}", table, e);
return mapper.writeValueAsString(metadata);
} catch (JsonProcessingException e) {
throw new IllegalArgumentException("vehicle identity metadata serialize failed", e);
}
}
private void upsert(String plate, String vin) {
String normalizedPlate = normalize(plate);
if (normalizedPlate.isBlank()) {
return;
}
String sql = "INSERT INTO " + table + " (plate, vin) "
+ "VALUES (?, ?) "
+ "ON DUPLICATE KEY UPDATE vin = VALUES(vin)";
try (Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setString(1, normalizedPlate);
statement.setString(2, vin.trim());
statement.executeUpdate();
} catch (SQLException e) {
throw new IllegalStateException("vehicle identity mysql bind failed: " + table, e);
}
}
private void upsertRegistration(VehicleRegistrationBinding registration) {
String phone = normalize(registration.phone());
if (phone.isBlank()) {
return;
}
String vin = registration.hasResolvedVin() ? registration.vin().trim() : "unknown";
String sql = "INSERT INTO " + registrationTable
+ " (protocol, phone, vin, device_id, plate, province, city, maker, device_type, plate_color) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "
+ "ON DUPLICATE KEY UPDATE "
+ "vin = CASE WHEN VALUES(vin) <> 'unknown' THEN VALUES(vin) ELSE vin END, "
+ "device_id = VALUES(device_id), plate = VALUES(plate), province = VALUES(province), "
+ "city = VALUES(city), maker = VALUES(maker), device_type = VALUES(device_type), "
+ "plate_color = VALUES(plate_color), last_registered_at = CURRENT_TIMESTAMP";
try (Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setString(1, protocolName(registration.protocol()));
statement.setString(2, phone);
statement.setString(3, vin);
statement.setString(4, normalize(registration.deviceId()));
statement.setString(5, normalize(registration.plate()));
setInteger(statement, 6, registration.province());
setInteger(statement, 7, registration.city());
statement.setString(8, normalize(registration.maker()));
statement.setString(9, normalize(registration.deviceType()));
setInteger(statement, 10, registration.plateColor());
statement.executeUpdate();
} catch (SQLException e) {
throw new IllegalStateException("vehicle identity mysql registration bind failed: " + registrationTable, e);
}
}
private static void setInteger(PreparedStatement statement, int index, Integer value) throws SQLException {
if (value == null) {
statement.setObject(index, null);
} else {
statement.setInt(index, value);
}
}
private static String sanitizeTable(String table) {
String value = table == null || table.isBlank() ? "vehicle_identity_binding" : table.trim();
if (!value.matches("[A-Za-z0-9_]+")) {
throw new IllegalArgumentException("vehicle identity mysql table must contain only letters, digits, and underscore");
}
return value;
}
private static String protocolName(ProtocolId protocol) {
private static String protocol(ProtocolId protocol) {
return protocol == null ? "UNKNOWN" : protocol.name();
}
private static ProtocolId protocol(String value) {
if (value == null || value.isBlank()) {
return ProtocolId.UNKNOWN;
private static String safeTableName(String value) {
String name = value == null || value.isBlank() ? "vehicle_identity_bindings" : value.trim();
if (!name.matches("[A-Za-z0-9_]+")) {
throw new IllegalArgumentException("invalid vehicle identity mysql table name: " + value);
}
try {
return ProtocolId.valueOf(value.trim().toUpperCase(Locale.ROOT));
} catch (IllegalArgumentException ignored) {
return ProtocolId.UNKNOWN;
}
}
private static String normalize(String value) {
return value == null ? "" : value.trim().toUpperCase(Locale.ROOT);
return name.toLowerCase(Locale.ROOT);
}
}

View File

@@ -2,18 +2,26 @@ package com.lingniu.ingest.identity;
import com.lingniu.ingest.api.ProtocolId;
import java.util.Map;
public record VehicleIdentityBinding(
ProtocolId protocol,
String vin,
String phone,
String deviceId,
String plate
String plate,
Map<String, String> metadata
) {
public VehicleIdentityBinding(ProtocolId protocol, String vin, String phone, String deviceId, String plate) {
this(protocol, vin, phone, deviceId, plate, Map.of());
}
public VehicleIdentityBinding {
vin = normalize(vin);
phone = normalize(phone);
deviceId = normalize(deviceId);
plate = normalize(plate);
metadata = metadata == null ? Map.of() : Map.copyOf(metadata);
if (vin.isBlank()) {
throw new IllegalArgumentException("vin must not be blank");
}

View File

@@ -2,6 +2,7 @@ package com.lingniu.ingest.identity;
public enum VehicleIdentitySource {
EXPLICIT_VIN,
REGISTERED,
BOUND_PHONE,
BOUND_DEVICE_ID,
BOUND_PLATE,

View File

@@ -11,15 +11,10 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;
import java.io.PrintWriter;
import java.nio.file.Path;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
@AutoConfiguration
@EnableConfigurationProperties(VehicleIdentityProperties.class)
@@ -40,22 +35,15 @@ public class VehicleIdentityAutoConfiguration {
return new FileVehicleIdentityService(Path.of(properties.getFile().getPath()), objectMapper);
}
@Bean
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(prefix = "lingniu.ingest.identity", name = "store", havingValue = "mysql")
public DataSource vehicleIdentityDataSource(VehicleIdentityProperties properties) {
VehicleIdentityProperties.Mysql mysql = properties.getMysql();
return new DriverManagerVehicleIdentityDataSource(
mysql.getDriverClassName(), mysql.getJdbcUrl(), mysql.getUsername(), mysql.getPassword());
}
@Bean
@ConditionalOnMissingBean({VehicleIdentityResolver.class, VehicleIdentityRegistry.class})
@ConditionalOnProperty(prefix = "lingniu.ingest.identity", name = "store", havingValue = "mysql")
public MySqlVehicleIdentityService mySqlVehicleIdentityService(VehicleIdentityProperties properties,
DataSource dataSource) {
public MySqlVehicleIdentityService mysqlVehicleIdentityService(VehicleIdentityProperties properties,
ObjectMapper objectMapper) {
VehicleIdentityProperties.Mysql mysql = properties.getMysql();
return new MySqlVehicleIdentityService(dataSource, mysql.getTable(), mysql.getRefreshInterval());
DataSource dataSource = new DriverManagerDataSource(
mysql.getJdbcUrl(), mysql.getUsername(), mysql.getPassword());
return new MySqlVehicleIdentityService(dataSource, mysql, objectMapper);
}
@Bean
@@ -65,61 +53,4 @@ public class VehicleIdentityAutoConfiguration {
public InMemoryVehicleIdentityService vehicleIdentityService() {
return new InMemoryVehicleIdentityService();
}
private static final class DriverManagerVehicleIdentityDataSource implements DataSource {
private final String jdbcUrl;
private final String username;
private final String password;
private PrintWriter logWriter;
private int loginTimeout;
private DriverManagerVehicleIdentityDataSource(String driverClassName,
String jdbcUrl,
String username,
String password) {
if (jdbcUrl == null || jdbcUrl.isBlank()) {
throw new IllegalArgumentException("lingniu.ingest.identity.mysql.jdbc-url is required");
}
if (driverClassName != null && !driverClassName.isBlank()) {
try {
Class.forName(driverClassName.trim());
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("vehicle identity mysql driver class not found: "
+ driverClassName, e);
}
}
this.jdbcUrl = jdbcUrl;
this.username = username == null ? "" : username;
this.password = password == null ? "" : password;
}
@Override
public Connection getConnection() throws SQLException {
DriverManager.setLoginTimeout(loginTimeout);
return DriverManager.getConnection(jdbcUrl, username, password);
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
DriverManager.setLoginTimeout(loginTimeout);
return DriverManager.getConnection(jdbcUrl, username, password);
}
@Override public PrintWriter getLogWriter() { return logWriter; }
@Override public void setLogWriter(PrintWriter out) { this.logWriter = out; }
@Override public void setLoginTimeout(int seconds) { this.loginTimeout = seconds; }
@Override public int getLoginTimeout() { return loginTimeout; }
@Override public Logger getParentLogger() throws SQLFeatureNotSupportedException {
throw new SQLFeatureNotSupportedException();
}
@Override public <T> T unwrap(Class<T> iface) throws SQLException {
if (iface.isInstance(this)) {
return iface.cast(this);
}
throw new SQLException("not a wrapper for " + iface);
}
@Override public boolean isWrapperFor(Class<?> iface) {
return iface.isInstance(this);
}
}
}

View File

@@ -2,8 +2,6 @@ package com.lingniu.ingest.identity.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.time.Duration;
@ConfigurationProperties(prefix = "lingniu.ingest.identity")
public class VehicleIdentityProperties {
@@ -26,24 +24,21 @@ public class VehicleIdentityProperties {
}
public static class Mysql {
private String table = "vehicle_identity_binding";
private String jdbcUrl = "";
private String username = "";
private String jdbcUrl = "jdbc:mysql://127.0.0.1:3306/lingniu_vehicle?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai";
private String username = "root";
private String password = "";
private String driverClassName = "com.mysql.cj.jdbc.Driver";
private Duration refreshInterval = Duration.ofSeconds(60);
private String tableName = "vehicle_identity_bindings";
private boolean initializeSchema = true;
public String getTable() { return table; }
public void setTable(String table) { this.table = table; }
public String getJdbcUrl() { return jdbcUrl; }
public void setJdbcUrl(String jdbcUrl) { this.jdbcUrl = jdbcUrl; }
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 String getDriverClassName() { return driverClassName; }
public void setDriverClassName(String driverClassName) { this.driverClassName = driverClassName; }
public Duration getRefreshInterval() { return refreshInterval; }
public void setRefreshInterval(Duration refreshInterval) { this.refreshInterval = refreshInterval; }
public String getTableName() { return tableName; }
public void setTableName(String tableName) { this.tableName = tableName; }
public boolean isInitializeSchema() { return initializeSchema; }
public void setInitializeSchema(boolean initializeSchema) { this.initializeSchema = initializeSchema; }
}
}