Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
afanti-open-api
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
JIRA
JIRA
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
java-ms
afanti-open-api
Commits
5a62112d
Commit
5a62112d
authored
Apr 25, 2025
by
何进财
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feat/reportData' into 'master'
feat: 完善时间校验的规则 See merge request
!73
parents
58c64827
949dee05
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
151 additions
and
103 deletions
+151
-103
GlobalExceptionHandler.java
...fanticar/afantiopenapi/config/GlobalExceptionHandler.java
+15
-0
DataReportRequestDTO.java
...anticar/afantiopenapi/model/dto/DataReportRequestDTO.java
+3
-5
DataReportService.java
...om/afanticar/afantiopenapi/service/DataReportService.java
+133
-98
No files found.
src/main/java/com/afanticar/afantiopenapi/config/GlobalExceptionHandler.java
View file @
5a62112d
...
...
@@ -3,9 +3,12 @@ package com.afanticar.afantiopenapi.config;
import
com.afanticar.afantiopenapi.constant.ExceptionEnum
;
import
com.afanticar.afantiopenapi.controller.BaseController
;
import
com.afanticar.afantiopenapi.model.BaseResponse
;
import
com.afanticar.common.core.api.ResultCodeEnum
;
import
com.afanticar.common.core.exception.ApiException
;
import
org.apache.commons.lang3.exception.ExceptionUtils
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.http.converter.HttpMessageNotReadableException
;
import
org.springframework.web.bind.annotation.ExceptionHandler
;
import
org.springframework.web.bind.annotation.RestControllerAdvice
;
...
...
@@ -32,6 +35,18 @@ public class GlobalExceptionHandler {
return
handleError
(
ExceptionEnum
.
ERROR
,
e
);
}
@ExceptionHandler
(
HttpMessageNotReadableException
.
class
)
public
BaseResponse
processHttpMessageNotReadableException
(
HttpMessageNotReadableException
e
)
{
LOGGER
.
error
(
"HttpMessageNotReadableException 调用异常 => :{}"
,
ExceptionUtils
.
getStackTrace
(
e
));
return
BaseController
.
error
(
ResultCodeEnum
.
VALIDATE_FAILED
.
getCode
().
toString
(),
e
.
getMessage
());
}
@ExceptionHandler
(
ApiException
.
class
)
public
BaseResponse
processApiException
(
ApiException
e
)
{
LOGGER
.
error
(
"api 调用异常 => :{}"
,
ExceptionUtils
.
getStackTrace
(
e
));
return
BaseController
.
error
(
e
.
getCode
().
toString
(),
e
.
getMessage
());
}
private
BaseResponse
<
Object
>
handleError
(
int
code
,
String
message
,
Exception
ex
)
{
return
BaseController
.
error
(
code
+
""
,
message
);
}
...
...
src/main/java/com/afanticar/afantiopenapi/model/dto/DataReportRequestDTO.java
View file @
5a62112d
...
...
@@ -6,8 +6,8 @@ import io.swagger.annotations.ApiModel;
import
io.swagger.annotations.ApiModelProperty
;
import
lombok.Data
;
import
javax.validation.constraints.NotBlank
;
import
javax.validation.constraints.NotEmpty
;
import
java.time.LocalDate
;
import
java.util.List
;
/**
...
...
@@ -20,12 +20,10 @@ import java.util.List;
public
class
DataReportRequestDTO
{
@ApiModelProperty
(
"开始时间。格式为:yyyy-MM-dd。例如2024-01-01"
)
@NotBlank
(
message
=
"开始时间不可为空"
)
private
String
startTime
;
private
LocalDate
startTime
;
@ApiModelProperty
(
"结束时间。格式为:yyyy-MM-dd。例如2024-01-01"
)
@NotBlank
(
message
=
"结束时间不可为空"
)
private
String
endTime
;
private
LocalDate
endTime
;
@ApiModelProperty
(
"平台类型 public-公共数据 douyin-抖音 kuaishou-快手xiaohongshu-小红书 shipinhao-视频号"
)
@NotEmpty
(
message
=
"平台类型不可为空,可选类型 public-公共数据 douyin-抖音 kuaishou-快手xiaohongshu-小红书 shipinhao-视频号 "
)
...
...
src/main/java/com/afanticar/afantiopenapi/service/DataReportService.java
View file @
5a62112d
...
...
@@ -11,12 +11,15 @@ import com.afanticar.afantiopenapi.model.dto.PageInfoDTO;
import
com.afanticar.afantiopenapi.model.dto.ReportDataInfoDTO
;
import
com.afanticar.afantiopenapi.model.entity.DwsAfantiAdbDataOssRecordEntity
;
import
com.afanticar.afantiopenapi.model.entity.OpenApiClientPrincipalRelationEntity
;
import
com.afanticar.common.core.api.ResultCodeEnum
;
import
com.afanticar.common.core.exception.ApiException
;
import
com.aliyun.oss.OSS
;
import
com.aliyun.oss.OSSClientBuilder
;
import
com.baomidou.mybatisplus.extension.plugins.pagination.Page
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.google.common.collect.Lists
;
import
lombok.SneakyThrows
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.stereotype.Service
;
...
...
@@ -26,8 +29,10 @@ import java.net.URI;
import
java.net.URISyntaxException
;
import
java.net.URL
;
import
java.time.Instant
;
import
java.time.LocalDate
;
import
java.util.Date
;
import
java.util.List
;
import
java.util.Objects
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
...
...
@@ -36,104 +41,134 @@ import java.util.regex.Pattern;
* @since 2025/4/24 9:41
**/
@Service
@Slf4j
public
class
DataReportService
{
@Resource
private
OpenApiClientPrincipalRelationMapper
openApiClientPrincipalRelationMapper
;
@Resource
private
DwsAfantiAdbDataOssRecordMapper
dwsAfantiAdbDataOssRecordMapper
;
@Value
(
"${spring.rocket-mq.accessKey}"
)
private
String
ossAccessKey
;
@Value
(
"${spring.rocket-mq.secretKey}"
)
private
String
ossAccessSecret
;
private
OSS
oss
;
@PostConstruct
public
void
init
()
{
String
ossEndpoint
=
"oss-cn-hangzhou.aliyuncs.com"
;
oss
=
new
OSSClientBuilder
().
build
(
ossEndpoint
,
ossAccessKey
,
ossAccessSecret
);
}
public
CommonPageInfoDTO
<
ReportDataInfoDTO
>
report
(
String
clientId
,
DataReportRequestDTO
requestBody
)
{
List
<
OpenApiClientPrincipalRelationEntity
>
openApiClientPrincipalEntityList
=
openApiClientPrincipalRelationMapper
.
selectByClientId
(
clientId
);
if
(
CollUtil
.
isEmpty
(
openApiClientPrincipalEntityList
))
{
throw
new
ApiException
(
"客户端未配置品牌,请联系管理员"
);
}
OpenApiClientPrincipalRelationEntity
openApiClientPrincipalRelationEntity
=
openApiClientPrincipalEntityList
.
get
(
0
);
String
principalId
=
openApiClientPrincipalRelationEntity
.
getPrincipalId
();
requestBody
.
setPrincipalId
(
principalId
);
Page
<
DwsAfantiAdbDataOssRecordEntity
>
page
=
dwsAfantiAdbDataOssRecordMapper
.
page
(
new
Page
<>(
requestBody
.
getPage
(),
requestBody
.
getSize
()),
requestBody
);
return
convertToCommonPageInfo
(
page
);
}
@SneakyThrows
private
String
generatePresignedUrl
(
String
ossUrl
)
{
// 生成一个带过期时间的url
String
[]
ossObjInfo
=
parseOSSUrl
(
ossUrl
);
Instant
expireInstant
=
Instant
.
now
().
plusSeconds
(
86400
);
URL
url
=
oss
.
generatePresignedUrl
(
ossObjInfo
[
0
],
ossObjInfo
[
1
],
Date
.
from
(
expireInstant
));
return
url
.
toString
();
}
public
static
String
[]
parseOSSUrl
(
String
ossUrl
)
throws
URISyntaxException
{
// 处理URL编码的特殊字符(如%2F)
// 使用正则表达式匹配bucket和object
Pattern
pattern
=
Pattern
.
compile
(
"https?://([^.]+)\\.oss(-[^.]+)?\\.([^/]+)/(.+)"
);
Matcher
matcher
=
pattern
.
matcher
(
ossUrl
);
if
(
matcher
.
find
())
{
String
bucket
=
matcher
.
group
(
1
);
// 从匹配结果中提取object,并去掉查询参数
String
fullObjectPath
=
matcher
.
group
(
4
);
String
object
=
fullObjectPath
.
split
(
"\\?"
)[
0
];
return
new
String
[]{
bucket
,
object
};
}
// 如果正则匹配失败,尝试URI解析
URI
uri
=
new
URI
(
ossUrl
);
String
host
=
uri
.
getHost
();
if
(
host
!=
null
&&
host
.
endsWith
(
".aliyuncs.com"
))
{
String
bucket
=
host
.
split
(
"\\."
)[
0
];
String
object
=
uri
.
getPath
().
substring
(
1
);
// 去掉开头的/
return
new
String
[]{
bucket
,
object
};
}
throw
new
IllegalArgumentException
(
"无法从URL中解析出OSS bucket和object: "
+
ossUrl
);
}
private
CommonPageInfoDTO
<
ReportDataInfoDTO
>
convertToCommonPageInfo
(
Page
<
DwsAfantiAdbDataOssRecordEntity
>
page
)
{
CommonPageInfoDTO
<
ReportDataInfoDTO
>
commonPageInfo
=
new
CommonPageInfoDTO
<>();
PageInfoDTO
pageInfoDTO
=
new
PageInfoDTO
();
pageInfoDTO
.
setPage
((
int
)
page
.
getCurrent
());
pageInfoDTO
.
setSize
((
int
)
page
.
getSize
());
pageInfoDTO
.
setTotal
((
int
)
page
.
getTotal
());
pageInfoDTO
.
setTotalPage
((
int
)
page
.
getPages
());
commonPageInfo
.
setPageInfo
(
pageInfoDTO
);
List
<
DwsAfantiAdbDataOssRecordEntity
>
entityList
=
page
.
getRecords
();
List
<
ReportDataInfoDTO
>
list
=
Lists
.
newArrayList
();
for
(
DwsAfantiAdbDataOssRecordEntity
entity
:
entityList
)
{
ReportDataInfoDTO
reportDataInfo
=
new
ReportDataInfoDTO
();
reportDataInfo
.
setStatisticsDay
(
entity
.
getStatisticsDay
().
toLocalDate
());
reportDataInfo
.
setPlatform
(
entity
.
getPlatform
());
reportDataInfo
.
setDataType
(
entity
.
getDataType
());
reportDataInfo
.
setFileUrl
(
generatePresignedUrl
(
entity
.
getOssUrl
()));
reportDataInfo
.
setCtime
(
entity
.
getCtime
());
reportDataInfo
.
setMtime
(
entity
.
getMtime
());
reportDataInfo
.
setId
(
StrUtil
.
format
(
"{}:{}:{}:{}"
,
entity
.
getPrincipalId
(),
DateUtil
.
format
(
entity
.
getStatisticsDay
(),
"yyyy-MM-dd"
),
entity
.
getPlatform
(),
entity
.
getDataType
()));
list
.
add
(
reportDataInfo
);
}
commonPageInfo
.
setRows
(
list
);
return
commonPageInfo
;
}
@Resource
private
OpenApiClientPrincipalRelationMapper
openApiClientPrincipalRelationMapper
;
@Resource
private
DwsAfantiAdbDataOssRecordMapper
dwsAfantiAdbDataOssRecordMapper
;
@Resource
private
ObjectMapper
objectMapper
;
@Value
(
"${spring.rocket-mq.accessKey}"
)
private
String
ossAccessKey
;
@Value
(
"${spring.rocket-mq.secretKey}"
)
private
String
ossAccessSecret
;
private
OSS
oss
;
@PostConstruct
public
void
init
()
{
String
ossEndpoint
=
"oss-cn-hangzhou.aliyuncs.com"
;
oss
=
new
OSSClientBuilder
().
build
(
ossEndpoint
,
ossAccessKey
,
ossAccessSecret
);
}
@SneakyThrows
public
CommonPageInfoDTO
<
ReportDataInfoDTO
>
report
(
String
clientId
,
DataReportRequestDTO
requestBody
)
{
log
.
info
(
"请求数据报表入参,client_id:{}, 请求参数:{}"
,
clientId
,
objectMapper
.
writeValueAsString
(
requestBody
));
handleTimeRange
(
requestBody
);
List
<
OpenApiClientPrincipalRelationEntity
>
openApiClientPrincipalEntityList
=
openApiClientPrincipalRelationMapper
.
selectByClientId
(
clientId
);
if
(
CollUtil
.
isEmpty
(
openApiClientPrincipalEntityList
))
{
throw
new
ApiException
(
"客户端未配置品牌,请联系管理员"
);
}
OpenApiClientPrincipalRelationEntity
openApiClientPrincipalRelationEntity
=
openApiClientPrincipalEntityList
.
get
(
0
);
String
principalId
=
openApiClientPrincipalRelationEntity
.
getPrincipalId
();
requestBody
.
setPrincipalId
(
principalId
);
Page
<
DwsAfantiAdbDataOssRecordEntity
>
page
=
dwsAfantiAdbDataOssRecordMapper
.
page
(
new
Page
<>(
requestBody
.
getPage
(),
requestBody
.
getSize
()),
requestBody
);
return
convertToCommonPageInfo
(
page
);
}
private
void
handleTimeRange
(
DataReportRequestDTO
requestBody
)
{
LocalDate
yesterday
=
LocalDate
.
now
().
minusDays
(
1
);
if
(
Objects
.
nonNull
(
requestBody
.
getStartTime
()))
{
LocalDate
sevenDaysAgo
=
LocalDate
.
now
().
minusDays
(
7
);
if
(
sevenDaysAgo
.
isAfter
(
requestBody
.
getStartTime
()))
{
throw
new
ApiException
(
ResultCodeEnum
.
VALIDATE_FAILED
.
getCode
(),
"开始时间不能早于前7天"
);
}
}
if
(
Objects
.
isNull
(
requestBody
.
getStartTime
())
&&
Objects
.
isNull
(
requestBody
.
getEndTime
()))
{
requestBody
.
setStartTime
(
yesterday
);
requestBody
.
setEndTime
(
yesterday
);
}
else
if
(
Objects
.
isNull
(
requestBody
.
getStartTime
())
&&
Objects
.
nonNull
(
requestBody
.
getEndTime
()))
{
requestBody
.
setStartTime
(
requestBody
.
getEndTime
());
}
else
if
(
Objects
.
isNull
(
requestBody
.
getEndTime
())
&&
Objects
.
nonNull
(
requestBody
.
getStartTime
()))
{
requestBody
.
setEndTime
(
requestBody
.
getStartTime
());
}
else
{
if
(
requestBody
.
getEndTime
().
isBefore
(
requestBody
.
getStartTime
()))
{
throw
new
ApiException
(
ResultCodeEnum
.
VALIDATE_FAILED
.
getCode
(),
"开始时间不能晚于结束时间"
);
}
}
}
@SneakyThrows
private
String
generatePresignedUrl
(
String
ossUrl
)
{
// 生成一个带过期时间的url
String
[]
ossObjInfo
=
parseOSSUrl
(
ossUrl
);
Instant
expireInstant
=
Instant
.
now
().
plusSeconds
(
86400
);
URL
url
=
oss
.
generatePresignedUrl
(
ossObjInfo
[
0
],
ossObjInfo
[
1
],
Date
.
from
(
expireInstant
));
return
url
.
toString
();
}
public
static
String
[]
parseOSSUrl
(
String
ossUrl
)
throws
URISyntaxException
{
// 处理URL编码的特殊字符(如%2F)
// 使用正则表达式匹配bucket和object
Pattern
pattern
=
Pattern
.
compile
(
"https?://([^.]+)\\.oss(-[^.]+)?\\.([^/]+)/(.+)"
);
Matcher
matcher
=
pattern
.
matcher
(
ossUrl
);
if
(
matcher
.
find
())
{
String
bucket
=
matcher
.
group
(
1
);
// 从匹配结果中提取object,并去掉查询参数
String
fullObjectPath
=
matcher
.
group
(
4
);
String
object
=
fullObjectPath
.
split
(
"\\?"
)[
0
];
return
new
String
[]{
bucket
,
object
};
}
// 如果正则匹配失败,尝试URI解析
URI
uri
=
new
URI
(
ossUrl
);
String
host
=
uri
.
getHost
();
if
(
host
!=
null
&&
host
.
endsWith
(
".aliyuncs.com"
))
{
String
bucket
=
host
.
split
(
"\\."
)[
0
];
String
object
=
uri
.
getPath
().
substring
(
1
);
// 去掉开头的/
return
new
String
[]{
bucket
,
object
};
}
throw
new
IllegalArgumentException
(
"无法从URL中解析出OSS bucket和object: "
+
ossUrl
);
}
private
CommonPageInfoDTO
<
ReportDataInfoDTO
>
convertToCommonPageInfo
(
Page
<
DwsAfantiAdbDataOssRecordEntity
>
page
)
{
CommonPageInfoDTO
<
ReportDataInfoDTO
>
commonPageInfo
=
new
CommonPageInfoDTO
<>();
PageInfoDTO
pageInfoDTO
=
new
PageInfoDTO
();
pageInfoDTO
.
setPage
((
int
)
page
.
getCurrent
());
pageInfoDTO
.
setSize
((
int
)
page
.
getSize
());
pageInfoDTO
.
setTotal
((
int
)
page
.
getTotal
());
pageInfoDTO
.
setTotalPage
((
int
)
page
.
getPages
());
commonPageInfo
.
setPageInfo
(
pageInfoDTO
);
List
<
DwsAfantiAdbDataOssRecordEntity
>
entityList
=
page
.
getRecords
();
List
<
ReportDataInfoDTO
>
list
=
Lists
.
newArrayList
();
for
(
DwsAfantiAdbDataOssRecordEntity
entity
:
entityList
)
{
ReportDataInfoDTO
reportDataInfo
=
new
ReportDataInfoDTO
();
reportDataInfo
.
setStatisticsDay
(
entity
.
getStatisticsDay
().
toLocalDate
());
reportDataInfo
.
setPlatform
(
entity
.
getPlatform
());
reportDataInfo
.
setDataType
(
entity
.
getDataType
());
reportDataInfo
.
setFileUrl
(
generatePresignedUrl
(
entity
.
getOssUrl
()));
reportDataInfo
.
setCtime
(
entity
.
getCtime
());
reportDataInfo
.
setMtime
(
entity
.
getMtime
());
reportDataInfo
.
setId
(
StrUtil
.
format
(
"{}:{}:{}:{}"
,
entity
.
getPrincipalId
(),
DateUtil
.
format
(
entity
.
getStatisticsDay
(),
"yyyy-MM-dd"
),
entity
.
getPlatform
(),
entity
.
getDataType
()));
list
.
add
(
reportDataInfo
);
}
commonPageInfo
.
setRows
(
list
);
return
commonPageInfo
;
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment