29 changed files with 539 additions and 35 deletions
@ -0,0 +1,19 @@ |
|||
package awesome.group.game.dao.bean; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.IdType; |
|||
import com.baomidou.mybatisplus.annotation.TableId; |
|||
import lombok.Data; |
|||
|
|||
import java.sql.Timestamp; |
|||
|
|||
@Data |
|||
public class MatrixAdvAggregation { |
|||
@TableId(value = "id", type = IdType.AUTO) |
|||
private Integer id; |
|||
private Integer appId; |
|||
private Integer date; |
|||
private Integer platform;//1穿山甲,2腾讯,3百度联盟,4 Mintegral,5 快手,6游可赢,7 Sigmob,8 Admob
|
|||
private Integer advType;//1横幅,2插页,3激励视频
|
|||
private Long income;//单位:分
|
|||
private Timestamp createdAt; |
|||
} |
@ -0,0 +1,17 @@ |
|||
package awesome.group.game.dao.mapper; |
|||
|
|||
import awesome.group.game.dao.bean.MatrixAdvAggregation; |
|||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
|||
import org.apache.ibatis.annotations.Insert; |
|||
|
|||
import java.util.List; |
|||
|
|||
public interface MatrixAdvAggregationMapper extends BaseMapper<MatrixAdvAggregation> { |
|||
@Insert("<script>" + |
|||
"insert ignore into matrix_adv_aggregation(app_id, date, platform, adv_type, income) values " + |
|||
"<foreach item = 'd' index = 'index' collection = 'data' separator =',' >" + |
|||
"(#{d.appId}, #{d.date}, #{d.platform}, #{d.advType}, #{d.income})" + |
|||
"</foreach>" + |
|||
"</script>") |
|||
int insertBatch(List<MatrixAdvAggregation> data); |
|||
} |
@ -0,0 +1,14 @@ |
|||
package awesome.group.game.service.bo; |
|||
|
|||
import java.util.List; |
|||
|
|||
public class OverviewBo { |
|||
public long todayIncome; |
|||
public long totalIncome; |
|||
public List<DateIncome> prev30DaysIncome; |
|||
|
|||
public static class DateIncome { |
|||
public int date; |
|||
public long income; |
|||
} |
|||
} |
@ -0,0 +1,118 @@ |
|||
package awesome.group.game.service.util; |
|||
|
|||
import java.text.SimpleDateFormat; |
|||
import java.time.Instant; |
|||
import java.time.LocalDate; |
|||
import java.time.LocalDateTime; |
|||
import java.time.ZoneOffset; |
|||
import java.time.format.DateTimeFormatter; |
|||
import java.util.*; |
|||
|
|||
public class DateUtil { |
|||
|
|||
public static final ZoneOffset ZONE_OFFSET = ZoneOffset.of("+8"); |
|||
|
|||
private static ThreadLocal<SimpleDateFormat> sdfLocal = new ThreadLocal<>(); |
|||
|
|||
public static SimpleDateFormat getSdf() { |
|||
SimpleDateFormat sdf = sdfLocal.get(); |
|||
if (sdf == null) { |
|||
sdf = new SimpleDateFormat("yyyyMMdd"); |
|||
sdfLocal.set(sdf); |
|||
} |
|||
return sdf; |
|||
} |
|||
|
|||
public static long getDayBeginTimestamp(long timeStamp) { |
|||
Calendar c = Calendar.getInstance(); |
|||
c.setTimeInMillis(timeStamp); |
|||
int y = c.get(Calendar.YEAR); |
|||
int m = c.get(Calendar.MONTH); |
|||
int d = c.get(Calendar.DATE); |
|||
|
|||
Calendar x = Calendar.getInstance(); |
|||
x.set(y, m, d, 0, 0, 0); |
|||
x.set(Calendar.MILLISECOND, 0); |
|||
return x.getTimeInMillis(); |
|||
} |
|||
|
|||
|
|||
public static LocalDate long2Date(long timestamp) { |
|||
return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), |
|||
TimeZone.getDefault().toZoneId()).toLocalDate(); |
|||
} |
|||
|
|||
public static long date2Long(int date) { |
|||
LocalDate localDate = number2Date(date); |
|||
return localDate.atStartOfDay().toInstant(ZONE_OFFSET).toEpochMilli(); |
|||
} |
|||
|
|||
/** |
|||
* @param dateNum yyyyMMdd格式的数字,比如:20200101 |
|||
*/ |
|||
public static LocalDate number2Date(Integer dateNum) { |
|||
return string2Date(dateNum + ""); |
|||
} |
|||
|
|||
public static LocalDate string2Date(String dateStr) { |
|||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); |
|||
return LocalDate.parse(dateStr + "", formatter); |
|||
} |
|||
|
|||
public static Integer currentDate() { |
|||
LocalDate todayDate = LocalDate.now(); |
|||
return date2Number(todayDate); |
|||
} |
|||
|
|||
public static Integer date2Number(LocalDate date) { |
|||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); |
|||
return Integer.parseInt(formatter.format(date)); |
|||
} |
|||
|
|||
public static Integer date2Number(Date date) { |
|||
SimpleDateFormat sdf = getSdf(); |
|||
return Integer.parseInt(sdf.format(date)); |
|||
} |
|||
|
|||
public static Integer datePlus(Integer date, int plus) { |
|||
LocalDate localDate = number2Date(date); |
|||
return date2Number(localDate.plusDays(plus)); |
|||
} |
|||
|
|||
public static List<Integer> dateRange(Integer startDate, Integer endDate) { |
|||
LocalDate begin = number2Date(startDate); |
|||
LocalDate end = number2Date(endDate); |
|||
List<Integer> res = new ArrayList<>(); |
|||
while (!begin.isAfter(end)) { |
|||
res.add(date2Number(begin)); |
|||
begin = begin.plusDays(1); |
|||
} |
|||
return res; |
|||
} |
|||
|
|||
public static List<Integer> latestDateRange(int minus, int plus) { |
|||
LocalDate todayDate = LocalDate.now(); |
|||
List<Integer> res = new ArrayList<>(); |
|||
for (int i = 0; i < minus; i++) { |
|||
LocalDate minusDate = todayDate.minusDays(minus - i); |
|||
res.add(date2Number(minusDate)); |
|||
} |
|||
res.add(date2Number(todayDate)); |
|||
for (int i = 1; i <= plus; i++) { |
|||
LocalDate plusDate = todayDate.plusDays(i); |
|||
res.add(date2Number(plusDate)); |
|||
} |
|||
return res; |
|||
} |
|||
|
|||
public static List<Integer> latestDate(int dayCnt) { |
|||
return latestDateRange(dayCnt, dayCnt); |
|||
} |
|||
|
|||
public static int dayCntBetween(int date1, int date2) { |
|||
LocalDate localDate1 = number2Date(date1); |
|||
LocalDate localDate2 = number2Date(date2); |
|||
return (int) (localDate2.toEpochDay() - localDate1.toEpochDay()); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,16 @@ |
|||
package awesome.group.game; |
|||
|
|||
import org.springframework.boot.SpringApplication; |
|||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
|||
|
|||
/** |
|||
* @author nidaren |
|||
*/ |
|||
@SpringBootApplication |
|||
public class ServiceTestApplication { |
|||
public static void main(String[] args) throws Exception { |
|||
|
|||
SpringApplication app = new SpringApplication(ServiceTestApplication.class); |
|||
app.run(args); |
|||
} |
|||
} |
@ -0,0 +1,26 @@ |
|||
package awesome.group.game.service; |
|||
|
|||
import awesome.group.game.service.util.DateUtil; |
|||
import org.junit.jupiter.api.Test; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
|
|||
import static org.junit.jupiter.api.Assertions.*; |
|||
|
|||
class AdminServiceTest extends BaseTest{ |
|||
@Autowired |
|||
private AdminService adminService; |
|||
|
|||
@Test |
|||
void calcTargetDate() { |
|||
int date = 20240401; |
|||
for(int i = 1; i < 60; i ++) { |
|||
adminService.calcTargetDate(date); |
|||
date = DateUtil.datePlus(date, -1); |
|||
} |
|||
} |
|||
|
|||
@Test |
|||
void calcAppIncome() { |
|||
adminService.calcAppIncome(); |
|||
} |
|||
} |
@ -0,0 +1,14 @@ |
|||
package awesome.group.game.service; |
|||
|
|||
import awesome.group.game.ServiceTestApplication; |
|||
import org.junit.runner.RunWith; |
|||
import org.springframework.boot.test.context.SpringBootTest; |
|||
import org.springframework.test.annotation.Commit; |
|||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; |
|||
|
|||
|
|||
@RunWith(SpringJUnit4ClassRunner.class) |
|||
@SpringBootTest(classes = ServiceTestApplication.class) |
|||
@Commit |
|||
public class BaseTest { |
|||
} |
@ -0,0 +1,55 @@ |
|||
spring: |
|||
application: |
|||
name: game |
|||
config: |
|||
activate: |
|||
on-profile: default |
|||
aop: |
|||
auto: true |
|||
proxy-target-class: true |
|||
pid: |
|||
file: pid #pid文件名 |
|||
datasource: |
|||
game: |
|||
type: com.zaxxer.hikari.HikariDataSource |
|||
jdbcUrl: jdbc:mysql://127.0.0.1:3306/game?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&connectTimeout=300&socketTimeout=2000&serverTimezone=Hongkong&zeroDateTimeBehavior=convertToNull |
|||
username: root |
|||
password: |
|||
connectionTimeout: 300 |
|||
maximumPoolSize: 5 |
|||
minimumIdle: 1 |
|||
idleTimeout: 600000 #This property controls the maximum amount of time that a connection is allowed to sit idle in the pool |
|||
maxLifetime: 3600000 #This property controls the maximum lifetime of a connection in the pool |
|||
|
|||
mybatis-plus: |
|||
configuration: |
|||
map-underscore-to-camel-case: true #数据库字段下划线映射java对象属性用驼峰命名 |
|||
|
|||
springdoc: |
|||
api-docs: |
|||
enabled: true # 开启OpenApi接口 |
|||
path: /api/v3/api-docs # 自定义路径,默认为 "/v3/api-docs" |
|||
swagger-ui: |
|||
enabled: true # 开启swagger界面,依赖OpenApi,需要OpenApi同时开启 |
|||
path: /api/swagger-ui/index.html # 自定义路径,默认为"/swagger-ui/index.html" |
|||
|
|||
swagger: |
|||
enable: true |
|||
applicationName: matrix |
|||
applicationDescription: matrix后台 |
|||
applicationVersion: 1.0 |
|||
|
|||
server: |
|||
port: 9001 |
|||
tomcat: |
|||
connection-timeout: 60000 #Time in milliseconds that connectors will wait for another HTTP request before closing the connection. |
|||
accept-count: 100 # Maximum queue length for incoming connection requests when all possible request processing threads are in use. |
|||
max-connections: 256 # Maximum number of connections that the server will accept and process at any given time. |
|||
max-http-form-post-size: 20MB |
|||
threads: |
|||
max: 16 |
|||
min-spare: 4 |
|||
servlet: |
|||
encoding: |
|||
enabled: true |
|||
charset: utf-8 |
@ -0,0 +1,4 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<configuration> |
|||
<include resource="logconfig.xml"/> |
|||
</configuration> |
@ -0,0 +1,114 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<included> |
|||
<property name="LOG_HOME" value="logs"/> |
|||
|
|||
<conversionRule conversionWord="hostIp" converterClass="awesome.group.game.service.common.log.IPLogConfig"/> |
|||
|
|||
<springProperty scope="context" name="springAppName" source="spring.application.name"/> |
|||
|
|||
|
|||
<property name="ENCODER_PATTERN" |
|||
value="[%level][%d{yyyy-MM-dd HH:mm:ss}][%t][${springAppName:-}][%X{X-B3-TraceId:-}][%X{X-B3-SpanId:-}][%X{X-B3-ParentSpanId:-}][%hostIp][%logger{5}] - %msg%n"/> |
|||
|
|||
<!-- 文件日志:输出全部日志到文件 --> |
|||
<appender name="OUTPUT_FILE" |
|||
class="ch.qos.logback.core.rolling.RollingFileAppender"> |
|||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"> |
|||
<level>INFO</level> |
|||
</filter> |
|||
<file>${LOG_HOME}/biz.log</file> |
|||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
|||
<fileNamePattern>${LOG_HOME}/biz.log.%d{yyyyMMddHH}</fileNamePattern> |
|||
<maxHistory>72</maxHistory> |
|||
<cleanHistoryOnStart>true</cleanHistoryOnStart> |
|||
</rollingPolicy> |
|||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> |
|||
<pattern>${ENCODER_PATTERN}</pattern> |
|||
</encoder> |
|||
</appender> |
|||
<!-- 异步输出 --> |
|||
<appender name="ASYNC_OUTPUT_FILE" class="ch.qos.logback.classic.AsyncAppender"> |
|||
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 --> |
|||
<discardingThreshold>0</discardingThreshold> |
|||
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 --> |
|||
<queueSize>64</queueSize> |
|||
<!-- 添加附加的appender,最多只能添加一个 --> |
|||
<appender-ref ref="OUTPUT_FILE"/> |
|||
</appender> |
|||
|
|||
|
|||
<!--trace log pattern--> |
|||
<property name="TRACE_ENCODER_PATTERN" |
|||
value="[%level][%d{yyyy-MM-dd HH:mm:ss}][%t][${springAppName:-}][%X{X-B3-TraceId:-}][%X{X-B3-SpanId:-}][%X{X-B3-ParentSpanId:-}][%hostIp][%X{key_action:-}] - %msg%n"/> |
|||
<!--trace log 输出文件--> |
|||
<appender name="TRACE_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
|||
<file>${LOG_HOME}/trace.log</file> |
|||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
|||
<fileNamePattern>${LOG_HOME}/trace.log.%d{yyyyMMddHH}</fileNamePattern> |
|||
<maxHistory>72</maxHistory> |
|||
<cleanHistoryOnStart>true</cleanHistoryOnStart> |
|||
</rollingPolicy> |
|||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> |
|||
<Pattern>${TRACE_ENCODER_PATTERN}</Pattern> |
|||
</encoder> |
|||
</appender> |
|||
|
|||
<!-- 异步输出 --> |
|||
<appender name="ASYNC_TRACE_FILE" class="ch.qos.logback.classic.AsyncAppender"> |
|||
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 --> |
|||
<discardingThreshold>0</discardingThreshold> |
|||
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 --> |
|||
<queueSize>64</queueSize> |
|||
<!-- 添加附加的appender,最多只能添加一个 --> |
|||
<appender-ref ref="TRACE_FILE"/> |
|||
</appender> |
|||
|
|||
<!-- api日志--> |
|||
<property name="API_ENCODER_PATTERN" |
|||
value="[%level][%d{yyyy-MM-dd HH:mm:ss}][%t][${springAppName:-}][%X{key_method_name:-}][%X{X-B3-TraceId:-}][%X{X-B3-SpanId:-}][%X{X-B3-ParentSpanId:-}][%hostIp][%X{key_cost:-}][%X{key_status:-}][%X{key_jwt:-}] - %msg%n"/> |
|||
<appender name="API_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
|||
<file>${LOG_HOME}/api.log</file> |
|||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
|||
<fileNamePattern>${LOG_HOME}/api.log.%d{yyyyMMddHH}</fileNamePattern> |
|||
<maxHistory>24</maxHistory> |
|||
<cleanHistoryOnStart>true</cleanHistoryOnStart> |
|||
</rollingPolicy> |
|||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> |
|||
<Pattern>${API_ENCODER_PATTERN}</Pattern> |
|||
</encoder> |
|||
</appender> |
|||
|
|||
<!-- 异步输出 --> |
|||
<appender name="ASYNC_API_FILE" class="ch.qos.logback.classic.AsyncAppender"> |
|||
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 --> |
|||
<discardingThreshold>0</discardingThreshold> |
|||
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 --> |
|||
<queueSize>64</queueSize> |
|||
<!-- 添加附加的appender,最多只能添加一个 --> |
|||
<appender-ref ref="API_FILE"/> |
|||
</appender> |
|||
<!-- api日志--> |
|||
|
|||
|
|||
<logger name="log.trace" level="INFO" additivity="false"> |
|||
<appender-ref ref="ASYNC_TRACE_FILE"/> |
|||
</logger> |
|||
|
|||
<logger name="log.api" level="INFO" additivity="false"> |
|||
<appender-ref ref="ASYNC_API_FILE"/> |
|||
</logger> |
|||
|
|||
|
|||
<logger name="org.apache.catalina.startup.DigesterFactory" level="ERROR"/> |
|||
<logger name="org.apache.catalina.util.LifecycleBase" level="ERROR"/> |
|||
<logger name="org.apache.coyote.http11.Http11NioProtocol" level="WARN"/> |
|||
<logger name="org.apache.sshd.common.util.SecurityUtils" level="WARN"/> |
|||
<logger name="org.apache.tomcat.util.net.NioSelectorPool" level="WARN"/> |
|||
<logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="ERROR"/> |
|||
<logger name="org.hibernate.validator.internal.util.Version" level="WARN"/> |
|||
|
|||
<root additivity="false"> |
|||
<level value="INFO"/> |
|||
<appender-ref ref="ASYNC_OUTPUT_FILE"/> |
|||
</root> |
|||
</included> |
@ -1,13 +1,15 @@ |
|||
package awesome.group; |
|||
package awesome.group.game; |
|||
|
|||
import org.springframework.boot.SpringApplication; |
|||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
|||
import org.springframework.boot.context.ApplicationPidFileWriter; |
|||
import org.springframework.boot.web.servlet.ServletComponentScan; |
|||
import org.springframework.context.annotation.EnableAspectJAutoProxy; |
|||
import org.springframework.scheduling.annotation.EnableScheduling; |
|||
|
|||
@SpringBootApplication |
|||
@ServletComponentScan |
|||
@EnableScheduling |
|||
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true) |
|||
public class Application { |
|||
public static void main(String[] args) { |
@ -1,4 +1,4 @@ |
|||
package awesome.group; |
|||
package awesome.group.game.web; |
|||
|
|||
import jakarta.servlet.http.HttpServletRequest; |
|||
import jakarta.servlet.http.HttpServletResponse; |
@ -1,4 +1,4 @@ |
|||
package awesome.group.aop; |
|||
package awesome.group.game.web.aop; |
|||
|
|||
import java.lang.annotation.ElementType; |
|||
import java.lang.annotation.Retention; |
@ -1,6 +1,6 @@ |
|||
package awesome.group.aop; |
|||
package awesome.group.game.web.aop; |
|||
|
|||
import awesome.group.RequestContext; |
|||
import awesome.group.game.web.RequestContext; |
|||
|
|||
import awesome.group.game.service.common.exception.PaganiException; |
|||
import awesome.group.game.service.common.exception.PaganiExceptionCode; |
@ -1,4 +1,4 @@ |
|||
package awesome.group.config; |
|||
package awesome.group.game.web.config; |
|||
|
|||
import io.swagger.v3.oas.models.ExternalDocumentation; |
|||
import io.swagger.v3.oas.models.OpenAPI; |
@ -1,4 +1,4 @@ |
|||
package awesome.group.config; |
|||
package awesome.group.game.web.config; |
|||
|
|||
import org.springframework.boot.context.properties.ConfigurationProperties; |
|||
import org.springframework.stereotype.Component; |
@ -1,6 +1,6 @@ |
|||
package awesome.group.controller; |
|||
package awesome.group.game.web.controller; |
|||
|
|||
import awesome.group.aop.RestApi; |
|||
import awesome.group.game.web.aop.RestApi; |
|||
import awesome.group.game.service.AppService; |
|||
import awesome.group.game.service.bo.AppInfo; |
|||
import awesome.group.game.service.common.response.R; |
@ -1,7 +1,7 @@ |
|||
package awesome.group.controller; |
|||
package awesome.group.game.web.controller; |
|||
|
|||
import awesome.group.RequestContext; |
|||
import awesome.group.aop.RestApi; |
|||
import awesome.group.game.web.RequestContext; |
|||
import awesome.group.game.web.aop.RestApi; |
|||
import awesome.group.game.service.WxService; |
|||
import awesome.group.game.service.bo.*; |
|||
import awesome.group.game.service.common.response.R; |
@ -1,7 +1,7 @@ |
|||
package awesome.group.controller; |
|||
package awesome.group.game.web.controller; |
|||
|
|||
import awesome.group.RequestContext; |
|||
import awesome.group.aop.RestApi; |
|||
import awesome.group.game.web.RequestContext; |
|||
import awesome.group.game.web.aop.RestApi; |
|||
import awesome.group.game.service.MatrixService; |
|||
import awesome.group.game.service.bo.MatrixAdvRecordEditBo; |
|||
import awesome.group.game.service.common.response.R; |
@ -1,6 +1,6 @@ |
|||
package awesome.group.filter; |
|||
package awesome.group.game.web.filter; |
|||
|
|||
import awesome.group.RequestContext; |
|||
import awesome.group.game.web.RequestContext; |
|||
import awesome.group.game.service.common.log.L; |
|||
import awesome.group.game.service.common.response.R; |
|||
import awesome.group.game.service.util.JwtUtils; |
@ -1,6 +1,6 @@ |
|||
package awesome.group.filter; |
|||
package awesome.group.game.web.filter; |
|||
|
|||
import awesome.group.RequestContext; |
|||
import awesome.group.game.web.RequestContext; |
|||
import awesome.group.game.service.common.log.L; |
|||
import awesome.group.game.service.common.response.R; |
|||
import awesome.group.game.service.util.JwtUtils; |
Loading…
Reference in new issue