Commit 594642e3 by chenzy

【新增】地铁日志同步

parent e44c53d0
......@@ -80,8 +80,21 @@
<artifactId>hutool-all</artifactId>
<version>5.8.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>syncdata</finalName>
......
......@@ -3,14 +3,18 @@ package com.keymobile.syncdata;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.PropertySource;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableDiscoveryClient
@ComponentScan(basePackages = {"com.keymobile.syncdata","com.keymobile.config.logging", "com.keymobile.config.naming",
"com.keymobile.config.redisclient", "com.keymobile.authservice.component"})
@PropertySource(value = "classpath:/application.yml")
@EnableFeignClients(basePackages = "com.keymobile.syncdata.feign")
@EnableScheduling
public class SyncDataApplication {
public static void main(String[] args) {
......
......@@ -3,6 +3,7 @@ package com.keymobile.syncdata.api;
import com.keymobile.syncdata.dto.EmailDTO;
import com.keymobile.syncdata.service.EmailService;
import com.keymobile.syncdata.service.SyncDataService;
import com.keymobile.syncdata.util.ObjectUtil;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
......@@ -24,9 +25,11 @@ public class EmailController {
@Operation(summary = "发送纯文本")
@PostMapping("sendTxt")
public void sendEmail(@RequestBody EmailDTO emailDTO) {
System.out.println("email通知用户:" + ObjectUtil.toJson(emailDTO));
List<String> username = emailDTO.getUsername();
List<String> userEmail = syncDataService.getUserEmail(username);
for (String email : userEmail) {
System.out.println("userEmail 地址 :" + ObjectUtil.toJson(userEmail));
emailService.sendTextMailMessage(email, emailDTO.getTitle(), emailDTO.getContent());
}
......
......@@ -10,27 +10,19 @@ import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.json.JsonData;
import com.keymobile.syncdata.dto.LoginStats;
import com.keymobile.syncdata.persistent.EsLog;
import com.keymobile.syncdata.persistent.entity.EsLog;
import com.keymobile.syncdata.util.DateUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.elasticsearch.client.RequestOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.client.elc.NativeQuery;
import org.springframework.data.elasticsearch.client.elc.NativeQueryBuilder;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.redis.core.convert.Bucket;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
......
......@@ -3,6 +3,7 @@ package com.keymobile.syncdata.api;
import com.keymobile.syncdata.dto.OAMessageDTO;
import com.keymobile.syncdata.service.OAService;
import com.keymobile.syncdata.service.SyncDataService;
import com.keymobile.syncdata.util.ObjectUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -28,8 +29,9 @@ public class OAMessageController {
@Operation(summary ="OA根据用户名发送待办信息")
@PostMapping("sendTodo")
public void sendTodo(@RequestBody OAMessageDTO oaMessageDTO){
System.out.println("OA通知用户:" + ObjectUtil.toJson(oaMessageDTO));
List<String> userNameList = syncDataService.getUserName(oaMessageDTO.getUsername());
// OA用户名就是平台的用户名
for (String oaAccount : userNameList) {
oaService.sendTodo(oaAccount, oaMessageDTO.getTitle(), oaMessageDTO.getLink());
......
......@@ -2,7 +2,7 @@ package com.keymobile.syncdata.api;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.MatchQuery;
import com.keymobile.syncdata.persistent.EsLog;
import com.keymobile.syncdata.persistent.entity.EsLog;
import com.keymobile.syncdata.service.StaticLoginData;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.beans.factory.annotation.Autowired;
......
......@@ -10,9 +10,13 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.keymobile.syncdata.properties.SystemProperties;
import com.keymobile.syncdata.service.SyncDataService;
import com.keymobile.syncdata.util.LogManager;
import com.keymobile.syncdata.util.ObjectUtil;
import jakarta.annotation.Nullable;
import org.bson.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
......@@ -44,10 +48,9 @@ public class SyncDataController {
@Autowired
private MongoTemplate mongoTemplate;
private static final String LOCK_NAME = "user_data_sync_lock";
private static final int BATCH_SIZE = 100;
private static final Logger syncdataLogger = LoggerFactory.getLogger("syncdata");
@PostMapping("/syncSystemData")
public void SyncSystemData(@RequestBody Map<String, Integer> requestBody) {
requestBody = requestBody != null && !requestBody.isEmpty() ? requestBody : defaultRequestBody;
......@@ -120,7 +123,7 @@ public class SyncDataController {
Pageable pageable = PageRequest.of(pageNum - 1, pageSize);
Map<String, String> requestBody = new HashMap<>();
requestBody.put("limit", String.valueOf(pageSize));
requestBody.put("offset", String.valueOf(pageNum * pageSize));
requestBody.put("offset", String.valueOf((pageNum - 1) * pageSize));
requestBody.put("deptid", orgId);
// 创建 HttpClient 实例
HttpClient client = HttpClient.newHttpClient();
......@@ -190,4 +193,14 @@ public class SyncDataController {
List<Document> documents = mongoTemplate.find(query, Document.class, "sync_user_data");
return PageableExecutionUtils.getPage(documents, pageable, () -> total);
}
@GetMapping("writeEslogToSysLog")
public void writeEslogToSysLog(){
syncDataService.writeEslogToSysLog();
}
@GetMapping("countBussinessData")
public void countBussinessData(){
syncDataService.countBussinessData();
}
}
package com.keymobile.syncdata.config;
import feign.auth.BasicAuthRequestInterceptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* FeignClientConfig.
* @author mahx
* @version 1.0
* @date 2019/12/27 16:55
*/
@Configuration
public class FeignClientConfig {
@Value("${security.authUser:root}")
private String authUser;
@Value("${security.authPwd:pwd}")
private String authPwd;
@Bean
public BasicAuthRequestInterceptor getBasicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor(authUser, authPwd);
}
}
\ No newline at end of file
package com.keymobile.syncdata.factory;
import com.keymobile.syncdata.persistent.SysLoginLogVRepository;
import com.keymobile.syncdata.persistent.entity.EsLog;
import com.keymobile.syncdata.persistent.entity.SysLoginLogId;
import com.keymobile.syncdata.persistent.entity.SysLoginLogV;
import com.keymobile.syncdata.util.DateUtil;
import com.keymobile.syncdata.util.ObjectUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.regex.Pattern;
@Component
public class LogMapperFactory {
// 存储映射规则:logger -> (messagePattern -> 映射函数)
private final Map<String, Map<Pattern, Function<EsLog, SysLoginLogV>>> mappingRules = new HashMap<>();
@Autowired
private SysLoginLogVRepository sysLoginLogVRepository;
private Long maxLoginId = null;
public LogMapperFactory() {
// 初始化映射规则(示例:根据实际需求扩展)
// registerMapping("tagmanage.TAGCATALOG", ".*登录成功.*", this::mapLoginSuccess);
// registerMapping("tagmanage.TAG", ".*登录成功.*", this::mapLoginSuccess);
// registerMapping("harvester.DATASOURCE", ".*登录成功.*", this::mapLoginSuccess);
// registerMapping("harvester.HARVESTERTASK", ".*登录成功.*", this::mapLoginSuccess);
// registerMapping("harvester.TASKSCHEDULE", ".*登录成功.*", this::mapLoginSuccess);
// registerMapping("harvester.TASK", ".*登录成功.*", this::mapLoginSuccess);
registerMapping("auth.AUDIT", ".*登录.*", this::mapCreateUser);
registerMapping("auth.AUDIT", ".*数据角色.*", this::mapUpdateRole);
// 更新元数据
registerMapping("metaRepo.META", ".*更新.*", this::mapUpdateMetaData);
// 保存元模型
registerMapping("metaRepo.META", ".*保存.*", this::mapUpdateMetaRelation);
// 导出元数据
registerMapping("metaRepo.META", ".*导出.*", this::mapOtherMatedata);
// 元数据关系 日志数据不全
// registerMapping("metaRepo.RELATION", ".*导入.*", this::mapOtherMataRelation);
// registerMapping("metaRepo.RELATION", ".*导出.*", this::mapOtherMataRelation);
// registerMapping("metaRepo.VERSION", ".*导入.*", this::mapOtherMatedata);
// 资产
registerMapping("dataAsset.AUDIT", ".*新增.*", this::mapAddDataAsset);
registerMapping("dataAsset.AUDIT", ".*修改.*", this::mapUpdateDataAsset);
registerMapping("dataAsset.AUDIT", ".*停用.*", this::mapOtherDataAsset);
registerMapping("dataAsset.AUDIT", ".*导入.*", this::mapOtherDataAsset);
registerMapping("dataAsset.AUDIT", ".*导出.*", this::mapOtherDataAsset);
// 创建用户和更新权限
registerMapping("sso.API", ".*登录.*", this::mapLoginSso);
//标准
registerMapping("standardManagement.API", ".*新增.*", this::mapAddStandard);
registerMapping("standardManagement.API", ".*删除.*", this::mapDeleteStandard);
registerMapping("standardManagement.API", ".*发布.*", this::mapOtherStandard);
registerMapping("standardManagement.API", ".*启用.*", this::mapOtherStandard);
registerMapping("standardManagement.API", ".*变更.*", this::mapOtherStandard);
registerMapping("standardManagement.API", ".*更新.*", this::mapUpdateStandard);
registerMapping("standardManagement.API", ".*获取.*", this::mapSelectStandard);
// 添加更多规则...
// 这是这么多类型,但是不用,应该是一条路径一个方法,然后去方法下面判断类型
}
private SysLoginLogV mapSelectStandard(EsLog esLog) {
SysLoginLogV logV = defaultSysLog(esLog);
// 菜单路径
logV.setLoginModeDir("数据标准-数据标准");
// 模块
logV.setLoginMode("数据标准");
// 操作类型
logV.setOptType("查询");
return logV;
}
private SysLoginLogV mapUpdateStandard(EsLog esLog) {
SysLoginLogV logV = defaultSysLog(esLog);
// 菜单路径
logV.setLoginModeDir("数据标准-数据标准");
// 模块
logV.setLoginMode("数据标准");
// 操作类型
logV.setOptType("更新");
return logV;
}
private SysLoginLogV mapOtherStandard(EsLog esLog) {
SysLoginLogV logV = defaultSysLog(esLog);
// 菜单路径
logV.setLoginModeDir("数据标准-数据标准");
// 模块
logV.setLoginMode("数据标准");
// 操作类型
logV.setOptType("其它");
return logV;
}
private SysLoginLogV mapDeleteStandard(EsLog esLog) {
SysLoginLogV logV = defaultSysLog(esLog);
// 菜单路径
logV.setLoginModeDir("数据标准-数据标准");
// 模块
logV.setLoginMode("数据标准");
// 操作类型
logV.setOptType("删除");
return logV;
}
private SysLoginLogV mapAddStandard(EsLog esLog) {
SysLoginLogV logV = defaultSysLog(esLog);
// 菜单路径
logV.setLoginModeDir("数据标准-数据标准");
// 模块
logV.setLoginMode("数据标准");
// 操作类型
logV.setOptType("新增");
return logV;
}
private SysLoginLogV mapLoginSso(EsLog esLog) {
SysLoginLogV logV = defaultSysLog(esLog);
// 菜单路径
logV.setLoginModeDir("系统管理-人员管理");
// 模块
logV.setLoginMode("人员管理");
// 操作类型
logV.setOptType("登录");
return logV;
}
private SysLoginLogV mapOtherDataAsset(EsLog esLog) {
SysLoginLogV logV = defaultSysLog(esLog);
// 菜单路径
logV.setLoginModeDir("数据资源-资源管理");
// 模块
logV.setLoginMode("资源管理");
// 操作类型
logV.setOptType("其它");
return logV;
}
private SysLoginLogV mapUpdateDataAsset(EsLog esLog) {
SysLoginLogV logV = defaultSysLog(esLog);
// 菜单路径
logV.setLoginModeDir("数据资源-资源管理");
// 模块
logV.setLoginMode("资源管理");
// 操作类型
logV.setOptType("更新");
return logV;
}
private SysLoginLogV mapAddDataAsset(EsLog esLog) {
SysLoginLogV logV = defaultSysLog(esLog);
// 菜单路径
logV.setLoginModeDir("数据资源-资源管理");
// 模块
logV.setLoginMode("资源管理");
// 操作类型
logV.setOptType("新增");
return logV;
}
private SysLoginLogV mapOtherMataRelation(EsLog esLog) {
SysLoginLogV logV = defaultSysLog(esLog);
// 菜单路径
logV.setLoginModeDir("元数据-元模型管理");
// 模块
logV.setLoginMode("元模型管理");
// 操作类型
logV.setOptType("其它");
return logV;
}
private SysLoginLogV mapOtherMatedata(EsLog esLog) {
SysLoginLogV logV = defaultSysLog(esLog);
// 菜单路径
logV.setLoginModeDir("元数据-元数据管理");
// 模块
logV.setLoginMode("元数据管理");
// 操作类型
logV.setOptType("其它");
return logV;
}
private SysLoginLogV mapUpdateMetaRelation(EsLog esLog) {
SysLoginLogV logV = defaultSysLog(esLog);
// 菜单路径
logV.setLoginModeDir("元数据-元模型管理");
// 模块
logV.setLoginMode("元模型管理");
// 操作类型
logV.setOptType("更新");
return logV;
}
private SysLoginLogV mapUpdateMetaData(EsLog esLog) {
SysLoginLogV logV = defaultSysLog(esLog);
// 菜单路径
logV.setLoginModeDir("元数据-元数据管理");
// 模块
logV.setLoginMode("元数据管理");
// 操作类型
logV.setOptType("更新");
return logV;
}
private SysLoginLogV mapUpdateRole(EsLog esLog) {
SysLoginLogV logV = defaultSysLog(esLog);
// 菜单路径
logV.setLoginModeDir("系统管理-角色权限管理");
// 模块
logV.setLoginMode("角色权限管理");
// 操作类型
logV.setOptType("更新");
return logV;
}
// 这里是默认的系统日志配置
private SysLoginLogV defaultSysLog(EsLog esLog) {
SysLoginLogV logV = new SysLoginLogV();
// 系统id
// 日志id,number类型不支持自增长,所以手动给它长
if (maxLoginId == null){
maxLoginId = sysLoginLogVRepository.findMaxLoginId();
maxLoginId = (maxLoginId == null) ? 0L : maxLoginId;
}
maxLoginId = maxLoginId + 1;
SysLoginLogId logId = new SysLoginLogId(1370L, maxLoginId);
logV.setId(logId);
// 用户账户名
logV.setLoginAccount(extractAccount(esLog.getUser()));
String clientIp = esLog.getClientAddr() == null ? "10.34.107.2" : esLog.getClientAddr();
// 用户地址
logV.setLoginAddress(clientIp);
// 时间戳
Date utcTime = esLog.getTimestamp();
logV.setLoginTime(utcTime);
// 操作说明
logV.setOptAction(StringUtils.substring(esLog.getMessage(), 0, 100));
return logV;
}
private SysLoginLogV mapCreateUser(EsLog esLog) {
SysLoginLogV logV = defaultSysLog(esLog);
// 菜单路径
logV.setLoginModeDir("系统管理-人员管理");
// 模块
logV.setLoginMode("人员管理");
// 操作类型
logV.setOptType("新增");
return logV;
}
// 注册映射规则(messagePattern 支持正则表达式)
private void registerMapping(String logger, String messagePattern, Function<EsLog, SysLoginLogV> mapper) {
mappingRules.computeIfAbsent(logger, k -> new HashMap<>())
.put(Pattern.compile(messagePattern), mapper);
}
// 根据 logger 和 message 获取映射函数
public Function<EsLog, SysLoginLogV> getMapper(String logger, String message) {
if (logger == null || message == null) {
return null;
}
// 先精确匹配 logger
Map<Pattern, Function<EsLog, SysLoginLogV>> messageRules = mappingRules.get(logger);
if (messageRules != null) {
// 再模糊匹配 message(按注册顺序匹配,先注册的规则优先级高)
for (Map.Entry<Pattern, Function<EsLog, SysLoginLogV>> entry : messageRules.entrySet()) {
if (entry.getKey().matcher(message).matches()) {
return entry.getValue();
}
}
}
return null; // 未匹配到规则时使用默认映射
}
private String extractAccount(String userStr) {
if (userStr == null || userStr.isEmpty()) {
return null; // 处理空值
}
// 按冒号分割,取第一个部分
String[] parts = userStr.split(":");
return parts.length > 0 ? parts[0] : null;
}
}
\ No newline at end of file
package com.keymobile.syncdata.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Map;
@FeignClient(value = "dataassetmanager")
//@FeignClient(value = "dataassetmanager", url = "http://das.shenzhenmc.com/api/dataassetmanager")
public interface DataAssetFeign {
@GetMapping(value = "/countApi/countKeyIndicators")
Map<String, Object> countKeyIndicators();
@GetMapping(value = "/countApi/countDataAssetChangeNumGroupByDate")
Map<String, Object> countDataAssetChangeNumGroupByDate(@RequestParam("beginTime") String beginTime, @RequestParam("endTime") String endTime);
}
\ No newline at end of file
package com.keymobile.syncdata.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Map;
//@FeignClient(value = "dataquality", url = "https://das.shenzhenmc.com/api/dataquality")
@FeignClient(value = "dataquality")
public interface DataQualityFeign {
@GetMapping(value = "//stats/overview")
Map<String, Object> overview();
}
package com.keymobile.syncdata.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Map;
//@FeignClient(value = "metadatarepo", url = "http://das.shenzhenmc.com/api/metadatarepo")
@FeignClient(value = "metadatarepo")
public interface MetadataRepoFeign {
@PostMapping(value = "/rest/operate/changeStatistics")
Map<String, Object> changeStatistics(@RequestParam("catalog") String catalog, @RequestParam("from") String from, @RequestParam("to") String to);
@GetMapping(value = "/rest/statistics/countByClass")
Integer countByClass(@RequestParam("catalog") String catalog, @RequestParam("clz") String clz);
}
package com.keymobile.syncdata.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.Map;
//@FeignClient(value = "standard", url = "http://das.shenzhenmc.com/api/standard/")
@FeignClient(value = "standard")
public interface StandardFeign {
@GetMapping(value = "/rest/standard/statistic/bannerStatistic")
Map<String, Object> bannerStatistic();
}
......@@ -9,7 +9,14 @@ import java.util.Map;
public interface AuthDataRoleRepository extends CrudRepository<AuthDataRole,Integer> {
@Query(value = "select role.data_role_id,role.data_role_name,count(role.data_role_id) as count from auth_data_role_users user inner join auth_data_role role on user.data_role_id=role.data_role_id and role.data_role_id !=1 group by role.data_role_id",nativeQuery = true)
@Query(value = "SELECT role.data_role_id,\n" +
" role.data_role_name,\n" +
" count(role.data_role_id) AS count\n" +
"FROM auth_data_role_users users\n" +
"INNER JOIN auth_data_role role\n" +
" ON users.data_role_id = role.data_role_id\n" +
" AND role.data_role_id != 1\n" +
"GROUP BY role.data_role_id, role.data_role_name",nativeQuery = true)
List<Map<String,Object>> statRoleByUser();
@Query(value = "select 1 from auth_data_role_users where user_id=?1 and data_role_id in ?2",nativeQuery = true)
......
package com.keymobile.syncdata.persistent;
import com.keymobile.syncdata.persistent.entity.SysBusinessStat;
import com.keymobile.syncdata.persistent.entity.SysLoginLogV;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface SysBusinessStatVRepository extends JpaRepository<SysBusinessStat, Long> {
}
package com.keymobile.syncdata.persistent;
import com.keymobile.syncdata.persistent.entity.SysLoginLogV;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.Date;
import java.util.List;
@Repository
public interface SysLoginLogVRepository extends JpaRepository<SysLoginLogV, Long> {
@Query(value = "SELECT MAX(LOGIN_TIME) FROM SYS_LOGIN_LOG_V", nativeQuery = true)
Date findMaxLoginTime();
@Query(value = "SELECT MAX(login_id) FROM SYS_LOGIN_LOG_V", nativeQuery = true)
Long findMaxLoginId();
}
\ No newline at end of file
package com.keymobile.syncdata.persistent;
package com.keymobile.syncdata.persistent.entity;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.DateFormat;
......@@ -7,6 +8,7 @@ import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import java.time.Instant;
import java.util.Date;
@Document(indexName="default-logstash")
......@@ -22,10 +24,12 @@ public class EsLog {
private String session;
@Field
private String user;
@Field(type = FieldType.Date, format = DateFormat.date_optional_time)
@JsonProperty(value = "@timestamp")
@Field(type = FieldType.Date, name = "@timestamp", pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX")
private Date timestamp;
@Field
private String clientAddr;
public EsLog() {}
public EsLog(String message) {
......@@ -72,4 +76,11 @@ public class EsLog {
this.user = user;
}
public String getClientAddr() {
return clientAddr;
}
public void setClientAddr(String clientAddr) {
this.clientAddr = clientAddr;
}
}
package com.keymobile.syncdata.persistent.entity;
import jakarta.persistence.*;
import java.util.Date;
@Entity
@Table(name = "SYS_BUSINESS_STAT_V")
@IdClass(SysBusinessStatId.class) // 联合主键类
public class SysBusinessStat {
@Id
@Column(name = "sid", nullable = false)
private Long sid; // 系统ID
@Id
@Temporal(TemporalType.DATE)
@Column(name = "stat_period", nullable = false)
private Date statPeriod; // 统计段(按天)
@Id
@Column(name = "stat_item", nullable = false, length = 30)
private String statItem; // 统计项(业务对象英文描述)
@Column(name = "stat_item_desc", nullable = false, length = 100)
private String statItemDesc; // 统计项目描述(中文)
@Column(name = "stat_value", nullable = false, columnDefinition = "NUMBER default 0")
private Integer statValue; // 统计值(默认0)
// 构造函数、Getter 和 Setter 方法
public SysBusinessStat() {}
public SysBusinessStat(Long sid, Date statPeriod, String statItem, String statItemDesc, Integer statValue) {
this.sid = sid;
this.statPeriod = statPeriod;
this.statItem = statItem;
this.statItemDesc = statItemDesc;
this.statValue = statValue;
}
// Getters and Setters
public Long getSid() { return sid; }
public void setSid(Long sid) { this.sid = sid; }
public Date getStatPeriod() { return statPeriod; }
public void setStatPeriod(Date statPeriod) { this.statPeriod = statPeriod; }
public String getStatItem() { return statItem; }
public void setStatItem(String statItem) { this.statItem = statItem; }
public String getStatItemDesc() { return statItemDesc; }
public void setStatItemDesc(String statItemDesc) { this.statItemDesc = statItemDesc; }
public Integer getStatValue() { return statValue; }
public void setStatValue(Integer statValue) { this.statValue = statValue; }
}
package com.keymobile.syncdata.persistent.entity;
import java.io.Serializable;
import java.util.Date;
// 联合主键类
class SysBusinessStatId implements Serializable {
private Long sid;
private Date statPeriod;
private String statItem;
// 必须提供无参构造函数
public SysBusinessStatId() {}
// Getters, Setters, equals 和 hashCode 方法
public Long getSid() { return sid; }
public void setSid(Long sid) { this.sid = sid; }
public Date getStatPeriod() { return statPeriod; }
public void setStatPeriod(Date statPeriod) { this.statPeriod = statPeriod; }
public String getStatItem() { return statItem; }
public void setStatItem(String statItem) { this.statItem = statItem; }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SysBusinessStatId that = (SysBusinessStatId) o;
return sid.equals(that.sid) &&
statPeriod.equals(that.statPeriod) &&
statItem.equals(that.statItem);
}
@Override
public int hashCode() {
return java.util.Objects.hash(sid, statPeriod, statItem);
}
}
\ No newline at end of file
package com.keymobile.syncdata.persistent.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import java.io.Serializable;
import java.util.Objects;
/**
* 登录日志联合主键标识类(无需@Embeddable)
*/
@Embeddable
public class SysLoginLogId implements Serializable {
@Column(name = "SID")
private Long sid;
@Column(name = "LOGIN_ID")
private Long loginId;
// 必须提供无参构造器
public SysLoginLogId() {}
public SysLoginLogId(Long sid, Long loginId) {
this.sid = sid;
this.loginId = loginId;
}
// 必须重写equals和hashCode
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SysLoginLogId that = (SysLoginLogId) o;
return Objects.equals(sid, that.sid) && Objects.equals(loginId, that.loginId);
}
@Override
public int hashCode() {
return Objects.hash(sid, loginId);
}
// getter/setter
public Long getSid() { return sid; }
public void setSid(Long sid) { this.sid = sid; }
public Long getLoginId() { return loginId; }
public void setLoginId(Long loginId) { this.loginId = loginId; }
}
\ No newline at end of file
package com.keymobile.syncdata.persistent.entity;
import jakarta.persistence.*;
import org.hibernate.annotations.GenericGenerator;
import java.util.Date;
@Entity
@Table(name = "SYS_LOGIN_LOG_V")
public class SysLoginLogV {
@Id
private SysLoginLogId id;
@Column(name = "LOGIN_ACCOUNT")
private String loginAccount;
@Column(name = "LOGIN_ADDRESS")
private String loginAddress;
@Column(name = "LOGIN_TIME")
@Temporal(TemporalType.TIMESTAMP)
private Date loginTime;
@Column(name = "LOGIN_MODE_DIR")
private String loginModeDir;
@Column(name = "LOGIN_MODULE_ID")
private Long loginModuleId;
@Column(name = "LOGIN_MODE")
private String loginMode;
@Column(name = "OPT_TYPE")
private String optType;
@Column(name = "OPT_TYPE_ID")
private Long optTypeId;
@Column(name = "OPT_ACTION")
private String optAction;
// getters and setters
public SysLoginLogId getId() {
return id;
}
public void setId(SysLoginLogId id) {
this.id = id;
}
public String getLoginAccount() {
return loginAccount;
}
public void setLoginAccount(String loginAccount) {
this.loginAccount = loginAccount;
}
public String getLoginAddress() {
return loginAddress;
}
public void setLoginAddress(String loginAddress) {
this.loginAddress = loginAddress;
}
public Date getLoginTime() {
return loginTime;
}
public void setLoginTime(Date loginTime) {
this.loginTime = loginTime;
}
public String getLoginModeDir() {
return loginModeDir;
}
public void setLoginModeDir(String loginModeDir) {
this.loginModeDir = loginModeDir;
}
public Long getLoginModuleId() {
return loginModuleId;
}
public void setLoginModuleId(Long loginModuleId) {
this.loginModuleId = loginModuleId;
}
public String getLoginMode() {
return loginMode;
}
public void setLoginMode(String loginMode) {
this.loginMode = loginMode;
}
public String getOptType() {
return optType;
}
public void setOptType(String optType) {
this.optType = optType;
}
public Long getOptTypeId() {
return optTypeId;
}
public void setOptTypeId(Long optTypeId) {
this.optTypeId = optTypeId;
}
public String getOptAction() {
return optAction;
}
public void setOptAction(String optAction) {
this.optAction = optAction;
}
}
\ No newline at end of file
package com.keymobile.syncdata.scheduler;
import com.keymobile.syncdata.service.SyncDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class ScheduledTasks {
@Autowired
private SyncDataService syncDataService;
/**
* 每天凌晨 00:00:00 执行的定时任务
* cron 表达式解析:
* - 秒:0
* - 分:0
* - 时:0
* - 日:*(每天)
* - 月:*(每月)
* - 周:*(每周)
*/
@Scheduled(cron = "0 0 1 * * ?")
public void performNightlyTask() {
syncDataService.writeEslogToSysLog();
syncDataService.countBussinessData();
}
}
\ No newline at end of file
......@@ -21,4 +21,10 @@ public interface SyncDataService {
List<String> getUserEmail(List<String> usernames);
List<String> getUserName(List<String> usernames);
void writeEslogToSysLog();
void countBussinessData();
}
......@@ -129,7 +129,8 @@ public class OAServiceImpl implements OAService {
RestTemplate template = new RestTemplate();
ResponseEntity<Map> exchange = template.exchange(url, HttpMethod.POST, entity, Map.class);
System.out.println(url);
System.out.println(ObjectUtil.toJson(entity));
System.out.println(exchange.getBody());
}
......
......@@ -3,17 +3,36 @@ package com.keymobile.syncdata.service.impl;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import co.elastic.clients.elasticsearch._types.SortOptions;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.MatchAllQuery;
import co.elastic.clients.json.JsonData;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.keymobile.syncdata.actor.DataSyncActor;
import com.keymobile.syncdata.actor.SyncDataMessage;
import com.keymobile.syncdata.factory.LogMapperFactory;
import com.keymobile.syncdata.feign.*;
import com.keymobile.syncdata.persistent.SysBusinessStatVRepository;
import com.keymobile.syncdata.persistent.SysLoginLogVRepository;
import com.keymobile.syncdata.persistent.entity.EsLog;
import com.keymobile.syncdata.persistent.entity.SysBusinessStat;
import com.keymobile.syncdata.persistent.entity.SysLoginLogV;
import com.keymobile.syncdata.properties.SystemProperties;
import com.keymobile.syncdata.service.SyncDataService;
import com.keymobile.syncdata.util.DateUtil;
import com.keymobile.syncdata.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.client.elc.NativeQuery;
import org.springframework.data.elasticsearch.client.elc.NativeQueryBuilder;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
......@@ -24,9 +43,10 @@ import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
@Slf4j
......@@ -38,6 +58,26 @@ public class SyncDataServiceImpl implements SyncDataService {
private SystemProperties systemProperties;
private static final ActorSystem syncDataActor = ActorSystem.create("SyncDataAkka");
@Autowired
private SysLoginLogVRepository sysLoginLogVRepository;
@Autowired
private SysBusinessStatVRepository sysBusinessStatVRepository;
@Autowired
private ElasticsearchOperations elasticsearchOperations;
private static final int PAGE_SIZE = 5000; // 每批获取5000条数据
@Autowired
private LogMapperFactory logMapperFactory;
@Autowired
private StandardFeign standardFeign;
@Autowired
private DataAssetFeign dataAssetFeign;
@Autowired
private DataQualityFeign dataQualityFeign;
@Autowired
private MetadataRepoFeign metadataRepoFeign;
@Override
public void syncSystemData(Map<String, Integer> requestBody) {
log.info("连接系统数据抽取接口");
......@@ -159,4 +199,169 @@ public class SyncDataServiceImpl implements SyncDataService {
}
log.info("数据插入完成,共插入:{} 条数据", rowsArray.size());
}
public void writeEslogToSysLog() {
Date maxLoginTime = sysLoginLogVRepository.findMaxLoginTime();
// 从es中得到所有数据
List<EsLog> esLogs = searchAllLogs(null, null, maxLoginTime);
List<SysLoginLogV> sysLoginLogVList = new ArrayList<>();
// 根据数据进行分类,写到mysql中
for (EsLog esLog : esLogs) {
Function<EsLog, SysLoginLogV> mapper = logMapperFactory.getMapper(esLog.getLogger(), esLog.getMessage());
if (mapper == null) {
continue;
}
SysLoginLogV sysLoginLogV = mapper.apply(esLog);
sysLoginLogVList.add(sysLoginLogV);
if (sysLoginLogV.getLoginModeDir() == null || sysLoginLogV.getLoginMode() == null) {
log.info("数据异常:{}", sysLoginLogV);
}
}
sysLoginLogVRepository.saveAll(sysLoginLogVList);
log.info("数据写入完成,更新{}条日志数据", sysLoginLogVList.size());
}
@Override
public void countBussinessData() {
List<SysBusinessStat> sysBusinessStatList= new ArrayList<>();
//META_TAB_SUM 元数据表总数
SysBusinessStat sysBusinessStat1 = new SysBusinessStat(1370L, DateUtil.getYesterday(), "META_TAB_SUM", "元数据表总数", 0);
sysBusinessStat1.setStatValue(metadataRepoFeign.countByClass("961678803", "Catalog,Database,Schema,Table"));
sysBusinessStatList.add(sysBusinessStat1);
//META_TAB_CHANGE_SUM 元数据变更次数
SysBusinessStat sysBusinessStat2 = new SysBusinessStat(1370L, DateUtil.getYesterday(), "META_TAB_CHANGE_SUM", "元数据变更次数", 0);
Map<String, Object> changeStatistics = metadataRepoFeign.changeStatistics("961678803", DateUtil.getYesterdayString(), DateUtil.getTodayString());
Object tableCount = changeStatistics.get("tableCount");
sysBusinessStat2.setStatValue((Integer) tableCount);
sysBusinessStatList.add(sysBusinessStat2);
//STAND_SUM 标准总数
Map<String, Object> standardBannerStatic = standardFeign.bannerStatistic();
Object dataStandardTotal = standardBannerStatic.get("dataStandardTotal");
Object matchedMetadata = standardBannerStatic.get("matchedMetadata");
SysBusinessStat sysBusinessStat3 = new SysBusinessStat(1370L, DateUtil.getYesterday(), "STAND_SUM", "标准总数", (Integer) dataStandardTotal);
//STAND_COL_SUM 落标结果总数
SysBusinessStat sysBusinessStat4 = new SysBusinessStat(1370L, DateUtil.getYesterday(), "STAND_COL_SUM", "落标结果总数", (Integer) matchedMetadata);
sysBusinessStatList.add(sysBusinessStat3);
sysBusinessStatList.add(sysBusinessStat4);
//QUALITY_TASK_SUM 质量任务总数
SysBusinessStat sysBusinessStat5 = new SysBusinessStat(1370L, DateUtil.getYesterday(), "QUALITY_TASK_SUM", "质量任务总数", 0);
Map<String, Object> overview = dataQualityFeign.overview();
sysBusinessStat5.setStatValue((Integer) overview.get("jobCount"));
sysBusinessStatList.add(sysBusinessStat5);
//ASSET_SUM 数据资源总数(L4)
Map<String, Object> countKeyIndicators = dataAssetFeign.countKeyIndicators();
Object level4 = countKeyIndicators.get("level4");
SysBusinessStat sysBusinessStat6 = new SysBusinessStat(1370L, DateUtil.getYesterday(), "ASSET_SUM", "数据资源总数(L4)", 0);
sysBusinessStat6.setStatValue((Integer) level4);
sysBusinessStatList.add(sysBusinessStat6);
//ASSET_CHANGE_SUM 数据资源变更数量
Map<String, Object> countDataAssetChangeNumGroupByDate = dataAssetFeign.countDataAssetChangeNumGroupByDate(DateUtil.getYesterdayString(), DateUtil.getYesterdayString());
Object dataAssetNum = countDataAssetChangeNumGroupByDate.get(DateUtil.getYesterdayString());
SysBusinessStat sysBusinessStat7 = new SysBusinessStat(1370L, DateUtil.getYesterday(), "ASSET_CHANGE_SUM", "数据资源变更数量", 0);
sysBusinessStat7.setStatValue((Integer) dataAssetNum);
sysBusinessStatList.add(sysBusinessStat7);
sysBusinessStatVRepository.saveAll(sysBusinessStatList);
log.info("统计业务量:元数据表总数 {}, 元数据变更次数 {}, 标准总数 {}, 落标结果总数 {}, 质量任务总数 {}, 数据资源总数 {}, 数据资源变更数量 {}",
sysBusinessStat1.getStatValue(), sysBusinessStat2.getStatValue(), sysBusinessStat3.getStatValue(), sysBusinessStat4.getStatValue(),
sysBusinessStat5.getStatValue(), sysBusinessStat6.getStatValue(), sysBusinessStat7.getStatValue());
}
public List<EsLog> searchAllLogs(String logger, String message, Date startTime) {
List<EsLog> allLogs = new ArrayList<>();
Object[] searchAfter = null; // 初始为null,表示从第一条开始
while (true) {
// 执行查询并获取当前批次的数据
SearchHits<EsLog> searchHits = executeSearch(logger, message, startTime, searchAfter);
// 没有更多结果时退出循环
if (searchHits.getSearchHits().isEmpty()) {
break;
}
// 添加当前批次的数据到结果列表
allLogs.addAll(searchHits.getSearchHits().stream()
.map(SearchHit::getContent)
.collect(Collectors.toList()));
// 获取最后一条记录的排序值,用于下一页查询
SearchHit<EsLog> lastHit = searchHits.getSearchHits().get(searchHits.getSearchHits().size() - 1);
searchAfter = lastHit.getSortValues().toArray();
// 日志记录(可选)
System.out.printf("已获取 %d 条数据,继续查询下一页...%n", allLogs.size());
}
return allLogs;
}
private SearchHits<EsLog> executeSearch(String logger, String message, Date startTime, Object[] searchAfter) {
// 构建查询
BoolQuery.Builder boolBuilder = new BoolQuery.Builder();
if (startTime != null) {
boolBuilder.must(m -> m
.range(r -> r
.field("@timestamp")
.gte(JsonData.of(startTime)) // 修正日期处理
)
);
} else {
boolBuilder.must(m -> m.matchAll(new MatchAllQuery.Builder().build()));
}
if (logger != null && !logger.isEmpty()) {
boolBuilder.must(m -> m
.match(t -> t
.field("logger")
.query(logger)
)
);
}
if (message != null && !message.isEmpty()) {
boolBuilder.must(m -> m
.wildcard(w -> w
.field("message")
.value("*" + message + "*")
)
);
}
// 构建排序
List<SortOptions> sortOptions = Arrays.asList(
SortOptions.of(s -> s
.field(f -> f
.field("@timestamp")
.order(SortOrder.Asc)
)
),
SortOptions.of(s -> s
.field(f -> f
.field("_id")
.order(SortOrder.Asc)
)
)
);
// 构建 NativeQuery
NativeQueryBuilder nativeQueryBuilder = NativeQuery.builder()
.withQuery(boolBuilder.build()._toQuery())
.withPageable(PageRequest.of(0, PAGE_SIZE))
.withSort(sortOptions);
// 设置 search_after
if (searchAfter != null) {
nativeQueryBuilder.withSearchAfter(Arrays.asList(searchAfter));
}
// 执行查询
return elasticsearchOperations.search(nativeQueryBuilder.build(), EsLog.class);
}
}
\ No newline at end of file
......@@ -5,8 +5,11 @@ import org.apache.commons.lang.time.DateUtils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
/**
* 日期工具类, 继承org.apache.commons.lang.time.DateUtils类
......@@ -18,7 +21,7 @@ public class DateUtil extends DateUtils {
private static String[] parsePatterns = { parse_pattern_dd, parse_pattern_ss, "yyyy-MM-dd HH:mm",
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm" };
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
/**
* 得到当前日期字符串 格式(yyyy-MM-dd)
*/
......@@ -46,146 +49,57 @@ public class DateUtil extends DateUtils {
return formatDate;
}
/**
* 得到日期时间字符串,转换格式(parse_pattern_ss)
*/
public static String formatDateTime(Date date) {
return formatDate(date, parse_pattern_ss);
}
/**
* 得到当前时间字符串 格式(HH:mm:ss)
*/
public static String getTime() {
return formatDate(new Date(), "HH:mm:ss");
}
/**
* 得到当前日期和时间字符串 格式(parse_pattern_ss)
*/
public static String getDateTime() {
return formatDate(new Date(), parse_pattern_ss);
}
/**
* 得到当前年份字符串 格式(yyyy)
*/
public static String getYear() {
return formatDate(new Date(), "yyyy");
}
/**
* 得到当前月份字符串 格式(MM)
*/
public static String getMonth() {
return formatDate(new Date(), "MM");
}
/**
* 得到当天字符串 格式(dd)
* 获取今天的日期字符串(格式:yyyy-MM-dd)
* @return 今天的日期字符串
*/
public static String getDay() {
return formatDate(new Date(), "dd");
public static String getTodayString() {
return LocalDate.now().format(FORMATTER);
}
/**
* 得到当前星期字符串 格式(E)星期几
* 获取昨天的日期字符串(格式:yyyy-MM-dd)
* @return 昨天的日期字符串
*/
public static String getWeek() {
return formatDate(new Date(), "E");
public static String getYesterdayString() {
return LocalDate.now().minusDays(1).format(FORMATTER);
}
/**
* 日期型字符串转化为日期 格式
* { parse_pattern_dd, parse_pattern_ss, "yyyy-MM-dd HH:mm",
* "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm" }
* 获取昨天的日期(默认系统时区)
* @return 昨天的Date对象(时间部分为00:00:00)
*/
public static Date parseDate(Object str) {
if (str == null){
return null;
}
try {
return parseDate(str.toString(), parsePatterns);
} catch (ParseException e) {
return null;
}
public static Date getYesterday() {
return getYesterday(TimeZone.getDefault());
}
/**
* 获取过去的天数
* @param date
* @return
* 获取指定时区的昨天日期
* @param timeZone 时区
* @return 昨天的Date对象(时间部分为00:00:00)
*/
public static long pastDays(Date date) {
long t = System.currentTimeMillis()-date.getTime();
return t/(24*60*60*1000);
}
public static Date getYesterday(TimeZone timeZone) {
Calendar calendar = Calendar.getInstance(timeZone);
calendar.add(Calendar.DAY_OF_MONTH, -1);
// 清空时分秒,只保留日期部分
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
public static Date getDateStart(Date date) {
if(date==null) {
return null;
}
SimpleDateFormat sdf = new SimpleDateFormat(parse_pattern_ss);
try {
date= sdf.parse(formatDate(date, parse_pattern_dd)+" 00:00:00");
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
public static Date getDateEnd(Date date) {
if(date==null) {
return null;
}
SimpleDateFormat sdf = new SimpleDateFormat(parse_pattern_ss);
try {
date= sdf.parse(formatDate(date, parse_pattern_dd) +" 23:59:59");
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
//得到上班时间
public static Date getDateStartWork(Date date) {
if(date==null) {
return null;
}
SimpleDateFormat sdf = new SimpleDateFormat(parse_pattern_ss);
try {
date= sdf.parse(formatDate(date, parse_pattern_dd)+" 09:00:00");
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
//得到下班时间
public static Date getDateEndWork(Date date) {
if(date==null) {
return null;
}
SimpleDateFormat sdf = new SimpleDateFormat(parse_pattern_ss);
try {
date= sdf.parse(formatDate(date, parse_pattern_dd) +" 17:30:00");
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
/* 获取传值日期之前几天的日期
* @param date 需要转换的日期 date 可以为NULL 此条件下则获取当前日期
* @param after 天数
* @param xFormat 转换字符串类型 (可以为NULL)
* @return
*/
public static Date getBeforeCountDate(Date date, int before) {
date = date == null ? new Date() : date;
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.DAY_OF_MONTH, -before);
return calendar.getTime();
}
}
package com.keymobile.syncdata.util;
import jakarta.servlet.http.HttpServletRequest;
/**
* IP地址工具类
*
*/
public class IpUtil {
/**
* 私有化构造器
*/
private IpUtil() {
}
/**
* 获取真实IP地址
* <p>使用getRealIP代替该方法</p>
*
* @param request req
* @return ip
*/
@Deprecated
public static String getClinetIpByReq(HttpServletRequest request) {
// 获取客户端ip地址
String clientIp = request.getHeader("x-forwarded-for");
if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {
clientIp = request.getHeader("Proxy-Client-IP");
}
if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {
clientIp = request.getHeader("WL-Proxy-Client-IP");
}
if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {
clientIp = request.getRemoteAddr();
}
/*
* 对于获取到多ip的情况下,找到公网ip.
*/
String sIP = null;
if (clientIp != null && !clientIp.contains("unknown") && clientIp.indexOf(",") > 0) {
String[] ipsz = clientIp.split(",");
for (String anIpsz : ipsz) {
if (!isInnerIP(anIpsz.trim())) {
sIP = anIpsz.trim();
break;
}
}
/*
* 如果多ip都是内网ip,则取第一个ip.
*/
if (null == sIP) {
sIP = ipsz[0].trim();
}
clientIp = sIP;
}
if (clientIp != null && clientIp.contains("unknown")) {
clientIp = clientIp.replaceAll("unknown,", "");
clientIp = clientIp.trim();
}
if ("".equals(clientIp) || null == clientIp) {
clientIp = "127.0.0.1";
}
return clientIp;
}
/**
* 判断IP是否是内网地址
*
* @param ipAddress ip地址
* @return 是否是内网地址
*/
public static boolean isInnerIP(String ipAddress) {
boolean isInnerIp;
long ipNum = getIpNum(ipAddress);
/**
私有IP:A类 10.0.0.0-10.255.255.255
B类 172.16.0.0-172.31.255.255
C类 192.168.0.0-192.168.255.255
当然,还有127这个网段是环回地址
**/
long aBegin = getIpNum("10.0.0.0");
long aEnd = getIpNum("10.255.255.255");
long bBegin = getIpNum("172.16.0.0");
long bEnd = getIpNum("172.31.255.255");
long cBegin = getIpNum("192.168.0.0");
long cEnd = getIpNum("192.168.255.255");
isInnerIp = isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd)
|| ipAddress.equals("127.0.0.1");
return isInnerIp;
}
private static long getIpNum(String ipAddress) {
String[] ip = ipAddress.split("\\.");
long a = Integer.parseInt(ip[0]);
long b = Integer.parseInt(ip[1]);
long c = Integer.parseInt(ip[2]);
long d = Integer.parseInt(ip[3]);
return a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d;
}
private static boolean isInner(long userIp, long begin, long end) {
return (userIp >= begin) && (userIp <= end);
}
public static String getRealIP(HttpServletRequest request) {
// 获取客户端ip地址
String clientIp = request.getHeader("x-forwarded-for");
if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {
clientIp = request.getRemoteAddr();
}
String[] clientIps = clientIp.split(",");
if (clientIps.length <= 1) return clientIp.trim();
// 判断是否来自CDN
if (isComefromCDN(request)) {
if (clientIps.length >= 2) return clientIps[clientIps.length - 2].trim();
}
return clientIps[clientIps.length - 1].trim();
}
private static boolean isComefromCDN(HttpServletRequest request) {
String host = request.getHeader("host");
return host.contains("www.189.cn") || host.contains("shouji.189.cn") || host.contains(
"image2.chinatelecom-ec.com") || host.contains(
"image1.chinatelecom-ec.com");
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment