Compare commits
65
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ebe6b1fcd | ||
|
|
21ee60de10 | ||
|
|
534dd4ed9c | ||
|
|
6d3b0db745 | ||
|
|
e1abbea5d9 | ||
|
|
a7bd61945d | ||
|
|
c8ceb9c8ca | ||
|
|
402baf2201 | ||
|
|
28aa1337b4 | ||
|
|
21920ea7fe | ||
|
|
fcae667457 | ||
|
|
afaef4d1b2 | ||
|
|
a6b651065f | ||
|
|
56b216406e | ||
|
|
3e1bbfbd02 | ||
|
|
251073b26d | ||
|
|
8d6a2860d9 | ||
|
|
b0c3c311af | ||
|
|
64785bb87d | ||
|
|
4d0738b391 | ||
|
|
6823ac07c4 | ||
|
|
28625f193c | ||
|
|
0fcc4c96ac | ||
|
|
3b0403052b | ||
|
|
bdf9b6dc5e | ||
|
|
a8654d0a35 | ||
|
|
310d87e851 | ||
|
|
5269fb9149 | ||
|
|
e940edeee9 | ||
|
|
c3f7bb571f | ||
|
|
db41228ce8 | ||
|
|
294e5efdae | ||
|
|
4efd86751a | ||
|
|
c1583de157 | ||
|
|
c35a05ac08 | ||
|
|
33299e3b2e | ||
|
|
2c9793858b | ||
|
|
a16e93ec09 | ||
|
|
a0634f15ac | ||
|
|
a4173984e5 | ||
|
|
a9f04eb785 | ||
|
|
251b4c660a | ||
|
|
790ded499c | ||
|
|
b8d957fccb | ||
|
|
24d20d954c | ||
|
|
da26b631a6 | ||
|
|
307fd4327f | ||
|
|
ae8d90a29a | ||
|
|
eb2e5204be | ||
|
|
2e301dc897 | ||
|
|
0856ff823c | ||
|
|
58819bb5b9 | ||
|
|
01efd2267a | ||
|
|
4d58244007 | ||
|
|
6abaa5cb5e | ||
|
|
e5534fe4a3 | ||
|
|
d56d195e99 | ||
|
|
ca0b85e8f1 | ||
|
|
2158909259 | ||
|
|
f9b0d65ab4 | ||
|
|
0d4bc5284f | ||
|
|
bcf984e191 | ||
|
|
06ad9b6782 | ||
|
|
a90d5c5ce7 | ||
|
|
7ce0439ab2 |
@@ -49,3 +49,5 @@ hs_err_pid*
|
||||
**/*.log
|
||||
**/gifs/
|
||||
**/deploy/
|
||||
|
||||
**/app-**.yml
|
||||
@@ -101,13 +101,15 @@ proxy:
|
||||
# 获取license提示间隔(秒)
|
||||
obtain-license-interval: 5
|
||||
```
|
||||
## 5.5、代理示意图
|
||||

|
||||
|
||||
## 5.5、启动客户端
|
||||
## 5.6、启动客户端
|
||||
> fun.asgc.neutrino.proxy.client.ProxyClient
|
||||
默认情况下,客户端会加载当前目录下的.neutrino-proxy.license里的license,可通过命令行参数指定,如:java -jar neutrino-proxy-client.jar license=xxx
|
||||
若启动参数未指定license,且是首次启动(当前目录下未缓存license),则需要根据命令行提示输入正确的license, 输入完成后完成连接,可在服务端管理页面控制端口转发,参见[2、运行示例](#2)
|
||||
|
||||
## 5.6、Docker快速启动
|
||||
## 5.7、Docker快速启动
|
||||
```shell script
|
||||
# 一键部署前端和后端,客户端按上方部署即可
|
||||
docker run -it -p 9000-9200:9000-9200/tcp -p 8888:8888 -d --name neutrino registry.cn-hangzhou.aliyuncs.com/asgc/aoshiguchen-docker-images:1.64
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.noear</groupId>
|
||||
<artifactId>solon-parent</artifactId>
|
||||
<version>2.2.2</version>
|
||||
</parent>
|
||||
|
||||
<groupId>fun.asgc</groupId>
|
||||
<artifactId>job-solon-plugin</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.noear</groupId>
|
||||
<artifactId>solon</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
<!--quartz-->
|
||||
<dependency>
|
||||
<groupId>org.quartz-scheduler</groupId>
|
||||
<artifactId>quartz</artifactId>
|
||||
<version>2.3.1</version>
|
||||
</dependency>
|
||||
<!--hutool-->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
<version>5.8.15</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package fun.asgc.solon.extend.job;
|
||||
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/9/4
|
||||
*/
|
||||
public class CustomThreadFactory implements ThreadFactory {
|
||||
private final ThreadGroup group;
|
||||
private final AtomicInteger threadNumber = new AtomicInteger(1);
|
||||
private final String namePrefix;
|
||||
|
||||
public CustomThreadFactory(String prefix) {
|
||||
SecurityManager s = System.getSecurityManager();
|
||||
group = (s != null) ? s.getThreadGroup() :
|
||||
Thread.currentThread().getThreadGroup();
|
||||
namePrefix = prefix + "-thread-";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
|
||||
if (t.isDaemon()) {
|
||||
t.setDaemon(false);
|
||||
}
|
||||
if (t.getPriority() != Thread.NORM_PRIORITY) {
|
||||
t.setPriority(Thread.NORM_PRIORITY);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package fun.asgc.solon.extend.job;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/9/4
|
||||
*/
|
||||
public interface IJobCallback {
|
||||
|
||||
/**
|
||||
* 执行日志
|
||||
* @param jobInfo
|
||||
* @param param
|
||||
* @param throwable
|
||||
*/
|
||||
void executeLog(JobInfo jobInfo, String param, Throwable throwable);
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package fun.asgc.solon.extend.job;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/9/4
|
||||
*/
|
||||
public interface IJobExecutor {
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @throws JobException
|
||||
*/
|
||||
void init() throws Exception;
|
||||
|
||||
/**
|
||||
* 新增job
|
||||
* @param jobInfo
|
||||
*/
|
||||
void add(JobInfo jobInfo);
|
||||
|
||||
/**
|
||||
* 删除job
|
||||
* @param jobName
|
||||
*/
|
||||
void remove(String jobName);
|
||||
|
||||
/**
|
||||
* 触发
|
||||
* @param jobName
|
||||
* @param param
|
||||
*/
|
||||
void trigger(String jobName, String param);
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package fun.asgc.solon.extend.job;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/9/4
|
||||
*/
|
||||
public interface IJobHandler {
|
||||
|
||||
/**
|
||||
* job执行
|
||||
* @param param
|
||||
* @throws Exception
|
||||
*/
|
||||
void execute(String param) throws Exception;
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package fun.asgc.solon.extend.job;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/9/4
|
||||
*/
|
||||
public interface IJobSource {
|
||||
|
||||
/**
|
||||
* 获取所有job列表
|
||||
* @return
|
||||
*/
|
||||
List<JobInfo> sourceList();
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package fun.asgc.solon.extend.job;
|
||||
|
||||
import fun.asgc.solon.extend.job.impl.JobExecutor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.noear.solon.Solon;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/9/4
|
||||
*/
|
||||
@Slf4j
|
||||
public class JobBean implements Job {
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
|
||||
JobExecutor jobExecutor = Solon.context().getBean(JobExecutor.class);
|
||||
if (null != jobExecutor) {
|
||||
jobExecutor.execute(jobExecutionContext);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package fun.asgc.solon.extend.job;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/9/4
|
||||
*/
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
public class JobInfo {
|
||||
private String id;
|
||||
private String name;
|
||||
private String desc;
|
||||
private String cron;
|
||||
private String param;
|
||||
private boolean enable;
|
||||
private Map<String, Object> extension;
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package fun.asgc.solon.extend.job;
|
||||
|
||||
import fun.asgc.solon.extend.job.annotation.EnableJob;
|
||||
import fun.asgc.solon.extend.job.impl.DefaultJobCallback;
|
||||
import fun.asgc.solon.extend.job.impl.DefaultJobSource;
|
||||
import fun.asgc.solon.extend.job.impl.JobExecutor;
|
||||
import org.noear.solon.Solon;
|
||||
import org.noear.solon.core.AopContext;
|
||||
import org.noear.solon.core.Plugin;
|
||||
import org.noear.solon.core.event.AppLoadEndEvent;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2023/3/11
|
||||
*/
|
||||
public class XPluginImp implements Plugin {
|
||||
|
||||
@Override
|
||||
public void start(AopContext context) throws Throwable {
|
||||
EnableJob enableJob = Solon.app().source().getAnnotation(EnableJob.class);
|
||||
if (null == enableJob || !enableJob.value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//应用加载完后,再启动任务
|
||||
Solon.app().onEvent(AppLoadEndEvent.class, e -> {
|
||||
IJobSource jobSource = context.getBean(IJobSource.class);
|
||||
IJobCallback jobCallback = context.getBean(IJobCallback.class);
|
||||
if (null == jobSource) {
|
||||
jobSource = new DefaultJobSource();
|
||||
}
|
||||
if (null == jobCallback) {
|
||||
jobCallback = new DefaultJobCallback();
|
||||
}
|
||||
|
||||
JobExecutor jobExecutor = new JobExecutor();
|
||||
jobExecutor.setJobSource(jobSource);
|
||||
jobExecutor.setJobCallback(jobCallback);
|
||||
jobExecutor.start();
|
||||
|
||||
context.wrapAndPut(JobExecutor.class, jobExecutor);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package fun.asgc.solon.extend.job.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2023/3/12
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface EnableJob {
|
||||
boolean value() default true;
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package fun.asgc.solon.extend.job.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/9/4
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface JobHandler {
|
||||
String name();
|
||||
String desc() default "";
|
||||
String cron();
|
||||
String param() default "";
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package fun.asgc.solon.extend.job.impl;
|
||||
|
||||
import fun.asgc.solon.extend.job.IJobCallback;
|
||||
import fun.asgc.solon.extend.job.JobInfo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2023/3/12
|
||||
*/
|
||||
@Slf4j
|
||||
public class DefaultJobCallback implements IJobCallback {
|
||||
|
||||
@Override
|
||||
public void executeLog(JobInfo jobInfo, String param, Throwable throwable) {
|
||||
if (null == throwable) {
|
||||
log.debug("[Solon Plugin Job] Job执行 id:{} name:{} desc:{} param:{}", jobInfo.getId(), jobInfo.getName(), jobInfo.getDesc(), param);
|
||||
} else {
|
||||
log.error("[Solon Plugin Job] Job执行 id:{} name:{} desc:{} param:{}", jobInfo.getId(), jobInfo.getName(), jobInfo.getDesc(), param, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package fun.asgc.solon.extend.job.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import fun.asgc.solon.extend.job.IJobHandler;
|
||||
import fun.asgc.solon.extend.job.IJobSource;
|
||||
import fun.asgc.solon.extend.job.annotation.JobHandler;
|
||||
import fun.asgc.solon.extend.job.JobInfo;
|
||||
import org.noear.solon.Solon;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/9/4
|
||||
*/
|
||||
public class DefaultJobSource implements IJobSource {
|
||||
|
||||
@Override
|
||||
public List<JobInfo> sourceList() {
|
||||
List<IJobHandler> jobHandlerList = Solon.context().getBeansOfType(IJobHandler.class);
|
||||
if (CollectionUtil.isEmpty(jobHandlerList)) {
|
||||
return CollectionUtil.newArrayList();
|
||||
}
|
||||
List<JobInfo> jobInfoList = CollectionUtil.newArrayList();
|
||||
for (IJobHandler jobHandler : jobHandlerList) {
|
||||
JobHandler handler = jobHandler.getClass().getAnnotation(JobHandler.class);
|
||||
if (null == handler || StrUtil.isEmpty(handler.name()) || StrUtil.isEmpty(handler.cron())) {
|
||||
continue;
|
||||
}
|
||||
jobInfoList.add(new JobInfo()
|
||||
.setId(handler.name())
|
||||
.setName(handler.name())
|
||||
.setDesc(handler.desc())
|
||||
.setCron(handler.cron())
|
||||
.setParam(handler.param())
|
||||
.setEnable(true)
|
||||
);
|
||||
}
|
||||
return jobInfoList;
|
||||
}
|
||||
|
||||
}
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
package fun.asgc.solon.extend.job.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import fun.asgc.solon.extend.job.*;
|
||||
import fun.asgc.solon.extend.job.annotation.JobHandler;
|
||||
import org.noear.solon.Solon;
|
||||
import org.quartz.*;
|
||||
import org.quartz.impl.StdSchedulerFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Job执行器
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/9/4
|
||||
*/
|
||||
public class JobExecutor implements IJobExecutor {
|
||||
private IJobSource jobSource;
|
||||
private ThreadPoolExecutor threadPoolExecutor;
|
||||
private Map<String, JobInfo> jobInfoMap = new ConcurrentHashMap<>();
|
||||
private SchedulerFactory schedulerFactory;
|
||||
private Scheduler scheduler;
|
||||
private Map<String, IJobHandler> jobHandlerMap = new ConcurrentHashMap<>();
|
||||
private Set<String> runJobSet = CollectionUtil.newHashSet();
|
||||
private IJobCallback jobCallback;
|
||||
private Map<String, TriggerKey> triggerKeyMap = new ConcurrentHashMap<>();
|
||||
|
||||
public void start() {
|
||||
if (null == threadPoolExecutor) {
|
||||
threadPoolExecutor = new ThreadPoolExecutor(5, 20, 10L, TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<>(), new CustomThreadFactory("SolonJob"));
|
||||
}
|
||||
|
||||
List<IJobHandler> jobHandlerList = Solon.context().getBeansOfType(IJobHandler.class);
|
||||
if (!CollectionUtil.isEmpty(jobHandlerList)) {
|
||||
for (IJobHandler item : jobHandlerList) {
|
||||
JobHandler jobHandler = item.getClass().getAnnotation(JobHandler.class);
|
||||
if (null == jobHandler) {
|
||||
continue;
|
||||
}
|
||||
jobHandlerMap.put(jobHandler.name(), item);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
this.schedulerFactory = new StdSchedulerFactory();
|
||||
this.scheduler = schedulerFactory.getScheduler();
|
||||
this.init();
|
||||
} catch (Exception e){
|
||||
throw new RuntimeException("job初始化异常");
|
||||
}
|
||||
}
|
||||
|
||||
public void setJobSource(IJobSource jobSource) {
|
||||
this.jobSource = jobSource;
|
||||
}
|
||||
|
||||
public void setThreadPoolExecutor(ThreadPoolExecutor threadPoolExecutor) {
|
||||
this.threadPoolExecutor = threadPoolExecutor;
|
||||
}
|
||||
|
||||
public void setJobCallback(IJobCallback jobCallback) {
|
||||
this.jobCallback = jobCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() throws Exception {
|
||||
List<JobInfo> jobInfoList = jobSource.sourceList();
|
||||
if (CollectionUtil.isEmpty(jobInfoList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (JobInfo jobInfo : jobInfoList) {
|
||||
add(jobInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(JobInfo jobInfo) {
|
||||
if (null == jobInfo || StrUtil.isEmpty(jobInfo.getId()) || StrUtil.isEmpty(jobInfo.getName()) ||
|
||||
StrUtil.isEmpty(jobInfo.getCron())) {
|
||||
return;
|
||||
}
|
||||
synchronized (jobInfo.getId()) {
|
||||
runJobSet.add(jobInfo.getName());
|
||||
jobInfoMap.put(jobInfo.getId(), jobInfo);
|
||||
|
||||
TriggerKey triggerKey = TriggerKey.triggerKey(jobInfo.getId());
|
||||
triggerKeyMap.put(jobInfo.getId(), triggerKey);
|
||||
JobKey jobKey = new JobKey(jobInfo.getName());
|
||||
|
||||
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(jobInfo.getCron()).withMisfireHandlingInstructionDoNothing();
|
||||
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
|
||||
JobDetail jobDetail = JobBuilder.newJob(JobBean.class).withIdentity(jobKey).build();
|
||||
|
||||
try {
|
||||
if (jobInfo.isEnable()) {
|
||||
scheduler.scheduleJob(jobDetail, cronTrigger);
|
||||
scheduler.start();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(String.format("新增job[name=%s]异常", jobInfo.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(String jobId) {
|
||||
JobInfo jobInfo = jobInfoMap.get(jobId);
|
||||
if (null == jobInfo) {
|
||||
return;
|
||||
}
|
||||
synchronized (jobId) {
|
||||
runJobSet.remove(jobInfo.getName());
|
||||
unscheduleJob(jobId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trigger(String jobId, String param) {
|
||||
doExecute(jobId, param);
|
||||
}
|
||||
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException {
|
||||
if (null == context || null == context.getTrigger()) {
|
||||
return;
|
||||
}
|
||||
String jobId = context.getTrigger().getKey().getName();
|
||||
JobInfo jobInfo = jobInfoMap.get(jobId);
|
||||
if (null == jobInfo) {
|
||||
unscheduleJob(jobId);
|
||||
return;
|
||||
}
|
||||
doExecute(jobId, jobInfo.getParam());
|
||||
}
|
||||
|
||||
private void unscheduleJob(String jobId) {
|
||||
TriggerKey triggerKey = triggerKeyMap.get(jobId);
|
||||
if (null != triggerKey) {
|
||||
try {
|
||||
scheduler.unscheduleJob(triggerKey);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void doExecute(String jobId, String param) {
|
||||
JobInfo jobInfo = jobInfoMap.get(jobId);
|
||||
if (null == jobInfo) {
|
||||
return;
|
||||
}
|
||||
IJobHandler jobHandler =jobHandlerMap.get(jobInfo.getName());
|
||||
if (null == jobHandler) {
|
||||
return;
|
||||
}
|
||||
threadPoolExecutor.submit(() -> {
|
||||
try {
|
||||
jobHandler.execute(param);
|
||||
if (null != jobCallback) {
|
||||
jobCallback.executeLog(jobInfo, param, null);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
jobCallback.executeLog(jobInfo, param, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
package fun.asgc.solon.extend.job;
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
solon.plugin=fun.asgc.solon.extend.job.XPluginImp
|
||||
solon.plugin.priority=2
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.noear</groupId>
|
||||
<artifactId>solon-parent</artifactId>
|
||||
<version>2.2.2</version>
|
||||
</parent>
|
||||
|
||||
<groupId>fun.asgc</groupId>
|
||||
<artifactId>orika-solon-plugin</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.noear</groupId>
|
||||
<artifactId>solon</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--orika-->
|
||||
<dependency>
|
||||
<groupId>ma.glasnost.orika</groupId>
|
||||
<artifactId>orika-core</artifactId>
|
||||
<version>1.5.4</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package fun.asgc.solon.extend.orika;
|
||||
|
||||
import ma.glasnost.orika.CustomConverter;
|
||||
import ma.glasnost.orika.Mapper;
|
||||
import ma.glasnost.orika.MapperFacade;
|
||||
import ma.glasnost.orika.MapperFactory;
|
||||
import ma.glasnost.orika.impl.DefaultMapperFactory;
|
||||
import ma.glasnost.orika.metadata.ClassMapBuilder;
|
||||
import org.noear.solon.core.AopContext;
|
||||
import org.noear.solon.core.Plugin;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2023/3/11
|
||||
*/
|
||||
public class XPluginImp implements Plugin {
|
||||
@Override
|
||||
public void start(AopContext context) throws Throwable {
|
||||
DefaultMapperFactory factory = new DefaultMapperFactory.Builder().build();
|
||||
context.subBeansOfType(CustomConverter.class, bean -> {
|
||||
factory.getConverterFactory().registerConverter(bean);
|
||||
});
|
||||
context.subBeansOfType(Mapper.class, bean -> {
|
||||
factory.registerMapper(bean);
|
||||
});
|
||||
context.subBeansOfType(ClassMapBuilder.class, bean -> {
|
||||
factory.registerClassMap((ClassMapBuilder<? extends Object, ? extends Object>) bean);
|
||||
});
|
||||
context.wrapAndPut(MapperFactory.class, factory);
|
||||
context.wrapAndPut(MapperFacade.class, factory.getMapperFacade());
|
||||
}
|
||||
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
package fun.asgc.solon.extend.orika;
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
solon.plugin=fun.asgc.solon.extend.orika.XPluginImp
|
||||
solon.plugin.priority=1
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 183 KiB |
@@ -26,21 +26,18 @@
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid</artifactId>
|
||||
<version>1.1.24</version>
|
||||
<groupId>com.zaxxer</groupId>
|
||||
<artifactId>HikariCP</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.29</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<version>3.7.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -36,4 +36,5 @@ import java.lang.annotation.*;
|
||||
@NonIntercept
|
||||
public @interface NeutrinoApplication {
|
||||
String[] scanBasePackages() default {};
|
||||
String environmentVariableKey() default "";
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import fun.asgc.neutrino.core.aop.compiler.internal.SpringBootJarClassLoader;
|
||||
import fun.asgc.neutrino.core.base.GlobalConfig;
|
||||
import fun.asgc.neutrino.core.util.CollectionUtil;
|
||||
import fun.asgc.neutrino.core.util.FileUtil;
|
||||
@@ -54,6 +55,7 @@ public class AsgcCompiler {
|
||||
private boolean isSaveClassFile;
|
||||
private String generatorCodeSavePath;
|
||||
private DynamicClassLoader dynamicClassLoader;
|
||||
private SpringBootJarClassLoader springBootJarClassLoader;
|
||||
|
||||
private final List<Diagnostic<? extends JavaFileObject>> errors = new ArrayList<Diagnostic<? extends JavaFileObject>>();
|
||||
private final List<Diagnostic<? extends JavaFileObject>> warnings = new ArrayList<Diagnostic<? extends JavaFileObject>>();
|
||||
@@ -73,11 +75,22 @@ public class AsgcCompiler {
|
||||
if (null == javaCompiler) {
|
||||
throw new RuntimeException("Can not load JavaCompiler from javax.tools.ToolProvider#getSystemJavaCompiler(),\n please confirm the application running in JDK not JRE.");
|
||||
}
|
||||
this.springBootJarClassLoader = new SpringBootJarClassLoader(classLoader);
|
||||
// if (SystemUtil.isStartupFromJar() && GlobalConfig.isIsUseSpringBootJar()) {
|
||||
// try {
|
||||
// log.debug("使用LaunchedURLClassLoader jar路径:{}", SystemUtil.getCurrentJarFilePath());
|
||||
// parent = new SpringBootJarClassLoader(classLoader);
|
||||
// log.debug("使用LaunchedURLClassLoader instance:{}", parent);
|
||||
// } catch (Exception e) {
|
||||
// // ignore
|
||||
// log.error("使用LaunchedURLClassLoader异常", e);
|
||||
// }
|
||||
// }
|
||||
this.collector = new DiagnosticCollector<>();
|
||||
this.standardJavaFileManager = javaCompiler.getStandardFileManager(collector, null, null);
|
||||
this.isSaveClassFile = false;
|
||||
this.generatorCodeSavePath = GlobalConfig.getGeneratorCodeSavePath();
|
||||
this.dynamicClassLoader = new DynamicClassLoader(classLoader, this);
|
||||
this.dynamicClassLoader = new DynamicClassLoader(springBootJarClassLoader, this);
|
||||
|
||||
addOption("-Xlint:unchecked");
|
||||
addOption("-implicit:class");
|
||||
@@ -169,19 +182,33 @@ public class AsgcCompiler {
|
||||
compilationUnits.add(javaFileObject);
|
||||
}
|
||||
|
||||
public void addDependSpringBootJar(String path) {
|
||||
try {
|
||||
this.springBootJarClassLoader.addJar(path);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 编译代码
|
||||
* @param pkg 包名
|
||||
* @param className 类名
|
||||
* @param sourceCode 源代码
|
||||
*/
|
||||
public Class<?> compile(String pkg, String className, String sourceCode) throws ClassNotFoundException {
|
||||
public Class<?> compile(String className, String sourceCode) throws ClassNotFoundException {
|
||||
log.info("options:" + getOptions());
|
||||
int index = className.lastIndexOf(".");
|
||||
String pkg = "";
|
||||
String simpleClassName = className;
|
||||
if (index >= 0) {
|
||||
pkg = className.substring(0, index);
|
||||
simpleClassName = className.substring(index + 1);
|
||||
}
|
||||
JavaFileManager javaFileManager = new DynamicJavaFileManager(standardJavaFileManager, dynamicClassLoader);
|
||||
Iterable<? extends JavaFileObject> compilationUnits = Lists.newArrayList(new StringSource(className, sourceCode));
|
||||
if (GlobalConfig.isSaveGeneratorCode()) {
|
||||
javaFileManager = standardJavaFileManager;
|
||||
File file = FileUtil.save(GlobalConfig.getGeneratorCodeSavePath() + pkg.replaceAll("\\.", "/"), className + ".java", sourceCode);
|
||||
File file = FileUtil.save(GlobalConfig.getGeneratorCodeSavePath() + pkg.replaceAll("\\.", "/"), simpleClassName + ".java", sourceCode);
|
||||
compilationUnits = standardJavaFileManager.getJavaFileObjects(file);
|
||||
addClasspath(GlobalConfig.getGeneratorCodeSavePath());
|
||||
}
|
||||
@@ -208,7 +235,7 @@ public class AsgcCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
return dynamicClassLoader.findClass(pkg + "." + className);
|
||||
return dynamicClassLoader.findClass(className);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+6
@@ -21,6 +21,8 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.core.aop.compiler;
|
||||
|
||||
import fun.asgc.neutrino.core.aop.compiler.internal.SpringBootJarParser;
|
||||
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.NestingKind;
|
||||
import javax.tools.JavaFileObject;
|
||||
@@ -50,6 +52,10 @@ public class CustomJavaFileObject implements JavaFileObject {
|
||||
|
||||
@Override
|
||||
public InputStream openInputStream() throws IOException {
|
||||
InputStream in = SpringBootJarParser.getInputStream(uri);
|
||||
if (null != in) {
|
||||
return in;
|
||||
}
|
||||
return uri.toURL().openStream();
|
||||
}
|
||||
|
||||
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal;
|
||||
|
||||
|
||||
import fun.asgc.neutrino.core.aop.compiler.internal.archive.Archive;
|
||||
import fun.asgc.neutrino.core.aop.compiler.internal.archive.JarFileArchive;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@link ClassLoader} used by the {@link Launcher}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Dave Syer
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class SpringBootJarClassLoader extends URLClassLoader {
|
||||
protected static final String BOOT_CLASSPATH_INDEX_ATTRIBUTE = "Spring-Boot-Classpath-Index";
|
||||
protected static final String DEFAULT_CLASSPATH_INDEX_FILE_NAME = "classpath.idx";
|
||||
|
||||
static {
|
||||
ClassLoader.registerAsParallelCapable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link SpringBootJarClassLoader} instance.
|
||||
* @param parent the parent class loader for delegation
|
||||
*/
|
||||
public SpringBootJarClassLoader(ClassLoader parent) {
|
||||
super(new URL[0], parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link SpringBootJarClassLoader} instance.
|
||||
*/
|
||||
public SpringBootJarClassLoader() {
|
||||
super(new URL[0], ClassLoader.getSystemClassLoader());
|
||||
}
|
||||
|
||||
public void addJar(String path) throws Exception {
|
||||
Archive archive = createArchive(path);
|
||||
Iterator<Archive> archives = getClassPathArchivesIterator(archive);
|
||||
List<URL> urls = new ArrayList<>(50);
|
||||
while (archives.hasNext()) {
|
||||
urls.add(archives.next().getUrl());
|
||||
}
|
||||
urls.forEach(url -> addURL(url));
|
||||
}
|
||||
|
||||
private Archive createArchive(String path) throws Exception {
|
||||
if (path == null) {
|
||||
throw new IllegalStateException("Unable to determine code source archive");
|
||||
}
|
||||
File root = new File(path);
|
||||
if (!root.exists()) {
|
||||
throw new IllegalStateException("Unable to determine code source archive from " + root);
|
||||
}
|
||||
return new JarFileArchive(root);
|
||||
}
|
||||
|
||||
protected Iterator<Archive> getClassPathArchivesIterator(Archive archive) throws Exception {
|
||||
Archive.EntryFilter searchFilter = this::isSearchCandidate;
|
||||
Iterator<Archive> archives = archive.getNestedArchives(searchFilter,
|
||||
(entry) -> isNestedArchive(entry));
|
||||
archives = applyClassPathArchivePostProcessing(archives);
|
||||
return archives;
|
||||
}
|
||||
|
||||
private Iterator<Archive> applyClassPathArchivePostProcessing(Iterator<Archive> archives) throws Exception {
|
||||
List<Archive> list = new ArrayList<>();
|
||||
while (archives.hasNext()) {
|
||||
list.add(archives.next());
|
||||
}
|
||||
return list.iterator();
|
||||
}
|
||||
|
||||
static final Archive.EntryFilter NESTED_ARCHIVE_ENTRY_FILTER = (entry) -> {
|
||||
if (entry.isDirectory()) {
|
||||
return entry.getName().equals("BOOT-INF/classes/");
|
||||
}
|
||||
return entry.getName().startsWith("BOOT-INF/lib/");
|
||||
};
|
||||
|
||||
protected boolean isNestedArchive(Archive.Entry entry) {
|
||||
return NESTED_ARCHIVE_ENTRY_FILTER.matches(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the specified entry is a candidate for further searching.
|
||||
* @param entry the entry to check
|
||||
* @return {@code true} if the entry is a candidate for further searching
|
||||
* @since 2.3.0
|
||||
*/
|
||||
protected boolean isSearchCandidate(Archive.Entry entry) {
|
||||
if (getArchiveEntryPathPrefix() == null) {
|
||||
return true;
|
||||
}
|
||||
return entry.getName().startsWith(getArchiveEntryPathPrefix());
|
||||
}
|
||||
|
||||
protected String getArchiveEntryPathPrefix() {
|
||||
return "BOOT-INF/";
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal;
|
||||
|
||||
import fun.asgc.neutrino.core.aop.compiler.internal.jar.JarFile;
|
||||
import fun.asgc.neutrino.core.aop.compiler.internal.jar.JarURLConnection;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2023/2/23
|
||||
*/
|
||||
public final class SpringBootJarParser {
|
||||
|
||||
/**
|
||||
* 根据一个URI从SpringBoot jar包中解析出输入流
|
||||
* 1、先尝试直接获取流,若能获取则到此结束
|
||||
* 2、若不能获取,且URI标识定位的是一个jar包,则进行处理(只处理SpringBoot情况的jar)
|
||||
* @param uri
|
||||
* @return
|
||||
*/
|
||||
public static InputStream getInputStream(URI uri) {
|
||||
try {
|
||||
return uri.toURL().openStream();
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
if (uri.getScheme().equals("jar")) {
|
||||
URL url = uri.toURL();
|
||||
String path = url.getPath();
|
||||
int index = path.indexOf("!");
|
||||
if (index >= 0) {
|
||||
path = path.substring(0, index);
|
||||
}
|
||||
if (path.startsWith("file:")) {
|
||||
path = path.substring(5);
|
||||
}
|
||||
JarFile jarFile = new JarFile(new File(path));
|
||||
return JarURLConnection.get(url, jarFile).getInputStream();
|
||||
}
|
||||
} catch (Exception e1) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.archive;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Iterator;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
/**
|
||||
* An archive that can be launched by the {@link Launcher}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.0.0
|
||||
* @see JarFileArchive
|
||||
*/
|
||||
public interface Archive extends Iterable<Archive.Entry>, AutoCloseable {
|
||||
|
||||
/**
|
||||
* Returns a URL that can be used to load the archive.
|
||||
* @return the archive URL
|
||||
* @throws MalformedURLException if the URL is malformed
|
||||
*/
|
||||
URL getUrl() throws MalformedURLException;
|
||||
|
||||
/**
|
||||
* Returns the manifest of the archive.
|
||||
* @return the manifest
|
||||
* @throws IOException if the manifest cannot be read
|
||||
*/
|
||||
Manifest getManifest() throws IOException;
|
||||
|
||||
/**
|
||||
* Returns nested {@link Archive}s for entries that match the specified filters.
|
||||
* @param searchFilter filter used to limit when additional sub-entry searching is
|
||||
* required or {@code null} if all entries should be considered.
|
||||
* @param includeFilter filter used to determine which entries should be included in
|
||||
* the result or {@code null} if all entries should be included
|
||||
* @return the nested archives
|
||||
* @throws IOException on IO error
|
||||
* @since 2.3.0
|
||||
*/
|
||||
Iterator<Archive> getNestedArchives(EntryFilter searchFilter, EntryFilter includeFilter) throws IOException;
|
||||
|
||||
/**
|
||||
* Return if the archive is exploded (already unpacked).
|
||||
* @return if the archive is exploded
|
||||
* @since 2.3.0
|
||||
*/
|
||||
default boolean isExploded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the {@code Archive}, releasing any open resources.
|
||||
* @throws Exception if an error occurs during close processing
|
||||
* @since 2.2.0
|
||||
*/
|
||||
@Override
|
||||
default void close() throws Exception {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a single entry in the archive.
|
||||
*/
|
||||
interface Entry {
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the entry represents a directory.
|
||||
* @return if the entry is a directory
|
||||
*/
|
||||
boolean isDirectory();
|
||||
|
||||
/**
|
||||
* Returns the name of the entry.
|
||||
* @return the name of the entry
|
||||
*/
|
||||
String getName();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy interface to filter {@link Entry Entries}.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
interface EntryFilter {
|
||||
|
||||
/**
|
||||
* Apply the jar entry filter.
|
||||
* @param entry the entry to filter
|
||||
* @return {@code true} if the filter matches
|
||||
*/
|
||||
boolean matches(Entry entry);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+318
@@ -0,0 +1,318 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.archive;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
/**
|
||||
* {@link Archive} implementation backed by an exploded archive directory.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @author Madhura Bhave
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class ExplodedArchive implements Archive {
|
||||
|
||||
private static final Set<String> SKIPPED_NAMES = new HashSet<>(Arrays.asList(".", ".."));
|
||||
|
||||
private final File root;
|
||||
|
||||
private final boolean recursive;
|
||||
|
||||
private final File manifestFile;
|
||||
|
||||
private Manifest manifest;
|
||||
|
||||
/**
|
||||
* Create a new {@link ExplodedArchive} instance.
|
||||
* @param root the root directory
|
||||
*/
|
||||
public ExplodedArchive(File root) {
|
||||
this(root, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ExplodedArchive} instance.
|
||||
* @param root the root directory
|
||||
* @param recursive if recursive searching should be used to locate the manifest.
|
||||
* Defaults to {@code true}, directories with a large tree might want to set this to
|
||||
* {@code false}.
|
||||
*/
|
||||
public ExplodedArchive(File root, boolean recursive) {
|
||||
if (!root.exists() || !root.isDirectory()) {
|
||||
throw new IllegalArgumentException("Invalid source directory " + root);
|
||||
}
|
||||
this.root = root;
|
||||
this.recursive = recursive;
|
||||
this.manifestFile = getManifestFile(root);
|
||||
}
|
||||
|
||||
private File getManifestFile(File root) {
|
||||
File metaInf = new File(root, "META-INF");
|
||||
return new File(metaInf, "MANIFEST.MF");
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getUrl() throws MalformedURLException {
|
||||
return this.root.toURI().toURL();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Manifest getManifest() throws IOException {
|
||||
if (this.manifest == null && this.manifestFile.exists()) {
|
||||
try (FileInputStream inputStream = new FileInputStream(this.manifestFile)) {
|
||||
this.manifest = new Manifest(inputStream);
|
||||
}
|
||||
}
|
||||
return this.manifest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Archive> getNestedArchives(EntryFilter searchFilter, EntryFilter includeFilter) throws IOException {
|
||||
return new ArchiveIterator(this.root, this.recursive, searchFilter, includeFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
// @Deprecated(since = "2.3.10", forRemoval = false)
|
||||
public Iterator<Entry> iterator() {
|
||||
return new EntryIterator(this.root, this.recursive, null, null);
|
||||
}
|
||||
|
||||
protected Archive getNestedArchive(Entry entry) {
|
||||
File file = ((FileEntry) entry).getFile();
|
||||
return (file.isDirectory() ? new ExplodedArchive(file) : new SimpleJarFileArchive((FileEntry) entry));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExploded() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return getUrl().toString();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return "exploded archive";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* File based {@link Entry} {@link Iterator}.
|
||||
*/
|
||||
private abstract static class AbstractIterator<T> implements Iterator<T> {
|
||||
|
||||
private static final Comparator<File> entryComparator = Comparator.comparing(File::getAbsolutePath);
|
||||
|
||||
private final File root;
|
||||
|
||||
private final boolean recursive;
|
||||
|
||||
private final EntryFilter searchFilter;
|
||||
|
||||
private final EntryFilter includeFilter;
|
||||
|
||||
private final Deque<Iterator<File>> stack = new LinkedList<>();
|
||||
|
||||
private FileEntry current;
|
||||
|
||||
private final String rootUrl;
|
||||
|
||||
AbstractIterator(File root, boolean recursive, EntryFilter searchFilter, EntryFilter includeFilter) {
|
||||
this.root = root;
|
||||
this.rootUrl = this.root.toURI().getPath();
|
||||
this.recursive = recursive;
|
||||
this.searchFilter = searchFilter;
|
||||
this.includeFilter = includeFilter;
|
||||
this.stack.add(listFiles(root));
|
||||
this.current = poll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return this.current != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
FileEntry entry = this.current;
|
||||
if (entry == null) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
this.current = poll();
|
||||
return adapt(entry);
|
||||
}
|
||||
|
||||
private FileEntry poll() {
|
||||
while (!this.stack.isEmpty()) {
|
||||
while (this.stack.peek().hasNext()) {
|
||||
File file = this.stack.peek().next();
|
||||
if (SKIPPED_NAMES.contains(file.getName())) {
|
||||
continue;
|
||||
}
|
||||
FileEntry entry = getFileEntry(file);
|
||||
if (isListable(entry)) {
|
||||
this.stack.addFirst(listFiles(file));
|
||||
}
|
||||
if (this.includeFilter == null || this.includeFilter.matches(entry)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
this.stack.poll();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private FileEntry getFileEntry(File file) {
|
||||
URI uri = file.toURI();
|
||||
String name = uri.getPath().substring(this.rootUrl.length());
|
||||
try {
|
||||
return new FileEntry(name, file, uri.toURL());
|
||||
}
|
||||
catch (MalformedURLException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isListable(FileEntry entry) {
|
||||
return entry.isDirectory() && (this.recursive || entry.getFile().getParentFile().equals(this.root))
|
||||
&& (this.searchFilter == null || this.searchFilter.matches(entry))
|
||||
&& (this.includeFilter == null || !this.includeFilter.matches(entry));
|
||||
}
|
||||
|
||||
private Iterator<File> listFiles(File file) {
|
||||
File[] files = file.listFiles();
|
||||
if (files == null) {
|
||||
return Collections.emptyIterator();
|
||||
}
|
||||
Arrays.sort(files, entryComparator);
|
||||
return Arrays.asList(files).iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException("remove");
|
||||
}
|
||||
|
||||
protected abstract T adapt(FileEntry entry);
|
||||
|
||||
}
|
||||
|
||||
private static class EntryIterator extends AbstractIterator<Entry> {
|
||||
|
||||
EntryIterator(File root, boolean recursive, EntryFilter searchFilter, EntryFilter includeFilter) {
|
||||
super(root, recursive, searchFilter, includeFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Entry adapt(FileEntry entry) {
|
||||
return entry;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class ArchiveIterator extends AbstractIterator<Archive> {
|
||||
|
||||
ArchiveIterator(File root, boolean recursive, EntryFilter searchFilter, EntryFilter includeFilter) {
|
||||
super(root, recursive, searchFilter, includeFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Archive adapt(FileEntry entry) {
|
||||
File file = entry.getFile();
|
||||
return (file.isDirectory() ? new ExplodedArchive(file) : new SimpleJarFileArchive(entry));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Entry} backed by a File.
|
||||
*/
|
||||
private static class FileEntry implements Entry {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final File file;
|
||||
|
||||
private final URL url;
|
||||
|
||||
FileEntry(String name, File file, URL url) {
|
||||
this.name = name;
|
||||
this.file = file;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
File getFile() {
|
||||
return this.file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectory() {
|
||||
return this.file.isDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
URL getUrl() {
|
||||
return this.url;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Archive} implementation backed by a simple JAR file that doesn't itself
|
||||
* contain nested archives.
|
||||
*/
|
||||
private static class SimpleJarFileArchive implements Archive {
|
||||
|
||||
private final URL url;
|
||||
|
||||
SimpleJarFileArchive(FileEntry file) {
|
||||
this.url = file.getUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getUrl() throws MalformedURLException {
|
||||
return this.url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Manifest getManifest() throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Archive> getNestedArchives(EntryFilter searchFilter, EntryFilter includeFilter)
|
||||
throws IOException {
|
||||
return Collections.emptyIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
// @Deprecated(since = "2.3.10", forRemoval = false)
|
||||
public Iterator<Entry> iterator() {
|
||||
return Collections.emptyIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return getUrl().toString();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return "jar archive";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
neutrino-core/src/main/java/fun/asgc/neutrino/core/aop/compiler/internal/archive/JarFileArchive.java
Executable
+290
@@ -0,0 +1,290 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.archive;
|
||||
|
||||
import fun.asgc.neutrino.core.aop.compiler.internal.jar.JarFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.FileAttribute;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.nio.file.attribute.PosixFilePermissions;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.UUID;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
/**
|
||||
* {@link Archive} implementation backed by a {@link JarFile}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class JarFileArchive implements Archive {
|
||||
|
||||
private static final String UNPACK_MARKER = "UNPACK:";
|
||||
|
||||
private static final int BUFFER_SIZE = 32 * 1024;
|
||||
|
||||
private static final FileAttribute<?>[] NO_FILE_ATTRIBUTES = {};
|
||||
|
||||
private static final EnumSet<PosixFilePermission> DIRECTORY_PERMISSIONS = EnumSet.of(PosixFilePermission.OWNER_READ,
|
||||
PosixFilePermission.OWNER_WRITE, PosixFilePermission.OWNER_EXECUTE);
|
||||
|
||||
private static final EnumSet<PosixFilePermission> FILE_PERMISSIONS = EnumSet.of(PosixFilePermission.OWNER_READ,
|
||||
PosixFilePermission.OWNER_WRITE);
|
||||
|
||||
private final JarFile jarFile;
|
||||
|
||||
private URL url;
|
||||
|
||||
private Path tempUnpackDirectory;
|
||||
|
||||
public JarFileArchive(File file) throws IOException {
|
||||
this(file, file.toURI().toURL());
|
||||
}
|
||||
|
||||
public JarFileArchive(File file, URL url) throws IOException {
|
||||
this(new JarFile(file));
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public JarFileArchive(JarFile jarFile) {
|
||||
this.jarFile = jarFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getUrl() throws MalformedURLException {
|
||||
if (this.url != null) {
|
||||
return this.url;
|
||||
}
|
||||
return this.jarFile.getUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Manifest getManifest() throws IOException {
|
||||
return this.jarFile.getManifest();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Archive> getNestedArchives(EntryFilter searchFilter, EntryFilter includeFilter) throws IOException {
|
||||
return new NestedArchiveIterator(this.jarFile.iterator(), searchFilter, includeFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
// @Deprecated(since = "2.3.10", forRemoval = false)
|
||||
public Iterator<Entry> iterator() {
|
||||
return new EntryIterator(this.jarFile.iterator(), null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
this.jarFile.close();
|
||||
}
|
||||
|
||||
protected Archive getNestedArchive(Entry entry) throws IOException {
|
||||
JarEntry jarEntry = ((JarFileEntry) entry).getJarEntry();
|
||||
if (jarEntry.getComment().startsWith(UNPACK_MARKER)) {
|
||||
return getUnpackedNestedArchive(jarEntry);
|
||||
}
|
||||
try {
|
||||
JarFile jarFile = this.jarFile.getNestedJarFile(jarEntry);
|
||||
return new JarFileArchive(jarFile);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException("Failed to get nested archive for entry " + entry.getName(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Archive getUnpackedNestedArchive(JarEntry jarEntry) throws IOException {
|
||||
String name = jarEntry.getName();
|
||||
if (name.lastIndexOf('/') != -1) {
|
||||
name = name.substring(name.lastIndexOf('/') + 1);
|
||||
}
|
||||
Path path = getTempUnpackDirectory().resolve(name);
|
||||
if (!Files.exists(path) || Files.size(path) != jarEntry.getSize()) {
|
||||
unpack(jarEntry, path);
|
||||
}
|
||||
return new JarFileArchive(path.toFile(), path.toUri().toURL());
|
||||
}
|
||||
|
||||
private Path getTempUnpackDirectory() {
|
||||
if (this.tempUnpackDirectory == null) {
|
||||
Path tempDirectory = Paths.get(System.getProperty("java.io.tmpdir"));
|
||||
this.tempUnpackDirectory = createUnpackDirectory(tempDirectory);
|
||||
}
|
||||
return this.tempUnpackDirectory;
|
||||
}
|
||||
|
||||
private Path createUnpackDirectory(Path parent) {
|
||||
int attempts = 0;
|
||||
while (attempts++ < 1000) {
|
||||
String fileName = Paths.get(this.jarFile.getName()).getFileName().toString();
|
||||
Path unpackDirectory = parent.resolve(fileName + "-spring-boot-libs-" + UUID.randomUUID());
|
||||
try {
|
||||
createDirectory(unpackDirectory);
|
||||
return unpackDirectory;
|
||||
}
|
||||
catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Failed to create unpack directory in directory '" + parent + "'");
|
||||
}
|
||||
|
||||
private void unpack(JarEntry entry, Path path) throws IOException {
|
||||
createFile(path);
|
||||
path.toFile().deleteOnExit();
|
||||
try (InputStream inputStream = this.jarFile.getInputStream(entry);
|
||||
OutputStream outputStream = Files.newOutputStream(path, StandardOpenOption.WRITE,
|
||||
StandardOpenOption.TRUNCATE_EXISTING)) {
|
||||
byte[] buffer = new byte[BUFFER_SIZE];
|
||||
int bytesRead;
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
outputStream.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private void createDirectory(Path path) throws IOException {
|
||||
Files.createDirectory(path, getFileAttributes(path.getFileSystem(), DIRECTORY_PERMISSIONS));
|
||||
}
|
||||
|
||||
private void createFile(Path path) throws IOException {
|
||||
Files.createFile(path, getFileAttributes(path.getFileSystem(), FILE_PERMISSIONS));
|
||||
}
|
||||
|
||||
private FileAttribute<?>[] getFileAttributes(FileSystem fileSystem, EnumSet<PosixFilePermission> ownerReadWrite) {
|
||||
if (!fileSystem.supportedFileAttributeViews().contains("posix")) {
|
||||
return NO_FILE_ATTRIBUTES;
|
||||
}
|
||||
return new FileAttribute<?>[] { PosixFilePermissions.asFileAttribute(ownerReadWrite) };
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return getUrl().toString();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return "jar archive";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract base class for iterator implementations.
|
||||
*/
|
||||
private abstract static class AbstractIterator<T> implements Iterator<T> {
|
||||
|
||||
private final Iterator<JarEntry> iterator;
|
||||
|
||||
private final EntryFilter searchFilter;
|
||||
|
||||
private final EntryFilter includeFilter;
|
||||
|
||||
private Entry current;
|
||||
|
||||
AbstractIterator(Iterator<JarEntry> iterator, EntryFilter searchFilter, EntryFilter includeFilter) {
|
||||
this.iterator = iterator;
|
||||
this.searchFilter = searchFilter;
|
||||
this.includeFilter = includeFilter;
|
||||
this.current = poll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return this.current != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
T result = adapt(this.current);
|
||||
this.current = poll();
|
||||
return result;
|
||||
}
|
||||
|
||||
private Entry poll() {
|
||||
while (this.iterator.hasNext()) {
|
||||
JarFileEntry candidate = new JarFileEntry(this.iterator.next());
|
||||
if ((this.searchFilter == null || this.searchFilter.matches(candidate))
|
||||
&& (this.includeFilter == null || this.includeFilter.matches(candidate))) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected abstract T adapt(Entry entry);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Entry} iterator implementation backed by {@link JarEntry}.
|
||||
*/
|
||||
private static class EntryIterator extends AbstractIterator<Entry> {
|
||||
|
||||
EntryIterator(Iterator<JarEntry> iterator, EntryFilter searchFilter, EntryFilter includeFilter) {
|
||||
super(iterator, searchFilter, includeFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Entry adapt(Entry entry) {
|
||||
return entry;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Nested {@link Archive} iterator implementation backed by {@link JarEntry}.
|
||||
*/
|
||||
private class NestedArchiveIterator extends AbstractIterator<Archive> {
|
||||
|
||||
NestedArchiveIterator(Iterator<JarEntry> iterator, EntryFilter searchFilter, EntryFilter includeFilter) {
|
||||
super(iterator, searchFilter, includeFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Archive adapt(Entry entry) {
|
||||
try {
|
||||
return getNestedArchive(entry);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Entry} implementation backed by a {@link JarEntry}.
|
||||
*/
|
||||
private static class JarFileEntry implements Entry {
|
||||
|
||||
private final JarEntry jarEntry;
|
||||
|
||||
JarFileEntry(JarEntry jarEntry) {
|
||||
this.jarEntry = jarEntry;
|
||||
}
|
||||
|
||||
JarEntry getJarEntry() {
|
||||
return this.jarEntry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectory() {
|
||||
return this.jarEntry.isDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.jarEntry.getName();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.data;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Interface that provides read-only random access to some underlying data.
|
||||
* Implementations must allow concurrent reads in a thread-safe manner.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public interface RandomAccessData {
|
||||
|
||||
/**
|
||||
* Returns an {@link InputStream} that can be used to read the underlying data. The
|
||||
* caller is responsible close the underlying stream.
|
||||
* @return a new input stream that can be used to read the underlying data.
|
||||
* @throws IOException if the stream cannot be opened
|
||||
*/
|
||||
InputStream getInputStream() throws IOException;
|
||||
|
||||
/**
|
||||
* Returns a new {@link RandomAccessData} for a specific subsection of this data.
|
||||
* @param offset the offset of the subsection
|
||||
* @param length the length of the subsection
|
||||
* @return the subsection data
|
||||
*/
|
||||
RandomAccessData getSubsection(long offset, long length);
|
||||
|
||||
/**
|
||||
* Reads all the data and returns it as a byte array.
|
||||
* @return the data
|
||||
* @throws IOException if the data cannot be read
|
||||
*/
|
||||
byte[] read() throws IOException;
|
||||
|
||||
/**
|
||||
* Reads the {@code length} bytes of data starting at the given {@code offset}.
|
||||
* @param offset the offset from which data should be read
|
||||
* @param length the number of bytes to be read
|
||||
* @return the data
|
||||
* @throws IOException if the data cannot be read
|
||||
* @throws IndexOutOfBoundsException if offset is beyond the end of the file or
|
||||
* subsection
|
||||
* @throws EOFException if offset plus length is greater than the length of the file
|
||||
* or subsection
|
||||
*/
|
||||
byte[] read(long offset, long length) throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the size of the data.
|
||||
* @return the size
|
||||
*/
|
||||
long getSize();
|
||||
|
||||
}
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.data;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* {@link RandomAccessData} implementation backed by a {@link RandomAccessFile}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class RandomAccessDataFile implements RandomAccessData {
|
||||
|
||||
private final FileAccess fileAccess;
|
||||
|
||||
private final long offset;
|
||||
|
||||
private final long length;
|
||||
|
||||
/**
|
||||
* Create a new {@link RandomAccessDataFile} backed by the specified file.
|
||||
* @param file the underlying file
|
||||
* @throws IllegalArgumentException if the file is null or does not exist
|
||||
*/
|
||||
public RandomAccessDataFile(File file) {
|
||||
if (file == null) {
|
||||
throw new IllegalArgumentException("File must not be null");
|
||||
}
|
||||
this.fileAccess = new FileAccess(file);
|
||||
this.offset = 0L;
|
||||
this.length = file.length();
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor used to create a {@link #getSubsection(long, long) subsection}.
|
||||
* @param fileAccess provides access to the underlying file
|
||||
* @param offset the offset of the section
|
||||
* @param length the length of the section
|
||||
*/
|
||||
private RandomAccessDataFile(FileAccess fileAccess, long offset, long length) {
|
||||
this.fileAccess = fileAccess;
|
||||
this.offset = offset;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying File.
|
||||
* @return the underlying file
|
||||
*/
|
||||
public File getFile() {
|
||||
return this.fileAccess.file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return new DataInputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RandomAccessData getSubsection(long offset, long length) {
|
||||
if (offset < 0 || length < 0 || offset + length > this.length) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
return new RandomAccessDataFile(this.fileAccess, this.offset + offset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] read() throws IOException {
|
||||
return read(0, this.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] read(long offset, long length) throws IOException {
|
||||
if (offset > this.length) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
if (offset + length > this.length) {
|
||||
throw new EOFException();
|
||||
}
|
||||
byte[] bytes = new byte[(int) length];
|
||||
read(bytes, offset, 0, bytes.length);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private int readByte(long position) throws IOException {
|
||||
if (position >= this.length) {
|
||||
return -1;
|
||||
}
|
||||
return this.fileAccess.readByte(this.offset + position);
|
||||
}
|
||||
|
||||
private int read(byte[] bytes, long position, int offset, int length) throws IOException {
|
||||
if (position > this.length) {
|
||||
return -1;
|
||||
}
|
||||
return this.fileAccess.read(bytes, this.offset + position, offset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSize() {
|
||||
return this.length;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
this.fileAccess.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link InputStream} implementation for the {@link RandomAccessDataFile}.
|
||||
*/
|
||||
private class DataInputStream extends InputStream {
|
||||
|
||||
private int position;
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
int read = RandomAccessDataFile.this.readByte(this.position);
|
||||
if (read > -1) {
|
||||
moveOn(1);
|
||||
}
|
||||
return read;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b) throws IOException {
|
||||
return read(b, 0, (b != null) ? b.length : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
if (b == null) {
|
||||
throw new NullPointerException("Bytes must not be null");
|
||||
}
|
||||
return doRead(b, off, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the actual read.
|
||||
* @param b the bytes to read or {@code null} when reading a single byte
|
||||
* @param off the offset of the byte array
|
||||
* @param len the length of data to read
|
||||
* @return the number of bytes read into {@code b} or the actual read byte if
|
||||
* {@code b} is {@code null}. Returns -1 when the end of the stream is reached
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
int doRead(byte[] b, int off, int len) throws IOException {
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
int cappedLen = cap(len);
|
||||
if (cappedLen <= 0) {
|
||||
return -1;
|
||||
}
|
||||
return (int) moveOn(RandomAccessDataFile.this.read(b, this.position, off, cappedLen));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long n) throws IOException {
|
||||
return (n <= 0) ? 0 : moveOn(cap(n));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return (int) RandomAccessDataFile.this.length - this.position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cap the specified value such that it cannot exceed the number of bytes
|
||||
* remaining.
|
||||
* @param n the value to cap
|
||||
* @return the capped value
|
||||
*/
|
||||
private int cap(long n) {
|
||||
return (int) Math.min(RandomAccessDataFile.this.length - this.position, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the stream position forwards the specified amount.
|
||||
* @param amount the amount to move
|
||||
* @return the amount moved
|
||||
*/
|
||||
private long moveOn(int amount) {
|
||||
this.position += amount;
|
||||
return amount;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class FileAccess {
|
||||
|
||||
private final Object monitor = new Object();
|
||||
|
||||
private final File file;
|
||||
|
||||
private RandomAccessFile randomAccessFile;
|
||||
|
||||
private FileAccess(File file) {
|
||||
this.file = file;
|
||||
openIfNecessary();
|
||||
}
|
||||
|
||||
private int read(byte[] bytes, long position, int offset, int length) throws IOException {
|
||||
synchronized (this.monitor) {
|
||||
openIfNecessary();
|
||||
this.randomAccessFile.seek(position);
|
||||
return this.randomAccessFile.read(bytes, offset, length);
|
||||
}
|
||||
}
|
||||
|
||||
private void openIfNecessary() {
|
||||
if (this.randomAccessFile == null) {
|
||||
try {
|
||||
this.randomAccessFile = new RandomAccessFile(this.file, "r");
|
||||
}
|
||||
catch (FileNotFoundException ex) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("File %s must exist", this.file.getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void close() throws IOException {
|
||||
synchronized (this.monitor) {
|
||||
if (this.randomAccessFile != null) {
|
||||
this.randomAccessFile.close();
|
||||
this.randomAccessFile = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int readByte(long position) throws IOException {
|
||||
synchronized (this.monitor) {
|
||||
openIfNecessary();
|
||||
this.randomAccessFile.seek(position);
|
||||
return this.randomAccessFile.read();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.jar;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.security.Permission;
|
||||
|
||||
/**
|
||||
* Base class for extended variants of {@link java.util.jar.JarFile}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
abstract class AbstractJarFile extends java.util.jar.JarFile {
|
||||
|
||||
/**
|
||||
* Create a new {@link AbstractJarFile}.
|
||||
* @param file the root jar file.
|
||||
* @throws IOException on IO error
|
||||
*/
|
||||
AbstractJarFile(File file) throws IOException {
|
||||
super(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a URL that can be used to access this JAR file. NOTE: the specified URL
|
||||
* cannot be serialized and or cloned.
|
||||
* @return the URL
|
||||
* @throws MalformedURLException if the URL is malformed
|
||||
*/
|
||||
abstract URL getUrl() throws MalformedURLException;
|
||||
|
||||
/**
|
||||
* Return the {@link JarFileType} of this instance.
|
||||
* @return the jar file type
|
||||
*/
|
||||
abstract JarFileType getType();
|
||||
|
||||
/**
|
||||
* Return the security permission for this JAR.
|
||||
* @return the security permission.
|
||||
*/
|
||||
abstract Permission getPermission();
|
||||
|
||||
/**
|
||||
* Return an {@link InputStream} for the entire jar contents.
|
||||
* @return the contents input stream
|
||||
* @throws IOException on IO error
|
||||
*/
|
||||
abstract InputStream getInputStream() throws IOException;
|
||||
|
||||
/**
|
||||
* The type of a {@link JarFile}.
|
||||
*/
|
||||
enum JarFileType {
|
||||
|
||||
DIRECT, NESTED_DIRECTORY, NESTED_JAR
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+239
@@ -0,0 +1,239 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.jar;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* Simple wrapper around a byte array that represents an ASCII. Used for performance
|
||||
* reasons to save constructing Strings for ZIP data.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
final class AsciiBytes {
|
||||
|
||||
private static final String EMPTY_STRING = "";
|
||||
|
||||
private static final int[] INITIAL_BYTE_BITMASK = { 0x7F, 0x1F, 0x0F, 0x07 };
|
||||
|
||||
private static final int SUBSEQUENT_BYTE_BITMASK = 0x3F;
|
||||
|
||||
private final byte[] bytes;
|
||||
|
||||
private final int offset;
|
||||
|
||||
private final int length;
|
||||
|
||||
private String string;
|
||||
|
||||
private int hash;
|
||||
|
||||
/**
|
||||
* Create a new {@link AsciiBytes} from the specified String.
|
||||
* @param string the source string
|
||||
*/
|
||||
AsciiBytes(String string) {
|
||||
this(string.getBytes(StandardCharsets.UTF_8));
|
||||
this.string = string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link AsciiBytes} from the specified bytes. NOTE: underlying bytes
|
||||
* are not expected to change.
|
||||
* @param bytes the source bytes
|
||||
*/
|
||||
AsciiBytes(byte[] bytes) {
|
||||
this(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link AsciiBytes} from the specified bytes. NOTE: underlying bytes
|
||||
* are not expected to change.
|
||||
* @param bytes the source bytes
|
||||
* @param offset the offset
|
||||
* @param length the length
|
||||
*/
|
||||
AsciiBytes(byte[] bytes, int offset, int length) {
|
||||
if (offset < 0 || length < 0 || (offset + length) > bytes.length) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
this.bytes = bytes;
|
||||
this.offset = offset;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
int length() {
|
||||
return this.length;
|
||||
}
|
||||
|
||||
boolean startsWith(AsciiBytes prefix) {
|
||||
if (this == prefix) {
|
||||
return true;
|
||||
}
|
||||
if (prefix.length > this.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < prefix.length; i++) {
|
||||
if (this.bytes[i + this.offset] != prefix.bytes[i + prefix.offset]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean endsWith(AsciiBytes postfix) {
|
||||
if (this == postfix) {
|
||||
return true;
|
||||
}
|
||||
if (postfix.length > this.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < postfix.length; i++) {
|
||||
if (this.bytes[this.offset + (this.length - 1) - i] != postfix.bytes[postfix.offset + (postfix.length - 1)
|
||||
- i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
AsciiBytes substring(int beginIndex) {
|
||||
return substring(beginIndex, this.length);
|
||||
}
|
||||
|
||||
AsciiBytes substring(int beginIndex, int endIndex) {
|
||||
int length = endIndex - beginIndex;
|
||||
if (this.offset + length > this.bytes.length) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
return new AsciiBytes(this.bytes, this.offset + beginIndex, length);
|
||||
}
|
||||
|
||||
boolean matches(CharSequence name, char suffix) {
|
||||
int charIndex = 0;
|
||||
int nameLen = name.length();
|
||||
int totalLen = nameLen + ((suffix != 0) ? 1 : 0);
|
||||
for (int i = this.offset; i < this.offset + this.length; i++) {
|
||||
int b = this.bytes[i];
|
||||
int remainingUtfBytes = getNumberOfUtfBytes(b) - 1;
|
||||
b &= INITIAL_BYTE_BITMASK[remainingUtfBytes];
|
||||
for (int j = 0; j < remainingUtfBytes; j++) {
|
||||
b = (b << 6) + (this.bytes[++i] & SUBSEQUENT_BYTE_BITMASK);
|
||||
}
|
||||
char c = getChar(name, suffix, charIndex++);
|
||||
if (b <= 0xFFFF) {
|
||||
if (c != b) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (c != ((b >> 0xA) + 0xD7C0)) {
|
||||
return false;
|
||||
}
|
||||
c = getChar(name, suffix, charIndex++);
|
||||
if (c != ((b & 0x3FF) + 0xDC00)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return charIndex == totalLen;
|
||||
}
|
||||
|
||||
private char getChar(CharSequence name, char suffix, int index) {
|
||||
if (index < name.length()) {
|
||||
return name.charAt(index);
|
||||
}
|
||||
if (index == name.length()) {
|
||||
return suffix;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int getNumberOfUtfBytes(int b) {
|
||||
if ((b & 0x80) == 0) {
|
||||
return 1;
|
||||
}
|
||||
int numberOfUtfBytes = 0;
|
||||
while ((b & 0x80) != 0) {
|
||||
b <<= 1;
|
||||
numberOfUtfBytes++;
|
||||
}
|
||||
return numberOfUtfBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj.getClass() == AsciiBytes.class) {
|
||||
AsciiBytes other = (AsciiBytes) obj;
|
||||
if (this.length == other.length) {
|
||||
for (int i = 0; i < this.length; i++) {
|
||||
if (this.bytes[this.offset + i] != other.bytes[other.offset + i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = this.hash;
|
||||
if (hash == 0 && this.bytes.length > 0) {
|
||||
for (int i = this.offset; i < this.offset + this.length; i++) {
|
||||
int b = this.bytes[i];
|
||||
int remainingUtfBytes = getNumberOfUtfBytes(b) - 1;
|
||||
b &= INITIAL_BYTE_BITMASK[remainingUtfBytes];
|
||||
for (int j = 0; j < remainingUtfBytes; j++) {
|
||||
b = (b << 6) + (this.bytes[++i] & SUBSEQUENT_BYTE_BITMASK);
|
||||
}
|
||||
if (b <= 0xFFFF) {
|
||||
hash = 31 * hash + b;
|
||||
}
|
||||
else {
|
||||
hash = 31 * hash + ((b >> 0xA) + 0xD7C0);
|
||||
hash = 31 * hash + ((b & 0x3FF) + 0xDC00);
|
||||
}
|
||||
}
|
||||
this.hash = hash;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (this.string == null) {
|
||||
if (this.length == 0) {
|
||||
this.string = EMPTY_STRING;
|
||||
}
|
||||
else {
|
||||
this.string = new String(this.bytes, this.offset, this.length, StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
return this.string;
|
||||
}
|
||||
|
||||
static String toString(byte[] bytes) {
|
||||
return new String(bytes, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
static int hashCode(CharSequence charSequence) {
|
||||
// We're compatible with String's hashCode()
|
||||
if (charSequence instanceof StringSequence) {
|
||||
// ... but save making an unnecessary String for StringSequence
|
||||
return charSequence.hashCode();
|
||||
}
|
||||
return charSequence.toString().hashCode();
|
||||
}
|
||||
|
||||
static int hashCode(int hash, char suffix) {
|
||||
return (suffix != 0) ? (31 * hash + suffix) : hash;
|
||||
}
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.jar;
|
||||
|
||||
/**
|
||||
* Utilities for dealing with bytes from ZIP files.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
final class Bytes {
|
||||
|
||||
private Bytes() {
|
||||
}
|
||||
|
||||
static long littleEndianValue(byte[] bytes, int offset, int length) {
|
||||
long value = 0;
|
||||
for (int i = length - 1; i >= 0; i--) {
|
||||
value = ((value << 8) | (bytes[offset + i] & 0xFF));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
+242
@@ -0,0 +1,242 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.jar;
|
||||
|
||||
import fun.asgc.neutrino.core.aop.compiler.internal.data.RandomAccessData;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A ZIP File "End of central directory record" (EOCD).
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @author Camille Vienot
|
||||
* @see <a href="https://en.wikipedia.org/wiki/Zip_%28file_format%29">Zip File Format</a>
|
||||
*/
|
||||
class CentralDirectoryEndRecord {
|
||||
|
||||
private static final int MINIMUM_SIZE = 22;
|
||||
|
||||
private static final int MAXIMUM_COMMENT_LENGTH = 0xFFFF;
|
||||
|
||||
private static final int MAXIMUM_SIZE = MINIMUM_SIZE + MAXIMUM_COMMENT_LENGTH;
|
||||
|
||||
private static final int SIGNATURE = 0x06054b50;
|
||||
|
||||
private static final int COMMENT_LENGTH_OFFSET = 20;
|
||||
|
||||
private static final int READ_BLOCK_SIZE = 256;
|
||||
|
||||
private final Zip64End zip64End;
|
||||
|
||||
private byte[] block;
|
||||
|
||||
private int offset;
|
||||
|
||||
private int size;
|
||||
|
||||
/**
|
||||
* Create a new {@link CentralDirectoryEndRecord} instance from the specified
|
||||
* {@link RandomAccessData}, searching backwards from the end until a valid block is
|
||||
* located.
|
||||
* @param data the source data
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
CentralDirectoryEndRecord(RandomAccessData data) throws IOException {
|
||||
this.block = createBlockFromEndOfData(data, READ_BLOCK_SIZE);
|
||||
this.size = MINIMUM_SIZE;
|
||||
this.offset = this.block.length - this.size;
|
||||
while (!isValid()) {
|
||||
this.size++;
|
||||
if (this.size > this.block.length) {
|
||||
if (this.size >= MAXIMUM_SIZE || this.size > data.getSize()) {
|
||||
throw new IOException(
|
||||
"Unable to find ZIP central directory records after reading " + this.size + " bytes");
|
||||
}
|
||||
this.block = createBlockFromEndOfData(data, this.size + READ_BLOCK_SIZE);
|
||||
}
|
||||
this.offset = this.block.length - this.size;
|
||||
}
|
||||
long startOfCentralDirectoryEndRecord = data.getSize() - this.size;
|
||||
Zip64Locator zip64Locator = Zip64Locator.find(data, startOfCentralDirectoryEndRecord);
|
||||
this.zip64End = (zip64Locator != null) ? new Zip64End(data, zip64Locator) : null;
|
||||
}
|
||||
|
||||
private byte[] createBlockFromEndOfData(RandomAccessData data, int size) throws IOException {
|
||||
int length = (int) Math.min(data.getSize(), size);
|
||||
return data.read(data.getSize() - length, length);
|
||||
}
|
||||
|
||||
private boolean isValid() {
|
||||
if (this.block.length < MINIMUM_SIZE || Bytes.littleEndianValue(this.block, this.offset + 0, 4) != SIGNATURE) {
|
||||
return false;
|
||||
}
|
||||
// Total size must be the structure size + comment
|
||||
long commentLength = Bytes.littleEndianValue(this.block, this.offset + COMMENT_LENGTH_OFFSET, 2);
|
||||
return this.size == MINIMUM_SIZE + commentLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the location in the data that the archive actually starts. For most files
|
||||
* the archive data will start at 0, however, it is possible to have prefixed bytes
|
||||
* (often used for startup scripts) at the beginning of the data.
|
||||
* @param data the source data
|
||||
* @return the offset within the data where the archive begins
|
||||
*/
|
||||
long getStartOfArchive(RandomAccessData data) {
|
||||
long length = Bytes.littleEndianValue(this.block, this.offset + 12, 4);
|
||||
long specifiedOffset = (this.zip64End != null) ? this.zip64End.centralDirectoryOffset
|
||||
: Bytes.littleEndianValue(this.block, this.offset + 16, 4);
|
||||
long zip64EndSize = (this.zip64End != null) ? this.zip64End.getSize() : 0L;
|
||||
int zip64LocSize = (this.zip64End != null) ? Zip64Locator.ZIP64_LOCSIZE : 0;
|
||||
long actualOffset = data.getSize() - this.size - length - zip64EndSize - zip64LocSize;
|
||||
return actualOffset - specifiedOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bytes of the "Central directory" based on the offset indicated in this
|
||||
* record.
|
||||
* @param data the source data
|
||||
* @return the central directory data
|
||||
*/
|
||||
RandomAccessData getCentralDirectory(RandomAccessData data) {
|
||||
if (this.zip64End != null) {
|
||||
return this.zip64End.getCentralDirectory(data);
|
||||
}
|
||||
long offset = Bytes.littleEndianValue(this.block, this.offset + 16, 4);
|
||||
long length = Bytes.littleEndianValue(this.block, this.offset + 12, 4);
|
||||
return data.getSubsection(offset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of ZIP entries in the file.
|
||||
* @return the number of records in the zip
|
||||
*/
|
||||
int getNumberOfRecords() {
|
||||
if (this.zip64End != null) {
|
||||
return this.zip64End.getNumberOfRecords();
|
||||
}
|
||||
long numberOfRecords = Bytes.littleEndianValue(this.block, this.offset + 10, 2);
|
||||
return (int) numberOfRecords;
|
||||
}
|
||||
|
||||
String getComment() {
|
||||
int commentLength = (int) Bytes.littleEndianValue(this.block, this.offset + COMMENT_LENGTH_OFFSET, 2);
|
||||
AsciiBytes comment = new AsciiBytes(this.block, this.offset + COMMENT_LENGTH_OFFSET + 2, commentLength);
|
||||
return comment.toString();
|
||||
}
|
||||
|
||||
boolean isZip64() {
|
||||
return this.zip64End != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A Zip64 end of central directory record.
|
||||
*
|
||||
* @see <a href="https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT">Chapter
|
||||
* 4.3.14 of Zip64 specification</a>
|
||||
*/
|
||||
private static final class Zip64End {
|
||||
|
||||
private static final int ZIP64_ENDTOT = 32; // total number of entries
|
||||
|
||||
private static final int ZIP64_ENDSIZ = 40; // central directory size in bytes
|
||||
|
||||
private static final int ZIP64_ENDOFF = 48; // offset of first CEN header
|
||||
|
||||
private final Zip64Locator locator;
|
||||
|
||||
private final long centralDirectoryOffset;
|
||||
|
||||
private final long centralDirectoryLength;
|
||||
|
||||
private final int numberOfRecords;
|
||||
|
||||
private Zip64End(RandomAccessData data, Zip64Locator locator) throws IOException {
|
||||
this.locator = locator;
|
||||
byte[] block = data.read(locator.getZip64EndOffset(), 56);
|
||||
this.centralDirectoryOffset = Bytes.littleEndianValue(block, ZIP64_ENDOFF, 8);
|
||||
this.centralDirectoryLength = Bytes.littleEndianValue(block, ZIP64_ENDSIZ, 8);
|
||||
this.numberOfRecords = (int) Bytes.littleEndianValue(block, ZIP64_ENDTOT, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of this zip 64 end of central directory record.
|
||||
* @return size of this zip 64 end of central directory record
|
||||
*/
|
||||
private long getSize() {
|
||||
return this.locator.getZip64EndSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bytes of the "Central directory" based on the offset indicated in
|
||||
* this record.
|
||||
* @param data the source data
|
||||
* @return the central directory data
|
||||
*/
|
||||
private RandomAccessData getCentralDirectory(RandomAccessData data) {
|
||||
return data.getSubsection(this.centralDirectoryOffset, this.centralDirectoryLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of entries in the zip64 archive.
|
||||
* @return the number of records in the zip
|
||||
*/
|
||||
private int getNumberOfRecords() {
|
||||
return this.numberOfRecords;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A Zip64 end of central directory locator.
|
||||
*
|
||||
* @see <a href="https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT">Chapter
|
||||
* 4.3.15 of Zip64 specification</a>
|
||||
*/
|
||||
private static final class Zip64Locator {
|
||||
|
||||
static final int SIGNATURE = 0x07064b50;
|
||||
|
||||
static final int ZIP64_LOCSIZE = 20; // locator size
|
||||
|
||||
static final int ZIP64_LOCOFF = 8; // offset of zip64 end
|
||||
|
||||
private final long zip64EndOffset;
|
||||
|
||||
private final long offset;
|
||||
|
||||
private Zip64Locator(long offset, byte[] block) {
|
||||
this.offset = offset;
|
||||
this.zip64EndOffset = Bytes.littleEndianValue(block, ZIP64_LOCOFF, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of the zip 64 end record located by this zip64 end locator.
|
||||
* @return size of the zip 64 end record located by this zip64 end locator
|
||||
*/
|
||||
private long getZip64EndSize() {
|
||||
return this.offset - this.zip64EndOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the offset to locate {@link Zip64End}.
|
||||
* @return offset of the Zip64 end of central directory record
|
||||
*/
|
||||
private long getZip64EndOffset() {
|
||||
return this.zip64EndOffset;
|
||||
}
|
||||
|
||||
private static Zip64Locator find(RandomAccessData data, long centralDirectoryEndOffset) throws IOException {
|
||||
long offset = centralDirectoryEndOffset - ZIP64_LOCSIZE;
|
||||
if (offset >= 0) {
|
||||
byte[] block = data.read(offset, ZIP64_LOCSIZE);
|
||||
if (Bytes.littleEndianValue(block, 0, 4) == SIGNATURE) {
|
||||
return new Zip64Locator(offset, block);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.jar;
|
||||
|
||||
import fun.asgc.neutrino.core.aop.compiler.internal.data.RandomAccessData;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.time.temporal.ValueRange;
|
||||
|
||||
/**
|
||||
* A ZIP File "Central directory file header record" (CDFH).
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @author Dmytro Nosan
|
||||
* @see <a href="https://en.wikipedia.org/wiki/Zip_%28file_format%29">Zip File Format</a>
|
||||
*/
|
||||
|
||||
final class CentralDirectoryFileHeader implements FileHeader {
|
||||
|
||||
private static final AsciiBytes SLASH = new AsciiBytes("/");
|
||||
|
||||
private static final byte[] NO_EXTRA = {};
|
||||
|
||||
private static final AsciiBytes NO_COMMENT = new AsciiBytes("");
|
||||
|
||||
private byte[] header;
|
||||
|
||||
private int headerOffset;
|
||||
|
||||
private AsciiBytes name;
|
||||
|
||||
private byte[] extra;
|
||||
|
||||
private AsciiBytes comment;
|
||||
|
||||
private long localHeaderOffset;
|
||||
|
||||
CentralDirectoryFileHeader() {
|
||||
}
|
||||
|
||||
CentralDirectoryFileHeader(byte[] header, int headerOffset, AsciiBytes name, byte[] extra, AsciiBytes comment,
|
||||
long localHeaderOffset) {
|
||||
this.header = header;
|
||||
this.headerOffset = headerOffset;
|
||||
this.name = name;
|
||||
this.extra = extra;
|
||||
this.comment = comment;
|
||||
this.localHeaderOffset = localHeaderOffset;
|
||||
}
|
||||
|
||||
void load(byte[] data, int dataOffset, RandomAccessData variableData, long variableOffset, JarEntryFilter filter)
|
||||
throws IOException {
|
||||
// Load fixed part
|
||||
this.header = data;
|
||||
this.headerOffset = dataOffset;
|
||||
long compressedSize = Bytes.littleEndianValue(data, dataOffset + 20, 4);
|
||||
long uncompressedSize = Bytes.littleEndianValue(data, dataOffset + 24, 4);
|
||||
long nameLength = Bytes.littleEndianValue(data, dataOffset + 28, 2);
|
||||
long extraLength = Bytes.littleEndianValue(data, dataOffset + 30, 2);
|
||||
long commentLength = Bytes.littleEndianValue(data, dataOffset + 32, 2);
|
||||
long localHeaderOffset = Bytes.littleEndianValue(data, dataOffset + 42, 4);
|
||||
// Load variable part
|
||||
dataOffset += 46;
|
||||
if (variableData != null) {
|
||||
data = variableData.read(variableOffset + 46, nameLength + extraLength + commentLength);
|
||||
dataOffset = 0;
|
||||
}
|
||||
this.name = new AsciiBytes(data, dataOffset, (int) nameLength);
|
||||
if (filter != null) {
|
||||
this.name = filter.apply(this.name);
|
||||
}
|
||||
this.extra = NO_EXTRA;
|
||||
this.comment = NO_COMMENT;
|
||||
if (extraLength > 0) {
|
||||
this.extra = new byte[(int) extraLength];
|
||||
System.arraycopy(data, (int) (dataOffset + nameLength), this.extra, 0, this.extra.length);
|
||||
}
|
||||
this.localHeaderOffset = getLocalHeaderOffset(compressedSize, uncompressedSize, localHeaderOffset, this.extra);
|
||||
if (commentLength > 0) {
|
||||
this.comment = new AsciiBytes(data, (int) (dataOffset + nameLength + extraLength), (int) commentLength);
|
||||
}
|
||||
}
|
||||
|
||||
private long getLocalHeaderOffset(long compressedSize, long uncompressedSize, long localHeaderOffset, byte[] extra)
|
||||
throws IOException {
|
||||
if (localHeaderOffset != 0xFFFFFFFFL) {
|
||||
return localHeaderOffset;
|
||||
}
|
||||
int extraOffset = 0;
|
||||
while (extraOffset < extra.length - 2) {
|
||||
int id = (int) Bytes.littleEndianValue(extra, extraOffset, 2);
|
||||
int length = (int) Bytes.littleEndianValue(extra, extraOffset, 2);
|
||||
extraOffset += 4;
|
||||
if (id == 1) {
|
||||
int localHeaderExtraOffset = 0;
|
||||
if (compressedSize == 0xFFFFFFFFL) {
|
||||
localHeaderExtraOffset += 4;
|
||||
}
|
||||
if (uncompressedSize == 0xFFFFFFFFL) {
|
||||
localHeaderExtraOffset += 4;
|
||||
}
|
||||
return Bytes.littleEndianValue(extra, extraOffset + localHeaderExtraOffset, 8);
|
||||
}
|
||||
extraOffset += length;
|
||||
}
|
||||
throw new IOException("Zip64 Extended Information Extra Field not found");
|
||||
}
|
||||
|
||||
AsciiBytes getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasName(CharSequence name, char suffix) {
|
||||
return this.name.matches(name, suffix);
|
||||
}
|
||||
|
||||
boolean isDirectory() {
|
||||
return this.name.endsWith(SLASH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMethod() {
|
||||
return (int) Bytes.littleEndianValue(this.header, this.headerOffset + 10, 2);
|
||||
}
|
||||
|
||||
long getTime() {
|
||||
long datetime = Bytes.littleEndianValue(this.header, this.headerOffset + 12, 4);
|
||||
return decodeMsDosFormatDateTime(datetime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode MS-DOS Date Time details. See <a href=
|
||||
* "https://docs.microsoft.com/en-gb/windows/desktop/api/winbase/nf-winbase-dosdatetimetofiletime">
|
||||
* Microsoft's documentation</a> for more details of the format.
|
||||
* @param datetime the date and time
|
||||
* @return the date and time as milliseconds since the epoch
|
||||
*/
|
||||
private long decodeMsDosFormatDateTime(long datetime) {
|
||||
int year = getChronoValue(((datetime >> 25) & 0x7f) + 1980, ChronoField.YEAR);
|
||||
int month = getChronoValue((datetime >> 21) & 0x0f, ChronoField.MONTH_OF_YEAR);
|
||||
int day = getChronoValue((datetime >> 16) & 0x1f, ChronoField.DAY_OF_MONTH);
|
||||
int hour = getChronoValue((datetime >> 11) & 0x1f, ChronoField.HOUR_OF_DAY);
|
||||
int minute = getChronoValue((datetime >> 5) & 0x3f, ChronoField.MINUTE_OF_HOUR);
|
||||
int second = getChronoValue((datetime << 1) & 0x3e, ChronoField.SECOND_OF_MINUTE);
|
||||
return ZonedDateTime.of(year, month, day, hour, minute, second, 0, ZoneId.systemDefault())
|
||||
.toInstant()
|
||||
.truncatedTo(ChronoUnit.SECONDS)
|
||||
.toEpochMilli();
|
||||
}
|
||||
|
||||
long getCrc() {
|
||||
return Bytes.littleEndianValue(this.header, this.headerOffset + 16, 4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCompressedSize() {
|
||||
return Bytes.littleEndianValue(this.header, this.headerOffset + 20, 4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSize() {
|
||||
return Bytes.littleEndianValue(this.header, this.headerOffset + 24, 4);
|
||||
}
|
||||
|
||||
byte[] getExtra() {
|
||||
return this.extra;
|
||||
}
|
||||
|
||||
boolean hasExtra() {
|
||||
return this.extra.length > 0;
|
||||
}
|
||||
|
||||
AsciiBytes getComment() {
|
||||
return this.comment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLocalHeaderOffset() {
|
||||
return this.localHeaderOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CentralDirectoryFileHeader clone() {
|
||||
byte[] header = new byte[46];
|
||||
System.arraycopy(this.header, this.headerOffset, header, 0, header.length);
|
||||
return new CentralDirectoryFileHeader(header, 0, this.name, header, this.comment, this.localHeaderOffset);
|
||||
}
|
||||
|
||||
static CentralDirectoryFileHeader fromRandomAccessData(RandomAccessData data, long offset, JarEntryFilter filter)
|
||||
throws IOException {
|
||||
CentralDirectoryFileHeader fileHeader = new CentralDirectoryFileHeader();
|
||||
byte[] bytes = data.read(offset, 46);
|
||||
fileHeader.load(bytes, 0, data, offset, filter);
|
||||
return fileHeader;
|
||||
}
|
||||
|
||||
private static int getChronoValue(long value, ChronoField field) {
|
||||
ValueRange range = field.range();
|
||||
return Math.toIntExact(Math.min(Math.max(value, range.getMinimum()), range.getMaximum()));
|
||||
}
|
||||
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.jar;
|
||||
|
||||
import fun.asgc.neutrino.core.aop.compiler.internal.data.RandomAccessData;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Parses the central directory from a JAR file.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @see CentralDirectoryVisitor
|
||||
*/
|
||||
class CentralDirectoryParser {
|
||||
|
||||
private static final int CENTRAL_DIRECTORY_HEADER_BASE_SIZE = 46;
|
||||
|
||||
private final List<CentralDirectoryVisitor> visitors = new ArrayList<>();
|
||||
|
||||
<T extends CentralDirectoryVisitor> T addVisitor(T visitor) {
|
||||
this.visitors.add(visitor);
|
||||
return visitor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the source data, triggering {@link CentralDirectoryVisitor visitors}.
|
||||
* @param data the source data
|
||||
* @param skipPrefixBytes if prefix bytes should be skipped
|
||||
* @return the actual archive data without any prefix bytes
|
||||
* @throws IOException on error
|
||||
*/
|
||||
RandomAccessData parse(RandomAccessData data, boolean skipPrefixBytes) throws IOException {
|
||||
CentralDirectoryEndRecord endRecord = new CentralDirectoryEndRecord(data);
|
||||
if (skipPrefixBytes) {
|
||||
data = getArchiveData(endRecord, data);
|
||||
}
|
||||
RandomAccessData centralDirectoryData = endRecord.getCentralDirectory(data);
|
||||
visitStart(endRecord, centralDirectoryData);
|
||||
parseEntries(endRecord, centralDirectoryData);
|
||||
visitEnd();
|
||||
return data;
|
||||
}
|
||||
|
||||
private void parseEntries(CentralDirectoryEndRecord endRecord, RandomAccessData centralDirectoryData)
|
||||
throws IOException {
|
||||
byte[] bytes = centralDirectoryData.read(0, centralDirectoryData.getSize());
|
||||
CentralDirectoryFileHeader fileHeader = new CentralDirectoryFileHeader();
|
||||
int dataOffset = 0;
|
||||
for (int i = 0; i < endRecord.getNumberOfRecords(); i++) {
|
||||
fileHeader.load(bytes, dataOffset, null, 0, null);
|
||||
visitFileHeader(dataOffset, fileHeader);
|
||||
dataOffset += CENTRAL_DIRECTORY_HEADER_BASE_SIZE + fileHeader.getName().length()
|
||||
+ fileHeader.getComment().length() + fileHeader.getExtra().length;
|
||||
}
|
||||
}
|
||||
|
||||
private RandomAccessData getArchiveData(CentralDirectoryEndRecord endRecord, RandomAccessData data) {
|
||||
long offset = endRecord.getStartOfArchive(data);
|
||||
if (offset == 0) {
|
||||
return data;
|
||||
}
|
||||
return data.getSubsection(offset, data.getSize() - offset);
|
||||
}
|
||||
|
||||
private void visitStart(CentralDirectoryEndRecord endRecord, RandomAccessData centralDirectoryData) {
|
||||
for (CentralDirectoryVisitor visitor : this.visitors) {
|
||||
visitor.visitStart(endRecord, centralDirectoryData);
|
||||
}
|
||||
}
|
||||
|
||||
private void visitFileHeader(long dataOffset, CentralDirectoryFileHeader fileHeader) {
|
||||
for (CentralDirectoryVisitor visitor : this.visitors) {
|
||||
visitor.visitFileHeader(fileHeader, dataOffset);
|
||||
}
|
||||
}
|
||||
|
||||
private void visitEnd() {
|
||||
for (CentralDirectoryVisitor visitor : this.visitors) {
|
||||
visitor.visitEnd();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.jar;
|
||||
|
||||
import fun.asgc.neutrino.core.aop.compiler.internal.data.RandomAccessData;
|
||||
|
||||
/**
|
||||
* Callback visitor triggered by {@link CentralDirectoryParser}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
interface CentralDirectoryVisitor {
|
||||
|
||||
void visitStart(CentralDirectoryEndRecord endRecord, RandomAccessData centralDirectoryData);
|
||||
|
||||
void visitFileHeader(CentralDirectoryFileHeader fileHeader, long dataOffset);
|
||||
|
||||
void visitEnd();
|
||||
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.jar;
|
||||
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
/**
|
||||
* A file header record that has been loaded from a Jar file.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @see JarEntry
|
||||
* @see CentralDirectoryFileHeader
|
||||
*/
|
||||
interface FileHeader {
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the header has the given name.
|
||||
* @param name the name to test
|
||||
* @param suffix an additional suffix (or {@code 0})
|
||||
* @return {@code true} if the header has the given name
|
||||
*/
|
||||
boolean hasName(CharSequence name, char suffix);
|
||||
|
||||
/**
|
||||
* Return the offset of the load file header within the archive data.
|
||||
* @return the local header offset
|
||||
*/
|
||||
long getLocalHeaderOffset();
|
||||
|
||||
/**
|
||||
* Return the compressed size of the entry.
|
||||
* @return the compressed size.
|
||||
*/
|
||||
long getCompressedSize();
|
||||
|
||||
/**
|
||||
* Return the uncompressed size of the entry.
|
||||
* @return the uncompressed size.
|
||||
*/
|
||||
long getSize();
|
||||
|
||||
/**
|
||||
* Return the method used to compress the data.
|
||||
* @return the zip compression method
|
||||
* @see ZipEntry#STORED
|
||||
* @see ZipEntry#DEFLATED
|
||||
*/
|
||||
int getMethod();
|
||||
|
||||
}
|
||||
+448
@@ -0,0 +1,448 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.jar;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.net.*;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* {@link URLStreamHandler} for Spring Boot loader {@link JarFile}s.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.0.0
|
||||
* @see JarFile#registerUrlProtocolHandler()
|
||||
*/
|
||||
public class Handler extends URLStreamHandler {
|
||||
|
||||
// NOTE: in order to be found as a URL protocol handler, this class must be public,
|
||||
// must be named Handler and must be in a package ending '.jar'
|
||||
|
||||
private static final String JAR_PROTOCOL = "jar:";
|
||||
|
||||
private static final String FILE_PROTOCOL = "file:";
|
||||
|
||||
private static final String TOMCAT_WARFILE_PROTOCOL = "war:file:";
|
||||
|
||||
private static final String SEPARATOR = "!/";
|
||||
|
||||
private static final Pattern SEPARATOR_PATTERN = Pattern.compile(SEPARATOR, Pattern.LITERAL);
|
||||
|
||||
private static final String CURRENT_DIR = "/./";
|
||||
|
||||
private static final Pattern CURRENT_DIR_PATTERN = Pattern.compile(CURRENT_DIR, Pattern.LITERAL);
|
||||
|
||||
private static final String PARENT_DIR = "/../";
|
||||
|
||||
private static final String PROTOCOL_HANDLER = "java.protocol.handler.pkgs";
|
||||
|
||||
private static final String[] FALLBACK_HANDLERS = { "sun.net.www.protocol.jar.Handler" };
|
||||
|
||||
private static URL jarContextUrl;
|
||||
|
||||
private static SoftReference<Map<File, JarFile>> rootFileCache;
|
||||
|
||||
static {
|
||||
rootFileCache = new SoftReference<>(null);
|
||||
}
|
||||
|
||||
private final JarFile jarFile;
|
||||
|
||||
private URLStreamHandler fallbackHandler;
|
||||
|
||||
public Handler() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public Handler(JarFile jarFile) {
|
||||
this.jarFile = jarFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected URLConnection openConnection(URL url) throws IOException {
|
||||
if (this.jarFile != null && isUrlInJarFile(url, this.jarFile)) {
|
||||
return fun.asgc.neutrino.core.aop.compiler.internal.jar.JarURLConnection.get(url, this.jarFile);
|
||||
}
|
||||
try {
|
||||
return fun.asgc.neutrino.core.aop.compiler.internal.jar.JarURLConnection.get(url, getRootJarFileFromUrl(url));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return openFallbackConnection(url, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isUrlInJarFile(URL url, JarFile jarFile) throws MalformedURLException {
|
||||
// Try the path first to save building a new url string each time
|
||||
return url.getPath().startsWith(jarFile.getUrl().getPath())
|
||||
&& url.toString().startsWith(jarFile.getUrlString());
|
||||
}
|
||||
|
||||
private URLConnection openFallbackConnection(URL url, Exception reason) throws IOException {
|
||||
try {
|
||||
URLConnection connection = openFallbackTomcatConnection(url);
|
||||
connection = (connection != null) ? connection : openFallbackContextConnection(url);
|
||||
return (connection != null) ? connection : openFallbackHandlerConnection(url);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (reason instanceof IOException) {
|
||||
log(false, "Unable to open fallback handler", ex);
|
||||
IOException ioException = (IOException)reason;
|
||||
throw ioException;
|
||||
}
|
||||
log(true, "Unable to open fallback handler", ex);
|
||||
if (reason instanceof RuntimeException) {
|
||||
RuntimeException runtimeException = (RuntimeException)reason;
|
||||
throw runtimeException;
|
||||
}
|
||||
throw new IllegalStateException(reason);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to open a Tomcat formatted 'jar:war:file:...' URL. This method allows us to
|
||||
* use our own nested JAR support to open the content rather than the logic in
|
||||
* {@code sun.net.www.protocol.jar.URLJarFile} which will extract the nested jar to
|
||||
* the temp folder to that its content can be accessed.
|
||||
* @param url the URL to open
|
||||
* @return a {@link URLConnection} or {@code null}
|
||||
*/
|
||||
private URLConnection openFallbackTomcatConnection(URL url) {
|
||||
String file = url.getFile();
|
||||
if (isTomcatWarUrl(file)) {
|
||||
file = file.substring(TOMCAT_WARFILE_PROTOCOL.length());
|
||||
file = file.replaceFirst("\\*/", "!/");
|
||||
try {
|
||||
URLConnection connection = openConnection(new URL("jar:file:" + file));
|
||||
connection.getInputStream().close();
|
||||
return connection;
|
||||
}
|
||||
catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isTomcatWarUrl(String file) {
|
||||
if (file.startsWith(TOMCAT_WARFILE_PROTOCOL) || !file.contains("*/")) {
|
||||
try {
|
||||
URLConnection connection = new URL(file).openConnection();
|
||||
if (connection.getClass().getName().startsWith("org.apache.catalina")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to open a fallback connection by using a context URL captured before the
|
||||
* jar handler was replaced with our own version. Since this method doesn't use
|
||||
* reflection it won't trigger "illegal reflective access operation has occurred"
|
||||
* warnings on Java 13+.
|
||||
* @param url the URL to open
|
||||
* @return a {@link URLConnection} or {@code null}
|
||||
*/
|
||||
private URLConnection openFallbackContextConnection(URL url) {
|
||||
try {
|
||||
if (jarContextUrl != null) {
|
||||
return new URL(jarContextUrl, url.toExternalForm()).openConnection();
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to open a fallback connection by using reflection to access Java's default
|
||||
* jar {@link URLStreamHandler}.
|
||||
* @param url the URL to open
|
||||
* @return the {@link URLConnection}
|
||||
* @throws Exception if not connection could be opened
|
||||
*/
|
||||
private URLConnection openFallbackHandlerConnection(URL url) throws Exception {
|
||||
URLStreamHandler fallbackHandler = getFallbackHandler();
|
||||
return new URL(null, url.toExternalForm(), fallbackHandler).openConnection();
|
||||
}
|
||||
|
||||
private URLStreamHandler getFallbackHandler() {
|
||||
if (this.fallbackHandler != null) {
|
||||
return this.fallbackHandler;
|
||||
}
|
||||
for (String handlerClassName : FALLBACK_HANDLERS) {
|
||||
try {
|
||||
Class<?> handlerClass = Class.forName(handlerClassName);
|
||||
this.fallbackHandler = (URLStreamHandler) handlerClass.getDeclaredConstructor().newInstance();
|
||||
return this.fallbackHandler;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Unable to find fallback handler");
|
||||
}
|
||||
|
||||
private void log(boolean warning, String message, Exception cause) {
|
||||
try {
|
||||
Level level = warning ? Level.WARNING : Level.FINEST;
|
||||
Logger.getLogger(getClass().getName()).log(level, message, cause);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (warning) {
|
||||
System.err.println("WARNING: " + message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseURL(URL context, String spec, int start, int limit) {
|
||||
if (spec.regionMatches(true, 0, JAR_PROTOCOL, 0, JAR_PROTOCOL.length())) {
|
||||
setFile(context, getFileFromSpec(spec.substring(start, limit)));
|
||||
}
|
||||
else {
|
||||
setFile(context, getFileFromContext(context, spec.substring(start, limit)));
|
||||
}
|
||||
}
|
||||
|
||||
private String getFileFromSpec(String spec) {
|
||||
int separatorIndex = spec.lastIndexOf("!/");
|
||||
if (separatorIndex == -1) {
|
||||
throw new IllegalArgumentException("No !/ in spec '" + spec + "'");
|
||||
}
|
||||
try {
|
||||
new URL(spec.substring(0, separatorIndex));
|
||||
return spec;
|
||||
}
|
||||
catch (MalformedURLException ex) {
|
||||
throw new IllegalArgumentException("Invalid spec URL '" + spec + "'", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private String getFileFromContext(URL context, String spec) {
|
||||
String file = context.getFile();
|
||||
if (spec.startsWith("/")) {
|
||||
return trimToJarRoot(file) + SEPARATOR + spec.substring(1);
|
||||
}
|
||||
if (file.endsWith("/")) {
|
||||
return file + spec;
|
||||
}
|
||||
int lastSlashIndex = file.lastIndexOf('/');
|
||||
if (lastSlashIndex == -1) {
|
||||
throw new IllegalArgumentException("No / found in context URL's file '" + file + "'");
|
||||
}
|
||||
return file.substring(0, lastSlashIndex + 1) + spec;
|
||||
}
|
||||
|
||||
private String trimToJarRoot(String file) {
|
||||
int lastSeparatorIndex = file.lastIndexOf(SEPARATOR);
|
||||
if (lastSeparatorIndex == -1) {
|
||||
throw new IllegalArgumentException("No !/ found in context URL's file '" + file + "'");
|
||||
}
|
||||
return file.substring(0, lastSeparatorIndex);
|
||||
}
|
||||
|
||||
private void setFile(URL context, String file) {
|
||||
String path = normalize(file);
|
||||
String query = null;
|
||||
int queryIndex = path.lastIndexOf('?');
|
||||
if (queryIndex != -1) {
|
||||
query = path.substring(queryIndex + 1);
|
||||
path = path.substring(0, queryIndex);
|
||||
}
|
||||
setURL(context, JAR_PROTOCOL, null, -1, null, null, path, query, context.getRef());
|
||||
}
|
||||
|
||||
private String normalize(String file) {
|
||||
if (!file.contains(CURRENT_DIR) && !file.contains(PARENT_DIR)) {
|
||||
return file;
|
||||
}
|
||||
int afterLastSeparatorIndex = file.lastIndexOf(SEPARATOR) + SEPARATOR.length();
|
||||
String afterSeparator = file.substring(afterLastSeparatorIndex);
|
||||
afterSeparator = replaceParentDir(afterSeparator);
|
||||
afterSeparator = replaceCurrentDir(afterSeparator);
|
||||
return file.substring(0, afterLastSeparatorIndex) + afterSeparator;
|
||||
}
|
||||
|
||||
private String replaceParentDir(String file) {
|
||||
int parentDirIndex;
|
||||
while ((parentDirIndex = file.indexOf(PARENT_DIR)) >= 0) {
|
||||
int precedingSlashIndex = file.lastIndexOf('/', parentDirIndex - 1);
|
||||
if (precedingSlashIndex >= 0) {
|
||||
file = file.substring(0, precedingSlashIndex) + file.substring(parentDirIndex + 3);
|
||||
}
|
||||
else {
|
||||
file = file.substring(parentDirIndex + 4);
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
private String replaceCurrentDir(String file) {
|
||||
return CURRENT_DIR_PATTERN.matcher(file).replaceAll("/");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int hashCode(URL u) {
|
||||
return hashCode(u.getProtocol(), u.getFile());
|
||||
}
|
||||
|
||||
private int hashCode(String protocol, String file) {
|
||||
int result = (protocol != null) ? protocol.hashCode() : 0;
|
||||
int separatorIndex = file.indexOf(SEPARATOR);
|
||||
if (separatorIndex == -1) {
|
||||
return result + file.hashCode();
|
||||
}
|
||||
String source = file.substring(0, separatorIndex);
|
||||
String entry = canonicalize(file.substring(separatorIndex + 2));
|
||||
try {
|
||||
result += new URL(source).hashCode();
|
||||
}
|
||||
catch (MalformedURLException ex) {
|
||||
result += source.hashCode();
|
||||
}
|
||||
result += entry.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean sameFile(URL u1, URL u2) {
|
||||
if (!u1.getProtocol().equals("jar") || !u2.getProtocol().equals("jar")) {
|
||||
return false;
|
||||
}
|
||||
int separator1 = u1.getFile().indexOf(SEPARATOR);
|
||||
int separator2 = u2.getFile().indexOf(SEPARATOR);
|
||||
if (separator1 == -1 || separator2 == -1) {
|
||||
return super.sameFile(u1, u2);
|
||||
}
|
||||
String nested1 = u1.getFile().substring(separator1 + SEPARATOR.length());
|
||||
String nested2 = u2.getFile().substring(separator2 + SEPARATOR.length());
|
||||
if (!nested1.equals(nested2)) {
|
||||
String canonical1 = canonicalize(nested1);
|
||||
String canonical2 = canonicalize(nested2);
|
||||
if (!canonical1.equals(canonical2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
String root1 = u1.getFile().substring(0, separator1);
|
||||
String root2 = u2.getFile().substring(0, separator2);
|
||||
try {
|
||||
return super.sameFile(new URL(root1), new URL(root2));
|
||||
}
|
||||
catch (MalformedURLException ex) {
|
||||
// Continue
|
||||
}
|
||||
return super.sameFile(u1, u2);
|
||||
}
|
||||
|
||||
private String canonicalize(String path) {
|
||||
return SEPARATOR_PATTERN.matcher(path).replaceAll("/");
|
||||
}
|
||||
|
||||
public JarFile getRootJarFileFromUrl(URL url) throws IOException {
|
||||
String spec = url.getFile();
|
||||
int separatorIndex = spec.indexOf(SEPARATOR);
|
||||
if (separatorIndex == -1) {
|
||||
throw new MalformedURLException("Jar URL does not contain !/ separator");
|
||||
}
|
||||
String name = spec.substring(0, separatorIndex);
|
||||
return getRootJarFile(name);
|
||||
}
|
||||
|
||||
private JarFile getRootJarFile(String name) throws IOException {
|
||||
try {
|
||||
if (!name.startsWith(FILE_PROTOCOL)) {
|
||||
throw new IllegalStateException("Not a file URL");
|
||||
}
|
||||
File file = new File(URI.create(name));
|
||||
Map<File, JarFile> cache = rootFileCache.get();
|
||||
JarFile result = (cache != null) ? cache.get(file) : null;
|
||||
if (result == null) {
|
||||
result = new JarFile(file);
|
||||
addToRootFileCache(file, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IOException("Unable to open root Jar file '" + name + "'", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given {@link JarFile} to the root file cache.
|
||||
* @param sourceFile the source file to add
|
||||
* @param jarFile the jar file.
|
||||
*/
|
||||
static void addToRootFileCache(File sourceFile, JarFile jarFile) {
|
||||
Map<File, JarFile> cache = rootFileCache.get();
|
||||
if (cache == null) {
|
||||
cache = new ConcurrentHashMap<>();
|
||||
rootFileCache = new SoftReference<>(cache);
|
||||
}
|
||||
cache.put(sourceFile, jarFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* If possible, capture a URL that is configured with the original jar handler so that
|
||||
* we can use it as a fallback context later. We can only do this if we know that we
|
||||
* can reset the handlers after.
|
||||
*/
|
||||
static void captureJarContextUrl() {
|
||||
if (canResetCachedUrlHandlers()) {
|
||||
String handlers = System.getProperty(PROTOCOL_HANDLER);
|
||||
try {
|
||||
System.clearProperty(PROTOCOL_HANDLER);
|
||||
try {
|
||||
resetCachedUrlHandlers();
|
||||
jarContextUrl = new URL("jar:file:context.jar!/");
|
||||
URLConnection connection = jarContextUrl.openConnection();
|
||||
if (connection instanceof fun.asgc.neutrino.core.aop.compiler.internal.jar.JarURLConnection) {
|
||||
jarContextUrl = null;
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (handlers == null) {
|
||||
System.clearProperty(PROTOCOL_HANDLER);
|
||||
}
|
||||
else {
|
||||
System.setProperty(PROTOCOL_HANDLER, handlers);
|
||||
}
|
||||
}
|
||||
resetCachedUrlHandlers();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean canResetCachedUrlHandlers() {
|
||||
try {
|
||||
resetCachedUrlHandlers();
|
||||
return true;
|
||||
}
|
||||
catch (Error ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void resetCachedUrlHandlers() {
|
||||
URL.setURLStreamHandlerFactory(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if a generic static exception can be thrown when a URL cannot be connected.
|
||||
* This optimization is used during class loading to save creating lots of exceptions
|
||||
* which are then swallowed.
|
||||
* @param useFastConnectionExceptions if fast connection exceptions can be used.
|
||||
*/
|
||||
public static void setUseFastConnectionExceptions(boolean useFastConnectionExceptions) {
|
||||
JarURLConnection.setUseFastExceptions(useFastConnectionExceptions);
|
||||
}
|
||||
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.jar;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.security.CodeSigner;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
/**
|
||||
* Extended variant of {@link java.util.jar.JarEntry} returned by {@link JarFile}s.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class JarEntry extends java.util.jar.JarEntry implements FileHeader {
|
||||
|
||||
private final int index;
|
||||
|
||||
private final AsciiBytes name;
|
||||
|
||||
private final AsciiBytes headerName;
|
||||
|
||||
private final JarFile jarFile;
|
||||
|
||||
private final long localHeaderOffset;
|
||||
|
||||
private volatile JarEntryCertification certification;
|
||||
|
||||
JarEntry(JarFile jarFile, int index, CentralDirectoryFileHeader header, AsciiBytes nameAlias) {
|
||||
super((nameAlias != null) ? nameAlias.toString() : header.getName().toString());
|
||||
this.index = index;
|
||||
this.name = (nameAlias != null) ? nameAlias : header.getName();
|
||||
this.headerName = header.getName();
|
||||
this.jarFile = jarFile;
|
||||
this.localHeaderOffset = header.getLocalHeaderOffset();
|
||||
setCompressedSize(header.getCompressedSize());
|
||||
setMethod(header.getMethod());
|
||||
setCrc(header.getCrc());
|
||||
setComment(header.getComment().toString());
|
||||
setSize(header.getSize());
|
||||
setTime(header.getTime());
|
||||
if (header.hasExtra()) {
|
||||
setExtra(header.getExtra());
|
||||
}
|
||||
}
|
||||
|
||||
int getIndex() {
|
||||
return this.index;
|
||||
}
|
||||
|
||||
AsciiBytes getAsciiBytesName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasName(CharSequence name, char suffix) {
|
||||
return this.headerName.matches(name, suffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link URL} for this {@link JarEntry}.
|
||||
* @return the URL for the entry
|
||||
* @throws MalformedURLException if the URL is not valid
|
||||
*/
|
||||
URL getUrl() throws MalformedURLException {
|
||||
return new URL(this.jarFile.getUrl(), getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Attributes getAttributes() throws IOException {
|
||||
Manifest manifest = this.jarFile.getManifest();
|
||||
return (manifest != null) ? manifest.getAttributes(getName()) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Certificate[] getCertificates() {
|
||||
return getCertification().getCertificates();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeSigner[] getCodeSigners() {
|
||||
return getCertification().getCodeSigners();
|
||||
}
|
||||
|
||||
private JarEntryCertification getCertification() {
|
||||
if (!this.jarFile.isSigned()) {
|
||||
return JarEntryCertification.NONE;
|
||||
}
|
||||
JarEntryCertification certification = this.certification;
|
||||
if (certification == null) {
|
||||
certification = this.jarFile.getCertification(this);
|
||||
this.certification = certification;
|
||||
}
|
||||
return certification;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLocalHeaderOffset() {
|
||||
return this.localHeaderOffset;
|
||||
}
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.jar;
|
||||
|
||||
import java.security.CodeSigner;
|
||||
import java.security.cert.Certificate;
|
||||
|
||||
/**
|
||||
* {@link Certificate} and {@link CodeSigner} details for a {@link JarEntry} from a signed
|
||||
* {@link JarFile}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class JarEntryCertification {
|
||||
|
||||
static final JarEntryCertification NONE = new JarEntryCertification(null, null);
|
||||
|
||||
private final Certificate[] certificates;
|
||||
|
||||
private final CodeSigner[] codeSigners;
|
||||
|
||||
JarEntryCertification(Certificate[] certificates, CodeSigner[] codeSigners) {
|
||||
this.certificates = certificates;
|
||||
this.codeSigners = codeSigners;
|
||||
}
|
||||
|
||||
Certificate[] getCertificates() {
|
||||
return (this.certificates != null) ? this.certificates.clone() : null;
|
||||
}
|
||||
|
||||
CodeSigner[] getCodeSigners() {
|
||||
return (this.codeSigners != null) ? this.codeSigners.clone() : null;
|
||||
}
|
||||
|
||||
static JarEntryCertification from(java.util.jar.JarEntry certifiedEntry) {
|
||||
Certificate[] certificates = (certifiedEntry != null) ? certifiedEntry.getCertificates() : null;
|
||||
CodeSigner[] codeSigners = (certifiedEntry != null) ? certifiedEntry.getCodeSigners() : null;
|
||||
if (certificates == null && codeSigners == null) {
|
||||
return NONE;
|
||||
}
|
||||
return new JarEntryCertification(certificates, codeSigners);
|
||||
}
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.jar;
|
||||
|
||||
/**
|
||||
* Interface that can be used to filter and optionally rename jar entries.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
interface JarEntryFilter {
|
||||
|
||||
/**
|
||||
* Apply the jar entry filter.
|
||||
* @param name the current entry name. This may be different that the original entry
|
||||
* name if a previous filter has been applied
|
||||
* @return the new name of the entry or {@code null} if the entry should not be
|
||||
* included.
|
||||
*/
|
||||
AsciiBytes apply(AsciiBytes name);
|
||||
|
||||
}
|
||||
+460
@@ -0,0 +1,460 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.jar;
|
||||
|
||||
import fun.asgc.neutrino.core.aop.compiler.internal.data.RandomAccessData;
|
||||
import fun.asgc.neutrino.core.aop.compiler.internal.data.RandomAccessDataFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilePermission;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLStreamHandler;
|
||||
import java.net.URLStreamHandlerFactory;
|
||||
import java.security.Permission;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
/**
|
||||
* Extended variant of {@link java.util.jar.JarFile} that behaves in the same way but
|
||||
* offers the following additional functionality.
|
||||
* <ul>
|
||||
* <li>A nested {@link JarFile} can be {@link #getNestedJarFile(ZipEntry) obtained} based
|
||||
* on any directory entry.</li>
|
||||
* <li>A nested {@link JarFile} can be {@link #getNestedJarFile(ZipEntry) obtained} for
|
||||
* embedded JAR files (as long as their entry is not compressed).</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class JarFile extends AbstractJarFile implements Iterable<java.util.jar.JarEntry> {
|
||||
|
||||
private static final String MANIFEST_NAME = "META-INF/MANIFEST.MF";
|
||||
|
||||
private static final String PROTOCOL_HANDLER = "java.protocol.handler.pkgs";
|
||||
|
||||
private static final String HANDLERS_PACKAGE = "org.springframework.boot.loader";
|
||||
|
||||
private static final AsciiBytes META_INF = new AsciiBytes("META-INF/");
|
||||
|
||||
private static final AsciiBytes SIGNATURE_FILE_EXTENSION = new AsciiBytes(".SF");
|
||||
|
||||
private static final String READ_ACTION = "read";
|
||||
|
||||
private final RandomAccessDataFile rootFile;
|
||||
|
||||
private final String pathFromRoot;
|
||||
|
||||
private final RandomAccessData data;
|
||||
|
||||
private final JarFileType type;
|
||||
|
||||
private URL url;
|
||||
|
||||
private String urlString;
|
||||
|
||||
private final JarFileEntries entries;
|
||||
|
||||
private final Supplier<Manifest> manifestSupplier;
|
||||
|
||||
private SoftReference<Manifest> manifest;
|
||||
|
||||
private boolean signed;
|
||||
|
||||
private String comment;
|
||||
|
||||
private volatile boolean closed;
|
||||
|
||||
private volatile JarFileWrapper wrapper;
|
||||
|
||||
/**
|
||||
* Create a new {@link JarFile} backed by the specified file.
|
||||
* @param file the root jar file
|
||||
* @throws IOException if the file cannot be read
|
||||
*/
|
||||
public JarFile(File file) throws IOException {
|
||||
this(new RandomAccessDataFile(file));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link JarFile} backed by the specified file.
|
||||
* @param file the root jar file
|
||||
* @throws IOException if the file cannot be read
|
||||
*/
|
||||
JarFile(RandomAccessDataFile file) throws IOException {
|
||||
this(file, "", file, JarFileType.DIRECT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor used to create a new {@link JarFile} either directly or from a
|
||||
* nested entry.
|
||||
* @param rootFile the root jar file
|
||||
* @param pathFromRoot the name of this file
|
||||
* @param data the underlying data
|
||||
* @param type the type of the jar file
|
||||
* @throws IOException if the file cannot be read
|
||||
*/
|
||||
private JarFile(RandomAccessDataFile rootFile, String pathFromRoot, RandomAccessData data, JarFileType type)
|
||||
throws IOException {
|
||||
this(rootFile, pathFromRoot, data, null, type, null);
|
||||
}
|
||||
|
||||
private JarFile(RandomAccessDataFile rootFile, String pathFromRoot, RandomAccessData data, JarEntryFilter filter,
|
||||
JarFileType type, Supplier<Manifest> manifestSupplier) throws IOException {
|
||||
super(rootFile.getFile());
|
||||
super.close();
|
||||
this.rootFile = rootFile;
|
||||
this.pathFromRoot = pathFromRoot;
|
||||
CentralDirectoryParser parser = new CentralDirectoryParser();
|
||||
this.entries = parser.addVisitor(new JarFileEntries(this, filter));
|
||||
this.type = type;
|
||||
parser.addVisitor(centralDirectoryVisitor());
|
||||
try {
|
||||
this.data = parser.parse(data, filter == null);
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
try {
|
||||
this.rootFile.close();
|
||||
super.close();
|
||||
}
|
||||
catch (IOException ioex) {
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
this.manifestSupplier = (manifestSupplier != null) ? manifestSupplier : () -> {
|
||||
try (InputStream inputStream = getInputStream(MANIFEST_NAME)) {
|
||||
if (inputStream == null) {
|
||||
return null;
|
||||
}
|
||||
return new Manifest(inputStream);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private CentralDirectoryVisitor centralDirectoryVisitor() {
|
||||
return new CentralDirectoryVisitor() {
|
||||
|
||||
@Override
|
||||
public void visitStart(CentralDirectoryEndRecord endRecord, RandomAccessData centralDirectoryData) {
|
||||
JarFile.this.comment = endRecord.getComment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFileHeader(CentralDirectoryFileHeader fileHeader, long dataOffset) {
|
||||
AsciiBytes name = fileHeader.getName();
|
||||
if (name.startsWith(META_INF) && name.endsWith(SIGNATURE_FILE_EXTENSION)) {
|
||||
JarFile.this.signed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
JarFileWrapper getWrapper() throws IOException {
|
||||
JarFileWrapper wrapper = this.wrapper;
|
||||
if (wrapper == null) {
|
||||
wrapper = new JarFileWrapper(this);
|
||||
this.wrapper = wrapper;
|
||||
}
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
Permission getPermission() {
|
||||
return new FilePermission(this.rootFile.getFile().getPath(), READ_ACTION);
|
||||
}
|
||||
|
||||
protected final RandomAccessDataFile getRootJarFile() {
|
||||
return this.rootFile;
|
||||
}
|
||||
|
||||
RandomAccessData getData() {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Manifest getManifest() throws IOException {
|
||||
Manifest manifest = (this.manifest != null) ? this.manifest.get() : null;
|
||||
if (manifest == null) {
|
||||
try {
|
||||
manifest = this.manifestSupplier.get();
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
throw new IOException(ex);
|
||||
}
|
||||
this.manifest = new SoftReference<>(manifest);
|
||||
}
|
||||
return manifest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<java.util.jar.JarEntry> entries() {
|
||||
return new JarEntryEnumeration(this.entries.iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<java.util.jar.JarEntry> stream() {
|
||||
Spliterator<java.util.jar.JarEntry> spliterator = Spliterators.spliterator(iterator(), size(),
|
||||
Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.IMMUTABLE | Spliterator.NONNULL);
|
||||
return StreamSupport.stream(spliterator, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an iterator for the contained entries.
|
||||
* @since 2.3.0
|
||||
* @see Iterable#iterator()
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public Iterator<java.util.jar.JarEntry> iterator() {
|
||||
return (Iterator) this.entries.iterator(this::ensureOpen);
|
||||
}
|
||||
|
||||
public JarEntry getJarEntry(CharSequence name) {
|
||||
return this.entries.getEntry(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JarEntry getJarEntry(String name) {
|
||||
return (JarEntry) getEntry(name);
|
||||
}
|
||||
|
||||
public boolean containsEntry(String name) {
|
||||
return this.entries.containsEntry(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZipEntry getEntry(String name) {
|
||||
ensureOpen();
|
||||
return this.entries.getEntry(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
InputStream getInputStream() throws IOException {
|
||||
return this.data.getInputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized InputStream getInputStream(ZipEntry entry) throws IOException {
|
||||
ensureOpen();
|
||||
if (entry instanceof JarEntry) {
|
||||
JarEntry jarEntry = (JarEntry) entry;
|
||||
return this.entries.getInputStream(jarEntry);
|
||||
}
|
||||
return getInputStream((entry != null) ? entry.getName() : null);
|
||||
}
|
||||
|
||||
InputStream getInputStream(String name) throws IOException {
|
||||
return this.entries.getInputStream(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a nested {@link JarFile} loaded from the specified entry.
|
||||
* @param entry the zip entry
|
||||
* @return a {@link JarFile} for the entry
|
||||
* @throws IOException if the nested jar file cannot be read
|
||||
*/
|
||||
public synchronized JarFile getNestedJarFile(ZipEntry entry) throws IOException {
|
||||
return getNestedJarFile((JarEntry) entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a nested {@link JarFile} loaded from the specified entry.
|
||||
* @param entry the zip entry
|
||||
* @return a {@link JarFile} for the entry
|
||||
* @throws IOException if the nested jar file cannot be read
|
||||
*/
|
||||
public synchronized JarFile getNestedJarFile(JarEntry entry) throws IOException {
|
||||
try {
|
||||
return createJarFileFromEntry(entry);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IOException("Unable to open nested jar file '" + entry.getName() + "'", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private JarFile createJarFileFromEntry(JarEntry entry) throws IOException {
|
||||
if (entry.isDirectory()) {
|
||||
return createJarFileFromDirectoryEntry(entry);
|
||||
}
|
||||
return createJarFileFromFileEntry(entry);
|
||||
}
|
||||
|
||||
private JarFile createJarFileFromDirectoryEntry(JarEntry entry) throws IOException {
|
||||
AsciiBytes name = entry.getAsciiBytesName();
|
||||
JarEntryFilter filter = (candidate) -> {
|
||||
if (candidate.startsWith(name) && !candidate.equals(name)) {
|
||||
return candidate.substring(name.length());
|
||||
}
|
||||
return null;
|
||||
};
|
||||
return new JarFile(this.rootFile, this.pathFromRoot + "!/" + entry.getName().substring(0, name.length() - 1),
|
||||
this.data, filter, JarFileType.NESTED_DIRECTORY, this.manifestSupplier);
|
||||
}
|
||||
|
||||
private JarFile createJarFileFromFileEntry(JarEntry entry) throws IOException {
|
||||
if (entry.getMethod() != ZipEntry.STORED) {
|
||||
throw new IllegalStateException(
|
||||
"Unable to open nested entry '" + entry.getName() + "'. It has been compressed and nested "
|
||||
+ "jar files must be stored without compression. Please check the "
|
||||
+ "mechanism used to create your executable jar file");
|
||||
}
|
||||
RandomAccessData entryData = this.entries.getEntryData(entry.getName());
|
||||
return new JarFile(this.rootFile, this.pathFromRoot + "!/" + entry.getName(), entryData,
|
||||
JarFileType.NESTED_JAR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComment() {
|
||||
ensureOpen();
|
||||
return this.comment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
ensureOpen();
|
||||
return this.entries.getSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (this.closed) {
|
||||
return;
|
||||
}
|
||||
super.close();
|
||||
if (this.type == JarFileType.DIRECT) {
|
||||
this.rootFile.close();
|
||||
}
|
||||
this.closed = true;
|
||||
}
|
||||
|
||||
private void ensureOpen() {
|
||||
if (this.closed) {
|
||||
throw new IllegalStateException("zip file closed");
|
||||
}
|
||||
}
|
||||
|
||||
boolean isClosed() {
|
||||
return this.closed;
|
||||
}
|
||||
|
||||
String getUrlString() throws MalformedURLException {
|
||||
if (this.urlString == null) {
|
||||
this.urlString = getUrl().toString();
|
||||
}
|
||||
return this.urlString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getUrl() throws MalformedURLException {
|
||||
if (this.url == null) {
|
||||
String file = this.rootFile.getFile().toURI() + this.pathFromRoot + "!/";
|
||||
file = file.replace("file:////", "file://"); // Fix UNC paths
|
||||
this.url = new URL("jar", "", -1, file, new Handler(this));
|
||||
}
|
||||
return this.url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.rootFile.getFile() + this.pathFromRoot;
|
||||
}
|
||||
|
||||
boolean isSigned() {
|
||||
return this.signed;
|
||||
}
|
||||
|
||||
JarEntryCertification getCertification(JarEntry entry) {
|
||||
try {
|
||||
return this.entries.getCertification(entry);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void clearCache() {
|
||||
this.entries.clearCache();
|
||||
}
|
||||
|
||||
protected String getPathFromRoot() {
|
||||
return this.pathFromRoot;
|
||||
}
|
||||
|
||||
@Override
|
||||
JarFileType getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a {@literal 'java.protocol.handler.pkgs'} property so that a
|
||||
* {@link URLStreamHandler} will be located to deal with jar URLs.
|
||||
*/
|
||||
public static void registerUrlProtocolHandler() {
|
||||
Handler.captureJarContextUrl();
|
||||
String handlers = System.getProperty(PROTOCOL_HANDLER, "");
|
||||
System.setProperty(PROTOCOL_HANDLER,
|
||||
((handlers == null || handlers.isEmpty()) ? HANDLERS_PACKAGE : handlers + "|" + HANDLERS_PACKAGE));
|
||||
resetCachedUrlHandlers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset any cached handlers just in case a jar protocol has already been used. We
|
||||
* reset the handler by trying to set a null {@link URLStreamHandlerFactory} which
|
||||
* should have no effect other than clearing the handlers cache.
|
||||
*/
|
||||
private static void resetCachedUrlHandlers() {
|
||||
try {
|
||||
URL.setURLStreamHandlerFactory(null);
|
||||
}
|
||||
catch (Error ex) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link Enumeration} on {@linkplain java.util.jar.JarEntry jar entries}.
|
||||
*/
|
||||
private static class JarEntryEnumeration implements Enumeration<java.util.jar.JarEntry> {
|
||||
|
||||
private final Iterator<JarEntry> iterator;
|
||||
|
||||
JarEntryEnumeration(Iterator<JarEntry> iterator) {
|
||||
this.iterator = iterator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMoreElements() {
|
||||
return this.iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.util.jar.JarEntry nextElement() {
|
||||
return this.iterator.next();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+470
@@ -0,0 +1,470 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.jar;
|
||||
|
||||
import fun.asgc.neutrino.core.aop.compiler.internal.data.RandomAccessData;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Attributes.Name;
|
||||
import java.util.jar.JarInputStream;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
/**
|
||||
* Provides access to entries from a {@link JarFile}. In order to reduce memory
|
||||
* consumption entry details are stored using arrays. The {@code hashCodes} array stores
|
||||
* the hash code of the entry name, the {@code centralDirectoryOffsets} provides the
|
||||
* offset to the central directory record and {@code positions} provides the original
|
||||
* order position of the entry. The arrays are stored in hashCode order so that a binary
|
||||
* search can be used to find a name.
|
||||
* <p>
|
||||
* A typical Spring Boot application will have somewhere in the region of 10,500 entries
|
||||
* which should consume about 122K.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class JarFileEntries implements CentralDirectoryVisitor, Iterable<JarEntry> {
|
||||
|
||||
private static final Runnable NO_VALIDATION = () -> {
|
||||
};
|
||||
|
||||
private static final String META_INF_PREFIX = "META-INF/";
|
||||
|
||||
private static final Name MULTI_RELEASE = new Name("Multi-Release");
|
||||
|
||||
private static final int BASE_VERSION = 8;
|
||||
|
||||
private static final int RUNTIME_VERSION = 1;// TODO Runtime.version().feature();
|
||||
|
||||
private static final long LOCAL_FILE_HEADER_SIZE = 30;
|
||||
|
||||
private static final char SLASH = '/';
|
||||
|
||||
private static final char NO_SUFFIX = 0;
|
||||
|
||||
protected static final int ENTRY_CACHE_SIZE = 25;
|
||||
|
||||
private final JarFile jarFile;
|
||||
|
||||
private final JarEntryFilter filter;
|
||||
|
||||
private RandomAccessData centralDirectoryData;
|
||||
|
||||
private int size;
|
||||
|
||||
private int[] hashCodes;
|
||||
|
||||
private Offsets centralDirectoryOffsets;
|
||||
|
||||
private int[] positions;
|
||||
|
||||
private Boolean multiReleaseJar;
|
||||
|
||||
private JarEntryCertification[] certifications;
|
||||
|
||||
private final Map<Integer, FileHeader> entriesCache = Collections
|
||||
.synchronizedMap(new LinkedHashMap<Integer, FileHeader>(16, 0.75f, true) {
|
||||
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry<Integer, FileHeader> eldest) {
|
||||
return size() >= ENTRY_CACHE_SIZE;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
JarFileEntries(JarFile jarFile, JarEntryFilter filter) {
|
||||
this.jarFile = jarFile;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitStart(CentralDirectoryEndRecord endRecord, RandomAccessData centralDirectoryData) {
|
||||
int maxSize = endRecord.getNumberOfRecords();
|
||||
this.centralDirectoryData = centralDirectoryData;
|
||||
this.hashCodes = new int[maxSize];
|
||||
this.centralDirectoryOffsets = Offsets.from(endRecord);
|
||||
this.positions = new int[maxSize];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFileHeader(CentralDirectoryFileHeader fileHeader, long dataOffset) {
|
||||
AsciiBytes name = applyFilter(fileHeader.getName());
|
||||
if (name != null) {
|
||||
add(name, dataOffset);
|
||||
}
|
||||
}
|
||||
|
||||
private void add(AsciiBytes name, long dataOffset) {
|
||||
this.hashCodes[this.size] = name.hashCode();
|
||||
this.centralDirectoryOffsets.set(this.size, dataOffset);
|
||||
this.positions[this.size] = this.size;
|
||||
this.size++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
sort(0, this.size - 1);
|
||||
int[] positions = this.positions;
|
||||
this.positions = new int[positions.length];
|
||||
for (int i = 0; i < this.size; i++) {
|
||||
this.positions[positions[i]] = i;
|
||||
}
|
||||
}
|
||||
|
||||
int getSize() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
private void sort(int left, int right) {
|
||||
// Quick sort algorithm, uses hashCodes as the source but sorts all arrays
|
||||
if (left < right) {
|
||||
int pivot = this.hashCodes[left + (right - left) / 2];
|
||||
int i = left;
|
||||
int j = right;
|
||||
while (i <= j) {
|
||||
while (this.hashCodes[i] < pivot) {
|
||||
i++;
|
||||
}
|
||||
while (this.hashCodes[j] > pivot) {
|
||||
j--;
|
||||
}
|
||||
if (i <= j) {
|
||||
swap(i, j);
|
||||
i++;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
if (left < j) {
|
||||
sort(left, j);
|
||||
}
|
||||
if (right > i) {
|
||||
sort(i, right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void swap(int i, int j) {
|
||||
swap(this.hashCodes, i, j);
|
||||
this.centralDirectoryOffsets.swap(i, j);
|
||||
swap(this.positions, i, j);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<JarEntry> iterator() {
|
||||
return new EntryIterator(NO_VALIDATION);
|
||||
}
|
||||
|
||||
Iterator<JarEntry> iterator(Runnable validator) {
|
||||
return new EntryIterator(validator);
|
||||
}
|
||||
|
||||
boolean containsEntry(CharSequence name) {
|
||||
return getEntry(name, FileHeader.class, true) != null;
|
||||
}
|
||||
|
||||
JarEntry getEntry(CharSequence name) {
|
||||
return getEntry(name, JarEntry.class, true);
|
||||
}
|
||||
|
||||
InputStream getInputStream(String name) throws IOException {
|
||||
FileHeader entry = getEntry(name, FileHeader.class, false);
|
||||
return getInputStream(entry);
|
||||
}
|
||||
|
||||
InputStream getInputStream(FileHeader entry) throws IOException {
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
InputStream inputStream = getEntryData(entry).getInputStream();
|
||||
if (entry.getMethod() == ZipEntry.DEFLATED) {
|
||||
inputStream = new ZipInflaterInputStream(inputStream, (int) entry.getSize());
|
||||
}
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
RandomAccessData getEntryData(String name) throws IOException {
|
||||
FileHeader entry = getEntry(name, FileHeader.class, false);
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
return getEntryData(entry);
|
||||
}
|
||||
|
||||
private RandomAccessData getEntryData(FileHeader entry) throws IOException {
|
||||
// aspectjrt-1.7.4.jar has a different ext bytes length in the
|
||||
// local directory to the central directory. We need to re-read
|
||||
// here to skip them
|
||||
RandomAccessData data = this.jarFile.getData();
|
||||
byte[] localHeader = data.read(entry.getLocalHeaderOffset(), LOCAL_FILE_HEADER_SIZE);
|
||||
long nameLength = Bytes.littleEndianValue(localHeader, 26, 2);
|
||||
long extraLength = Bytes.littleEndianValue(localHeader, 28, 2);
|
||||
return data.getSubsection(entry.getLocalHeaderOffset() + LOCAL_FILE_HEADER_SIZE + nameLength + extraLength,
|
||||
entry.getCompressedSize());
|
||||
}
|
||||
|
||||
private <T extends FileHeader> T getEntry(CharSequence name, Class<T> type, boolean cacheEntry) {
|
||||
T entry = doGetEntry(name, type, cacheEntry, null);
|
||||
if (!isMetaInfEntry(name) && isMultiReleaseJar()) {
|
||||
int version = RUNTIME_VERSION;
|
||||
AsciiBytes nameAlias = (entry instanceof JarEntry) ? ((JarEntry)entry).getAsciiBytesName()
|
||||
: new AsciiBytes(name.toString());
|
||||
while (version > BASE_VERSION) {
|
||||
T versionedEntry = doGetEntry("META-INF/versions/" + version + "/" + name, type, cacheEntry, nameAlias);
|
||||
if (versionedEntry != null) {
|
||||
return versionedEntry;
|
||||
}
|
||||
version--;
|
||||
}
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
private boolean isMetaInfEntry(CharSequence name) {
|
||||
return name.toString().startsWith(META_INF_PREFIX);
|
||||
}
|
||||
|
||||
private boolean isMultiReleaseJar() {
|
||||
Boolean multiRelease = this.multiReleaseJar;
|
||||
if (multiRelease != null) {
|
||||
return multiRelease;
|
||||
}
|
||||
try {
|
||||
Manifest manifest = this.jarFile.getManifest();
|
||||
if (manifest == null) {
|
||||
multiRelease = false;
|
||||
}
|
||||
else {
|
||||
Attributes attributes = manifest.getMainAttributes();
|
||||
multiRelease = attributes.containsKey(MULTI_RELEASE);
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
multiRelease = false;
|
||||
}
|
||||
this.multiReleaseJar = multiRelease;
|
||||
return multiRelease;
|
||||
}
|
||||
|
||||
private <T extends FileHeader> T doGetEntry(CharSequence name, Class<T> type, boolean cacheEntry,
|
||||
AsciiBytes nameAlias) {
|
||||
int hashCode = AsciiBytes.hashCode(name);
|
||||
T entry = getEntry(hashCode, name, NO_SUFFIX, type, cacheEntry, nameAlias);
|
||||
if (entry == null) {
|
||||
hashCode = AsciiBytes.hashCode(hashCode, SLASH);
|
||||
entry = getEntry(hashCode, name, SLASH, type, cacheEntry, nameAlias);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
private <T extends FileHeader> T getEntry(int hashCode, CharSequence name, char suffix, Class<T> type,
|
||||
boolean cacheEntry, AsciiBytes nameAlias) {
|
||||
int index = getFirstIndex(hashCode);
|
||||
while (index >= 0 && index < this.size && this.hashCodes[index] == hashCode) {
|
||||
T entry = getEntry(index, type, cacheEntry, nameAlias);
|
||||
if (entry.hasName(name, suffix)) {
|
||||
return entry;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T extends FileHeader> T getEntry(int index, Class<T> type, boolean cacheEntry, AsciiBytes nameAlias) {
|
||||
try {
|
||||
long offset = this.centralDirectoryOffsets.get(index);
|
||||
FileHeader cached = this.entriesCache.get(index);
|
||||
FileHeader entry = (cached != null) ? cached
|
||||
: CentralDirectoryFileHeader.fromRandomAccessData(this.centralDirectoryData, offset, this.filter);
|
||||
if (CentralDirectoryFileHeader.class.equals(entry.getClass()) && type.equals(JarEntry.class)) {
|
||||
entry = new JarEntry(this.jarFile, index, (CentralDirectoryFileHeader) entry, nameAlias);
|
||||
}
|
||||
if (cacheEntry && cached != entry) {
|
||||
this.entriesCache.put(index, entry);
|
||||
}
|
||||
return (T) entry;
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private int getFirstIndex(int hashCode) {
|
||||
int index = Arrays.binarySearch(this.hashCodes, 0, this.size, hashCode);
|
||||
if (index < 0) {
|
||||
return -1;
|
||||
}
|
||||
while (index > 0 && this.hashCodes[index - 1] == hashCode) {
|
||||
index--;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
void clearCache() {
|
||||
this.entriesCache.clear();
|
||||
}
|
||||
|
||||
private AsciiBytes applyFilter(AsciiBytes name) {
|
||||
return (this.filter != null) ? this.filter.apply(name) : name;
|
||||
}
|
||||
|
||||
JarEntryCertification getCertification(JarEntry entry) throws IOException {
|
||||
JarEntryCertification[] certifications = this.certifications;
|
||||
if (certifications == null) {
|
||||
certifications = new JarEntryCertification[this.size];
|
||||
// We fall back to use JarInputStream to obtain the certs. This isn't that
|
||||
// fast, but hopefully doesn't happen too often.
|
||||
try (JarInputStream certifiedJarStream = new JarInputStream(this.jarFile.getData().getInputStream())) {
|
||||
java.util.jar.JarEntry certifiedEntry;
|
||||
while ((certifiedEntry = certifiedJarStream.getNextJarEntry()) != null) {
|
||||
// Entry must be closed to trigger a read and set entry certificates
|
||||
certifiedJarStream.closeEntry();
|
||||
int index = getEntryIndex(certifiedEntry.getName());
|
||||
if (index != -1) {
|
||||
certifications[index] = JarEntryCertification.from(certifiedEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.certifications = certifications;
|
||||
}
|
||||
JarEntryCertification certification = certifications[entry.getIndex()];
|
||||
return (certification != null) ? certification : JarEntryCertification.NONE;
|
||||
}
|
||||
|
||||
private int getEntryIndex(CharSequence name) {
|
||||
int hashCode = AsciiBytes.hashCode(name);
|
||||
int index = getFirstIndex(hashCode);
|
||||
while (index >= 0 && index < this.size && this.hashCodes[index] == hashCode) {
|
||||
FileHeader candidate = getEntry(index, FileHeader.class, false, null);
|
||||
if (candidate.hasName(name, NO_SUFFIX)) {
|
||||
return index;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static void swap(int[] array, int i, int j) {
|
||||
int temp = array[i];
|
||||
array[i] = array[j];
|
||||
array[j] = temp;
|
||||
}
|
||||
|
||||
private static void swap(long[] array, int i, int j) {
|
||||
long temp = array[i];
|
||||
array[i] = array[j];
|
||||
array[j] = temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterator for contained entries.
|
||||
*/
|
||||
private final class EntryIterator implements Iterator<JarEntry> {
|
||||
|
||||
private final Runnable validator;
|
||||
|
||||
private int index = 0;
|
||||
|
||||
private EntryIterator(Runnable validator) {
|
||||
this.validator = validator;
|
||||
validator.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
this.validator.run();
|
||||
return this.index < JarFileEntries.this.size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JarEntry next() {
|
||||
this.validator.run();
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
int entryIndex = JarFileEntries.this.positions[this.index];
|
||||
this.index++;
|
||||
return getEntry(entryIndex, JarEntry.class, false, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface to manage offsets to central directory records. Regular zip files are
|
||||
* backed by an {@code int[]} based implementation, Zip64 files are backed by a
|
||||
* {@code long[]} and will consume more memory.
|
||||
*/
|
||||
private interface Offsets {
|
||||
|
||||
void set(int index, long value);
|
||||
|
||||
long get(int index);
|
||||
|
||||
void swap(int i, int j);
|
||||
|
||||
static Offsets from(CentralDirectoryEndRecord endRecord) {
|
||||
int size = endRecord.getNumberOfRecords();
|
||||
return endRecord.isZip64() ? new Zip64Offsets(size) : new ZipOffsets(size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Offsets} implementation for regular zip files.
|
||||
*/
|
||||
private static final class ZipOffsets implements Offsets {
|
||||
|
||||
private final int[] offsets;
|
||||
|
||||
private ZipOffsets(int size) {
|
||||
this.offsets = new int[size];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swap(int i, int j) {
|
||||
JarFileEntries.swap(this.offsets, i, j);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(int index, long value) {
|
||||
this.offsets[index] = (int) value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long get(int index) {
|
||||
return this.offsets[index];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Offsets} implementation for zip64 files.
|
||||
*/
|
||||
private static final class Zip64Offsets implements Offsets {
|
||||
|
||||
private final long[] offsets;
|
||||
|
||||
private Zip64Offsets(int size) {
|
||||
this.offsets = new long[size];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swap(int i, int j) {
|
||||
JarFileEntries.swap(this.offsets, i, j);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(int index, long value) {
|
||||
this.offsets[index] = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long get(int index) {
|
||||
return this.offsets[index];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.jar;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.security.Permission;
|
||||
import java.util.Enumeration;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
/**
|
||||
* A wrapper used to create a copy of a {@link JarFile} so that it can be safely closed
|
||||
* without closing the original.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class JarFileWrapper extends AbstractJarFile {
|
||||
|
||||
private final JarFile parent;
|
||||
|
||||
JarFileWrapper(JarFile parent) throws IOException {
|
||||
super(parent.getRootJarFile().getFile());
|
||||
this.parent = parent;
|
||||
super.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
URL getUrl() throws MalformedURLException {
|
||||
return this.parent.getUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
JarFileType getType() {
|
||||
return this.parent.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
Permission getPermission() {
|
||||
return this.parent.getPermission();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Manifest getManifest() throws IOException {
|
||||
return this.parent.getManifest();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<JarEntry> entries() {
|
||||
return this.parent.entries();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<JarEntry> stream() {
|
||||
return this.parent.stream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JarEntry getJarEntry(String name) {
|
||||
return this.parent.getJarEntry(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZipEntry getEntry(String name) {
|
||||
return this.parent.getEntry(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
InputStream getInputStream() throws IOException {
|
||||
return this.parent.getInputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized InputStream getInputStream(ZipEntry ze) throws IOException {
|
||||
return this.parent.getInputStream(ze);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComment() {
|
||||
return this.parent.getComment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.parent.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.parent.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.parent.getName();
|
||||
}
|
||||
|
||||
static JarFile unwrap(java.util.jar.JarFile jarFile) {
|
||||
if (jarFile instanceof JarFile) {
|
||||
return (JarFile)jarFile;
|
||||
}
|
||||
if (jarFile instanceof JarFileWrapper) {
|
||||
return unwrap(((JarFileWrapper)jarFile).parent);
|
||||
}
|
||||
throw new IllegalStateException("Not a JarFile or Wrapper");
|
||||
}
|
||||
|
||||
}
|
||||
+369
@@ -0,0 +1,369 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.jar;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.security.Permission;
|
||||
|
||||
/**
|
||||
* {@link java.net.JarURLConnection} used to support {@link JarFile#getUrl()}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @author Rostyslav Dudka
|
||||
*/
|
||||
public final class JarURLConnection extends java.net.JarURLConnection {
|
||||
|
||||
private static final ThreadLocal<Boolean> useFastExceptions = new ThreadLocal<>();
|
||||
|
||||
private static final FileNotFoundException FILE_NOT_FOUND_EXCEPTION = new FileNotFoundException(
|
||||
"Jar file or entry not found");
|
||||
|
||||
private static final IllegalStateException NOT_FOUND_CONNECTION_EXCEPTION = new IllegalStateException(
|
||||
FILE_NOT_FOUND_EXCEPTION);
|
||||
|
||||
private static final String SEPARATOR = "!/";
|
||||
|
||||
private static final URL EMPTY_JAR_URL;
|
||||
|
||||
static {
|
||||
try {
|
||||
EMPTY_JAR_URL = new URL("jar:", null, 0, "file:!/", new URLStreamHandler() {
|
||||
@Override
|
||||
protected URLConnection openConnection(URL u) throws IOException {
|
||||
// Stub URLStreamHandler to prevent the wrong JAR Handler from being
|
||||
// Instantiated and cached.
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (MalformedURLException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static final JarEntryName EMPTY_JAR_ENTRY_NAME = new JarEntryName(new StringSequence(""));
|
||||
|
||||
private static final JarURLConnection NOT_FOUND_CONNECTION = JarURLConnection.notFound();
|
||||
|
||||
private final AbstractJarFile jarFile;
|
||||
|
||||
private Permission permission;
|
||||
|
||||
private URL jarFileUrl;
|
||||
|
||||
private final JarEntryName jarEntryName;
|
||||
|
||||
private java.util.jar.JarEntry jarEntry;
|
||||
|
||||
private JarURLConnection(URL url, AbstractJarFile jarFile, JarEntryName jarEntryName) throws IOException {
|
||||
// What we pass to super is ultimately ignored
|
||||
super(EMPTY_JAR_URL);
|
||||
this.url = url;
|
||||
this.jarFile = jarFile;
|
||||
this.jarEntryName = jarEntryName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect() throws IOException {
|
||||
if (this.jarFile == null) {
|
||||
throw FILE_NOT_FOUND_EXCEPTION;
|
||||
}
|
||||
if (!this.jarEntryName.isEmpty() && this.jarEntry == null) {
|
||||
this.jarEntry = this.jarFile.getJarEntry(getEntryName());
|
||||
if (this.jarEntry == null) {
|
||||
throwFileNotFound(this.jarEntryName, this.jarFile);
|
||||
}
|
||||
}
|
||||
this.connected = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.util.jar.JarFile getJarFile() throws IOException {
|
||||
connect();
|
||||
return this.jarFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getJarFileURL() {
|
||||
if (this.jarFile == null) {
|
||||
throw NOT_FOUND_CONNECTION_EXCEPTION;
|
||||
}
|
||||
if (this.jarFileUrl == null) {
|
||||
this.jarFileUrl = buildJarFileUrl();
|
||||
}
|
||||
return this.jarFileUrl;
|
||||
}
|
||||
|
||||
private URL buildJarFileUrl() {
|
||||
try {
|
||||
String spec = this.jarFile.getUrl().getFile();
|
||||
if (spec.endsWith(SEPARATOR)) {
|
||||
spec = spec.substring(0, spec.length() - SEPARATOR.length());
|
||||
}
|
||||
if (!spec.contains(SEPARATOR)) {
|
||||
return new URL(spec);
|
||||
}
|
||||
return new URL("jar:" + spec);
|
||||
}
|
||||
catch (MalformedURLException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.util.jar.JarEntry getJarEntry() throws IOException {
|
||||
if (this.jarEntryName == null || this.jarEntryName.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
connect();
|
||||
return this.jarEntry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntryName() {
|
||||
if (this.jarFile == null) {
|
||||
throw NOT_FOUND_CONNECTION_EXCEPTION;
|
||||
}
|
||||
return this.jarEntryName.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
if (this.jarFile == null) {
|
||||
throw FILE_NOT_FOUND_EXCEPTION;
|
||||
}
|
||||
if (this.jarEntryName.isEmpty() && this.jarFile.getType() == JarFile.JarFileType.DIRECT) {
|
||||
throw new IOException("no entry name specified");
|
||||
}
|
||||
connect();
|
||||
InputStream inputStream = (this.jarEntryName.isEmpty() ? this.jarFile.getInputStream()
|
||||
: this.jarFile.getInputStream(this.jarEntry));
|
||||
if (inputStream == null) {
|
||||
throwFileNotFound(this.jarEntryName, this.jarFile);
|
||||
}
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
private void throwFileNotFound(Object entry, AbstractJarFile jarFile) throws FileNotFoundException {
|
||||
if (Boolean.TRUE.equals(useFastExceptions.get())) {
|
||||
throw FILE_NOT_FOUND_EXCEPTION;
|
||||
}
|
||||
throw new FileNotFoundException("JAR entry " + entry + " not found in " + jarFile.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentLength() {
|
||||
long length = getContentLengthLong();
|
||||
if (length > Integer.MAX_VALUE) {
|
||||
return -1;
|
||||
}
|
||||
return (int) length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getContentLengthLong() {
|
||||
if (this.jarFile == null) {
|
||||
return -1;
|
||||
}
|
||||
try {
|
||||
if (this.jarEntryName.isEmpty()) {
|
||||
return this.jarFile.size();
|
||||
}
|
||||
java.util.jar.JarEntry entry = getJarEntry();
|
||||
return (entry != null) ? (int) entry.getSize() : -1;
|
||||
}
|
||||
catch (IOException ex) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getContent() throws IOException {
|
||||
connect();
|
||||
return this.jarEntryName.isEmpty() ? this.jarFile : super.getContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return (this.jarEntryName != null) ? this.jarEntryName.getContentType() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permission getPermission() throws IOException {
|
||||
if (this.jarFile == null) {
|
||||
throw FILE_NOT_FOUND_EXCEPTION;
|
||||
}
|
||||
if (this.permission == null) {
|
||||
this.permission = this.jarFile.getPermission();
|
||||
}
|
||||
return this.permission;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastModified() {
|
||||
if (this.jarFile == null || this.jarEntryName.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
java.util.jar.JarEntry entry = getJarEntry();
|
||||
return (entry != null) ? entry.getTime() : 0;
|
||||
}
|
||||
catch (IOException ex) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void setUseFastExceptions(boolean useFastExceptions) {
|
||||
JarURLConnection.useFastExceptions.set(useFastExceptions);
|
||||
}
|
||||
|
||||
public static JarURLConnection get(URL url, JarFile jarFile) throws IOException {
|
||||
StringSequence spec = new StringSequence(url.getFile());
|
||||
int index = indexOfRootSpec(spec, jarFile.getPathFromRoot());
|
||||
if (index == -1) {
|
||||
return (Boolean.TRUE.equals(useFastExceptions.get()) ? NOT_FOUND_CONNECTION
|
||||
: new JarURLConnection(url, null, EMPTY_JAR_ENTRY_NAME));
|
||||
}
|
||||
int separator;
|
||||
while ((separator = spec.indexOf(SEPARATOR, index)) > 0) {
|
||||
JarEntryName entryName = JarEntryName.get(spec.subSequence(index, separator));
|
||||
JarEntry jarEntry = jarFile.getJarEntry(entryName.toCharSequence());
|
||||
if (jarEntry == null) {
|
||||
return JarURLConnection.notFound(jarFile, entryName);
|
||||
}
|
||||
jarFile = jarFile.getNestedJarFile(jarEntry);
|
||||
index = separator + SEPARATOR.length();
|
||||
}
|
||||
JarEntryName jarEntryName = JarEntryName.get(spec, index);
|
||||
if (Boolean.TRUE.equals(useFastExceptions.get()) && !jarEntryName.isEmpty()
|
||||
&& !jarFile.containsEntry(jarEntryName.toString())) {
|
||||
return NOT_FOUND_CONNECTION;
|
||||
}
|
||||
return new JarURLConnection(url, jarFile.getWrapper(), jarEntryName);
|
||||
}
|
||||
|
||||
private static int indexOfRootSpec(StringSequence file, String pathFromRoot) {
|
||||
int separatorIndex = file.indexOf(SEPARATOR);
|
||||
if (separatorIndex < 0 || !file.startsWith(pathFromRoot, separatorIndex)) {
|
||||
return -1;
|
||||
}
|
||||
return separatorIndex + SEPARATOR.length() + pathFromRoot.length();
|
||||
}
|
||||
|
||||
private static JarURLConnection notFound() {
|
||||
try {
|
||||
return notFound(null, null);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static JarURLConnection notFound(JarFile jarFile, JarEntryName jarEntryName) throws IOException {
|
||||
if (Boolean.TRUE.equals(useFastExceptions.get())) {
|
||||
return NOT_FOUND_CONNECTION;
|
||||
}
|
||||
return new JarURLConnection(null, jarFile, jarEntryName);
|
||||
}
|
||||
|
||||
/**
|
||||
* A JarEntryName parsed from a URL String.
|
||||
*/
|
||||
static class JarEntryName {
|
||||
|
||||
private final StringSequence name;
|
||||
|
||||
private String contentType;
|
||||
|
||||
JarEntryName(StringSequence spec) {
|
||||
this.name = decode(spec);
|
||||
}
|
||||
|
||||
private StringSequence decode(StringSequence source) {
|
||||
if (source.isEmpty() || (source.indexOf('%') < 0)) {
|
||||
return source;
|
||||
}
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(source.length());
|
||||
write(source.toString(), bos);
|
||||
// AsciiBytes is what is used to store the JarEntries so make it symmetric
|
||||
return new StringSequence(AsciiBytes.toString(bos.toByteArray()));
|
||||
}
|
||||
|
||||
private void write(String source, ByteArrayOutputStream outputStream) {
|
||||
int length = source.length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
int c = source.charAt(i);
|
||||
if (c > 127) {
|
||||
try {
|
||||
String encoded = URLEncoder.encode(String.valueOf((char) c), "UTF-8");
|
||||
write(encoded, outputStream);
|
||||
}
|
||||
catch (UnsupportedEncodingException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (c == '%') {
|
||||
if ((i + 2) >= length) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid encoded sequence \"" + source.substring(i) + "\"");
|
||||
}
|
||||
c = decodeEscapeSequence(source, i);
|
||||
i += 2;
|
||||
}
|
||||
outputStream.write(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private char decodeEscapeSequence(String source, int i) {
|
||||
int hi = Character.digit(source.charAt(i + 1), 16);
|
||||
int lo = Character.digit(source.charAt(i + 2), 16);
|
||||
if (hi == -1 || lo == -1) {
|
||||
throw new IllegalArgumentException("Invalid encoded sequence \"" + source.substring(i) + "\"");
|
||||
}
|
||||
return ((char) ((hi << 4) + lo));
|
||||
}
|
||||
|
||||
CharSequence toCharSequence() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name.toString();
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
return this.name.isEmpty();
|
||||
}
|
||||
|
||||
String getContentType() {
|
||||
if (this.contentType == null) {
|
||||
this.contentType = deduceContentType();
|
||||
}
|
||||
return this.contentType;
|
||||
}
|
||||
|
||||
private String deduceContentType() {
|
||||
// Guess the content type, don't bother with streams as mark is not supported
|
||||
String type = isEmpty() ? "x-java/jar" : null;
|
||||
type = (type != null) ? type : guessContentTypeFromName(toString());
|
||||
type = (type != null) ? type : "content/unknown";
|
||||
return type;
|
||||
}
|
||||
|
||||
static JarEntryName get(StringSequence spec) {
|
||||
return get(spec, 0);
|
||||
}
|
||||
|
||||
static JarEntryName get(StringSequence spec, int beginIndex) {
|
||||
if (spec.length() <= beginIndex) {
|
||||
return EMPTY_JAR_ENTRY_NAME;
|
||||
}
|
||||
return new JarEntryName(spec.subSequence(beginIndex));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.jar;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A {@link CharSequence} backed by a single shared {@link String}. Unlike a regular
|
||||
* {@link String}, {@link #subSequence(int, int)} operations will not copy the underlying
|
||||
* character array.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
final class StringSequence implements CharSequence {
|
||||
|
||||
private final String source;
|
||||
|
||||
private final int start;
|
||||
|
||||
private final int end;
|
||||
|
||||
private int hash;
|
||||
|
||||
StringSequence(String source) {
|
||||
this(source, 0, (source != null) ? source.length() : -1);
|
||||
}
|
||||
|
||||
StringSequence(String source, int start, int end) {
|
||||
Objects.requireNonNull(source, "Source must not be null");
|
||||
if (start < 0) {
|
||||
throw new StringIndexOutOfBoundsException(start);
|
||||
}
|
||||
if (end > source.length()) {
|
||||
throw new StringIndexOutOfBoundsException(end);
|
||||
}
|
||||
this.source = source;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
StringSequence subSequence(int start) {
|
||||
return subSequence(start, length());
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringSequence subSequence(int start, int end) {
|
||||
int subSequenceStart = this.start + start;
|
||||
int subSequenceEnd = this.start + end;
|
||||
if (subSequenceStart > this.end) {
|
||||
throw new StringIndexOutOfBoundsException(start);
|
||||
}
|
||||
if (subSequenceEnd > this.end) {
|
||||
throw new StringIndexOutOfBoundsException(end);
|
||||
}
|
||||
if (start == 0 && subSequenceEnd == this.end) {
|
||||
return this;
|
||||
}
|
||||
return new StringSequence(this.source, subSequenceStart, subSequenceEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the sequence is empty. Public to be compatible with JDK 15.
|
||||
* @return {@code true} if {@link #length()} is {@code 0}, otherwise {@code false}
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return length() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return this.end - this.start;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char charAt(int index) {
|
||||
return this.source.charAt(this.start + index);
|
||||
}
|
||||
|
||||
int indexOf(char ch) {
|
||||
return this.source.indexOf(ch, this.start) - this.start;
|
||||
}
|
||||
|
||||
int indexOf(String str) {
|
||||
return this.source.indexOf(str, this.start) - this.start;
|
||||
}
|
||||
|
||||
int indexOf(String str, int fromIndex) {
|
||||
return this.source.indexOf(str, this.start + fromIndex) - this.start;
|
||||
}
|
||||
|
||||
boolean startsWith(String prefix) {
|
||||
return startsWith(prefix, 0);
|
||||
}
|
||||
|
||||
boolean startsWith(String prefix, int offset) {
|
||||
int prefixLength = prefix.length();
|
||||
int length = length();
|
||||
if (length - prefixLength - offset < 0) {
|
||||
return false;
|
||||
}
|
||||
return this.source.startsWith(prefix, this.start + offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof CharSequence)) {
|
||||
return false;
|
||||
}
|
||||
CharSequence other = (CharSequence)obj;
|
||||
int n = length();
|
||||
if (n != other.length()) {
|
||||
return false;
|
||||
}
|
||||
int i = 0;
|
||||
while (n-- != 0) {
|
||||
if (charAt(i) != other.charAt(i)) {
|
||||
return false;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = this.hash;
|
||||
if (hash == 0 && length() > 0) {
|
||||
for (int i = this.start; i < this.end; i++) {
|
||||
hash = 31 * hash + this.source.charAt(i);
|
||||
}
|
||||
this.hash = hash;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.source.substring(this.start, this.end);
|
||||
}
|
||||
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package fun.asgc.neutrino.core.aop.compiler.internal.jar;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.zip.Inflater;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
/**
|
||||
* {@link InflaterInputStream} that supports the writing of an extra "dummy" byte (which
|
||||
* is required with JDK 6) and returns accurate available() results.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class ZipInflaterInputStream extends InflaterInputStream {
|
||||
|
||||
private int available;
|
||||
|
||||
private boolean extraBytesWritten;
|
||||
|
||||
ZipInflaterInputStream(InputStream inputStream, int size) {
|
||||
super(inputStream, new Inflater(true), getInflaterBufferSize(size));
|
||||
this.available = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
if (this.available < 0) {
|
||||
return super.available();
|
||||
}
|
||||
return this.available;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
int result = super.read(b, off, len);
|
||||
if (result != -1) {
|
||||
this.available -= result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
super.close();
|
||||
this.inf.end();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fill() throws IOException {
|
||||
try {
|
||||
super.fill();
|
||||
}
|
||||
catch (EOFException ex) {
|
||||
if (this.extraBytesWritten) {
|
||||
throw ex;
|
||||
}
|
||||
this.len = 1;
|
||||
this.buf[0] = 0x0;
|
||||
this.extraBytesWritten = true;
|
||||
this.inf.setInput(this.buf, 0, this.len);
|
||||
}
|
||||
}
|
||||
|
||||
private static int getInflaterBufferSize(long size) {
|
||||
size += 2; // inflater likes some space
|
||||
size = (size > 65536) ? 8192 : size;
|
||||
size = (size <= 0) ? 4096 : size;
|
||||
return (int) size;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -85,7 +85,7 @@ public class AsgcProxyFactory implements ProxyFactory {
|
||||
if (GlobalConfig.isPrintGeneratorCode()) {
|
||||
log.debug("类:{} 的代理类源码:\n{}", targetType.getName(), sourceCode);
|
||||
}
|
||||
Class<P> retClass = (Class<P>)compiler.compile(proxyClass.getPkg(), proxyClass.getName(), proxyClass.getSourceCode());
|
||||
Class<P> retClass = (Class<P>)compiler.compile(proxyClass.getClassName(), proxyClass.getSourceCode());
|
||||
P obj = retClass.newInstance();
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.core.aop.proxy;
|
||||
|
||||
import fun.asgc.neutrino.core.util.StringUtil;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -65,4 +66,11 @@ public class ProxyClass {
|
||||
public ProxyClass() {
|
||||
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
if (StringUtil.isEmpty(pkg)) {
|
||||
return name;
|
||||
}
|
||||
return String.format("%s.%s", pkg, name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,10 @@ public class GlobalConfig {
|
||||
* 当程序是以jar方式运行时,强制保存生成的代码
|
||||
*/
|
||||
private static volatile boolean isSaveGeneratorCode = false;
|
||||
/**
|
||||
* 是否使用SpringBoot方式的jar
|
||||
*/
|
||||
private static volatile boolean isUseSpringBootJar = true;
|
||||
/**
|
||||
* 自动生成代码保存路径
|
||||
*/
|
||||
@@ -88,4 +92,12 @@ public class GlobalConfig {
|
||||
public static String getMapperXmlFileBasePath() {
|
||||
return mapperXmlFileBasePath;
|
||||
}
|
||||
|
||||
public static boolean isIsPrintGeneratorCode() {
|
||||
return isPrintGeneratorCode;
|
||||
}
|
||||
|
||||
public static boolean isIsUseSpringBootJar() {
|
||||
return isUseSpringBootJar;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,557 @@
|
||||
package fun.asgc.neutrino.core.base;
|
||||
|
||||
|
||||
import fun.asgc.neutrino.core.util.TypeUtil;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 用于统一参数配置 <br/>
|
||||
* <p>
|
||||
* 1、有序性(适用于方法参数)<br/>
|
||||
* 2、key为String类型时,忽略大小写、忽略分隔符(_、-),兼容启动命令传参 + 配置文件传参 <br/>
|
||||
* 3、父级委托机制:如果存在父级,且当前实例查不到,则委托父级查找。(适用于配置优先级:启动参数 > 配置文件 > 默认值) <br/>
|
||||
* </p>
|
||||
*
|
||||
* 使用说明:<br/>
|
||||
* 1、take开头的方法,适用于配置层。利用parent委托机制,做优先级。 如5级配置:默认值 -> 内部配置文件 -> 环境变量 -> 外部配置文件 -> 启动参数 <br/>
|
||||
* 2、inx开头的方法,适用于不关心参数名称,根据下标取值。如普通方法参数、sql顺序参数(非具名参数) <br/>
|
||||
* 3、get方法取值,没有委托机制,适用于sql具名参数、bean方法具名参数 <br/>
|
||||
* 4、setAlias用于为一个key设置别名,用于解决应用层简化配置,避免冗长的配置名。<br/>
|
||||
* @author: aoshiguchen
|
||||
* @date: 2023/3/1
|
||||
*/
|
||||
public class NvMap<K,V> implements Map<K,V> , Serializable, Cloneable {
|
||||
private HashMap<K,K> aliasMap;
|
||||
private LinkedHashMap<K, V> _m;
|
||||
private HashMap<K, K> _k;
|
||||
private Locale locale;
|
||||
private String SEPARATOR = "_|-";
|
||||
private NvMap<K,V> parent;
|
||||
|
||||
private NvMap() {
|
||||
this(null, 16, null);
|
||||
}
|
||||
|
||||
private NvMap(NvMap<K,V> parent) {
|
||||
this(parent, 16, null);
|
||||
}
|
||||
|
||||
public static <K,V> NvMap<K,V> of() {
|
||||
return new NvMap<>();
|
||||
}
|
||||
|
||||
public static <K,V> NvMap<K,V> of(NvMap<K,V> parent) {
|
||||
NvMap<K,V> nvMap = new NvMap(parent);
|
||||
nvMap.aliasMap.putAll(parent.aliasMap);
|
||||
return nvMap;
|
||||
}
|
||||
|
||||
public NvMap<K,V> set(K k, V v) {
|
||||
if (this.aliasMap.containsKey(convertKey(k))) {
|
||||
this.put(this.aliasMap.get(convertKey(k)), v);
|
||||
} else {
|
||||
this.put(k, v);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public NvMap<K,V> set(K k, K alias, V v) {
|
||||
this.set(k, v);
|
||||
this.setAlias(k, alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
public NvMap<K,V> setAlias(K k, K alias) {
|
||||
this.aliasMap.put(convertKey(alias), convertKey(k));
|
||||
return this;
|
||||
}
|
||||
|
||||
public NvMap(NvMap<K,V> parent, int initialCapacity, Locale locale) {
|
||||
this.parent = parent;
|
||||
this._m = new LinkedHashMap<K, V>(initialCapacity) {
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return NvMap.this.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
|
||||
boolean doRemove = NvMap.this.removeEldestEntry(eldest);
|
||||
if (doRemove) {
|
||||
_k.remove(convertKey(eldest.getKey()));
|
||||
}
|
||||
return doRemove;
|
||||
}
|
||||
};
|
||||
this._k = new HashMap<>(initialCapacity);
|
||||
this.aliasMap = new HashMap<>(initialCapacity);
|
||||
this.locale = (locale != null ? locale : Locale.getDefault());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this._m.size();
|
||||
}
|
||||
|
||||
public int stackSize() {
|
||||
return this._m.size() + (null == parent ? 0 : parent.stackSize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this._m.isEmpty();
|
||||
}
|
||||
|
||||
public boolean isStackEmpty() {
|
||||
boolean res = this._m.isEmpty();
|
||||
if (res && null != parent) {
|
||||
res = parent.isStackEmpty();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return this._k.containsKey(convertKey(key));
|
||||
}
|
||||
|
||||
public boolean stackContainsKey(K k) {
|
||||
return this.containsKey(k) || (null != parent && parent.containsKey(k));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return this._m.containsValue(value);
|
||||
}
|
||||
|
||||
public boolean stackContainsValue(Object value) {
|
||||
return this.containsValue(value) || (null != parent && parent.containsValue(value));
|
||||
}
|
||||
|
||||
public V stackGet(K k) {
|
||||
V res = get(k);
|
||||
if (null == res && null != parent) {
|
||||
res = parent.stackGet(k);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public V stackGetOrDefault(K k, V defaultValue) {
|
||||
V res = this.stackGet(k);
|
||||
if (null == res) {
|
||||
res = defaultValue;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
K k = key;
|
||||
if (null != k && k instanceof String) {
|
||||
k = (K) convertKey((String) key);
|
||||
}
|
||||
K oldKey = this._k.put(k, key);
|
||||
if (null != oldKey && !oldKey.equals(key)) {
|
||||
this._m.remove(oldKey);
|
||||
}
|
||||
return this._m.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
K k1 = null;
|
||||
try {
|
||||
k1 = (K) key;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
K k2 = null;
|
||||
if (k1 instanceof String) {
|
||||
k1 = (K) convertKey((String) k1);
|
||||
k2 = this._k.remove(k1);
|
||||
} else {
|
||||
k2 = this._k.remove(k1);
|
||||
}
|
||||
if (null != k2) {
|
||||
return this._m.remove(k2);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> m) {
|
||||
if (m.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
m.forEach(this::put);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this._k.clear();
|
||||
this._m.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return this._m.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
return this._m.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
return this._m.entrySet();
|
||||
}
|
||||
|
||||
public Locale getLocale() {
|
||||
return this.locale;
|
||||
}
|
||||
|
||||
protected String convertKey(String key) {
|
||||
return key.toLowerCase(getLocale()).replaceAll(SEPARATOR, "");
|
||||
}
|
||||
|
||||
protected K convertKey(Object k) {
|
||||
K res = null;
|
||||
try {
|
||||
res = (K) convertKey((String) k);
|
||||
} catch (Exception e) {
|
||||
res = (K)k;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NvMap<K,V> clone() {
|
||||
NvMap<K,V> res = new NvMap<>();
|
||||
if (null != parent) {
|
||||
res.parent = parent.clone();
|
||||
}
|
||||
res._m = (LinkedHashMap<K, V>) _m.clone();
|
||||
res._k = (HashMap<K, K>) _k.clone();
|
||||
res.aliasMap = (HashMap<K, K>) aliasMap.clone();
|
||||
res.locale = locale;
|
||||
return res;
|
||||
}
|
||||
|
||||
// ====== 为了方便取值操作,get方法保持Map接口原有语义,不支持栈式取值 =======
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
V res = null;
|
||||
if (this.aliasMap.containsKey(convertKey(key))) {
|
||||
Object aliasKey = this.aliasMap.get(convertKey(key));
|
||||
res = this._m.get(this._k.get(convertKey(aliasKey)));
|
||||
}
|
||||
if (null == res) {
|
||||
res = this._m.get(this._k.get(convertKey(key)));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public V get(Object key, V defaultValue) {
|
||||
V res = get(key);
|
||||
if (null == res) {
|
||||
res = defaultValue;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public String getStr(K k) {
|
||||
return TypeUtil.conversion(get(k), String.class);
|
||||
}
|
||||
|
||||
public String getStr(K k, String defaultValue) {
|
||||
return TypeUtil.conversion(get(k, (V)defaultValue), String.class);
|
||||
}
|
||||
|
||||
public Byte getByte(K k) {
|
||||
return TypeUtil.conversion(get(k), Byte.class);
|
||||
}
|
||||
|
||||
public Byte getByte(K k, Byte defaultValue) {
|
||||
return TypeUtil.conversion(get(k, (V)defaultValue), Byte.class);
|
||||
}
|
||||
|
||||
public Character getChar(K k) {
|
||||
return TypeUtil.conversion(get(k), Character.class);
|
||||
}
|
||||
|
||||
public Character getChar(K k, Character defaultValue) {
|
||||
return TypeUtil.conversion(get(k, (V)defaultValue), Character.class);
|
||||
}
|
||||
|
||||
public Boolean getBool(K k) {
|
||||
return TypeUtil.conversion(get(k), Boolean.class);
|
||||
}
|
||||
|
||||
public Boolean getBool(K k, Boolean defaultValue) {
|
||||
return TypeUtil.conversion(get(k, (V)defaultValue), Boolean.class);
|
||||
}
|
||||
|
||||
public Short getShort(K k) {
|
||||
return TypeUtil.conversion(get(k), Short.class);
|
||||
}
|
||||
|
||||
public Short getShort(K k, Short defaultValue) {
|
||||
return TypeUtil.conversion(get(k, (V)defaultValue), Short.class);
|
||||
}
|
||||
|
||||
public Integer getInt(K k) {
|
||||
return TypeUtil.conversion(get(k), Integer.class);
|
||||
}
|
||||
|
||||
public Integer getInt(K k, Integer defaultValue) {
|
||||
return TypeUtil.conversion(get(k, (V)defaultValue), Integer.class);
|
||||
}
|
||||
|
||||
public Long getLong(K k) {
|
||||
return TypeUtil.conversion(get(k), Long.class);
|
||||
}
|
||||
|
||||
public Long getLong(K k, Long defaultValue) {
|
||||
return TypeUtil.conversion(get(k, (V)defaultValue), Long.class);
|
||||
}
|
||||
|
||||
public Float getFloat(K k) {
|
||||
return TypeUtil.conversion(get(k), Float.class);
|
||||
}
|
||||
|
||||
public Float getFloat(K k, Float defaultValue) {
|
||||
return TypeUtil.conversion(get(k, (V)defaultValue), Float.class);
|
||||
}
|
||||
|
||||
public Double getDouble(K k) {
|
||||
return TypeUtil.conversion(get(k), Double.class);
|
||||
}
|
||||
|
||||
public Double getDouble(K k, Double defaultValue) {
|
||||
return TypeUtil.conversion(get(k, (V)defaultValue), Double.class);
|
||||
}
|
||||
|
||||
public Date getDate(K k) {
|
||||
return TypeUtil.conversion(get(k), Date.class);
|
||||
}
|
||||
|
||||
public Date getDate(K k, Date defaultValue) {
|
||||
return TypeUtil.conversion(get(k, (V)defaultValue), Date.class);
|
||||
}
|
||||
|
||||
public K getAlias(K k) {
|
||||
return this.aliasMap.get(convertKey(k));
|
||||
}
|
||||
|
||||
public K stackGetAlias(K k) {
|
||||
K res = getAlias(k);
|
||||
if (null == res && null != parent) {
|
||||
res = parent.stackGetAlias(k);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// ====== 为了方便取值操作,take开头的方法,全部基于栈式取值 =======
|
||||
public V take(K k) {
|
||||
V res = null;
|
||||
K aliasK = this.getAlias(k);
|
||||
if (null != aliasK) {
|
||||
res = stackGet(aliasK);
|
||||
}
|
||||
if (null == res) {
|
||||
res = stackGet(k);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public V take(K k, V defaultValue) {
|
||||
V res = take(k);
|
||||
if (null == res ) {
|
||||
res = defaultValue;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public String takeStr(K k) {
|
||||
return TypeUtil.conversion(take(k), String.class);
|
||||
}
|
||||
|
||||
public String takeStr(K k, String defaultValue) {
|
||||
return TypeUtil.conversion(take(k, (V)defaultValue), String.class);
|
||||
}
|
||||
|
||||
public Byte takeByte(K k) {
|
||||
return TypeUtil.conversion(take(k), Byte.class);
|
||||
}
|
||||
|
||||
public Byte takeByte(K k, Byte defaultValue) {
|
||||
return TypeUtil.conversion(take(k, (V)defaultValue), Byte.class);
|
||||
}
|
||||
|
||||
public Character takeChar(K k) {
|
||||
return TypeUtil.conversion(take(k), Character.class);
|
||||
}
|
||||
|
||||
public Character takeChar(K k, Character defaultValue) {
|
||||
return TypeUtil.conversion(take(k, (V)defaultValue), Character.class);
|
||||
}
|
||||
|
||||
public Boolean takeBool(K k) {
|
||||
return TypeUtil.conversion(take(k), Boolean.class);
|
||||
}
|
||||
|
||||
public Boolean takeBool(K k, Boolean defaultValue) {
|
||||
return TypeUtil.conversion(take(k, (V)defaultValue), Boolean.class);
|
||||
}
|
||||
|
||||
public Short takeShort(K k) {
|
||||
return TypeUtil.conversion(take(k), Short.class);
|
||||
}
|
||||
|
||||
public Short takeShort(K k, Short defaultValue) {
|
||||
return TypeUtil.conversion(take(k, (V)defaultValue), Short.class);
|
||||
}
|
||||
|
||||
public Integer takeInt(K k) {
|
||||
return TypeUtil.conversion(take(k), Integer.class);
|
||||
}
|
||||
|
||||
public Integer takeInt(K k, Integer defaultValue) {
|
||||
return TypeUtil.conversion(take(k, (V)defaultValue), Integer.class);
|
||||
}
|
||||
|
||||
public Long takeLong(K k) {
|
||||
return TypeUtil.conversion(take(k), Long.class);
|
||||
}
|
||||
|
||||
public Long takeLong(K k, Long defaultValue) {
|
||||
return TypeUtil.conversion(take(k, (V)defaultValue), Long.class);
|
||||
}
|
||||
|
||||
public Float takeFloat(K k) {
|
||||
return TypeUtil.conversion(take(k), Float.class);
|
||||
}
|
||||
|
||||
public Float takeFloat(K k, Float defaultValue) {
|
||||
return TypeUtil.conversion(take(k, (V)defaultValue), Float.class);
|
||||
}
|
||||
|
||||
public Double takeDouble(K k) {
|
||||
return TypeUtil.conversion(take(k), Double.class);
|
||||
}
|
||||
|
||||
public Double takeDouble(K k, Double defaultValue) {
|
||||
return TypeUtil.conversion(take(k, (V)defaultValue), Double.class);
|
||||
}
|
||||
|
||||
public Date takeDate(K k) {
|
||||
return TypeUtil.conversion(take(k), Date.class);
|
||||
}
|
||||
|
||||
public Date takeDate(K k, Date defaultValue) {
|
||||
return TypeUtil.conversion(take(k, (V)defaultValue), Date.class);
|
||||
}
|
||||
|
||||
// ====== 为了方便取值操作,idx开头的方法,全部基于下标取值 =======
|
||||
public V idx(int i) {
|
||||
if (i >= 0 && i < this.size()) {
|
||||
return (V)this._m.values().toArray(new Object[]{})[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public V idx(int i, V defaultValue) {
|
||||
V res = idx(i);
|
||||
if (null == res) {
|
||||
res = defaultValue;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public String idxStr(int i) {
|
||||
return TypeUtil.conversion(idx(i), String.class);
|
||||
}
|
||||
|
||||
public String idxStr(int i, String defaultValue) {
|
||||
return TypeUtil.conversion(idx(i, (V)defaultValue), String.class);
|
||||
}
|
||||
|
||||
public Byte idxByte(int i) {
|
||||
return TypeUtil.conversion(idx(i), Byte.class);
|
||||
}
|
||||
|
||||
public Byte idxByte(int i, Byte defaultValue) {
|
||||
return TypeUtil.conversion(idx(i, (V)defaultValue), Byte.class);
|
||||
}
|
||||
|
||||
public Character idxChar(int i) {
|
||||
return TypeUtil.conversion(idx(i), Character.class);
|
||||
}
|
||||
|
||||
public Character idxChar(int i, Character defaultValue) {
|
||||
return TypeUtil.conversion(idx(i, (V)defaultValue), Character.class);
|
||||
}
|
||||
|
||||
public Boolean idxBool(int i) {
|
||||
return TypeUtil.conversion(idx(i), Boolean.class);
|
||||
}
|
||||
|
||||
public Boolean idxBool(int i, Boolean defaultValue) {
|
||||
return TypeUtil.conversion(idx(i, (V)defaultValue), Boolean.class);
|
||||
}
|
||||
|
||||
public Short idxShort(int i) {
|
||||
return TypeUtil.conversion(idx(i), Short.class);
|
||||
}
|
||||
|
||||
public Short idxShort(int i, Short defaultValue) {
|
||||
return TypeUtil.conversion(idx(i, (V)defaultValue), Short.class);
|
||||
}
|
||||
|
||||
public Integer idxInt(int i) {
|
||||
return TypeUtil.conversion(idx(i), Integer.class);
|
||||
}
|
||||
|
||||
public Integer idxInt(int i, Integer defaultValue) {
|
||||
return TypeUtil.conversion(idx(i, (V)defaultValue), Integer.class);
|
||||
}
|
||||
|
||||
public Long idxLong(int i) {
|
||||
return TypeUtil.conversion(idx(i), Long.class);
|
||||
}
|
||||
|
||||
public Long idxLong(int i, Long defaultValue) {
|
||||
return TypeUtil.conversion(idx(i, (V)defaultValue), Long.class);
|
||||
}
|
||||
|
||||
public Float idxFloat(int i) {
|
||||
return TypeUtil.conversion(idx(i), Float.class);
|
||||
}
|
||||
|
||||
public Float idxFloat(int i, Float defaultValue) {
|
||||
return TypeUtil.conversion(idx(i, (V)defaultValue), Float.class);
|
||||
}
|
||||
|
||||
public Double idxDouble(int i) {
|
||||
return TypeUtil.conversion(idx(i), Double.class);
|
||||
}
|
||||
|
||||
public Double idxDouble(int i, Double defaultValue) {
|
||||
return TypeUtil.conversion(idx(i, (V)defaultValue), Double.class);
|
||||
}
|
||||
|
||||
public Date idxDate(int i) {
|
||||
return TypeUtil.conversion(idx(i), Date.class);
|
||||
}
|
||||
|
||||
public Date idxDate(int i, Date defaultValue) {
|
||||
return TypeUtil.conversion(idx(i, (V)defaultValue), Date.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
package fun.asgc.neutrino.core.base;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import fun.asgc.neutrino.core.constant.FileTypeEnum;
|
||||
import fun.asgc.neutrino.core.constant.MetaDataConstant;
|
||||
import fun.asgc.neutrino.core.util.*;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* 配置管理器
|
||||
*
|
||||
* <p>
|
||||
* 支持以下五级配置:
|
||||
* 1、别名、默认值
|
||||
* 2、内部配置文件
|
||||
* 3、环境变量
|
||||
* 4、外部配置文件
|
||||
* 5、启动参数
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 支持以下3种配置文件格式:
|
||||
* 1、yml
|
||||
* 2、properties
|
||||
* 3、json
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 支持指定以下配置:
|
||||
* 1、内部配置文件路径、格式 (可根据文件后缀自动识别格式)
|
||||
* 2、环境变量前缀 (若指定了前缀,则只加载包含该前缀的环境变量)
|
||||
* 3、外部配置文件路径、格式(可根据文件后缀自动识别格式)
|
||||
* 4、启动参数前缀(若指定了前缀,则只加载包含该前缀的启动参数)
|
||||
* </p>
|
||||
* @author: aoshiguchen
|
||||
* @date: 2023/3/5
|
||||
*/
|
||||
public final class NvMaps {
|
||||
private NvMap nvMap;
|
||||
|
||||
private NvMaps() {
|
||||
this.nvMap = NvMap.of();
|
||||
}
|
||||
|
||||
public static NvMaps of() {
|
||||
return new NvMaps();
|
||||
}
|
||||
|
||||
public NvMaps stageDone() {
|
||||
this.nvMap = NvMap.of(this.nvMap);
|
||||
return this;
|
||||
}
|
||||
|
||||
public NvMap getNvMap() {
|
||||
return this.nvMap;
|
||||
}
|
||||
|
||||
public NvMaps setKv(Object k, Object v) {
|
||||
this.nvMap.set(k, v);
|
||||
return this;
|
||||
}
|
||||
|
||||
public NvMaps setKv(Object k, Object alias, Object v) {
|
||||
this.nvMap.set(k, alias, v);
|
||||
return this;
|
||||
}
|
||||
|
||||
public NvMaps setAlias(Object k, Object alias) {
|
||||
this.nvMap.setAlias(k, alias);
|
||||
return this;
|
||||
}
|
||||
public NvMaps loadFile(String path) throws IOException {
|
||||
if (StringUtil.isEmpty(path)) {
|
||||
return this;
|
||||
}
|
||||
String suffix = FileUtil.getFileSuffix(path);
|
||||
if (StringUtil.isEmpty(suffix)) {
|
||||
return this;
|
||||
}
|
||||
suffix = suffix.toLowerCase();
|
||||
if (FileTypeEnum.YML.getSuffixSet().contains(suffix)) {
|
||||
return loadFile(FileTypeEnum.YML, path);
|
||||
} else if (FileTypeEnum.PROPERTIES.getSuffixSet().contains(suffix)) {
|
||||
return loadFile(FileTypeEnum.PROPERTIES, path);
|
||||
} else if (FileTypeEnum.JSON.getSuffixSet().contains(suffix)) {
|
||||
return loadFile(FileTypeEnum.JSON, path);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public NvMaps loadYmlFile(String path) throws IOException {
|
||||
return loadFile(FileTypeEnum.YML, path);
|
||||
}
|
||||
public NvMaps loadPropertiesFile(String path) throws IOException {
|
||||
return loadFile(FileTypeEnum.PROPERTIES, path);
|
||||
}
|
||||
public NvMaps loadJsonFile(String path) throws IOException {
|
||||
return loadFile(FileTypeEnum.JSON, path);
|
||||
}
|
||||
public NvMaps loadFile(FileTypeEnum fileType, String path) throws IOException {
|
||||
try (InputStream in = FileUtil.getInputStream(path)){
|
||||
return loadFile(fileType, in);
|
||||
}
|
||||
}
|
||||
public NvMaps loadFile(FileTypeEnum fileType, InputStream in) throws IOException {
|
||||
if (null == fileType || null == in) {
|
||||
return this;
|
||||
}
|
||||
if (fileType == FileTypeEnum.YML) {
|
||||
Map<String, Object> map = new Yaml().load(in);
|
||||
load(map);
|
||||
} else if (fileType == FileTypeEnum.PROPERTIES) {
|
||||
Properties properties = new Properties();
|
||||
properties.load(in);
|
||||
load(properties);
|
||||
} else if (fileType == FileTypeEnum.JSON) {
|
||||
String content = FileUtil.readContentAsString(in);
|
||||
JSONObject jsonObject = JSONObject.parseObject(content);
|
||||
load(jsonObject);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public NvMaps load(Properties properties) {
|
||||
if (null == properties) {
|
||||
return this;
|
||||
}
|
||||
for (String k : properties.stringPropertyNames()) {
|
||||
this.setKv(k, properties.getProperty(k));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public NvMaps load(Map<String, Object> config) {
|
||||
if (CollectionUtil.isEmpty(config)) {
|
||||
return this;
|
||||
}
|
||||
for (String key : config.keySet()) {
|
||||
Object value = config.get(key);
|
||||
if (null != value && Map.class.isAssignableFrom(value.getClass())) {
|
||||
load(key, (Map)config.get(key));
|
||||
} else {
|
||||
this.setKv(key, value);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private void load(String prefix, Map<Object, Object> config) {
|
||||
for (Object key : config.keySet()) {
|
||||
String k = TypeUtil.conversion(key, String.class);
|
||||
if (null == k) {
|
||||
continue;
|
||||
}
|
||||
Object value = config.get(key);
|
||||
if (null != value && Map.class.isAssignableFrom(value.getClass())) {
|
||||
load(prefix.concat("." + k), (Map)config.get(key));
|
||||
} else {
|
||||
this.setKv(prefix.concat("." + k), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public NvMaps loadEnvironmentVariable(String envKey) {
|
||||
String env = System.getenv(MetaDataConstant.ENVIRONMENT_VARIABLE_KEY);
|
||||
if (StringUtil.isEmpty(env)) {
|
||||
return this;
|
||||
}
|
||||
String[] tmp = env.split(File.pathSeparator);
|
||||
if (ArrayUtil.isEmpty(tmp) || tmp.length < 2) {
|
||||
return this;
|
||||
}
|
||||
load(kvListToMap(tmp));
|
||||
return this;
|
||||
}
|
||||
|
||||
public NvMaps loadMainArgs(String[] mainArgs) {
|
||||
load(kvListToMap(mainArgs));
|
||||
return this;
|
||||
}
|
||||
|
||||
private Map<String, Object> kvListToMap(String[] args) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
if (ArrayUtil.isEmpty(args)) {
|
||||
return map;
|
||||
}
|
||||
for (String kv : args) {
|
||||
if (!StringUtil.isEmpty(kv)) {
|
||||
int index = kv.indexOf("=");
|
||||
if (index > 0 && index < kv.length() - 1) {
|
||||
String key = kv.substring(0, index);
|
||||
String val = kv.substring(index + 1);
|
||||
map.put(key, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package fun.asgc.neutrino.core.constant;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2023/3/6
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum FileTypeEnum {
|
||||
YML(1, "yml", Sets.newHashSet(".yml", ".yaml")),
|
||||
PROPERTIES(2, "properties", Sets.newHashSet(".properties")),
|
||||
JSON(3, "json", Sets.newHashSet(".json")),
|
||||
;
|
||||
|
||||
private Integer type;
|
||||
private String desc;
|
||||
private Set<String> suffixSet;
|
||||
private static final Map<Integer, FileTypeEnum> typeMap = Stream.of(FileTypeEnum.values()).collect(Collectors.toMap(FileTypeEnum::getType, Function.identity()));
|
||||
|
||||
public static FileTypeEnum ofType(Integer type) {
|
||||
return typeMap.get(type);
|
||||
}
|
||||
}
|
||||
@@ -84,4 +84,41 @@ public interface MetaDataConstant {
|
||||
* app生命周期主题
|
||||
*/
|
||||
String TOPIC_APP_LIFE_CYCLE = "TP_APP_LIFE_CYCLE";
|
||||
/**
|
||||
* 环境变量key
|
||||
*/
|
||||
String ENVIRONMENT_VARIABLE_KEY = "NEUTRINO_PROXY";
|
||||
|
||||
interface Config {
|
||||
String NEUTRINO_APPLICATION_NAME = "neutrino.application.name";
|
||||
String NEUTRINO_HTTP_ENABLE = "neutrino.http.enable";
|
||||
String NEUTRINO_HTTP_PORT = "neutrino.http.port";
|
||||
String NEUTRINO_HTTP_CONTEXT_PATH = "neutrino.http.context-path";
|
||||
String NEUTRINO_HTTP_MAX_CONTENT_LENGTH_DESC = "neutrino.http.max-content-length-desc";
|
||||
String NEUTRINO_HTTP_STATIC_RESOURCE_LOCATIONS = "neutrino.http.static-resource.locations";
|
||||
String NEUTRINO_PROXY_PROTOCOL_MAX_FRAME_LENGTH = "neutrino.proxy.protocol.max-frame-length";
|
||||
String NEUTRINO_PROXY_PROTOCOL_LENGTH_FIELD_OFFSET = "neutrino.proxy.protocol.length-field-offset";
|
||||
String NEUTRINO_PROXY_PROTOCOL_LENGTH_FIELD_LENGTH = "neutrino.proxy.protocol.length-field-length";
|
||||
String NEUTRINO_PROXY_PROTOCOL_INITIAL_BYTES_TO_STRIP = "neutrino.proxy.protocol.initial-bytes-to-strip";
|
||||
String NEUTRINO_PROXY_PROTOCOL_LENGTH_ADJUSTMENT = "neutrino.proxy.protocol.length-adjustment";
|
||||
String NEUTRINO_PROXY_PROTOCOL_READ_IDLE_TIME = "neutrino.proxy.protocol.read-idle-time";
|
||||
String NEUTRINO_PROXY_PROTOCOL_WRITE_IDLE_TIME = "neutrino.proxy.protocol.write-idle-time";
|
||||
String NEUTRINO_PROXY_PROTOCOL_ALL_IDLE_TIME_SECONDS = "neutrino.proxy.protocol.all-idle-time-seconds";
|
||||
String NEUTRINO_PROXY_SERVER_PORT = "neutrino.proxy.server.port";
|
||||
String NEUTRINO_PROXY_SERVER_SSL_PORT = "neutrino.proxy.server.ssl-port";
|
||||
String NEUTRINO_PROXY_SERVER_KEY_STORE_PASSWORD = "neutrino.proxy.server.key-store-password";
|
||||
String NEUTRINO_PROXY_SERVER_KEY_MANAGER_PASSWORD = "neutrino.proxy.server.key-manager-password";
|
||||
String NEUTRINO_PROXY_SERVER_JKS_PATH = "neutrino.proxy.server.jks-path";
|
||||
String NEUTRINO_PROXY_CLIENT_KEY_STORE_PASSWORD = "neutrino.proxy.client.key-store-password";
|
||||
String NEUTRINO_PROXY_CLIENT_JKS_PATH = "neutrino.proxy.client.jks-path";
|
||||
String NEUTRINO_PROXY_CLIENT_SERVER_IP = "neutrino.proxy.client.server-ip";
|
||||
String NEUTRINO_PROXY_CLIENT_SERVER_PORT = "neutrino.proxy.client.server-port";
|
||||
String NEUTRINO_PROXY_CLIENT_SSL_ENABLE = "neutrino.proxy.client.ssl-enable";
|
||||
String NEUTRINO_PROXY_CLIENT_OBTAIN_LICENSE_INTERVAL = "neutrino.proxy.client.obtain-license-interval";
|
||||
String NEUTRINO_DATA_DB_TYPE = "neutrino.data.db.type";
|
||||
String NEUTRINO_DATA_DB_URL = "neutrino.data.db.url";
|
||||
String NEUTRINO_DATA_DB_DRIVER_CLASS = "neutrino.data.db.driver-class";
|
||||
String NEUTRINO_DATA_DB_USERNAME = "neutrino.data.db.username";
|
||||
String NEUTRINO_DATA_DB_PASSWORD = "neutrino.data.db.password";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,8 +125,7 @@ public class ApplicationContext implements LifeCycle {
|
||||
continue;
|
||||
}
|
||||
Optional<Method> methodOptional = methodSet.stream().filter(m -> m.getName().equals(name) && Modifier.isStatic(m.getModifiers())
|
||||
&& (m.getParameterCount() == 0 ||
|
||||
(m.getParameterCount() == 1 && m.getParameters()[0].getType().isArray() && String.class.isAssignableFrom(m.getParameters()[0].getType().getComponentType()))))
|
||||
&& (m.getParameterCount() == 0 || m.getParameterCount() == 1))
|
||||
.findFirst();
|
||||
if (!methodOptional.isPresent()) {
|
||||
continue;
|
||||
@@ -136,8 +135,16 @@ public class ApplicationContext implements LifeCycle {
|
||||
log.debug("PreLoad execute {}#{}", c.getName(), method.getName());
|
||||
if (method.getParameterCount() == 0) {
|
||||
method.invoke(o);
|
||||
} else if (method.getParameterCount() == 1){
|
||||
if (String[].class.isAssignableFrom(method.getParameters()[0].getType())) {
|
||||
method.invoke(o, new Object[]{this.environment.getMainArgs()});
|
||||
} else if (Environment.class.isAssignableFrom(method.getParameters()[0].getType())){
|
||||
method.invoke(o, this.environment);
|
||||
} else {
|
||||
log.error("PreLoad execute failed. init method args nonsupport!");
|
||||
}
|
||||
} else {
|
||||
method.invoke(o, new Object[]{this.environment.getMainArgs()});
|
||||
log.error("PreLoad execute failed. init method args nonsupport!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,10 @@
|
||||
|
||||
package fun.asgc.neutrino.core.context;
|
||||
|
||||
import fun.asgc.neutrino.core.base.NvMap;
|
||||
import fun.asgc.neutrino.core.base.NvMaps;
|
||||
import fun.asgc.neutrino.core.base.event.SimpleApplicationEventManager;
|
||||
import fun.asgc.neutrino.core.constant.MetaDataConstant;
|
||||
import fun.asgc.neutrino.core.util.ArrayUtil;
|
||||
import fun.asgc.neutrino.core.util.LockUtil;
|
||||
import fun.asgc.neutrino.core.util.StringUtil;
|
||||
@@ -34,6 +37,8 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static fun.asgc.neutrino.core.constant.MetaDataConstant.Config.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
@@ -74,11 +79,92 @@ public class Environment {
|
||||
* 默认的应用事件管理器
|
||||
*/
|
||||
private SimpleApplicationEventManager defaultApplicationEventManager;
|
||||
/**
|
||||
* 全局配置
|
||||
*/
|
||||
private NvMap nvMap;
|
||||
|
||||
public NvMap getNvMap() {
|
||||
return nvMap;
|
||||
}
|
||||
|
||||
public void loadNvMap(String envKey) throws Exception {
|
||||
// 创建NvMaps实例
|
||||
NvMaps nvMaps = NvMaps.of();
|
||||
|
||||
// 阶段1:设置内部默认值、别名
|
||||
nvMaps.setAlias(NEUTRINO_APPLICATION_NAME, "app.name");
|
||||
nvMaps.setKv(NEUTRINO_APPLICATION_NAME, "neutrino-app");
|
||||
|
||||
nvMaps.setAlias(NEUTRINO_HTTP_ENABLE, "http.enable");
|
||||
nvMaps.setKv(NEUTRINO_HTTP_ENABLE, true);
|
||||
nvMaps.setAlias(NEUTRINO_HTTP_PORT, "http.port");
|
||||
nvMaps.setKv(NEUTRINO_HTTP_PORT, 8080);
|
||||
nvMaps.setAlias(NEUTRINO_HTTP_CONTEXT_PATH, "http.context-path");
|
||||
nvMaps.setKv(NEUTRINO_HTTP_CONTEXT_PATH, "/");
|
||||
nvMaps.setAlias(NEUTRINO_HTTP_MAX_CONTENT_LENGTH_DESC, "http.max-content-length-desc");
|
||||
nvMaps.setKv(NEUTRINO_HTTP_MAX_CONTENT_LENGTH_DESC, "/");
|
||||
nvMaps.setAlias(NEUTRINO_HTTP_STATIC_RESOURCE_LOCATIONS, "http.static-resource");
|
||||
|
||||
nvMaps.setAlias(NEUTRINO_PROXY_PROTOCOL_MAX_FRAME_LENGTH, "protocol.max-frame-length");
|
||||
nvMaps.setAlias(NEUTRINO_PROXY_PROTOCOL_LENGTH_FIELD_OFFSET, "protocol.length-field-offset");
|
||||
nvMaps.setAlias(NEUTRINO_PROXY_PROTOCOL_LENGTH_FIELD_LENGTH, "protocol.length-field-length");
|
||||
nvMaps.setAlias(NEUTRINO_PROXY_PROTOCOL_INITIAL_BYTES_TO_STRIP, "protocol.initial-bytes-to-strip");
|
||||
nvMaps.setAlias(NEUTRINO_PROXY_PROTOCOL_LENGTH_ADJUSTMENT, "protocol.length-adjustment");
|
||||
nvMaps.setAlias(NEUTRINO_PROXY_PROTOCOL_READ_IDLE_TIME, "protocol.read-idle-time");
|
||||
nvMaps.setAlias(NEUTRINO_PROXY_PROTOCOL_WRITE_IDLE_TIME, "protocol.write-idle-time");
|
||||
nvMaps.setAlias(NEUTRINO_PROXY_PROTOCOL_ALL_IDLE_TIME_SECONDS, "protocol.all-idle-time-seconds");
|
||||
|
||||
nvMaps.setAlias(NEUTRINO_PROXY_SERVER_PORT, "proxy.port");
|
||||
nvMaps.setAlias(NEUTRINO_PROXY_SERVER_SSL_PORT, "proxy.ssl-port");
|
||||
nvMaps.setAlias(NEUTRINO_PROXY_SERVER_KEY_STORE_PASSWORD, "proxy.key-store-password");
|
||||
nvMaps.setAlias(NEUTRINO_PROXY_SERVER_KEY_MANAGER_PASSWORD, "proxy.key-manager-password");
|
||||
nvMaps.setAlias(NEUTRINO_PROXY_SERVER_JKS_PATH, "proxy.jks-path");
|
||||
|
||||
nvMaps.setAlias(NEUTRINO_PROXY_CLIENT_KEY_STORE_PASSWORD, "proxy.key-store-password");
|
||||
nvMaps.setAlias(NEUTRINO_PROXY_CLIENT_JKS_PATH, "proxy.jks-path");
|
||||
nvMaps.setAlias(NEUTRINO_PROXY_CLIENT_SERVER_IP, "proxy.server-ip");
|
||||
nvMaps.setAlias(NEUTRINO_PROXY_CLIENT_SERVER_PORT, "proxy.server-port");
|
||||
nvMaps.setAlias(NEUTRINO_PROXY_CLIENT_SSL_ENABLE, "proxy.ssl-enable");
|
||||
nvMaps.setAlias(NEUTRINO_PROXY_CLIENT_OBTAIN_LICENSE_INTERVAL, "proxy.obtain-license-interval");
|
||||
|
||||
nvMaps.setAlias(NEUTRINO_DATA_DB_TYPE, "db.type");
|
||||
nvMaps.setAlias(NEUTRINO_DATA_DB_URL, "db.url");
|
||||
nvMaps.setAlias(NEUTRINO_DATA_DB_DRIVER_CLASS, "db.driver-class");
|
||||
nvMaps.setAlias(NEUTRINO_DATA_DB_USERNAME, "db.username");
|
||||
nvMaps.setAlias(NEUTRINO_DATA_DB_PASSWORD, "db.password");
|
||||
|
||||
nvMaps.stageDone();
|
||||
|
||||
// 阶段2:内部配置文件
|
||||
nvMaps.loadFile(MetaDataConstant.CLASSPATH_RESOURCE_IDENTIFIER.concat("/application.yml"));
|
||||
nvMaps.stageDone();
|
||||
|
||||
// 阶段3:环境变量
|
||||
if (!StringUtil.isEmpty(envKey)) {
|
||||
nvMaps.loadEnvironmentVariable(envKey);
|
||||
nvMaps.stageDone();
|
||||
}
|
||||
|
||||
// 结算4:外部配置文件
|
||||
nvMaps.loadFile("./.application.properties");
|
||||
nvMaps.stageDone();
|
||||
|
||||
// 阶段5:启动参数
|
||||
nvMaps.loadMainArgs(this.mainArgs);
|
||||
nvMaps.stageDone();
|
||||
|
||||
// 获取NvMap实例
|
||||
this.nvMap = nvMaps.getNvMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数map
|
||||
*/
|
||||
@Deprecated
|
||||
private Map<String, String> mainArgsMap = null;
|
||||
|
||||
@Deprecated
|
||||
private Map<String, String> getMainArgsMap() {
|
||||
return LockUtil.doubleCheckProcessForNoException(
|
||||
() -> null == mainArgsMap,
|
||||
@@ -103,10 +189,12 @@ public class Environment {
|
||||
);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private String getMainArgs(String key) {
|
||||
return getMainArgsMap().get(key);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Integer getMainArgsForInteger(String key, Integer defaultValue) {
|
||||
String val = getMainArgs(key);
|
||||
Integer res = null;
|
||||
@@ -120,6 +208,7 @@ public class Environment {
|
||||
return (null != res) ? res : defaultValue;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Boolean getMainArgsForBoolean(String key, Boolean defaultValue) {
|
||||
String val = getMainArgs(key);
|
||||
Boolean res = null;
|
||||
@@ -133,11 +222,13 @@ public class Environment {
|
||||
return (null != res) ? res : defaultValue;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public String getMainArgsForString(String key, String defaultValue) {
|
||||
String res = getMainArgs(key);
|
||||
return !StringUtil.isEmpty(res) ? res : defaultValue;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public String getMainArgsForString(String key) {
|
||||
return getMainArgsForString(key, null);
|
||||
}
|
||||
|
||||
@@ -118,7 +118,13 @@ public class NeutrinoLauncher {
|
||||
|
||||
// 加载应用配置
|
||||
environment.setConfig(ConfigUtil.getYmlConfig(ApplicationConfig.class));
|
||||
log.info("load ApplicationConfig finished.");
|
||||
try {
|
||||
environment.loadNvMap(neutrinoApplication.environmentVariableKey());
|
||||
log.info("load ApplicationConfig finished.");
|
||||
} catch (Exception e) {
|
||||
log.error("load ApplicationConfig err.", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+10
-8
@@ -26,11 +26,12 @@ import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.annotation.Param;
|
||||
import fun.asgc.neutrino.core.aop.Invocation;
|
||||
import fun.asgc.neutrino.core.aop.interceptor.Interceptor;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageInfo;
|
||||
import fun.asgc.neutrino.core.db.template.JdbcTemplate;
|
||||
import fun.asgc.neutrino.core.util.*;
|
||||
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -65,14 +66,14 @@ public class SqlMapperInterceptor implements Interceptor {
|
||||
res = jdbcTemplate.queryForListByMap(resultComponentType, sql, (Map)params);
|
||||
}
|
||||
} else {
|
||||
if (Page.class.isAssignableFrom(inv.getTargetMethod().getParameters()[0].getType())) {
|
||||
if (PageInfo.class.isAssignableFrom(inv.getTargetMethod().getParameters()[0].getType())) {
|
||||
// 分页查询 TODO 此处暂时临时处理,假设后面的参数是一个DO对象
|
||||
Page page = (Page) inv.getArgs()[0];
|
||||
int offset = (page.getCurrentPage() - 1) * page.getPageSize();
|
||||
PageInfo pageInfo = (PageInfo) inv.getArgs()[0];
|
||||
int offset = (pageInfo.getCurrent() - 1) * pageInfo.getSize();
|
||||
long total = jdbcTemplate.queryForLongByModel(String.format("select count(1) from (%s) T", sql), inv.getArgs()[1]);
|
||||
List resultList = jdbcTemplate.queryForListByModel(resultComponentType, String.format("%s limit %s,%s", sql, offset, page.getPageSize()), inv.getArgs()[1]);
|
||||
page.setTotal(total);
|
||||
page.setRecords(resultList);
|
||||
List resultList = jdbcTemplate.queryForListByModel(resultComponentType, String.format("%s limit %s,%s", sql, offset, pageInfo.getSize()), inv.getArgs()[1]);
|
||||
pageInfo.setTotal(total);
|
||||
pageInfo.setRecords(resultList);
|
||||
} else {
|
||||
Object params = getParams(inv);
|
||||
if (null == params || params.getClass().isArray()) {
|
||||
@@ -86,7 +87,8 @@ public class SqlMapperInterceptor implements Interceptor {
|
||||
int argsCount = ArrayUtil.isEmpty(inv.getArgs()) ? 0 : inv.getArgs().length;
|
||||
if (argsCount == 1 && inv.getArgs()[0] instanceof Map) {
|
||||
res = jdbcTemplate.updateByMap(sql, (Map)inv.getArgs()[0]);
|
||||
} else if (argsCount == 1 && !TypeUtil.isNormalBasicType(inv.getArgs()[0].getClass())) {
|
||||
// 临时解决只有一个参数,且参数类型不是实体类型时,参数未起作用的情况
|
||||
} else if (argsCount == 1 && !TypeUtil.isNormalBasicType(inv.getArgs()[0].getClass()) && !(inv.getArgs()[0] instanceof Date)) {
|
||||
res = jdbcTemplate.updateByModel(sql, inv.getArgs()[0]);
|
||||
} else {
|
||||
Object params = getParams(inv);
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.core.db.page;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/6
|
||||
*/
|
||||
@Data
|
||||
public class PageInfo<T> implements Serializable {
|
||||
private static final long serialVersionUID = 8545996863226528797L;
|
||||
private List<T> records;
|
||||
private Long total;
|
||||
private Integer size;
|
||||
private Integer current;
|
||||
|
||||
public PageInfo() {
|
||||
this.records = Collections.emptyList();
|
||||
this.total = 0L;
|
||||
this.size = 10;
|
||||
this.current = 1;
|
||||
}
|
||||
|
||||
public PageInfo(Integer current, Integer size) {
|
||||
this(current, size, 0L);
|
||||
}
|
||||
|
||||
public PageInfo(Integer current, Integer size, Long total) {
|
||||
this.records = Collections.emptyList();
|
||||
this.total = 0L;
|
||||
this.size = 10;
|
||||
this.current = 1;
|
||||
if ((long)current > 1L) {
|
||||
this.current = current;
|
||||
}
|
||||
|
||||
this.size = size;
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
public Long getPages() {
|
||||
if ((long)this.getSize() == 0L) {
|
||||
return 0L;
|
||||
} else {
|
||||
Long pages = this.getTotal() / (long)this.getSize();
|
||||
if (this.getTotal() % (long)this.getSize() != 0L) {
|
||||
pages = pages + 1L;
|
||||
}
|
||||
|
||||
return pages;
|
||||
}
|
||||
}
|
||||
|
||||
public Long getTotal() {
|
||||
return this.total;
|
||||
}
|
||||
|
||||
public Integer getSize() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
public boolean hasPrevious() {
|
||||
return (long)this.current > 1L;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return (long)this.current < this.getPages();
|
||||
}
|
||||
|
||||
public List<T> getRecords() {
|
||||
return this.records;
|
||||
}
|
||||
|
||||
public PageInfo<T> setRecords(List<T> records) {
|
||||
this.records = records;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PageInfo<T> setTotal(Long total) {
|
||||
this.total = total;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PageInfo<T> setSize(Integer size) {
|
||||
this.size = size;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getCurrent() {
|
||||
return this.current;
|
||||
}
|
||||
|
||||
public PageInfo<T> setCurrent(Integer current) {
|
||||
this.current = current;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -21,34 +21,23 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.core.db.page;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/6
|
||||
*/
|
||||
public class PageQuery {
|
||||
@Data
|
||||
public class PageQuery implements Serializable {
|
||||
/**
|
||||
* 当前页
|
||||
*/
|
||||
private int currentPage = 1;
|
||||
private int current = 1;
|
||||
/**
|
||||
* 分页大小
|
||||
*/
|
||||
private int pageSize = 10;
|
||||
|
||||
public int getCurrentPage() {
|
||||
return currentPage;
|
||||
}
|
||||
|
||||
public void setCurrentPage(int currentPage) {
|
||||
this.currentPage = currentPage;
|
||||
}
|
||||
|
||||
public int getPageSize() {
|
||||
return pageSize;
|
||||
}
|
||||
|
||||
public void setPageSize(int pageSize) {
|
||||
this.pageSize = pageSize;
|
||||
}
|
||||
private int size = 10;
|
||||
}
|
||||
|
||||
+51
-50
@@ -1,16 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* <p>
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* <p>
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* <p>
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
@@ -27,6 +27,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -36,59 +37,59 @@ import java.sql.SQLException;
|
||||
@Slf4j
|
||||
public abstract class PreparedStatementJdbcCallback<T> implements JdbcCallback<T> {
|
||||
|
||||
@Override
|
||||
public T execute() throws SQLException {
|
||||
PreparedStatement pstm = null;
|
||||
Object[] params = this.getParams();
|
||||
Connection conn = getConnection();
|
||||
@Override
|
||||
public T execute() throws SQLException {
|
||||
PreparedStatement pstm = null;
|
||||
Object[] params = this.getParams();
|
||||
Connection conn = getConnection();
|
||||
|
||||
T res = null;
|
||||
T res = null;
|
||||
|
||||
log.debug("sql:" + this.getSql());
|
||||
StringBuffer sb = new StringBuffer();
|
||||
if (ArrayUtil.notEmpty(params)) {
|
||||
for(Object o : params){
|
||||
sb.append(o).append(",");
|
||||
}
|
||||
log.debug("sql:" + this.getSql());
|
||||
StringBuffer sb = new StringBuffer();
|
||||
if (ArrayUtil.notEmpty(params)) {
|
||||
for (Object o : params) {
|
||||
sb.append(o).append(",");
|
||||
}
|
||||
|
||||
if(sb.length() > 0 && sb.charAt(sb.length() - 1) == ','){
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
}
|
||||
}
|
||||
log.debug("params:" + sb.toString());
|
||||
pstm = conn.prepareStatement(this.getSql());
|
||||
if (ArrayUtil.notEmpty(params)) {
|
||||
for(int i = 0;i < params.length;i++){
|
||||
pstm.setObject(i + 1, params[i]);
|
||||
}
|
||||
}
|
||||
res = this.execute(pstm);
|
||||
if (sb.length() > 0 && sb.charAt(sb.length() - 1) == ',') {
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
}
|
||||
}
|
||||
log.debug("params:" + sb.toString());
|
||||
pstm = conn.prepareStatement(this.getSql(), Statement.RETURN_GENERATED_KEYS);
|
||||
if (ArrayUtil.notEmpty(params)) {
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
pstm.setObject(i + 1, params[i]);
|
||||
}
|
||||
}
|
||||
res = this.execute(pstm);
|
||||
|
||||
return res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取参数
|
||||
* @return
|
||||
*/
|
||||
abstract Object[] getParams();
|
||||
/**
|
||||
* 获取参数
|
||||
* @return
|
||||
*/
|
||||
abstract Object[] getParams();
|
||||
|
||||
/**
|
||||
* 获取sql语句
|
||||
* @return
|
||||
*/
|
||||
abstract String getSql();
|
||||
/**
|
||||
* 获取sql语句
|
||||
* @return
|
||||
*/
|
||||
abstract String getSql();
|
||||
|
||||
/**
|
||||
* 执行
|
||||
* @param ps
|
||||
* @return
|
||||
*/
|
||||
abstract T execute(PreparedStatement ps) throws SQLException;
|
||||
/**
|
||||
* 执行
|
||||
* @param ps
|
||||
* @return
|
||||
*/
|
||||
abstract T execute(PreparedStatement ps) throws SQLException;
|
||||
|
||||
/**
|
||||
* 获取数据库连接
|
||||
* @return
|
||||
*/
|
||||
abstract Connection getConnection();
|
||||
/**
|
||||
* 获取数据库连接
|
||||
* @return
|
||||
*/
|
||||
abstract Connection getConnection();
|
||||
}
|
||||
|
||||
@@ -28,10 +28,6 @@ import org.apache.commons.io.FileDeleteStrategy;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
@@ -90,6 +86,20 @@ public class FileUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取文件内容
|
||||
* @param in
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public static String readContentAsString(InputStream in) {
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(in))){
|
||||
return br.lines().collect(Collectors.joining("\n"));
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取文件内容
|
||||
* @param path
|
||||
@@ -220,4 +230,15 @@ public class FileUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String getFileSuffix(String path) {
|
||||
if (StringUtils.isBlank(path)) {
|
||||
return "";
|
||||
}
|
||||
int index = path.lastIndexOf(".");
|
||||
if (index >= 0) {
|
||||
return path.substring(index);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
package fun.asgc.neutrino.core.util;
|
||||
|
||||
import fun.asgc.neutrino.core.base.CodeBlock;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -31,6 +32,7 @@ import java.util.Objects;
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@Slf4j
|
||||
public class SystemUtil {
|
||||
|
||||
public static void addShutdownHook(Runnable runnable) {
|
||||
@@ -98,14 +100,17 @@ public class SystemUtil {
|
||||
if (!isStartupFromJar()) {
|
||||
return null;
|
||||
}
|
||||
String url = SystemUtil.class.getResource("").getPath();
|
||||
if (url.startsWith("file:")) {
|
||||
url = url.substring(5);
|
||||
String path = SystemUtil.class.getResource("").getPath();
|
||||
String res = path;
|
||||
if (res.startsWith("file:")) {
|
||||
res = res.substring(5);
|
||||
}
|
||||
if (url.contains("!")) {
|
||||
url = url.substring(0, url.indexOf("!"));
|
||||
int index = res.indexOf("!");
|
||||
if (index >= 0) {
|
||||
res = res.substring(0, index);
|
||||
}
|
||||
return url;
|
||||
log.debug("getCurrentJarFilePath path:{} index:{} url:{}", path, index, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
public static boolean isWindows() {
|
||||
|
||||
-1
@@ -23,7 +23,6 @@ package fun.asgc.neutrino.core.web.interceptor;
|
||||
|
||||
import fun.asgc.neutrino.core.web.context.HttpRequestWrapper;
|
||||
import fun.asgc.neutrino.core.web.context.HttpResponseWrapper;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
||||
/**
|
||||
* 异常处理
|
||||
|
||||
+50
-5
@@ -26,6 +26,7 @@ import org.junit.Test;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -43,7 +44,7 @@ public class AsgcCompilerTest {
|
||||
"\t\tSystem.out.println(\"hello\");\n" +
|
||||
"\t}\n" +
|
||||
"}\n";
|
||||
Class clazz = compiler.compile("a.b","Hello", code);
|
||||
Class clazz = compiler.compile("a.b.Hello", code);
|
||||
Method method = ReflectUtil.getMethods(clazz).stream().filter(m -> m.getName().equals("hello")).findFirst().get();
|
||||
Object instance = clazz.newInstance();
|
||||
method.invoke(instance);
|
||||
@@ -59,7 +60,7 @@ public class AsgcCompilerTest {
|
||||
"\t\tSystem.out.println(\"熊猫正在吃\" + food);\n" +
|
||||
"\t}\n" +
|
||||
"}\n";
|
||||
Class clazz = compiler.compile("a.b","Panda", code);
|
||||
Class clazz = compiler.compile("a.b.Panda", code);
|
||||
Method method = ReflectUtil.getMethods(clazz).stream().filter(m -> m.getName().equals("eat")).findFirst().get();
|
||||
Object instance = clazz.newInstance();
|
||||
method.invoke(instance, "竹子");
|
||||
@@ -76,7 +77,7 @@ public class AsgcCompilerTest {
|
||||
"\t\tSystem.out.println(\"收音机播放\");\n" +
|
||||
"\t}\n" +
|
||||
"}\n";
|
||||
Class clazz = compiler.compile("a.b","RadioPlayer", code);
|
||||
Class clazz = compiler.compile("a.b.RadioPlayer", code);
|
||||
Method method = ReflectUtil.getMethods(clazz).stream().filter(m -> m.getName().equals("play")).findFirst().get();
|
||||
Object instance = clazz.newInstance();
|
||||
method.invoke(instance);
|
||||
@@ -98,12 +99,56 @@ public class AsgcCompilerTest {
|
||||
"\t}\n" +
|
||||
"}\n";
|
||||
// GlobalConfig.setIsSaveGeneratorCode(true);
|
||||
Class clazz = compiler.compile("a.b","RadioPlayer", code);
|
||||
Class clazz = compiler.compile("a.b.RadioPlayer", code);
|
||||
Method method = ReflectUtil.getMethods(clazz).stream().filter(m -> m.getName().equals("play")).findFirst().get();
|
||||
Object instance = clazz.newInstance();
|
||||
method.invoke(instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* jar in jar测试
|
||||
*
|
||||
* 使用jdk1.8跑,tools.jar放在classpath下
|
||||
* 测试jar in jar
|
||||
* jar结构:
|
||||
* asgc-package-lab2.jar
|
||||
* - BOOT-INF/
|
||||
* - classes/fun/asgc/lab/pkg/lab2/
|
||||
* - Console.class
|
||||
* - lib/asgc-package-lab1-1.0-SNAPSHOT.jar
|
||||
* - BOOT-INF/classes/fun/asgc/lab/pkg/lab1/
|
||||
* - Dog.class
|
||||
*/
|
||||
@Test
|
||||
public void compileAndLoadClass5() throws Exception {
|
||||
AsgcCompiler compiler = new AsgcCompiler();
|
||||
compiler.addDependSpringBootJar(AsgcCompilerTest.class.getResource("/asgc-package-lab2.jar").getPath());
|
||||
String code = "package a.b;\n" +
|
||||
"import fun.asgc.lab.pkg.lab2.Console;\n" +
|
||||
"import fun.asgc.lab.pkg.lab1.Dog;\n" +
|
||||
"public class Test {\n" +
|
||||
"\tpublic void execute() {\n" +
|
||||
"\t\tSystem.out.println(\"1122\");\n" +
|
||||
"\t}\n" +
|
||||
"\tpublic void echo(String str){\n" +
|
||||
"\t\tConsole.println(str);\n" +
|
||||
"\t}\n" +
|
||||
"\tpublic String dogEat(String name, String food){\n" +
|
||||
"\t\treturn new Dog(name).eat(food);\n" +
|
||||
"\t}\n" +
|
||||
"}\n";
|
||||
System.out.println(code);
|
||||
Class clazz = compiler.compile("a.b.Test", code);
|
||||
Method executeMethod = ReflectUtil.getMethods(clazz).stream().filter(m -> m.getName().equals("execute")).findFirst().get();
|
||||
Method echoMethod = Stream.of(clazz.getDeclaredMethods()).filter(m -> m.getName().equals("echo")).findFirst().get();
|
||||
Method dogEatMethod = Stream.of(clazz.getDeclaredMethods()).filter(m -> m.getName().equals("dogEat")).findFirst().get();
|
||||
|
||||
Object instance = clazz.newInstance();
|
||||
executeMethod.invoke(instance);
|
||||
echoMethod.invoke(instance, "哈哈哈哈");
|
||||
System.out.println(dogEatMethod.invoke(instance, "大黄", "骨头"));
|
||||
}
|
||||
|
||||
private Object eval(String expression) {
|
||||
String code = "package fun.asgc.test;\n" +
|
||||
"import static java.lang.Math.*;\n" +
|
||||
@@ -114,7 +159,7 @@ public class AsgcCompilerTest {
|
||||
"}\n";
|
||||
AsgcCompiler compiler = new AsgcCompiler();
|
||||
try {
|
||||
Class clazz = compiler.compile( "fun.asgc.test","Calc", code);
|
||||
Class clazz = compiler.compile( "fun.asgc.test.Calc", code);
|
||||
Method method = ReflectUtil.getMethods(clazz).stream().filter(m -> m.getName().equals("invoke")).findFirst().get();
|
||||
return method.invoke(null);
|
||||
} catch (ClassNotFoundException|IllegalAccessException|InvocationTargetException e) {
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package fun.asgc.neutrino.core.base;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2023/3/1
|
||||
*/
|
||||
public class NvMapTest {
|
||||
@Test
|
||||
public void test1() {
|
||||
Object key1 = new Object();
|
||||
NvMap nvMap0 = NvMap.of()
|
||||
.setAlias("app.server.http.http-port", "aaa")
|
||||
;
|
||||
|
||||
NvMap nvMap1 = NvMap.of(nvMap0)
|
||||
.set("app.server.http.http-port", 8080)
|
||||
.set("app.server.http.jks_Path", "/123/456")
|
||||
.set("app.server.websocket.port", "ws-port", 8888) // 设值的同时设置别名
|
||||
.set(key1, 1)
|
||||
.setAlias("app.server.http.http-port", "http-port")
|
||||
;
|
||||
|
||||
|
||||
NvMap nvMap2 = NvMap.of(nvMap1)
|
||||
.set("app.server.http.httpPort", 8081)
|
||||
.set("app.server.http.context-path", "/")
|
||||
;
|
||||
|
||||
NvMap nvMap3 = NvMap.of(nvMap2)
|
||||
.setAlias("app.server.http.http-port", "port")
|
||||
.setAlias("http-port", "p");
|
||||
|
||||
Assert.assertTrue(!nvMap1.isEmpty());
|
||||
Assert.assertTrue(nvMap1.size() == 4);
|
||||
Assert.assertTrue(nvMap1.stackSize() == 4);
|
||||
Assert.assertTrue(nvMap1.get("app.server.http.http-port").equals(8080));
|
||||
Assert.assertTrue(nvMap1.get("app.server.http.httpPort").equals(8080));
|
||||
Assert.assertTrue(nvMap1.idx(0).equals(8080));
|
||||
Assert.assertTrue(nvMap1.get("app.server.http.jks_Path").equals("/123/456"));
|
||||
Assert.assertTrue(nvMap1.get("app.server.http.jksPath").equals("/123/456"));
|
||||
Assert.assertTrue(nvMap1.idx(1).equals("/123/456"));
|
||||
Assert.assertTrue(nvMap1.containsKey("app.server.http.http-port"));
|
||||
Assert.assertTrue(nvMap1.containsKey(key1));
|
||||
Assert.assertFalse(nvMap1.containsKey(new Object()));
|
||||
|
||||
Assert.assertTrue(!nvMap2.isEmpty());
|
||||
Assert.assertTrue(nvMap2.size() == 2);
|
||||
Assert.assertTrue(nvMap2.stackSize() == 6);
|
||||
Assert.assertTrue(nvMap2.get("app.server.http.http-port").equals(8081));
|
||||
Assert.assertTrue(nvMap2.get("app.server.http.httpPort").equals(8081));
|
||||
Assert.assertTrue(nvMap2.get("app.server.http.jks-path") == null);
|
||||
Assert.assertTrue(nvMap2.get("app.server.http.jksPath") == null);
|
||||
Assert.assertTrue(nvMap2.get("app.server.http.context-path").equals("/"));
|
||||
|
||||
Assert.assertTrue(nvMap2.stackGet("app.server.http.jks-path").equals("/123/456"));
|
||||
Assert.assertTrue(nvMap2.stackGet("app.server.http.jksPath").equals("/123/456"));
|
||||
Assert.assertTrue(nvMap2.stackGet("app.server.http.context-path").equals("/"));
|
||||
|
||||
Assert.assertTrue(nvMap3.isEmpty());
|
||||
Assert.assertTrue(!nvMap3.isStackEmpty());
|
||||
Assert.assertTrue(nvMap3.size() == 0);
|
||||
Assert.assertTrue(nvMap3.stackSize() == 6);
|
||||
Assert.assertTrue(nvMap3.get("app.server.http.jks-path") == null);
|
||||
Assert.assertTrue(nvMap3.get("app.server.http.jksPath") == null);
|
||||
Assert.assertTrue(nvMap3.get("app.server.http.context-path") == null);
|
||||
Assert.assertTrue(nvMap3.stackGet("app.server.http.jks-path").equals("/123/456"));
|
||||
Assert.assertTrue(nvMap3.stackGet("app.server.http.jksPath").equals("/123/456"));
|
||||
Assert.assertTrue(nvMap3.stackGet("app.server.http.context-path").equals("/"));
|
||||
|
||||
Assert.assertTrue(nvMap3.stackGetOrDefault("app.server.http.timeout", 60000).equals(60000));
|
||||
|
||||
Assert.assertTrue(nvMap3.takeStr("app.server.http.http-port").equals("8081"));
|
||||
Assert.assertNull(nvMap3.take(null));
|
||||
Assert.assertTrue(nvMap3.takeStr("httpPort").equals("8081"));
|
||||
Assert.assertTrue(nvMap3.takeInt("http-port").equals(8081));
|
||||
Assert.assertTrue(nvMap3.takeInt("port").equals(8081));
|
||||
// 注意:第3层的别名p,指向了第1层的别名http-port
|
||||
Assert.assertTrue(nvMap3.takeInt("p").equals(8081));
|
||||
Assert.assertTrue(nvMap3.takeStr("aaa").equals("8081"));
|
||||
Assert.assertTrue(nvMap3.takeInt("wsPort").equals(8888));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package fun.asgc.neutrino.core.base;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2023/3/6
|
||||
*/
|
||||
public class NvMapsTest {
|
||||
|
||||
/**
|
||||
* 先给电脑设置环境变量,然后重启idea
|
||||
* EUTRINO_PROXY=http-port=6000:app-name=neutrino-proxy-client
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void test1() throws IOException {
|
||||
// 创建NvMaps实例
|
||||
NvMaps nvMaps = NvMaps.of();
|
||||
|
||||
// 阶段1:设置内部默认值
|
||||
nvMaps.setKv("neutrino.application.name", "app-name",null);
|
||||
nvMaps.setKv("neutrino.http.enable", true);
|
||||
nvMaps.setKv("neutrino.http.port", "httpPort",null);
|
||||
nvMaps.setKv("neutrino.http.context-path", "context-path", "/");
|
||||
nvMaps.stageDone();
|
||||
|
||||
// 阶段2:内部配置文件
|
||||
nvMaps.loadFile(NvMapsTest.class.getResource("/application.yml").getPath());
|
||||
nvMaps.stageDone();
|
||||
|
||||
// 阶段3:环境变量
|
||||
nvMaps.loadEnvironmentVariable("NEUTRINO_PROXY");
|
||||
nvMaps.stageDone();
|
||||
|
||||
// 结算4:外部配置文件
|
||||
// nvMaps.loadFile(NvMapsTest.class.getResource("/aaa.json").getPath());
|
||||
nvMaps.loadFile(NvMapsTest.class.getResource("/aaa.properties").getPath());
|
||||
nvMaps.stageDone();
|
||||
|
||||
// 阶段5:启动参数
|
||||
String[] mainArgs = new String[]{
|
||||
"httpPort=8100"
|
||||
};
|
||||
nvMaps.loadMainArgs(mainArgs);
|
||||
nvMaps.stageDone();
|
||||
|
||||
// 获取NvMap实例
|
||||
NvMap nvMap = nvMaps.getNvMap();
|
||||
|
||||
System.out.println(nvMap.takeInt("httpPort"));
|
||||
System.out.println(nvMap.takeInt("neutrino.http.port"));
|
||||
|
||||
System.out.println(nvMap.takeStr("appName"));
|
||||
System.out.println(nvMap.takeStr("neutrino.application.name"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,7 +21,7 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.core.db.dao;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import fun.asgc.neutrino.core.db.annotation.Column;
|
||||
import fun.asgc.neutrino.core.db.annotation.Id;
|
||||
import lombok.Data;
|
||||
@@ -29,6 +29,7 @@ import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.activation.DataSource;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@@ -39,12 +40,12 @@ import java.util.List;
|
||||
* @date: 2022/6/28
|
||||
*/
|
||||
public class DaoTest {
|
||||
private DruidDataSource dataSource;
|
||||
private HikariDataSource dataSource;
|
||||
private DBType dbType;
|
||||
|
||||
{
|
||||
dataSource = new DruidDataSource();
|
||||
dataSource.setUrl("jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8");
|
||||
dataSource = new HikariDataSource();
|
||||
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8");
|
||||
dataSource.setUsername("root");
|
||||
dataSource.setPassword("YWasgc@10520");
|
||||
dbType = DBType.MYSQL;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.core.db.mapper;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import fun.asgc.neutrino.core.annotation.Bean;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Order;
|
||||
@@ -38,8 +38,8 @@ public class Configuration {
|
||||
|
||||
@Bean
|
||||
public JdbcTemplate jdbcTemplate() {
|
||||
DruidDataSource dataSource = new DruidDataSource();
|
||||
dataSource.setUrl("jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8");
|
||||
HikariDataSource dataSource = new HikariDataSource();
|
||||
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8");
|
||||
dataSource.setUsername("root");
|
||||
dataSource.setPassword("YWasgc@10520");
|
||||
return new JdbcTemplate(dataSource);
|
||||
|
||||
+3
-3
@@ -21,7 +21,7 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.core.db.template;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import fun.asgc.neutrino.core.db.annotation.Id;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
@@ -42,8 +42,8 @@ public class JdbcTemplateTestForMySql {
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
{
|
||||
DruidDataSource dataSource = new DruidDataSource();
|
||||
dataSource.setUrl("jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8");
|
||||
HikariDataSource dataSource = new HikariDataSource();
|
||||
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8");
|
||||
dataSource.setUsername("root");
|
||||
dataSource.setPassword("YWasgc@10520");
|
||||
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
|
||||
+3
-4
@@ -21,8 +21,7 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.core.db.template;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import fun.asgc.neutrino.core.db.annotation.Id;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
@@ -41,9 +40,9 @@ public class JdbcTemplateTestForSqlite {
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
{
|
||||
DruidDataSource dataSource = new DruidDataSource();
|
||||
HikariDataSource dataSource = new HikariDataSource();
|
||||
// dataSource.setUrl("jdbc:sqlite:" + JdbcTemplateTestForSqlite.class.getResource("/sqlite.db").getPath());
|
||||
dataSource.setUrl("jdbc:sqlite:../data.db");
|
||||
dataSource.setJdbcUrl("jdbc:sqlite:../data.db");
|
||||
dataSource.setDriverClassName("org.sqlite.JDBC");
|
||||
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"neutrino": {
|
||||
"application": {
|
||||
"name": "test-app"
|
||||
},
|
||||
"http": {
|
||||
"port": 8000
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
#neutrino.application.name=test
|
||||
app-name=test1
|
||||
@@ -62,7 +62,7 @@ You need to install [node](http://nodejs.org/) and [git](https://git-scm.com/) l
|
||||
- Dynamic breadcrumb
|
||||
- I18n
|
||||
- Customizable theme
|
||||
- Tags-view(Tab page Support right-click operation)
|
||||
- Tags-view(Tab pageInfo Support right-click operation)
|
||||
- Rich text editor
|
||||
- Markdown editor
|
||||
- JSON editor
|
||||
@@ -73,7 +73,7 @@ You need to install [node](http://nodejs.org/) and [git](https://git-scm.com/) l
|
||||
- Mock data
|
||||
- Echarts
|
||||
- Clipboard
|
||||
- 401/404 error page
|
||||
- 401/404 error pageInfo
|
||||
- Error log
|
||||
- Export excel
|
||||
- Export zip
|
||||
|
||||
@@ -47,12 +47,12 @@
|
||||
</el-table>
|
||||
<div class="pagination-end" v-if="isPagination">
|
||||
<el-pagination
|
||||
:hide-on-single-page="false"
|
||||
:hide-on-single-pageInfo="false"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="PaginationData.currentPage"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="PaginationData.pageSize"
|
||||
:current-pageInfo="PaginationData.currentPage"
|
||||
:pageInfo-sizes="[10, 20, 50, 100]"
|
||||
:pageInfo-size="PaginationData.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="PaginationData.total"
|
||||
>
|
||||
|
||||
@@ -26,7 +26,7 @@ export default {
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: '380px'
|
||||
default: '450px'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
<template>
|
||||
<scroll-bar>
|
||||
<div class="log-div">
|
||||
<div class="log-max-div" v-if="sidebar.opened">
|
||||
<img :src="logCross"/>
|
||||
</div>
|
||||
<div class="log-mini-div" v-else>
|
||||
<img :src="logMini">
|
||||
</div>
|
||||
<el-menu mode="vertical" :default-active="$route.path" :collapse="isCollapse" background-color="#304156" text-color="#bfcbd9" active-text-color="#409EFF">
|
||||
<sidebar-item :routes="permission_routers"></sidebar-item>
|
||||
</el-menu>
|
||||
@@ -14,6 +17,7 @@ import { mapGetters } from 'vuex'
|
||||
import SidebarItem from './SidebarItem'
|
||||
import ScrollBar from '@/components/ScrollBar'
|
||||
import logCross from '@/assets/logo/logo-text-cross.svg'
|
||||
import logMini from '@/assets/logo/logo.svg'
|
||||
|
||||
export default {
|
||||
components: { SidebarItem, ScrollBar },
|
||||
@@ -28,17 +32,26 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
logCross
|
||||
logCross,
|
||||
logMini
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.log-div{
|
||||
.log-max-div{
|
||||
padding: 10px 0 5px 15px;
|
||||
img{
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
.log-mini-div{
|
||||
text-align: center;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 10px;
|
||||
img{
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination-container">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="listQuery.currentPage"
|
||||
:page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-pageInfo.sync="listQuery.currentPage"
|
||||
:pageInfo-sizes="[10,20,30, 50]" :pageInfo-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
@@ -124,16 +124,16 @@ export default {
|
||||
})
|
||||
},
|
||||
handleFilter() {
|
||||
this.listQuery.currentPage = 1
|
||||
this.listQuery.current = 1
|
||||
this.getList()
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.listQuery.pageSize = val
|
||||
this.listQuery.currentPage = 1
|
||||
this.listQuery.size = val
|
||||
this.listQuery.current = 1
|
||||
this.getList()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.listQuery.currentPage = val
|
||||
this.listQuery.current = val
|
||||
this.getList()
|
||||
},
|
||||
handleLookOver(row) {
|
||||
|
||||
@@ -46,8 +46,8 @@
|
||||
</el-table-column>-->
|
||||
</el-table>
|
||||
<div class="pagination-container">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="listQuery.currentPage"
|
||||
:page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-pageInfo.sync="listQuery.currentPage"
|
||||
:pageInfo-sizes="[10,20,30, 50]" :pageInfo-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
@@ -148,16 +148,16 @@ export default {
|
||||
})
|
||||
},
|
||||
handleFilter() {
|
||||
this.listQuery.currentPage = 1
|
||||
this.listQuery.current = 1
|
||||
this.getList()
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.listQuery.pageSize = val
|
||||
this.listQuery.currentPage = 1
|
||||
this.listQuery.size = val
|
||||
this.listQuery.current = 1
|
||||
this.getList()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.listQuery.currentPage = val
|
||||
this.listQuery.current = val
|
||||
this.getList()
|
||||
},
|
||||
handleShowClick(row) {
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination-container">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="listQuery.currentPage"
|
||||
:page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-pageInfo.sync="listQuery.currentPage"
|
||||
:pageInfo-sizes="[10,20,30, 50]" :pageInfo-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
@@ -116,16 +116,16 @@ export default {
|
||||
})
|
||||
},
|
||||
handleFilter() {
|
||||
this.listQuery.currentPage = 1
|
||||
this.listQuery.current = 1
|
||||
this.getList()
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.listQuery.pageSize = val
|
||||
this.listQuery.currentPage = 1
|
||||
this.listQuery.size = val
|
||||
this.listQuery.current = 1
|
||||
this.getList()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.listQuery.currentPage = val
|
||||
this.listQuery.current = val
|
||||
this.getList()
|
||||
},
|
||||
handleShowClick(row) {
|
||||
|
||||
@@ -60,8 +60,8 @@
|
||||
</el-table>
|
||||
|
||||
<div class="pagination-container">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="listQuery.currentPage"
|
||||
:page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-pageInfo.sync="listQuery.currentPage"
|
||||
:pageInfo-sizes="[10,20,30, 50]" :pageInfo-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
@@ -213,15 +213,15 @@
|
||||
})
|
||||
},
|
||||
handleFilter() {
|
||||
this.listQuery.currentPage = 1
|
||||
this.listQuery.current = 1
|
||||
this.getList()
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.listQuery.pageSize = val
|
||||
this.listQuery.size = val
|
||||
this.getList()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.listQuery.currentPage = val
|
||||
this.listQuery.current = val
|
||||
this.getList()
|
||||
},
|
||||
handleModifyStatus(row, enable) {
|
||||
|
||||
@@ -65,8 +65,8 @@
|
||||
</el-table>
|
||||
|
||||
<div class="pagination-container">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="listQuery.currentPage"
|
||||
:page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-pageInfo.sync="listQuery.currentPage"
|
||||
:pageInfo-sizes="[10,20,30, 50]" :pageInfo-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
@@ -264,15 +264,15 @@
|
||||
})
|
||||
},
|
||||
handleFilter() {
|
||||
this.listQuery.currentPage = 1
|
||||
this.listQuery.current = 1
|
||||
this.getList()
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.listQuery.pageSize = val
|
||||
this.listQuery.size = val
|
||||
this.getList()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.listQuery.currentPage = val
|
||||
this.listQuery.current = val
|
||||
this.getList()
|
||||
},
|
||||
handleModifyStatus(row, enable) {
|
||||
|
||||
@@ -51,8 +51,8 @@
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination-container">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="listQuery.currentPage"
|
||||
:page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-pageInfo.sync="listQuery.currentPage"
|
||||
:pageInfo-sizes="[10,20,30, 50]" :pageInfo-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
@@ -171,15 +171,15 @@
|
||||
})
|
||||
},
|
||||
handleFilter() {
|
||||
this.listQuery.currentPage = 1
|
||||
this.listQuery.current = 1
|
||||
this.getList()
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.listQuery.pageSize = val
|
||||
this.listQuery.size = val
|
||||
this.getList()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.listQuery.currentPage = val
|
||||
this.listQuery.current = val
|
||||
this.getList()
|
||||
},
|
||||
handleModifyStatus(row, enable) {
|
||||
|
||||
@@ -43,8 +43,8 @@
|
||||
</el-table>
|
||||
|
||||
<div class="pagination-container">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="listQuery.currentPage"
|
||||
:page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-pageInfo.sync="listQuery.currentPage"
|
||||
:pageInfo-sizes="[10,20,30, 50]" :pageInfo-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
@@ -173,15 +173,15 @@
|
||||
})
|
||||
},
|
||||
handleFilter() {
|
||||
this.listQuery.currentPage = 1
|
||||
this.listQuery.current = 1
|
||||
this.getList()
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.listQuery.pageSize = val
|
||||
this.listQuery.size = val
|
||||
this.getList()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.listQuery.currentPage = val
|
||||
this.listQuery.current = val
|
||||
this.getList()
|
||||
},
|
||||
handleModifyStatus(row, enable) {
|
||||
|
||||
@@ -50,8 +50,8 @@
|
||||
</el-table>
|
||||
|
||||
<div class="pagination-container">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="listQuery.currentPage"
|
||||
:page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-pageInfo.sync="listQuery.currentPage"
|
||||
:pageInfo-sizes="[10,20,30, 50]" :pageInfo-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
@@ -197,15 +197,15 @@
|
||||
})
|
||||
},
|
||||
handleFilter() {
|
||||
this.listQuery.currentPage = 1
|
||||
this.listQuery.current = 1
|
||||
this.getList()
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.listQuery.pageSize = val
|
||||
this.listQuery.size = val
|
||||
this.getList()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.listQuery.currentPage = val
|
||||
this.listQuery.current = val
|
||||
this.getList()
|
||||
},
|
||||
handleModifyStatus(row, enable) {
|
||||
|
||||
@@ -14,11 +14,20 @@
|
||||
<artifactId>neutrino-proxy-client</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>fun.asgc.neutrino</groupId>-->
|
||||
<!-- <artifactId>neutrino-core</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>fun.asgc.neutrino</groupId>
|
||||
<artifactId>neutrino-proxy-core</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.noear</groupId>
|
||||
<artifactId>solon-lib</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<!-- <build>-->
|
||||
|
||||
+24
-26
@@ -1,40 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package fun.asgc.neutrino.proxy.client;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.NeutrinoApplication;
|
||||
import fun.asgc.neutrino.core.context.NeutrinoLauncher;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import org.noear.solon.Solon;
|
||||
import org.noear.solon.SolonApp;
|
||||
import org.noear.solon.annotation.SolonMain;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@NeutrinoApplication
|
||||
@SolonMain
|
||||
public class ProxyClient {
|
||||
|
||||
public static void main(String[] args) {
|
||||
NeutrinoLauncher.run(ProxyClient.class, args);
|
||||
Solon.start(ProxyClient.class, args, app -> {
|
||||
setAlias("neutrino.proxy.client.serverIp", "serverIp");
|
||||
setAlias("neutrino.proxy.client.serverPort", "serverPort");
|
||||
setAlias("neutrino.proxy.client.sslEnable", "sslEnable");
|
||||
setAlias("neutrino.proxy.client.jksPath", "jksPath");
|
||||
setAlias("neutrino.proxy.client.keyStorePassword", "keyStorePassword");
|
||||
setAlias("neutrino.proxy.client.licenseKey", "licenseKey");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 别名处理,支持较短的启动参数名
|
||||
* @param key
|
||||
* @param alias
|
||||
*/
|
||||
private static void setAlias(String key, String alias) {
|
||||
String val = Solon.cfg().argx().get(alias);
|
||||
if (StrUtil.isNotBlank(val)) {
|
||||
Solon.cfg().put(key, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-49
@@ -1,31 +1,8 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package fun.asgc.neutrino.proxy.client.config;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Configuration;
|
||||
import fun.asgc.neutrino.core.annotation.Init;
|
||||
import fun.asgc.neutrino.core.annotation.Value;
|
||||
import lombok.Data;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -33,53 +10,33 @@ import lombok.Data;
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@Data
|
||||
@Configuration(prefix = "neutrino.proxy")
|
||||
@Component
|
||||
public class ProxyConfig {
|
||||
public static ProxyConfig instance;
|
||||
@Inject("${neutrino.proxy.protocol}")
|
||||
private Protocol protocol;
|
||||
@Inject("${neutrino.proxy.client}")
|
||||
private Client client;
|
||||
private String licenseKey;
|
||||
private CustomConfig customConfig;
|
||||
public static volatile boolean authSuccess;
|
||||
|
||||
@Data
|
||||
public static class Protocol {
|
||||
@Value("max-frame-length")
|
||||
private Integer maxFrameLength;
|
||||
@Value("length-field-offset")
|
||||
private Integer lengthFieldOffset;
|
||||
@Value("length-field-length")
|
||||
private Integer lengthFieldLength;
|
||||
@Value("initial-bytes-to-strip")
|
||||
private Integer initialBytesToStrip;
|
||||
@Value("length-adjustment")
|
||||
private Integer lengthAdjustment;
|
||||
@Value("read-idle-time")
|
||||
private Integer readIdleTime;
|
||||
@Value("write-idle-time")
|
||||
private Integer writeIdleTime;
|
||||
@Value("all-idle-time-seconds")
|
||||
private Integer allIdleTimeSeconds;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Client {
|
||||
@Value("key-store-password")
|
||||
private String keyStorePassword;
|
||||
@Value("jks-path")
|
||||
private String jksPath;
|
||||
@Value("server-ip")
|
||||
private String serverIp;
|
||||
@Value("server-port")
|
||||
private Integer serverPort;
|
||||
@Value("ssl-enable")
|
||||
private Boolean sslEnable;
|
||||
@Value("obtain-license-interval")
|
||||
private Integer obtainLicenseInterval;
|
||||
}
|
||||
|
||||
@Init
|
||||
public void init() {
|
||||
instance = this;
|
||||
private String licenseKey;
|
||||
}
|
||||
}
|
||||
|
||||
+30
-36
@@ -1,51 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.client.config;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Bean;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Order;
|
||||
import fun.asgc.neutrino.core.base.DefaultDispatcher;
|
||||
import fun.asgc.neutrino.core.base.Dispatcher;
|
||||
import fun.asgc.neutrino.core.base.Ordered;
|
||||
import fun.asgc.neutrino.core.util.BeanManager;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyDataTypeEnum;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessage;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessageHandler;
|
||||
import fun.asgc.neutrino.proxy.core.dispatcher.DefaultDispatcher;
|
||||
import fun.asgc.neutrino.proxy.core.dispatcher.Dispatcher;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import org.noear.solon.Solon;
|
||||
import org.noear.solon.annotation.Bean;
|
||||
import org.noear.solon.annotation.Configuration;
|
||||
import org.noear.solon.core.bean.LifecycleBean;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 代理配置
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/8
|
||||
*/
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
@Component
|
||||
public class ProxyConfiguration {
|
||||
@Configuration
|
||||
public class ProxyConfiguration implements LifecycleBean {
|
||||
|
||||
@Bean
|
||||
public Dispatcher<ChannelHandlerContext, ProxyMessage> dispatcher() {
|
||||
return new DefaultDispatcher<>("消息调度器",
|
||||
BeanManager.getBeanListBySuperClass(ProxyMessageHandler.class),
|
||||
proxyMessage -> ProxyDataTypeEnum.of((int)proxyMessage.getType()) == null ? null : ProxyDataTypeEnum.of((int)proxyMessage.getType()).getName());
|
||||
@Override
|
||||
public void start() throws Throwable {
|
||||
List<ProxyMessageHandler> list = Solon.context().getBeansOfType(ProxyMessageHandler.class);
|
||||
Dispatcher<ChannelHandlerContext, ProxyMessage> dispatcher = new DefaultDispatcher<>("消息调度器", list,
|
||||
proxyMessage -> ProxyDataTypeEnum.of((int)proxyMessage.getType()) == null ?
|
||||
null : ProxyDataTypeEnum.of((int)proxyMessage.getType()).getName());
|
||||
Solon.context().wrapAndPut(Dispatcher.class, dispatcher);
|
||||
}
|
||||
|
||||
@Bean("bootstrap")
|
||||
public Bootstrap bootstrap() {
|
||||
return new Bootstrap();
|
||||
}
|
||||
|
||||
@Bean("realServerBootstrap")
|
||||
public Bootstrap realServerBootstrap() {
|
||||
return new Bootstrap();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+55
-55
@@ -1,55 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.client.core;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.annotation.Subscribe;
|
||||
import fun.asgc.neutrino.core.base.event.ApplicationEvent;
|
||||
import fun.asgc.neutrino.core.base.event.ApplicationEventReceiver;
|
||||
import fun.asgc.neutrino.core.constant.AppLifeCycleStatusEnum;
|
||||
import fun.asgc.neutrino.core.constant.MetaDataConstant;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 应用生命周期事件监听器
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/10
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
@Subscribe(topic = MetaDataConstant.TOPIC_APP_LIFE_CYCLE)
|
||||
public class ApplicationLifeCycleListener extends ApplicationEventReceiver<AppLifeCycleStatusEnum> {
|
||||
@Autowired
|
||||
private LicenseObtainService licenseObtainService;
|
||||
|
||||
@Override
|
||||
public void receive(ApplicationEvent<AppLifeCycleStatusEnum> msg) {
|
||||
log.debug("ApplicationLifeCycleListener:{}", msg.data().getDesc());
|
||||
if (msg.data() == AppLifeCycleStatusEnum.APP_STARTUP) {
|
||||
licenseObtainService.start();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
///**
|
||||
// * Copyright (c) 2022 aoshiguchen
|
||||
// *
|
||||
// * Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// * of this software and associated documentation files (the "Software"), to deal
|
||||
// * in the Software without restriction, including without limitation the rights
|
||||
// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// * copies of the Software, and to permit persons to whom the Software is
|
||||
// * furnished to do so, subject to the following conditions:
|
||||
// *
|
||||
// * The above copyright notice and this permission notice shall be included in all
|
||||
// * copies or substantial portions of the Software.
|
||||
// *
|
||||
// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// * SOFTWARE.
|
||||
// */
|
||||
//package fun.asgc.neutrino.proxy.client.core;
|
||||
//
|
||||
//import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
//import fun.asgc.neutrino.core.annotation.Component;
|
||||
//import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
//import fun.asgc.neutrino.core.annotation.Subscribe;
|
||||
//import fun.asgc.neutrino.core.base.event.ApplicationEvent;
|
||||
//import fun.asgc.neutrino.core.base.event.ApplicationEventReceiver;
|
||||
//import fun.asgc.neutrino.core.constant.AppLifeCycleStatusEnum;
|
||||
//import fun.asgc.neutrino.core.constant.MetaDataConstant;
|
||||
//import lombok.extern.slf4j.Slf4j;
|
||||
//
|
||||
///**
|
||||
// * 应用生命周期事件监听器
|
||||
// * @author: aoshiguchen
|
||||
// * @date: 2022/10/10
|
||||
// */
|
||||
//@Slf4j
|
||||
//@NonIntercept
|
||||
//@Component
|
||||
//@Subscribe(topic = MetaDataConstant.TOPIC_APP_LIFE_CYCLE)
|
||||
//public class ApplicationLifeCycleListener extends ApplicationEventReceiver<AppLifeCycleStatusEnum> {
|
||||
// @Autowired
|
||||
// private LicenseObtainService licenseObtainService;
|
||||
//
|
||||
// @Override
|
||||
// public void receive(ApplicationEvent<AppLifeCycleStatusEnum> msg) {
|
||||
// log.debug("ApplicationLifeCycleListener:{}", msg.data().getDesc());
|
||||
// if (msg.data() == AppLifeCycleStatusEnum.APP_STARTUP) {
|
||||
// licenseObtainService.start();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
||||
+3
-31
@@ -1,38 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package fun.asgc.neutrino.proxy.client.core;
|
||||
|
||||
import fun.asgc.neutrino.core.base.Dispatcher;
|
||||
import fun.asgc.neutrino.core.util.BeanManager;
|
||||
import fun.asgc.neutrino.proxy.client.util.ProxyUtil;
|
||||
import fun.asgc.neutrino.proxy.core.Constants;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessage;
|
||||
import fun.asgc.neutrino.proxy.core.dispatcher.Dispatcher;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.timeout.IdleStateEvent;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.noear.solon.Solon;
|
||||
|
||||
/**
|
||||
* 处理与服务端之间的数据传输
|
||||
@@ -42,19 +20,13 @@ import lombok.extern.slf4j.Slf4j;
|
||||
@Slf4j
|
||||
public class ClientChannelHandler extends SimpleChannelInboundHandler<ProxyMessage> {
|
||||
|
||||
private static volatile Dispatcher<ChannelHandlerContext, ProxyMessage> dispatcher;
|
||||
|
||||
|
||||
public ClientChannelHandler() {
|
||||
dispatcher = BeanManager.getBean(Dispatcher.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, ProxyMessage proxyMessage) throws Exception {
|
||||
if (ProxyMessage.TYPE_HEARTBEAT != proxyMessage.getType()) {
|
||||
log.info("recieved proxy message, type is {}", proxyMessage.getType());
|
||||
}
|
||||
dispatcher.dispatch(ctx, proxyMessage);
|
||||
Solon.context().getBean(Dispatcher.class).dispatch(ctx, proxyMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+25
-20
@@ -19,32 +19,37 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.base.rest.config;
|
||||
package fun.asgc.neutrino.proxy.client.core;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Bean;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.quartz.JobExecutor;
|
||||
import fun.asgc.neutrino.proxy.server.service.JobInfoService;
|
||||
import fun.asgc.neutrino.proxy.server.service.JobLogService;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* 定时任务配置
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/9/4
|
||||
*/
|
||||
@Component
|
||||
public class JobConfig {
|
||||
@Autowired
|
||||
private JobLogService jobLogService;
|
||||
@Autowired
|
||||
private JobInfoService jobInfoService;
|
||||
public class CustomThreadFactory implements ThreadFactory {
|
||||
private final ThreadGroup group;
|
||||
private final AtomicInteger threadNumber = new AtomicInteger(1);
|
||||
private final String namePrefix;
|
||||
|
||||
@Bean
|
||||
public JobExecutor jobExecutor() {
|
||||
JobExecutor executor = new JobExecutor();
|
||||
executor.setJobSource(jobInfoService);
|
||||
executor.setJobCallback(jobLogService);
|
||||
return executor;
|
||||
public CustomThreadFactory(String prefix) {
|
||||
SecurityManager s = System.getSecurityManager();
|
||||
group = (s != null) ? s.getThreadGroup() :
|
||||
Thread.currentThread().getThreadGroup();
|
||||
namePrefix = prefix + "-thread-";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
|
||||
if (t.isDaemon()) {
|
||||
t.setDaemon(false);
|
||||
}
|
||||
if (t.getPriority() != Thread.NORM_PRIORITY) {
|
||||
t.setPriority(Thread.NORM_PRIORITY);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
}
|
||||
+166
-175
@@ -1,175 +1,166 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.client.core;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.base.CustomThreadFactory;
|
||||
import fun.asgc.neutrino.core.context.Environment;
|
||||
import fun.asgc.neutrino.core.util.ArrayUtil;
|
||||
import fun.asgc.neutrino.core.util.FileUtil;
|
||||
import fun.asgc.neutrino.core.util.StringUtil;
|
||||
import fun.asgc.neutrino.proxy.client.config.CustomConfig;
|
||||
import fun.asgc.neutrino.proxy.client.config.ProxyConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Scanner;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* license获取服务
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/9/4
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
public class LicenseObtainService {
|
||||
@Autowired
|
||||
private ProxyConfig proxyConfig;
|
||||
/**
|
||||
* 调度器
|
||||
*/
|
||||
private static final ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor(new CustomThreadFactory("LicenseObtain"));
|
||||
|
||||
@Autowired
|
||||
private ProxyClientService proxyClientService;
|
||||
private ReentrantLock runLock = new ReentrantLock();
|
||||
private Scanner scanner = new Scanner(System.in);
|
||||
@Autowired
|
||||
private Environment environment;
|
||||
|
||||
public void start() {
|
||||
scheduledExecutor.scheduleWithFixedDelay(() -> {
|
||||
boolean lock = runLock.tryLock();
|
||||
try {
|
||||
if (lock) {
|
||||
this.process(this.environment.getMainArgs());
|
||||
}
|
||||
} finally {
|
||||
if (runLock.isHeldByCurrentThread()){
|
||||
runLock.unlock();
|
||||
}
|
||||
}
|
||||
}, 0, proxyConfig.getClient().getObtainLicenseInterval(), TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
scheduledExecutor.shutdown();
|
||||
log.info("licenseKey获取任务停止");
|
||||
}
|
||||
|
||||
public void process(String[] args) {
|
||||
CustomConfig customConfig = getCustomConfigByCliParams(args);
|
||||
proxyConfig.getClient().setJksPath(customConfig.getJksPath());
|
||||
proxyConfig.getClient().setServerIp(customConfig.getServerIp());
|
||||
proxyConfig.getClient().setServerPort(customConfig.getServerPort());
|
||||
proxyConfig.getClient().setSslEnable(customConfig.getSslEnable());
|
||||
proxyConfig.setLicenseKey(customConfig.getLicenseKey());
|
||||
proxyConfig.setCustomConfig(customConfig);
|
||||
proxyClientService.start();
|
||||
}
|
||||
|
||||
private CustomConfig getCustomConfigByCliParams(String[] args) {
|
||||
CustomConfig customConfig = new CustomConfig();
|
||||
// 默认无需输入
|
||||
customConfig.setJksPath(environment.getMainArgsForString("jksPath", proxyConfig.getClient().getJksPath()));
|
||||
customConfig.setServerIp(environment.getMainArgsForString("serverIp", proxyConfig.getClient().getServerIp()));
|
||||
customConfig.setServerPort(environment.getMainArgsForInteger("serverPort", proxyConfig.getClient().getServerPort()));
|
||||
customConfig.setSslEnable(environment.getMainArgsForBoolean("sslEnable", proxyConfig.getClient().getSslEnable()));
|
||||
customConfig.setLicenseKey(environment.getMainArgsForString("licenseKey"));
|
||||
// 启动参数指定了license,则无需后续处理
|
||||
if (StringUtil.notEmpty(customConfig.getLicenseKey())) {
|
||||
// FileUtil.write("./.neutrino-proxy-client.json", JSONObject.toJSONString(customConfig, SerializerFeature.PrettyFormat));
|
||||
return customConfig;
|
||||
}
|
||||
|
||||
// 启动参数未指定license,则优先读取外部配置
|
||||
String config = FileUtil.readContentAsString("./.neutrino-proxy-client.json");
|
||||
if (StringUtil.notEmpty(config)) {
|
||||
try {
|
||||
CustomConfig tmp = JSONObject.parseObject(config, CustomConfig.class);
|
||||
if (!StringUtil.isEmpty(tmp.getJksPath())) {
|
||||
customConfig.setJksPath(tmp.getJksPath());
|
||||
}
|
||||
if (!StringUtil.isEmpty(tmp.getServerIp())) {
|
||||
customConfig.setServerIp(tmp.getServerIp());
|
||||
}
|
||||
if (null != tmp.getServerPort()) {
|
||||
customConfig.setServerPort(tmp.getServerPort());
|
||||
}
|
||||
if (null != tmp.getSslEnable()) {
|
||||
customConfig.setSslEnable(tmp.getSslEnable());
|
||||
}
|
||||
if (!StringUtil.isEmpty(tmp.getLicenseKey())) {
|
||||
customConfig.setLicenseKey(tmp.getLicenseKey());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("file '.neutrino-proxy-client.json' config exception!", e);
|
||||
}
|
||||
if (StringUtil.notEmpty(customConfig.getLicenseKey())) {
|
||||
// FileUtil.write("./.neutrino-proxy-client.json", JSONObject.toJSONString(customConfig, SerializerFeature.PrettyFormat));
|
||||
return customConfig;
|
||||
}
|
||||
}
|
||||
|
||||
String license = "";
|
||||
while (StringUtil.isEmpty(license)) {
|
||||
System.out.print("Please input license:");
|
||||
license = scanner.next();
|
||||
}
|
||||
customConfig.setLicenseKey(license);
|
||||
// FileUtil.write("./.neutrino-proxy-client.json", JSONObject.toJSONString(customConfig, SerializerFeature.PrettyFormat));
|
||||
|
||||
return customConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取命令行参数
|
||||
* @param args
|
||||
* @return
|
||||
*/
|
||||
private Map<String, String> getCliParams(String[] args) {
|
||||
Map<String, String> res = new HashMap<>();
|
||||
if (ArrayUtil.notEmpty(args)) {
|
||||
for (String item : args) {
|
||||
if (StringUtil.isEmpty(item) || !item.contains("=")) {
|
||||
continue;
|
||||
}
|
||||
int index = item.indexOf("=");
|
||||
if (index <= 0 || index == item.length() - 1) {
|
||||
continue;
|
||||
}
|
||||
res.put(item.substring(0, index), item.substring(index + 1));
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
///**
|
||||
// * Copyright (c) 2022 aoshiguchen
|
||||
// *
|
||||
// * Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// * of this software and associated documentation files (the "Software"), to deal
|
||||
// * in the Software without restriction, including without limitation the rights
|
||||
// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// * copies of the Software, and to permit persons to whom the Software is
|
||||
// * furnished to do so, subject to the following conditions:
|
||||
// *
|
||||
// * The above copyright notice and this permission notice shall be included in all
|
||||
// * copies or substantial portions of the Software.
|
||||
// *
|
||||
// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// * SOFTWARE.
|
||||
// */
|
||||
//package fun.asgc.neutrino.proxy.client.core;
|
||||
//
|
||||
//import com.alibaba.fastjson.JSONObject;
|
||||
//import fun.asgc.neutrino.core.base.CustomThreadFactory;
|
||||
//import fun.asgc.neutrino.core.util.ArrayUtil;
|
||||
//import fun.asgc.neutrino.core.util.FileUtil;
|
||||
//import fun.asgc.neutrino.core.util.StringUtil;
|
||||
//import fun.asgc.neutrino.proxy.client.config.CustomConfig;
|
||||
//import fun.asgc.neutrino.proxy.client.config.ProxyConfig;
|
||||
//import lombok.extern.slf4j.Slf4j;
|
||||
//import org.noear.solon.annotation.Component;
|
||||
//import org.noear.solon.annotation.Inject;
|
||||
//
|
||||
//import java.util.HashMap;
|
||||
//import java.util.Map;
|
||||
//import java.util.Scanner;
|
||||
//import java.util.concurrent.Executors;
|
||||
//import java.util.concurrent.ScheduledExecutorService;
|
||||
//import java.util.concurrent.TimeUnit;
|
||||
//import java.util.concurrent.locks.ReentrantLock;
|
||||
//
|
||||
///**
|
||||
// * license获取服务
|
||||
// * @author: aoshiguchen
|
||||
// * @date: 2022/9/4
|
||||
// */
|
||||
//@Slf4j
|
||||
//@Component
|
||||
//public class LicenseObtainService {
|
||||
// /**
|
||||
// * 调度器
|
||||
// */
|
||||
// private static final ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor(new CustomThreadFactory("LicenseObtain"));
|
||||
// private ReentrantLock runLock = new ReentrantLock();
|
||||
// private Scanner scanner = new Scanner(System.in);
|
||||
// @Inject
|
||||
// private ProxyConfig proxyConfig;
|
||||
// @Inject
|
||||
// private ProxyClientService proxyClientService;
|
||||
//
|
||||
// public void start() {
|
||||
// scheduledExecutor.scheduleWithFixedDelay(() -> {
|
||||
// boolean lock = runLock.tryLock();
|
||||
// try {
|
||||
// if (lock) {
|
||||
// this.process();
|
||||
// }
|
||||
// } finally {
|
||||
// if (runLock.isHeldByCurrentThread()){
|
||||
// runLock.unlock();
|
||||
// }
|
||||
// }
|
||||
// }, 0, proxyConfig.getClient().getObtainLicenseInterval(), TimeUnit.SECONDS);
|
||||
// }
|
||||
//
|
||||
// public void stop() {
|
||||
// scheduledExecutor.shutdown();
|
||||
// log.info("licenseKey获取任务停止");
|
||||
// }
|
||||
//
|
||||
// public void process() {
|
||||
//
|
||||
//
|
||||
// proxyClientService.start();
|
||||
// }
|
||||
//
|
||||
// private String
|
||||
//
|
||||
// private CustomConfig getCustomConfigByCliParams() {
|
||||
// CustomConfig customConfig = new CustomConfig();
|
||||
// // 默认无需输入
|
||||
// customConfig.setJksPath(environment.getMainArgsForString("jksPath", proxyConfig.getClient().getJksPath()));
|
||||
// customConfig.setServerIp(environment.getMainArgsForString("serverIp", proxyConfig.getClient().getServerIp()));
|
||||
// customConfig.setServerPort(environment.getMainArgsForInteger("serverPort", proxyConfig.getClient().getServerPort()));
|
||||
// customConfig.setSslEnable(environment.getMainArgsForBoolean("sslEnable", proxyConfig.getClient().getSslEnable()));
|
||||
// customConfig.setLicenseKey(environment.getMainArgsForString("licenseKey"));
|
||||
// // 启动参数指定了license,则无需后续处理
|
||||
// if (StringUtil.notEmpty(customConfig.getLicenseKey())) {
|
||||
//// FileUtil.write("./.neutrino-proxy-client.json", JSONObject.toJSONString(customConfig, SerializerFeature.PrettyFormat));
|
||||
// return customConfig;
|
||||
// }
|
||||
//
|
||||
// // 启动参数未指定license,则优先读取外部配置
|
||||
// String config = FileUtil.readContentAsString("./.neutrino-proxy-client.json");
|
||||
// if (StringUtil.notEmpty(config)) {
|
||||
// try {
|
||||
// CustomConfig tmp = JSONObject.parseObject(config, CustomConfig.class);
|
||||
// if (!StringUtil.isEmpty(tmp.getJksPath())) {
|
||||
// customConfig.setJksPath(tmp.getJksPath());
|
||||
// }
|
||||
// if (!StringUtil.isEmpty(tmp.getServerIp())) {
|
||||
// customConfig.setServerIp(tmp.getServerIp());
|
||||
// }
|
||||
// if (null != tmp.getServerPort()) {
|
||||
// customConfig.setServerPort(tmp.getServerPort());
|
||||
// }
|
||||
// if (null != tmp.getSslEnable()) {
|
||||
// customConfig.setSslEnable(tmp.getSslEnable());
|
||||
// }
|
||||
// if (!StringUtil.isEmpty(tmp.getLicenseKey())) {
|
||||
// customConfig.setLicenseKey(tmp.getLicenseKey());
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// log.error("file '.neutrino-proxy-client.json' config exception!", e);
|
||||
// }
|
||||
// if (StringUtil.notEmpty(customConfig.getLicenseKey())) {
|
||||
//// FileUtil.write("./.neutrino-proxy-client.json", JSONObject.toJSONString(customConfig, SerializerFeature.PrettyFormat));
|
||||
// return customConfig;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// String license = "";
|
||||
// while (StringUtil.isEmpty(license)) {
|
||||
// System.out.print("Please input license:");
|
||||
// license = scanner.next();
|
||||
// }
|
||||
// customConfig.setLicenseKey(license);
|
||||
//// FileUtil.write("./.neutrino-proxy-client.json", JSONObject.toJSONString(customConfig, SerializerFeature.PrettyFormat));
|
||||
//
|
||||
// return customConfig;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 获取命令行参数
|
||||
// * @param args
|
||||
// * @return
|
||||
// */
|
||||
// private Map<String, String> getCliParams(String[] args) {
|
||||
// Map<String, String> res = new HashMap<>();
|
||||
// if (ArrayUtil.notEmpty(args)) {
|
||||
// for (String item : args) {
|
||||
// if (StringUtil.isEmpty(item) || !item.contains("=")) {
|
||||
// continue;
|
||||
// }
|
||||
// int index = item.indexOf("=");
|
||||
// if (index <= 0 || index == item.length() - 1) {
|
||||
// continue;
|
||||
// }
|
||||
// res.put(item.substring(0, index), item.substring(index + 1));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return res;
|
||||
// }
|
||||
//}
|
||||
|
||||
+35
-51
@@ -1,37 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package fun.asgc.neutrino.proxy.client.core;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.*;
|
||||
import fun.asgc.neutrino.core.base.CustomThreadFactory;
|
||||
import fun.asgc.neutrino.core.context.Environment;
|
||||
import fun.asgc.neutrino.core.util.FileUtil;
|
||||
import fun.asgc.neutrino.core.util.StringUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import fun.asgc.neutrino.proxy.client.config.ProxyConfig;
|
||||
import fun.asgc.neutrino.proxy.client.util.ProxyUtil;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessage;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessageDecoder;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessageEncoder;
|
||||
import fun.asgc.neutrino.proxy.core.util.FileUtil;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
@@ -40,6 +15,10 @@ import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
import io.netty.handler.timeout.IdleStateHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.noear.solon.Solon;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Init;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
@@ -57,18 +36,14 @@ import java.util.concurrent.TimeUnit;
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
public class ProxyClientService {
|
||||
@Autowired
|
||||
@Inject
|
||||
private ProxyConfig proxyConfig;
|
||||
@Autowired("bootstrap")
|
||||
private static Bootstrap bootstrap;
|
||||
@Autowired("realServerBootstrap")
|
||||
private static Bootstrap realServerBootstrap;
|
||||
private static NioEventLoopGroup workerGroup;
|
||||
@Autowired
|
||||
private Environment environment;
|
||||
@Inject("bootstrap")
|
||||
private Bootstrap bootstrap;
|
||||
@Inject("realServerBootstrap")
|
||||
private Bootstrap realServerBootstrap;
|
||||
private volatile Channel channel;
|
||||
/**
|
||||
* 重连间隔(秒)
|
||||
@@ -91,7 +66,7 @@ public class ProxyClientService {
|
||||
public void init() {
|
||||
this.reconnectExecutor.scheduleWithFixedDelay(this::reconnect, 0, RECONNECT_INTERVAL_SECONDS, TimeUnit.SECONDS);
|
||||
|
||||
workerGroup = new NioEventLoopGroup();
|
||||
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
realServerBootstrap.group(workerGroup);
|
||||
realServerBootstrap.channel(NioSocketChannel.class);
|
||||
realServerBootstrap.handler(new ChannelInitializer<SocketChannel>() {
|
||||
@@ -120,20 +95,39 @@ public class ProxyClientService {
|
||||
ch.pipeline().addLast(new ClientChannelHandler());
|
||||
}
|
||||
});
|
||||
this.start();
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (StringUtil.isEmpty(proxyConfig.getLicenseKey())) {
|
||||
if (StrUtil.isEmpty(proxyConfig.getClient().getServerIp())) {
|
||||
log.error("not found server-ip config.");
|
||||
Solon.stop();
|
||||
return;
|
||||
}
|
||||
if (null == proxyConfig.getClient().getServerPort()) {
|
||||
log.error("not found server-port config.");
|
||||
Solon.stop();
|
||||
return;
|
||||
}
|
||||
if (null != proxyConfig.getClient().getSslEnable() && proxyConfig.getClient().getSslEnable()
|
||||
&& StrUtil.isEmpty(proxyConfig.getClient().getJksPath())) {
|
||||
log.error("not found jks-path config.");
|
||||
Solon.stop();
|
||||
return;
|
||||
}
|
||||
if (StrUtil.isEmpty(proxyConfig.getClient().getLicenseKey())) {
|
||||
log.error("not found license-key config.");
|
||||
Solon.stop();
|
||||
return;
|
||||
}
|
||||
if (null == channel || !channel.isActive()) {
|
||||
try {
|
||||
connectProxyServer();
|
||||
} catch (Exception e) {
|
||||
log.error("启动异常", e);
|
||||
log.error("client start error", e);
|
||||
}
|
||||
} else {
|
||||
channel.writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getLicenseKey()));
|
||||
channel.writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getClient().getLicenseKey()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +144,7 @@ public class ProxyClientService {
|
||||
channel = future.channel();
|
||||
// 连接成功,向服务器发送客户端认证信息(licenseKey)
|
||||
ProxyUtil.setCmdChannel(future.channel());
|
||||
future.channel().writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getLicenseKey()));
|
||||
future.channel().writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getClient().getLicenseKey()));
|
||||
log.info("连接代理服务成功. channelId:{}", future.channel().id().asLongText());
|
||||
|
||||
reconnectServiceEnable = true;
|
||||
@@ -199,14 +193,4 @@ public class ProxyClientService {
|
||||
log.error("重连异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Bootstrap bootstrap() {
|
||||
return new Bootstrap();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Bootstrap realServerBootstrap() {
|
||||
return new Bootstrap();
|
||||
}
|
||||
}
|
||||
|
||||
+2
-41
@@ -1,41 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.client.handler;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Match;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.util.FileUtil;
|
||||
import fun.asgc.neutrino.proxy.client.config.ProxyConfig;
|
||||
import fun.asgc.neutrino.proxy.client.core.LicenseObtainService;
|
||||
import fun.asgc.neutrino.proxy.core.Constants;
|
||||
import fun.asgc.neutrino.proxy.core.ExceptionEnum;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessage;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessageHandler;
|
||||
import fun.asgc.neutrino.proxy.core.dispatcher.Match;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.noear.solon.annotation.Component;
|
||||
|
||||
/**
|
||||
* 认证信息处理器
|
||||
@@ -43,25 +15,14 @@ import lombok.extern.slf4j.Slf4j;
|
||||
* @date: 2022/9/4
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Match(type = Constants.ProxyDataTypeName.AUTH)
|
||||
@Component
|
||||
public class ProxyMessageAuthHandler implements ProxyMessageHandler {
|
||||
@Autowired
|
||||
private LicenseObtainService licenseObtainService;
|
||||
@Autowired
|
||||
private ProxyConfig proxyConfig;
|
||||
|
||||
@Override
|
||||
public void handle(ChannelHandlerContext context, ProxyMessage proxyMessage) {
|
||||
String info = proxyMessage.getInfo();
|
||||
JSONObject data = JSONObject.parseObject(info);
|
||||
Integer code = data.getInteger("code");
|
||||
log.info("认证结果:{}", info);
|
||||
if (ExceptionEnum.SUCCESS.getCode().equals(code)) {
|
||||
ProxyConfig.authSuccess = true;
|
||||
FileUtil.write("./.neutrino-proxy-client.json", JSONObject.toJSONString(proxyConfig.getCustomConfig(), SerializerFeature.PrettyFormat));
|
||||
licenseObtainService.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-31
@@ -1,51 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package fun.asgc.neutrino.proxy.client.handler;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Match;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.proxy.client.config.ProxyConfig;
|
||||
import fun.asgc.neutrino.proxy.client.core.ProxyChannelBorrowListener;
|
||||
import fun.asgc.neutrino.proxy.client.util.ProxyUtil;
|
||||
import fun.asgc.neutrino.proxy.core.*;
|
||||
import fun.asgc.neutrino.proxy.core.Constants;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyDataTypeEnum;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessage;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessageHandler;
|
||||
import fun.asgc.neutrino.proxy.core.dispatcher.Match;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.*;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
|
||||
/**
|
||||
* 连接信息处理器
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@NonIntercept
|
||||
@Match(type = Constants.ProxyDataTypeName.CONNECT)
|
||||
@Component
|
||||
public class ProxyMessageConnectHandler implements ProxyMessageHandler {
|
||||
@Autowired("bootstrap")
|
||||
@Inject("bootstrap")
|
||||
private Bootstrap bootstrap;
|
||||
@Autowired("realServerBootstrap")
|
||||
@Inject("realServerBootstrap")
|
||||
private Bootstrap realServerBootstrap;
|
||||
@Inject
|
||||
private ProxyConfig proxyConfig;
|
||||
|
||||
@Override
|
||||
public void handle(ChannelHandlerContext ctx, ProxyMessage proxyMessage) {
|
||||
@@ -76,7 +57,7 @@ public class ProxyMessageConnectHandler implements ProxyMessageHandler {
|
||||
realServerChannel.attr(Constants.NEXT_CHANNEL).set(channel);
|
||||
|
||||
// 远程绑定
|
||||
channel.writeAndFlush(ProxyMessage.buildConnectMessage(visitorId + "@" + ProxyConfig.instance.getLicenseKey()));
|
||||
channel.writeAndFlush(ProxyMessage.buildConnectMessage(visitorId + "@" + proxyConfig.getClient().getLicenseKey()));
|
||||
|
||||
realServerChannel.config().setOption(ChannelOption.AUTO_READ, true);
|
||||
ProxyUtil.addRealServerChannel(visitorId, realServerChannel);
|
||||
|
||||
+2
-26
@@ -1,46 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package fun.asgc.neutrino.proxy.client.handler;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Match;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.proxy.client.util.ProxyUtil;
|
||||
import fun.asgc.neutrino.proxy.core.Constants;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyDataTypeEnum;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessage;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessageHandler;
|
||||
import fun.asgc.neutrino.proxy.core.dispatcher.Match;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import org.noear.solon.annotation.Component;
|
||||
|
||||
/**
|
||||
* 断开连接信息处理器
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@NonIntercept
|
||||
@Match(type = Constants.ProxyDataTypeName.DISCONNECT)
|
||||
@Component
|
||||
public class ProxyMessageDisconnectHandler implements ProxyMessageHandler {
|
||||
|
||||
+2
-26
@@ -1,34 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package fun.asgc.neutrino.proxy.client.handler;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Match;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.proxy.core.*;
|
||||
import fun.asgc.neutrino.proxy.core.dispatcher.Match;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.noear.solon.annotation.Component;
|
||||
|
||||
/**
|
||||
* 异常信息处理器
|
||||
@@ -36,7 +13,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Match(type = Constants.ProxyDataTypeName.ERROR)
|
||||
@Component
|
||||
public class ProxyMessageErrorHandler implements ProxyMessageHandler {
|
||||
|
||||
+2
-26
@@ -1,44 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package fun.asgc.neutrino.proxy.client.handler;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Match;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.proxy.core.Constants;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyDataTypeEnum;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessage;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessageHandler;
|
||||
import fun.asgc.neutrino.proxy.core.dispatcher.Match;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import org.noear.solon.annotation.Component;
|
||||
|
||||
/**
|
||||
* 传输信息处理器
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@NonIntercept
|
||||
@Match(type = Constants.ProxyDataTypeName.TRANSFER)
|
||||
@Component
|
||||
public class ProxyMessageTransferHandler implements ProxyMessageHandler {
|
||||
|
||||
+8
-9
@@ -31,6 +31,7 @@ import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.util.AttributeKey;
|
||||
import org.noear.solon.Solon;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
@@ -62,15 +63,13 @@ public class ProxyUtil {
|
||||
return;
|
||||
}
|
||||
|
||||
bootstrap.connect(ProxyConfig.instance.getClient().getServerIp(), ProxyConfig.instance.getClient().getServerPort()).addListener(new ChannelFutureListener() {
|
||||
|
||||
@Override
|
||||
public void operationComplete(ChannelFuture future) throws Exception {
|
||||
if (future.isSuccess()) {
|
||||
borrowListener.success(future.channel());
|
||||
} else {
|
||||
borrowListener.error(future.cause());
|
||||
}
|
||||
String serverIp = Solon.cfg().get("neutrino.proxy.client.server-ip");
|
||||
Integer serverPort = Solon.cfg().getInt("neutrino.proxy.client.server-port", 9000);
|
||||
bootstrap.connect(serverIp, serverPort).addListener((ChannelFutureListener) future -> {
|
||||
if (future.isSuccess()) {
|
||||
borrowListener.success(future.channel());
|
||||
} else {
|
||||
borrowListener.error(future.cause());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+1
@@ -19,3 +19,4 @@ neutrino:
|
||||
server-port: 9002
|
||||
ssl-enable: true
|
||||
obtain-license-interval: 5
|
||||
license-key:
|
||||
@@ -14,9 +14,19 @@
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>fun.asgc.neutrino</groupId>
|
||||
<artifactId>neutrino-core</artifactId>
|
||||
<version>${revision}</version>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
</dependency>
|
||||
<!--hutool -->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
<version>${hutool.ver}</version>
|
||||
</dependency>
|
||||
<!--lombok-->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
+1
-23
@@ -1,28 +1,6 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package fun.asgc.neutrino.proxy.core;
|
||||
|
||||
import fun.asgc.neutrino.core.base.Handler;
|
||||
import fun.asgc.neutrino.proxy.core.dispatcher.Handler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
||||
/**
|
||||
|
||||
+8
-8
@@ -19,19 +19,19 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.aop.Intercept;
|
||||
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
|
||||
package fun.asgc.neutrino.proxy.core.base;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/31
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@Intercept(ignoreGlobal = true)
|
||||
@Component
|
||||
public interface UserConnectRecordMapper extends SqlMapper {
|
||||
@FunctionalInterface
|
||||
public interface CodeBlock {
|
||||
|
||||
/**
|
||||
* 执行
|
||||
*/
|
||||
void execute() throws Exception;
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
|
||||
|
||||
package fun.asgc.neutrino.proxy.core.base;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
public class InternalException extends RuntimeException {
|
||||
|
||||
public InternalException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public InternalException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
package fun.asgc.neutrino.proxy.core.base;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
public interface MetaDataConstant {
|
||||
|
||||
String DEFAULT_BANNER = "\n _____ _____ _____ _____ _____ _____ _____ _______ \n" +
|
||||
" /\\ \\ /\\ \\ /\\ \\ /\\ \\ /\\ \\ /\\ \\ /\\ \\ /::\\ \\ \n" +
|
||||
" /::\\____\\ /::\\ \\ /::\\____\\ /::\\ \\ /::\\ \\ /::\\ \\ /::\\____\\ /::::\\ \\ \n" +
|
||||
" /::::| | /::::\\ \\ /:::/ / \\:::\\ \\ /::::\\ \\ \\:::\\ \\ /::::| | /::::::\\ \\ \n" +
|
||||
" /:::::| | /::::::\\ \\ /:::/ / \\:::\\ \\ /::::::\\ \\ \\:::\\ \\ /:::::| | /::::::::\\ \\ \n" +
|
||||
" /::::::| | /:::/\\:::\\ \\ /:::/ / \\:::\\ \\ /:::/\\:::\\ \\ \\:::\\ \\ /::::::| | /:::/~~\\:::\\ \\ \n" +
|
||||
" /:::/|::| | /:::/__\\:::\\ \\ /:::/ / \\:::\\ \\ /:::/__\\:::\\ \\ \\:::\\ \\ /:::/|::| | /:::/ \\:::\\ \\ \n" +
|
||||
" /:::/ |::| | /::::\\ \\:::\\ \\ /:::/ / /::::\\ \\ /::::\\ \\:::\\ \\ /::::\\ \\ /:::/ |::| | /:::/ / \\:::\\ \\ \n" +
|
||||
" /:::/ |::| | _____ /::::::\\ \\:::\\ \\ /:::/ / _____ /::::::\\ \\ /::::::\\ \\:::\\ \\ ____ /::::::\\ \\ /:::/ |::| | _____ /:::/____/ \\:::\\____\\ \n" +
|
||||
" /:::/ |::| |/\\ \\ /:::/\\:::\\ \\:::\\ \\ /:::/____/ /\\ \\ /:::/\\:::\\ \\ /:::/\\:::\\ \\:::\\____\\ /\\ \\ /:::/\\:::\\ \\ /:::/ |::| |/\\ \\ |:::| | |:::| |\n" +
|
||||
"/:: / |::| /::\\____\\/:::/__\\:::\\ \\:::\\____\\|:::| / /::\\____\\ /:::/ \\:::\\____\\/:::/ \\:::\\ \\:::| |/::\\ \\/:::/ \\:::\\____\\/:: / |::| /::\\____\\|:::|____| |:::| |\n" +
|
||||
"\\::/ /|::| /:::/ /\\:::\\ \\:::\\ \\::/ /|:::|____\\ /:::/ / /:::/ \\::/ /\\::/ |::::\\ /:::|____|\\:::\\ /:::/ \\::/ /\\::/ /|::| /:::/ / \\:::\\ \\ /:::/ / \n" +
|
||||
" \\/____/ |::| /:::/ / \\:::\\ \\:::\\ \\/____/ \\:::\\ \\ /:::/ / /:::/ / \\/____/ \\/____|:::::\\/:::/ / \\:::\\/:::/ / \\/____/ \\/____/ |::| /:::/ / \\:::\\ \\ /:::/ / \n" +
|
||||
" |::|/:::/ / \\:::\\ \\:::\\ \\ \\:::\\ \\ /:::/ / /:::/ / |:::::::::/ / \\::::::/ / |::|/:::/ / \\:::\\ /:::/ / \n" +
|
||||
" |::::::/ / \\:::\\ \\:::\\____\\ \\:::\\ /:::/ / /:::/ / |::|\\::::/ / \\::::/____/ |::::::/ / \\:::\\__/:::/ / \n" +
|
||||
" |:::::/ / \\:::\\ \\::/ / \\:::\\__/:::/ / \\::/ / |::| \\::/____/ \\:::\\ \\ |:::::/ / \\::::::::/ / \n" +
|
||||
" |::::/ / \\:::\\ \\/____/ \\::::::::/ / \\/____/ |::| ~| \\:::\\ \\ |::::/ / \\::::::/ / \n" +
|
||||
" /:::/ / \\:::\\ \\ \\::::::/ / |::| | \\:::\\ \\ /:::/ / \\::::/ / \n" +
|
||||
" /:::/ / \\:::\\____\\ \\::::/ / \\::| | \\:::\\____\\ /:::/ / \\::/____/ \n" +
|
||||
" \\::/ / \\::/ / \\::/____/ \\:| | \\::/ / \\::/ / ~~ \n" +
|
||||
" \\/____/ \\/____/ ~~ \\|___| \\/____/ \\/____/ \n" +
|
||||
" ";
|
||||
|
||||
/**
|
||||
* classpath标识符
|
||||
*/
|
||||
String CLASSPATH_IDENTIFIER = "classpath";
|
||||
|
||||
/**
|
||||
* classpath资源标识
|
||||
*/
|
||||
String CLASSPATH_RESOURCE_IDENTIFIER = CLASSPATH_IDENTIFIER + ":";
|
||||
|
||||
/**
|
||||
* 默认的yml配置文件名
|
||||
*/
|
||||
String DEFAULT_YML_CONFIG_FILE_NAME = "application.yml";
|
||||
|
||||
/**
|
||||
* 应用banner路径
|
||||
*/
|
||||
String APP_BANNER_FILE_PATH = CLASSPATH_RESOURCE_IDENTIFIER.concat("/banner.txt");
|
||||
|
||||
/**
|
||||
* 默认的http页面路径
|
||||
*/
|
||||
String DEFAULT_HTTP_PAGE_PATH = CLASSPATH_RESOURCE_IDENTIFIER.concat("/webapp/");
|
||||
/**
|
||||
* 服务版本
|
||||
*/
|
||||
String SERVER_VS = "Neutrino-1.0";
|
||||
/**
|
||||
* app生命周期主题
|
||||
*/
|
||||
String TOPIC_APP_LIFE_CYCLE = "TP_APP_LIFE_CYCLE";
|
||||
/**
|
||||
* 环境变量key
|
||||
*/
|
||||
String ENVIRONMENT_VARIABLE_KEY = "NEUTRINO_PROXY";
|
||||
|
||||
interface Config {
|
||||
String NEUTRINO_APPLICATION_NAME = "neutrino.application.name";
|
||||
String NEUTRINO_HTTP_ENABLE = "neutrino.http.enable";
|
||||
String NEUTRINO_HTTP_PORT = "neutrino.http.port";
|
||||
String NEUTRINO_HTTP_CONTEXT_PATH = "neutrino.http.context-path";
|
||||
String NEUTRINO_HTTP_MAX_CONTENT_LENGTH_DESC = "neutrino.http.max-content-length-desc";
|
||||
String NEUTRINO_HTTP_STATIC_RESOURCE_LOCATIONS = "neutrino.http.static-resource.locations";
|
||||
String NEUTRINO_PROXY_PROTOCOL_MAX_FRAME_LENGTH = "neutrino.proxy.protocol.max-frame-length";
|
||||
String NEUTRINO_PROXY_PROTOCOL_LENGTH_FIELD_OFFSET = "neutrino.proxy.protocol.length-field-offset";
|
||||
String NEUTRINO_PROXY_PROTOCOL_LENGTH_FIELD_LENGTH = "neutrino.proxy.protocol.length-field-length";
|
||||
String NEUTRINO_PROXY_PROTOCOL_INITIAL_BYTES_TO_STRIP = "neutrino.proxy.protocol.initial-bytes-to-strip";
|
||||
String NEUTRINO_PROXY_PROTOCOL_LENGTH_ADJUSTMENT = "neutrino.proxy.protocol.length-adjustment";
|
||||
String NEUTRINO_PROXY_PROTOCOL_READ_IDLE_TIME = "neutrino.proxy.protocol.read-idle-time";
|
||||
String NEUTRINO_PROXY_PROTOCOL_WRITE_IDLE_TIME = "neutrino.proxy.protocol.write-idle-time";
|
||||
String NEUTRINO_PROXY_PROTOCOL_ALL_IDLE_TIME_SECONDS = "neutrino.proxy.protocol.all-idle-time-seconds";
|
||||
String NEUTRINO_PROXY_SERVER_PORT = "neutrino.proxy.server.port";
|
||||
String NEUTRINO_PROXY_SERVER_SSL_PORT = "neutrino.proxy.server.ssl-port";
|
||||
String NEUTRINO_PROXY_SERVER_KEY_STORE_PASSWORD = "neutrino.proxy.server.key-store-password";
|
||||
String NEUTRINO_PROXY_SERVER_KEY_MANAGER_PASSWORD = "neutrino.proxy.server.key-manager-password";
|
||||
String NEUTRINO_PROXY_SERVER_JKS_PATH = "neutrino.proxy.server.jks-path";
|
||||
String NEUTRINO_PROXY_CLIENT_KEY_STORE_PASSWORD = "neutrino.proxy.client.key-store-password";
|
||||
String NEUTRINO_PROXY_CLIENT_JKS_PATH = "neutrino.proxy.client.jks-path";
|
||||
String NEUTRINO_PROXY_CLIENT_SERVER_IP = "neutrino.proxy.client.server-ip";
|
||||
String NEUTRINO_PROXY_CLIENT_SERVER_PORT = "neutrino.proxy.client.server-port";
|
||||
String NEUTRINO_PROXY_CLIENT_SSL_ENABLE = "neutrino.proxy.client.ssl-enable";
|
||||
String NEUTRINO_PROXY_CLIENT_OBTAIN_LICENSE_INTERVAL = "neutrino.proxy.client.obtain-license-interval";
|
||||
String NEUTRINO_DATA_DB_TYPE = "neutrino.data.db.type";
|
||||
String NEUTRINO_DATA_DB_URL = "neutrino.data.db.url";
|
||||
String NEUTRINO_DATA_DB_DRIVER_CLASS = "neutrino.data.db.driver-class";
|
||||
String NEUTRINO_DATA_DB_USERNAME = "neutrino.data.db.username";
|
||||
String NEUTRINO_DATA_DB_PASSWORD = "neutrino.data.db.password";
|
||||
}
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package fun.asgc.neutrino.proxy.core.dispatcher;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import fun.asgc.neutrino.proxy.core.util.TypeUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@Slf4j
|
||||
public class DefaultDispatcher<Context, Data> implements Dispatcher<Context, Data> {
|
||||
|
||||
/**
|
||||
* 调度器名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 处理器映射
|
||||
*/
|
||||
private Map<String, Handler<Context,Data>> handlerMap;
|
||||
/**
|
||||
* 匹配器
|
||||
*/
|
||||
private Function<Data,String> matcher;
|
||||
|
||||
public DefaultDispatcher(String name, List<? extends Handler<Context,Data>> handlerList, Function<Data,String> matcher) {
|
||||
Assert.notNull(name, "名称不能为空!");
|
||||
Assert.notNull(matcher, "匹配器不能为空!");
|
||||
if (CollectionUtil.isEmpty(handlerList)) {
|
||||
log.error("{} 处理器列表为空.", name);
|
||||
return;
|
||||
}
|
||||
this.name = name == null ? "" : name;
|
||||
this.handlerMap = new HashMap<>();
|
||||
this.matcher = matcher;
|
||||
|
||||
for (Handler handler : handlerList) {
|
||||
Match match = handler.getClass().getAnnotation(Match.class);
|
||||
if (null == match) {
|
||||
log.warn("{} 类: {} 缺失Match注解", this.name, handler.getClass().getName());
|
||||
continue;
|
||||
}
|
||||
if (StrUtil.isEmpty(match.type())) {
|
||||
log.warn("{} 类: {} match注解缺失type参数!", this.name, handler.getClass().getName());
|
||||
continue;
|
||||
}
|
||||
if (handlerMap.containsKey(match.type())) {
|
||||
log.warn("{} 类: {} match注解type值{} 存在重复!", this.name, handler.getClass().getName(), match.type());
|
||||
continue;
|
||||
}
|
||||
handlerMap.put(match.type(), handler);
|
||||
}
|
||||
log.info("{} 处理器初始化完成", this.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatch(Context context, Data data) {
|
||||
if (CollectionUtil.isEmpty(handlerMap)) {
|
||||
return;
|
||||
}
|
||||
String type = matcher.apply(data);
|
||||
if (null == type) {
|
||||
log.warn("{} 获取匹配类型失败 data:{}", this.name, JSONObject.toJSONString(data));
|
||||
return;
|
||||
}
|
||||
Handler<Context,Data> handler = handlerMap.get(type);
|
||||
if (null == handler) {
|
||||
// log.debug("{} 找不到匹配的处理器 type:{}", this.name, type);
|
||||
return;
|
||||
}
|
||||
String handlerName = handler.name();
|
||||
if (StrUtil.isEmpty(handlerName)) {
|
||||
handlerName = TypeUtil.getSimpleName(handler.getClass());
|
||||
}
|
||||
log.debug("{} 处理器[{}]执行.", this.name, handlerName);
|
||||
handler.handle(context, data);
|
||||
}
|
||||
}
|
||||
+7
-29
@@ -19,42 +19,20 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.core.util;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
package fun.asgc.neutrino.proxy.core.dispatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/9/3
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
public class ChannelUtil {
|
||||
public interface Dispatcher<Context, Data> {
|
||||
|
||||
/**
|
||||
* 获取ip地址
|
||||
* @param channel
|
||||
* @return
|
||||
* 调度
|
||||
* @param context
|
||||
* @param data
|
||||
*/
|
||||
public static String getIP(Channel channel) {
|
||||
if (null == channel) {
|
||||
return "";
|
||||
}
|
||||
String ip = ((InetSocketAddress)channel.remoteAddress()).getAddress().getHostAddress();
|
||||
if (ip.equals("127.0.0.1") || ip.equals("0:0:0:0:0:0:0:1")) {
|
||||
//根据网卡取本机配置的IP
|
||||
InetAddress inet = null;
|
||||
try {
|
||||
inet = InetAddress.getLocalHost();
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
ip = inet.getHostAddress();
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
|
||||
void dispatch(Context context, Data data);
|
||||
}
|
||||
+17
-21
@@ -19,32 +19,28 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.core.db.page;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
package fun.asgc.neutrino.proxy.core.dispatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/6
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@Data
|
||||
public class Page<T> extends PageQuery {
|
||||
/**
|
||||
* 数据总数
|
||||
*/
|
||||
private Long total;
|
||||
/**
|
||||
* 结果数据
|
||||
*/
|
||||
private List<T> records;
|
||||
public interface Handler<Context, Data> {
|
||||
|
||||
public static <T> Page<T> create(PageQuery pageQuery) {
|
||||
Page page = new Page();
|
||||
page.setPageSize(pageQuery.getPageSize());
|
||||
page.setCurrentPage(pageQuery.getCurrentPage());
|
||||
return page;
|
||||
}
|
||||
/**
|
||||
* 处理
|
||||
* @param context
|
||||
* @param data
|
||||
*/
|
||||
void handle(Context context, Data data);
|
||||
|
||||
/**
|
||||
* 名称
|
||||
* @return
|
||||
*/
|
||||
default String name() {
|
||||
return "";
|
||||
};
|
||||
}
|
||||
+9
-10
@@ -19,20 +19,19 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.base.rest.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
package fun.asgc.neutrino.proxy.core.dispatcher;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 暂不做复杂权限控制,仅用该注解标注,部分接口禁止游客身份调用
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/14
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@Target({ElementType.METHOD})
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface OnlyAdmin {
|
||||
|
||||
@Documented
|
||||
public @interface Match {
|
||||
String type();
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package fun.asgc.neutrino.proxy.core.type;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 抽象的匹配器组
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/29
|
||||
*/
|
||||
public abstract class AbstractMatcherGroup implements TypeMatcherGroup {
|
||||
/**
|
||||
* 最小距离
|
||||
*/
|
||||
protected int distanceMin;
|
||||
|
||||
/**
|
||||
* 最大距离
|
||||
*/
|
||||
protected int distanceMax;
|
||||
|
||||
/**
|
||||
* 匹配器列表
|
||||
*/
|
||||
private List<TypeMatcher> matchers;
|
||||
|
||||
public AbstractMatcherGroup(int distanceMin, int distanceMax) {
|
||||
this.distanceMin = distanceMin;
|
||||
this.distanceMax = distanceMax;
|
||||
this.matchers = new ArrayList<>();
|
||||
this.init();
|
||||
}
|
||||
|
||||
protected abstract void init();
|
||||
|
||||
@Override
|
||||
public List<TypeMatcher> matchers() {
|
||||
return matchers;
|
||||
}
|
||||
|
||||
public synchronized void add(TypeMatcher matcher) {
|
||||
if (null != matcher) {
|
||||
this.matchers.add(matcher);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDistanceMin() {
|
||||
return distanceMin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDistanceMax() {
|
||||
return distanceMax;
|
||||
}
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
package fun.asgc.neutrino.proxy.core.type;
|
||||
|
||||
import fun.asgc.neutrino.proxy.core.util.TypeUtil;
|
||||
|
||||
/**
|
||||
* 默认的类型匹配器组
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/7/1
|
||||
*/
|
||||
public class DefaultTypeMatcherGroup extends AbstractMatcherGroup {
|
||||
|
||||
public DefaultTypeMatcherGroup(int distanceMin, int distanceMax) {
|
||||
super(distanceMin, distanceMax);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
// 空匹配
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (null == clazz) {
|
||||
matchInfo.setTypeDistance(TypeMatchLevel.NULL.getDistanceMin());
|
||||
matchInfo.setTypeConverter((value, type) -> TypeUtil.getDefaultValue(type));
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
// 完美匹配
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (clazz == targetClass) {
|
||||
matchInfo.setTypeDistance(TypeMatchLevel.PERFECT.getDistanceMin());
|
||||
matchInfo.setTypeConverter((value, type) -> value);
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
// 装箱匹配
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (TypeUtil.isStrictBasicType(clazz) && TypeUtil.getWrapType(clazz) == targetClass) {
|
||||
matchInfo.setTypeDistance(TypeMatchLevel.PACKING.getDistanceMin());
|
||||
matchInfo.setTypeConverter((value, type) -> value);
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
// 拆箱匹配
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (TypeUtil.isStrictBasicType(targetClass) && TypeUtil.getWrapType(targetClass) == clazz) {
|
||||
matchInfo.setTypeDistance(TypeMatchLevel.UNPACKING.getDistanceMin());
|
||||
matchInfo.setTypeConverter((value, type) -> value);
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
// 类型提升匹配
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
int index1 = TypeUtil.basicTypeList.indexOf(clazz);
|
||||
int index2 = TypeUtil.basicTypeList.indexOf(targetClass);
|
||||
if (index2 > index1 && index1 >= 0) {
|
||||
matchInfo.setTypeDistance(TypeMatchLevel.ASCENSION.getDistanceMin() + (index2 - index1));
|
||||
matchInfo.setTypeConverter((value, type) -> {
|
||||
if (value == type || TypeUtil.getWrapType(value.getClass()) == type) {
|
||||
return value;
|
||||
}
|
||||
if (TypeUtil.isInteger(clazz) && TypeUtil.isLong(targetClass)) {
|
||||
return Long.valueOf(String.valueOf(value));
|
||||
}
|
||||
if (TypeUtil.isBoolean(value.getClass())) {
|
||||
return ((boolean)value) ? 1 : 0;
|
||||
}
|
||||
if (TypeUtil.isBoolean(type)) {
|
||||
return TypeUtil.isChar(value.getClass()) ? ((char)value == 0 ? false : true) :
|
||||
(((Number)value).intValue() == 0 ? false : true);
|
||||
}
|
||||
if (TypeUtil.isChar(type)) {
|
||||
return (char)(int)value;
|
||||
}
|
||||
return value;
|
||||
});
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
// 超类匹配
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (targetClass.isAssignableFrom(clazz)) {
|
||||
int level = TypeUtil.getInheritLevel(targetClass, clazz);
|
||||
matchInfo.setTypeDistance(TypeMatchLevel.SUPER.getDistanceMin() + level);
|
||||
matchInfo.setTypeConverter((value, type) -> value);
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package fun.asgc.neutrino.proxy.core.type;
|
||||
|
||||
/**
|
||||
* 类型转换器
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/17
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface TypeConverter {
|
||||
/**
|
||||
* 类型转换
|
||||
* @param value
|
||||
* @param targetType
|
||||
* @return
|
||||
*/
|
||||
Object convert(Object value, Class<?> targetType);
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package fun.asgc.neutrino.proxy.core.type;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
public class TypeMatchInfo {
|
||||
|
||||
/**
|
||||
* 目标类型类型
|
||||
*/
|
||||
private Class<?> targetType;
|
||||
|
||||
/**
|
||||
* 值类型
|
||||
*/
|
||||
private Class<?> valueType;
|
||||
|
||||
/**
|
||||
* 类型距离
|
||||
*/
|
||||
private int typeDistance;
|
||||
|
||||
/**
|
||||
* 类型匹配器
|
||||
*/
|
||||
private TypeMatcher typeMatcher;
|
||||
|
||||
/**
|
||||
* 类型转换器
|
||||
*/
|
||||
private TypeConverter typeConverter;
|
||||
|
||||
public TypeMatchInfo(Class<?> valueType, Class<?> targetType, TypeMatcher typeMatcher) {
|
||||
this.valueType = valueType;
|
||||
this.targetType = targetType;
|
||||
this.typeMatcher = typeMatcher;
|
||||
this.typeDistance = TypeMatchLevel.NOT.getDistanceMin();
|
||||
}
|
||||
|
||||
public boolean isNotMatch() {
|
||||
return !isMatched();
|
||||
}
|
||||
|
||||
public boolean isMatched() {
|
||||
TypeMatchLevel matchLevel = TypeMatchLevel.byTypeDistance(this.typeDistance);
|
||||
return matchLevel != null && matchLevel != TypeMatchLevel.NOT && typeConverter != null;
|
||||
}
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package fun.asgc.neutrino.proxy.core.type;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 类型匹配等级
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/17
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum TypeMatchLevel {
|
||||
// 当且仅当匹配类为空(即匹配对象为null没有类型)时
|
||||
NULL(0, 0, 0, "空匹配"),
|
||||
// 当且仅当匹配类与目标类完全相等
|
||||
PERFECT(1, 1, 1, "完美匹配"),
|
||||
// 当且仅当匹配类为严格基本数据类型,且目标类为对应的包装类型
|
||||
PACKING(2, 100, 100, "装箱匹配"),
|
||||
// 当且仅当目标类为严格基本数据类型,且匹配类为对应的包装类型
|
||||
UNPACKING(3, 200,200,"拆箱匹配"),
|
||||
// 当且仅当匹配类和目标类均为一般基本数据类型(非严格),且目标类型的范围更加宽泛时
|
||||
ASCENSION(4, 1000, 2000, "类型提升匹配"),
|
||||
// 超类匹配,当且仅当目标类是匹配类的超类时
|
||||
SUPER(5, 1000000, 2000000, "超类匹配"),
|
||||
// 内置的扩展匹配
|
||||
EXTENSION(6, 10000000, 50000000, "扩展匹配"),
|
||||
// 自定义匹配
|
||||
CUSTOM(7, 100000000, 500000000, "自定义匹配"),
|
||||
// 不匹配
|
||||
NOT(8, Integer.MAX_VALUE, Integer.MAX_VALUE, "不匹配");
|
||||
private static Map<Integer,TypeMatchLevel> levelMap = Stream.of(TypeMatchLevel.values()).collect(Collectors.toMap(TypeMatchLevel::getLevel, Function.identity()));
|
||||
|
||||
/**
|
||||
* 匹配级别
|
||||
*/
|
||||
private int level;
|
||||
/**
|
||||
* 类型距离最小值
|
||||
*/
|
||||
private int distanceMin;
|
||||
/**
|
||||
* 类型距离最大值
|
||||
*/
|
||||
private int distanceMax;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private String desc;
|
||||
|
||||
public static TypeMatchLevel byLevel(int level) {
|
||||
return levelMap.get(level);
|
||||
}
|
||||
|
||||
public static TypeMatchLevel byTypeDistance(int typeDistance) {
|
||||
for (TypeMatchLevel item : values()) {
|
||||
if (typeDistance >= item.getDistanceMin() && typeDistance <= item.getDistanceMax()) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
package fun.asgc.neutrino.proxy.core.type;
|
||||
|
||||
/**
|
||||
* 值类型匹配器
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/17
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface TypeMatcher {
|
||||
|
||||
/**
|
||||
* 匹配
|
||||
* @param clazz
|
||||
* @param targetClass
|
||||
* @return
|
||||
*/
|
||||
TypeMatchInfo match(Class<?> clazz, Class<?> targetClass);
|
||||
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package fun.asgc.neutrino.proxy.core.type;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 匹配器组
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/29
|
||||
*/
|
||||
public interface TypeMatcherGroup {
|
||||
/**
|
||||
* 匹配器列表
|
||||
* @return
|
||||
*/
|
||||
List<TypeMatcher> matchers();
|
||||
|
||||
/**
|
||||
* 获取最小距离
|
||||
* @return
|
||||
*/
|
||||
int getDistanceMin();
|
||||
|
||||
/**
|
||||
* 获取最大距离
|
||||
* @return
|
||||
*/
|
||||
int getDistanceMax();
|
||||
}
|
||||
+218
@@ -0,0 +1,218 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.core.type;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import fun.asgc.neutrino.proxy.core.type.extension.*;
|
||||
import fun.asgc.neutrino.proxy.core.util.Assert;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/17
|
||||
*/
|
||||
public class TypeMatchers {
|
||||
/**
|
||||
* 默认的基本匹配器列表
|
||||
*/
|
||||
private static List<TypeMatcher> defaultTypeMatcherList = new ArrayList<>();
|
||||
/**
|
||||
* 默认内置扩展的匹配器列表
|
||||
*/
|
||||
private static List<TypeMatcher> extensionMatcherList = new ArrayList<>();
|
||||
/**
|
||||
* 内置扩展匹配器组列表
|
||||
*/
|
||||
private static List<TypeMatcherGroup> extensionMatcherGroupList = new ArrayList<>();
|
||||
/**
|
||||
* 用户自定义的匹配器列表
|
||||
*/
|
||||
private List<TypeMatcher> customTypeMatcherList = new ArrayList<>();
|
||||
/**
|
||||
* 是否启用内置扩展匹配器
|
||||
*/
|
||||
private volatile boolean enableExtensionMatcher = true;
|
||||
|
||||
static {
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册内置扩展匹配器组
|
||||
* @param typeMatcherGroup
|
||||
*/
|
||||
private static synchronized void registerExtensionTypeMatcher(TypeMatcherGroup typeMatcherGroup) {
|
||||
if (null == typeMatcherGroup || CollectionUtil.isEmpty(typeMatcherGroup.matchers())) {
|
||||
return;
|
||||
}
|
||||
// 内置扩展匹配器距离区间检测
|
||||
if (typeMatcherGroup.getDistanceMin() < TypeMatchLevel.EXTENSION.getDistanceMin() ||
|
||||
typeMatcherGroup.getDistanceMax() > TypeMatchLevel.EXTENSION.getDistanceMax() ||
|
||||
typeMatcherGroup.getDistanceMax() < typeMatcherGroup.getDistanceMin()) {
|
||||
throw new RuntimeException(String.format("内置扩展匹配器:[%s] 距离区间定义有误!", typeMatcherGroup.getClass().getSimpleName()));
|
||||
}
|
||||
for (TypeMatcherGroup group : extensionMatcherGroupList) {
|
||||
// 距离区间不能重叠
|
||||
if (!(typeMatcherGroup.getDistanceMin() > group.getDistanceMax() || typeMatcherGroup.getDistanceMax() < group.getDistanceMin())) {
|
||||
throw new RuntimeException(String.format("内置扩展匹配器:[%s]与[%s] 距离区间定义有重叠!", typeMatcherGroup.getClass().getSimpleName(), group.getClass().getSimpleName()));
|
||||
}
|
||||
}
|
||||
extensionMatcherGroupList.add(typeMatcherGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册默认的类型匹配器组
|
||||
* @param typeMatcherGroup
|
||||
*/
|
||||
private static synchronized void registerDefaultTypeMatcher(TypeMatcherGroup typeMatcherGroup) {
|
||||
if (null == typeMatcherGroup || CollectionUtil.isEmpty(typeMatcherGroup.matchers())) {
|
||||
return;
|
||||
}
|
||||
// 自定义匹配器距离区间检测
|
||||
if (typeMatcherGroup.getDistanceMin() < TypeMatchLevel.NULL.getDistanceMin() ||
|
||||
typeMatcherGroup.getDistanceMax() > TypeMatchLevel.SUPER.getDistanceMax() ||
|
||||
typeMatcherGroup.getDistanceMax() < typeMatcherGroup.getDistanceMin()) {
|
||||
throw new RuntimeException(String.format("默认匹配器组器:[%s] 距离区间定义有误!", typeMatcherGroup.getClass().getSimpleName()));
|
||||
}
|
||||
defaultTypeMatcherList.addAll(typeMatcherGroup.matchers());
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册自定义类型匹配器具
|
||||
* @param typeMatcher
|
||||
*/
|
||||
public synchronized void registerCustomTypeMatcher(TypeMatcher typeMatcher) {
|
||||
Assert.notNull(typeMatcher, "匹配器不能为空!");
|
||||
customTypeMatcherList.add(typeMatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册自定义匹配器组
|
||||
* @param typeMatcherGroup
|
||||
*/
|
||||
public synchronized void registerCustomTypeMatcher(TypeMatcherGroup typeMatcherGroup) {
|
||||
if (null == typeMatcherGroup || CollectionUtil.isEmpty(typeMatcherGroup.matchers())) {
|
||||
return;
|
||||
}
|
||||
// 自定义匹配器距离区间检测
|
||||
if (typeMatcherGroup.getDistanceMin() < TypeMatchLevel.CUSTOM.getDistanceMin() ||
|
||||
typeMatcherGroup.getDistanceMax() > TypeMatchLevel.CUSTOM.getDistanceMax() ||
|
||||
typeMatcherGroup.getDistanceMax() < typeMatcherGroup.getDistanceMin()) {
|
||||
throw new RuntimeException(String.format("自定义扩展匹配器:[%s] 距离区间定义有误!", typeMatcherGroup.getClass().getSimpleName()));
|
||||
}
|
||||
customTypeMatcherList.addAll(typeMatcherGroup.matchers());
|
||||
}
|
||||
|
||||
/**
|
||||
* 匹配
|
||||
* @param clazz
|
||||
* @param targetClass
|
||||
* @return
|
||||
*/
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
// 先匹配自定义的
|
||||
for (TypeMatcher matcher : customTypeMatcherList) {
|
||||
TypeMatchInfo typeMatchInfo = matcher.match(clazz, targetClass);
|
||||
if (typeMatchInfo.isMatched()) {
|
||||
return typeMatchInfo;
|
||||
}
|
||||
}
|
||||
// 再匹配内置默认的
|
||||
for (TypeMatcher matcher : defaultTypeMatcherList) {
|
||||
TypeMatchInfo typeMatchInfo = matcher.match(clazz, targetClass);
|
||||
if (typeMatchInfo.isMatched()) {
|
||||
return typeMatchInfo;
|
||||
}
|
||||
}
|
||||
if (enableExtensionMatcher) {
|
||||
// 再匹配内置扩展的
|
||||
for (TypeMatcher matcher : extensionMatcherList) {
|
||||
TypeMatchInfo typeMatchInfo = matcher.match(clazz, targetClass);
|
||||
if (typeMatchInfo.isMatched()) {
|
||||
return typeMatchInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isEnableExtensionMatcher() {
|
||||
return enableExtensionMatcher;
|
||||
}
|
||||
|
||||
public void setEnableExtensionMatcher(boolean enableExtensionMatcher) {
|
||||
this.enableExtensionMatcher = enableExtensionMatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* 类型转换
|
||||
* @param value
|
||||
* @param targetType
|
||||
* @return
|
||||
*/
|
||||
public Object conversion(Object value, Class<?> targetType) {
|
||||
Assert.notNull(targetType, "目标类型不能为空!");
|
||||
TypeMatchInfo typeMatchInfo = match(value == null ? null : value.getClass(), targetType);
|
||||
if (null == typeMatchInfo || typeMatchInfo.isNotMatch()) {
|
||||
return null;
|
||||
}
|
||||
return typeMatchInfo.getTypeConverter().convert(value, targetType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
private static void init() {
|
||||
// 注册默认的类型匹配器组
|
||||
registerDefaultTypeMatcher(new DefaultTypeMatcherGroup(TypeMatchLevel.NULL.getDistanceMin(), TypeMatchLevel.SUPER.getDistanceMax()));
|
||||
|
||||
// 注册内置扩展匹配
|
||||
int extensionMatcherGroupSize = 100000;
|
||||
int extensionMatcherGroupDistance = TypeMatchLevel.EXTENSION.getDistanceMin();
|
||||
|
||||
registerExtensionTypeMatcher(new StringMatcherGroup(extensionMatcherGroupDistance + extensionMatcherGroupSize * 0,
|
||||
extensionMatcherGroupDistance + extensionMatcherGroupSize * 1 - 1));
|
||||
registerExtensionTypeMatcher(new BooleanMatcherGroup(extensionMatcherGroupDistance + extensionMatcherGroupSize * 1,
|
||||
extensionMatcherGroupDistance + extensionMatcherGroupSize * 2 - 1));
|
||||
registerExtensionTypeMatcher(new NumberMatcherGroup(extensionMatcherGroupDistance + extensionMatcherGroupSize * 2,
|
||||
extensionMatcherGroupDistance + extensionMatcherGroupSize * 3 - 1));
|
||||
registerExtensionTypeMatcher(new DateMatcherGroup(extensionMatcherGroupDistance + extensionMatcherGroupSize * 3,
|
||||
extensionMatcherGroupDistance + extensionMatcherGroupSize * 4 - 1));
|
||||
registerExtensionTypeMatcher(new ListMatcherGroup(extensionMatcherGroupDistance + extensionMatcherGroupSize * 4,
|
||||
extensionMatcherGroupDistance + extensionMatcherGroupSize * 5 - 1));
|
||||
registerExtensionTypeMatcher(new SetMatcherGroup(extensionMatcherGroupDistance + extensionMatcherGroupSize * 5,
|
||||
extensionMatcherGroupDistance + extensionMatcherGroupSize * 6 - 1));
|
||||
registerExtensionTypeMatcher(new MapMatcherGroup(extensionMatcherGroupDistance + extensionMatcherGroupSize * 6,
|
||||
extensionMatcherGroupDistance + extensionMatcherGroupSize * 7 - 1));
|
||||
registerExtensionTypeMatcher(new ArrayMatcherGroup(extensionMatcherGroupDistance + extensionMatcherGroupSize * 7,
|
||||
extensionMatcherGroupDistance + extensionMatcherGroupSize * 8 - 1));
|
||||
|
||||
// 按照距离区间排序
|
||||
extensionMatcherList = extensionMatcherGroupList.stream().sorted(Comparator.comparing(TypeMatcherGroup::getDistanceMin))
|
||||
.map(TypeMatcherGroup::matchers).flatMap(List::stream).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package fun.asgc.neutrino.proxy.core.type.extension;
|
||||
|
||||
import fun.asgc.neutrino.proxy.core.type.AbstractMatcherGroup;
|
||||
import fun.asgc.neutrino.proxy.core.type.TypeMatchInfo;
|
||||
import fun.asgc.neutrino.proxy.core.type.TypeMatcher;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 数组匹配器组
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/29
|
||||
*/
|
||||
public class ArrayMatcherGroup extends AbstractMatcherGroup {
|
||||
|
||||
public ArrayMatcherGroup(int distanceMin, int distanceMax) {
|
||||
super(distanceMin, distanceMax);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
// List -> Object[]
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (List.class.isAssignableFrom(clazz) && targetClass.isArray()) {
|
||||
matchInfo.setTypeDistance(getDistanceMin());
|
||||
matchInfo.setTypeConverter((value, targetType) -> ((List)value).toArray());
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
|
||||
// Set -> Object[]
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (Set.class.isAssignableFrom(clazz) && targetClass.isArray()) {
|
||||
matchInfo.setTypeDistance(getDistanceMin() + 1);
|
||||
matchInfo.setTypeConverter((value, targetType) -> ((Set)value).toArray());
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package fun.asgc.neutrino.proxy.core.type.extension;
|
||||
|
||||
import fun.asgc.neutrino.proxy.core.type.AbstractMatcherGroup;
|
||||
import fun.asgc.neutrino.proxy.core.type.TypeMatchInfo;
|
||||
import fun.asgc.neutrino.proxy.core.type.TypeMatcher;
|
||||
import fun.asgc.neutrino.proxy.core.util.TypeUtil;
|
||||
|
||||
/**
|
||||
* 布尔值匹配器组
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/29
|
||||
*/
|
||||
public class BooleanMatcherGroup extends AbstractMatcherGroup {
|
||||
|
||||
public BooleanMatcherGroup(int distanceMin, int distanceMax) {
|
||||
super(distanceMin, distanceMax);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (TypeUtil.isString(clazz) && TypeUtil.isBoolean(targetClass)) {
|
||||
matchInfo.setTypeDistance(getDistanceMin());
|
||||
matchInfo.setTypeConverter(((value, targetType) -> ((String)value).toLowerCase().equals("true")));
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package fun.asgc.neutrino.proxy.core.type.extension;
|
||||
|
||||
import fun.asgc.neutrino.proxy.core.type.AbstractMatcherGroup;
|
||||
import fun.asgc.neutrino.proxy.core.type.TypeMatchInfo;
|
||||
import fun.asgc.neutrino.proxy.core.type.TypeMatcher;
|
||||
import fun.asgc.neutrino.proxy.core.util.TypeUtil;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 日期匹配器组
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/29
|
||||
*/
|
||||
public class DateMatcherGroup extends AbstractMatcherGroup {
|
||||
|
||||
public DateMatcherGroup(int distanceMin, int distanceMax) {
|
||||
super(distanceMin, distanceMax);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
// Long -> Date
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (TypeUtil.isLong(clazz) && TypeUtil.isDate(targetClass)) {
|
||||
matchInfo.setTypeDistance(getDistanceMin());
|
||||
matchInfo.setTypeConverter(((value, targetType) -> {
|
||||
if (targetClass == Date.class) {
|
||||
return new Date((long)value);
|
||||
} else {
|
||||
return new java.sql.Date((long)value);
|
||||
}
|
||||
}));
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
// LocalDateTime -> Date
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (LocalDateTime.class.isAssignableFrom(clazz) && TypeUtil.isDate(targetClass)) {
|
||||
matchInfo.setTypeDistance(getDistanceMin() + 1);
|
||||
matchInfo.setTypeConverter(((value, targetType) -> {
|
||||
ZoneId zone = ZoneId.systemDefault();
|
||||
Instant instant = ((LocalDateTime)value).atZone(zone).toInstant();
|
||||
return Date.from(instant);
|
||||
}));
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package fun.asgc.neutrino.proxy.core.type.extension;
|
||||
|
||||
import fun.asgc.neutrino.proxy.core.type.AbstractMatcherGroup;
|
||||
import fun.asgc.neutrino.proxy.core.type.TypeMatchInfo;
|
||||
import fun.asgc.neutrino.proxy.core.type.TypeMatcher;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* list匹配器组
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/29
|
||||
*/
|
||||
public class ListMatcherGroup extends AbstractMatcherGroup {
|
||||
|
||||
public ListMatcherGroup(int distanceMin, int distanceMax) {
|
||||
super(distanceMin, distanceMax);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (List.class == targetClass && clazz.isArray()) {
|
||||
matchInfo.setTypeDistance(getDistanceMin());
|
||||
matchInfo.setTypeConverter(((value, targetType) -> Stream.of((Object[])value).collect(Collectors.toList())));
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package fun.asgc.neutrino.proxy.core.type.extension;
|
||||
|
||||
import fun.asgc.neutrino.proxy.core.type.AbstractMatcherGroup;
|
||||
|
||||
/**
|
||||
* Map匹配器组
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/29
|
||||
*/
|
||||
public class MapMatcherGroup extends AbstractMatcherGroup {
|
||||
|
||||
public MapMatcherGroup(int distanceMin, int distanceMax) {
|
||||
super(distanceMin, distanceMax);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
package fun.asgc.neutrino.proxy.core.type.extension;
|
||||
|
||||
import fun.asgc.neutrino.proxy.core.type.AbstractMatcherGroup;
|
||||
import fun.asgc.neutrino.proxy.core.type.TypeMatchInfo;
|
||||
import fun.asgc.neutrino.proxy.core.type.TypeMatcher;
|
||||
import fun.asgc.neutrino.proxy.core.util.TypeUtil;
|
||||
|
||||
/**
|
||||
* 字符串匹配器组
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/29
|
||||
*/
|
||||
public class NumberMatcherGroup extends AbstractMatcherGroup {
|
||||
|
||||
public NumberMatcherGroup(int distanceMin, int distanceMax) {
|
||||
super(distanceMin, distanceMax);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
// String -> Byte
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (TypeUtil.isString(clazz) && TypeUtil.isByte(targetClass)) {
|
||||
matchInfo.setTypeDistance(getDistanceMin());
|
||||
matchInfo.setTypeConverter((value, targetType) -> {
|
||||
try {
|
||||
return Byte.valueOf((String)value);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
// String -> Short
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (TypeUtil.isString(clazz) && TypeUtil.isShort(targetClass)) {
|
||||
matchInfo.setTypeDistance(getDistanceMin() + 1);
|
||||
matchInfo.setTypeConverter((value, targetType) -> {
|
||||
try {
|
||||
return Short.valueOf((String)value);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
// String -> Integer
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (TypeUtil.isString(clazz) && TypeUtil.isInteger(targetClass)) {
|
||||
matchInfo.setTypeDistance(getDistanceMin() + 2);
|
||||
matchInfo.setTypeConverter((value, targetType) -> {
|
||||
try {
|
||||
return Integer.valueOf((String)value);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
// String -> Long
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (TypeUtil.isString(clazz) && TypeUtil.isLong(targetClass)) {
|
||||
matchInfo.setTypeDistance(getDistanceMin() + 3);
|
||||
matchInfo.setTypeConverter((value, targetType) -> {
|
||||
try {
|
||||
return Long.valueOf((String)value);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
// String -> Float
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (TypeUtil.isString(clazz) && TypeUtil.isFloat(targetClass)) {
|
||||
matchInfo.setTypeDistance(getDistanceMin() + 4);
|
||||
matchInfo.setTypeConverter((value, targetType) -> {
|
||||
try {
|
||||
return Float.valueOf((String)value);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
// String -> Double
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (TypeUtil.isString(clazz) && TypeUtil.isDouble(targetClass)) {
|
||||
matchInfo.setTypeDistance(getDistanceMin() + 5);
|
||||
matchInfo.setTypeConverter((value, targetType) -> {
|
||||
try {
|
||||
return Double.valueOf((String)value);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
// date -> Long
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (TypeUtil.isLong(targetClass) && TypeUtil.isDate(clazz)) {
|
||||
matchInfo.setTypeDistance(getDistanceMin() + 6);
|
||||
matchInfo.setTypeConverter(((value, targetType) -> ((java.util.Date)value).getTime()));
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
// Long - > int
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (TypeUtil.isInteger(targetClass) && TypeUtil.isLong(clazz)) {
|
||||
matchInfo.setTypeDistance(getDistanceMin() + 7);
|
||||
matchInfo.setTypeConverter(((value, targetType) -> ((Long)value).intValue()));
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package fun.asgc.neutrino.proxy.core.type.extension;
|
||||
|
||||
import fun.asgc.neutrino.proxy.core.type.AbstractMatcherGroup;
|
||||
import fun.asgc.neutrino.proxy.core.type.TypeMatchInfo;
|
||||
import fun.asgc.neutrino.proxy.core.type.TypeMatcher;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* set匹配器组
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/29
|
||||
*/
|
||||
public class SetMatcherGroup extends AbstractMatcherGroup {
|
||||
|
||||
public SetMatcherGroup(int distanceMin, int distanceMax) {
|
||||
super(distanceMin, distanceMax);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (Set.class == targetClass && clazz.isArray()) {
|
||||
matchInfo.setTypeDistance(getDistanceMin());
|
||||
matchInfo.setTypeConverter(((value, targetType) -> Stream.of((Object[])value).collect(Collectors.toSet())));
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (Set.class == targetClass && Collection.class.isAssignableFrom(clazz)) {
|
||||
matchInfo.setTypeDistance(getDistanceMin() + 1);
|
||||
matchInfo.setTypeConverter(((value, targetType) -> ((Collection)value).stream().collect(Collectors.toSet())));
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package fun.asgc.neutrino.proxy.core.type.extension;
|
||||
|
||||
import fun.asgc.neutrino.proxy.core.type.AbstractMatcherGroup;
|
||||
import fun.asgc.neutrino.proxy.core.type.TypeMatchInfo;
|
||||
import fun.asgc.neutrino.proxy.core.type.TypeMatcher;
|
||||
import fun.asgc.neutrino.proxy.core.util.TypeUtil;
|
||||
|
||||
/**
|
||||
* 字符串匹配器组
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/29
|
||||
*/
|
||||
public class StringMatcherGroup extends AbstractMatcherGroup {
|
||||
|
||||
public StringMatcherGroup(int distanceMin, int distanceMax) {
|
||||
super(distanceMin, distanceMax);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
// 基本类型 -> String
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (TypeUtil.isNormalBasicType(clazz) && TypeUtil.isString(targetClass)) {
|
||||
matchInfo.setTypeDistance(getDistanceMin());
|
||||
matchInfo.setTypeConverter(((value, targetType) -> String.valueOf(value)));
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
// String -> char
|
||||
add(new TypeMatcher() {
|
||||
@Override
|
||||
public TypeMatchInfo match(Class<?> clazz, Class<?> targetClass) {
|
||||
TypeMatchInfo matchInfo = new TypeMatchInfo(clazz, targetClass, this);
|
||||
if (TypeUtil.isChar(targetClass) && TypeUtil.isString(clazz)) {
|
||||
matchInfo.setTypeDistance(getDistanceMin() + 1);
|
||||
matchInfo.setTypeConverter(((value, targetType) -> ((String)value).charAt(0)));
|
||||
}
|
||||
return matchInfo;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
package fun.asgc.neutrino.proxy.core.util;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
public abstract class Assert {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param expression
|
||||
* @param message
|
||||
*/
|
||||
public static void state(boolean expression, String message) {
|
||||
if (!expression) {
|
||||
throw new IllegalStateException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param expression
|
||||
* @param messageSupplier
|
||||
*/
|
||||
public static void state(boolean expression, Supplier<String> messageSupplier) {
|
||||
if (!expression) {
|
||||
throw new IllegalStateException(nullSafeGet(messageSupplier));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param expression
|
||||
* @param message
|
||||
*/
|
||||
public static void isTrue(boolean expression, String message) {
|
||||
if (!expression) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param expression
|
||||
* @param messageSupplier
|
||||
*/
|
||||
public static void isTrue(boolean expression, Supplier<String> messageSupplier) {
|
||||
if (!expression) {
|
||||
throw new IllegalArgumentException(nullSafeGet(messageSupplier));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param object
|
||||
* @param message
|
||||
*/
|
||||
public static void isNull(Object object, String message) {
|
||||
if (object != null) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param object
|
||||
* @param messageSupplier
|
||||
*/
|
||||
public static void isNull(Object object, Supplier<String> messageSupplier) {
|
||||
if (object != null) {
|
||||
throw new IllegalArgumentException(nullSafeGet(messageSupplier));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param object
|
||||
* @param message
|
||||
*/
|
||||
public static void notNull(Object object, String message) {
|
||||
if (object == null) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param object
|
||||
* @param messageSupplier
|
||||
*/
|
||||
public static void notNull(Object object, Supplier<String> messageSupplier) {
|
||||
if (object == null) {
|
||||
throw new IllegalArgumentException(nullSafeGet(messageSupplier));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param array
|
||||
* @param message
|
||||
*/
|
||||
public static void notEmpty(Object[] array, String message) {
|
||||
if (ObjectUtils.isEmpty(array)) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void notEmpty(String s, String message) {
|
||||
if (StrUtil.isEmpty(s)) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param array
|
||||
* @param messageSupplier
|
||||
*/
|
||||
public static void notEmpty(Object[] array, Supplier<String> messageSupplier) {
|
||||
if (ObjectUtils.isEmpty(array)) {
|
||||
throw new IllegalArgumentException(nullSafeGet(messageSupplier));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param array
|
||||
* @param message
|
||||
*/
|
||||
public static void noNullElements(Object[] array, String message) {
|
||||
if (array != null) {
|
||||
for (Object element : array) {
|
||||
if (element == null) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param array
|
||||
* @param messageSupplier
|
||||
*/
|
||||
public static void noNullElements(Object[] array, Supplier<String> messageSupplier) {
|
||||
if (array != null) {
|
||||
for (Object element : array) {
|
||||
if (element == null) {
|
||||
throw new IllegalArgumentException(nullSafeGet(messageSupplier));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param collection
|
||||
* @param message
|
||||
*/
|
||||
public static void notEmpty(Collection<?> collection, String message) {
|
||||
if (CollectionUtil.isEmpty(collection)) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param collection
|
||||
* @param messageSupplier
|
||||
*/
|
||||
public static void notEmpty(Collection<?> collection, Supplier<String> messageSupplier) {
|
||||
if (CollectionUtil.isEmpty(collection)) {
|
||||
throw new IllegalArgumentException(nullSafeGet(messageSupplier));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param map
|
||||
* @param message
|
||||
*/
|
||||
public static void notEmpty(Map<?, ?> map, String message) {
|
||||
if (CollectionUtil.isEmpty(map)) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param map
|
||||
* @param messageSupplier
|
||||
*/
|
||||
public static void notEmpty(Map<?, ?> map, Supplier<String> messageSupplier) {
|
||||
if (CollectionUtil.isEmpty(map)) {
|
||||
throw new IllegalArgumentException(nullSafeGet(messageSupplier));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean endsWithSeparator(String msg) {
|
||||
return (msg.endsWith(":") || msg.endsWith(";") || msg.endsWith(",") || msg.endsWith("."));
|
||||
}
|
||||
|
||||
private static String messageWithTypeName(String msg, Object typeName) {
|
||||
return msg + (msg.endsWith(" ") ? "" : ": ") + typeName;
|
||||
}
|
||||
|
||||
private static String nullSafeGet(Supplier<String> messageSupplier) {
|
||||
return (messageSupplier != null ? messageSupplier.get() : null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,357 @@
|
||||
package fun.asgc.neutrino.proxy.core.util;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/28
|
||||
*/
|
||||
public class DateUtil {
|
||||
public static final long SECOND_LONG = 1000L;
|
||||
public static final long MINUTE_LONG = 60 * SECOND_LONG;
|
||||
public static final long HOUR_LONG = 60 * MINUTE_LONG;
|
||||
|
||||
private static final Map<String, SimpleDateFormat> sdfCache = new HashMap<>();
|
||||
private static SimpleDateFormat getSimpleDateFormat(String format) {
|
||||
try {
|
||||
return LockUtil.doubleCheckProcess(
|
||||
() -> !sdfCache.containsKey(format),
|
||||
format,
|
||||
() -> sdfCache.put(format, new SimpleDateFormat(format)),
|
||||
() -> sdfCache.get(format)
|
||||
);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析日期
|
||||
*
|
||||
* @param date 日期类
|
||||
* @param pattern 日期格式
|
||||
* @return 返回日期
|
||||
*/
|
||||
public static Date parseStr(String date, String pattern) {
|
||||
if (date == null || pattern == null) {
|
||||
return null;
|
||||
}
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
|
||||
Date parse = null;
|
||||
try {
|
||||
parse = simpleDateFormat.parse(date);
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return parse;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param date 时间。若为空,则返回空串
|
||||
* @param pattern 时间格式化
|
||||
* @return 格式化后的时间字符串.
|
||||
*/
|
||||
public static String format(Date date, String pattern) {
|
||||
if (date == null) {
|
||||
return "";
|
||||
}
|
||||
return new SimpleDateFormat(pattern).format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param date 日期
|
||||
* @param pattern 格式
|
||||
* @return 日期类型
|
||||
*/
|
||||
public static Date parse(String date, String pattern) {
|
||||
try {
|
||||
return new SimpleDateFormat(pattern).parse(date);
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否在指定时间段之间
|
||||
*
|
||||
* @param judgeTime 比较时间
|
||||
* @param beginTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @param flag 0-[beginTime<=judgeTime<=endTime]
|
||||
* 1-[beginTime<judgeTime<=endTime]
|
||||
* 2-[beginTime<=judgeTime<endTime]
|
||||
* 3-[beginTime<judgeTime<endTime]
|
||||
* @return 判断结果
|
||||
*/
|
||||
public static boolean isBetweenTimes(Date judgeTime, Date beginTime, Date endTime, int flag) {
|
||||
switch (flag) {
|
||||
case 0:
|
||||
return (beginTime.getTime() <= judgeTime.getTime() && judgeTime.getTime() <= endTime.getTime());
|
||||
case 1:
|
||||
return (beginTime.getTime() < judgeTime.getTime() && judgeTime.getTime() <= endTime.getTime());
|
||||
case 2:
|
||||
return (beginTime.getTime() <= judgeTime.getTime() && judgeTime.getTime() < endTime.getTime());
|
||||
case 3:
|
||||
return (beginTime.getTime() < judgeTime.getTime() && judgeTime.getTime() < endTime.getTime());
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得日期所在月的month个月同一天<br />
|
||||
*
|
||||
* @param date 日期
|
||||
* @param month 月
|
||||
* @return 日期
|
||||
*/
|
||||
public static Date getMonthDay(Date date, int month) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
if (date != null) {
|
||||
cal.setTime(date);
|
||||
}
|
||||
cal.add(Calendar.MONTH, month);
|
||||
return cal.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取该日期当月第一天
|
||||
*
|
||||
* @param date 日期
|
||||
* @return 结果日期
|
||||
*/
|
||||
public static Date getMonthBegin(Date date) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(getDayBegin(date));
|
||||
calendar.set(Calendar.DAY_OF_MONTH, 1);
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取该日期当月最后一天
|
||||
*
|
||||
* @param date 日期
|
||||
* @return 结果日期
|
||||
*/
|
||||
public static Date getMonthEnd(Date date) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(getDayBegin(date));
|
||||
calendar.add(Calendar.MONTH, 1);
|
||||
calendar.set(Calendar.DAY_OF_MONTH, 1);
|
||||
calendar.add(Calendar.MILLISECOND, -1);
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算当期时间相差的日期
|
||||
*
|
||||
* @param date 设置时间
|
||||
* @param field 日历字段.<br/>eg:Calendar.MONTH,Calendar.DAY_OF_MONTH,<br/>Calendar.HOUR_OF_DAY等.
|
||||
* @param amount 相差的数值
|
||||
* @return 计算后的日志
|
||||
*/
|
||||
public static Date addDate(Date date, int field, int amount) {
|
||||
Calendar c = Calendar.getInstance();
|
||||
if (date != null) {
|
||||
c.setTime(date);
|
||||
}
|
||||
c.add(field, amount);
|
||||
return c.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算当期时间相差的日期
|
||||
*
|
||||
* @param field 日历字段.<br/>eg:Calendar.MONTH,Calendar.DAY_OF_MONTH,<br/>Calendar.HOUR_OF_DAY等.
|
||||
* @param amount 相差的数值
|
||||
* @return 计算后的日志
|
||||
*/
|
||||
public static Date addDate(int field, int amount) {
|
||||
return addDate(null, field, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Calendar的小时、分钟、秒、毫秒
|
||||
*
|
||||
* @param calendar 日历
|
||||
* @param hour 小时
|
||||
* @param minute 分钟
|
||||
* @param second 秒
|
||||
* @param milliSecond 毫秒
|
||||
* @return 结果日期
|
||||
*/
|
||||
public static void setCalender(Calendar calendar, int hour, int minute, int second, int milliSecond) {
|
||||
calendar.set(Calendar.HOUR_OF_DAY, hour);
|
||||
calendar.set(Calendar.MINUTE, minute);
|
||||
calendar.set(Calendar.SECOND, second);
|
||||
calendar.set(Calendar.MILLISECOND, milliSecond);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某个时间段内的每天时间日期
|
||||
*
|
||||
* @param beginDate 开始日期
|
||||
* @param endDate 结束日期
|
||||
* @return 返回结果
|
||||
*/
|
||||
public static List<String> getBetweenTimes(String beginDate, String endDate) {
|
||||
if (StringUtils.isEmpty(beginDate) || StringUtils.isEmpty(endDate)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
Date dBegin = null;
|
||||
Date dEnd = null;
|
||||
try {
|
||||
dBegin = sdf.parse(beginDate);
|
||||
dEnd = sdf.parse(endDate);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(beginDate) || StringUtils.isEmpty(endDate)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return findDates(dBegin, dEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dBegin 开始时间
|
||||
* @param dEnd 结束时间
|
||||
* @return 结果集
|
||||
*/
|
||||
public static List<String> findDates(Date dBegin, Date dEnd) {
|
||||
List<String> lDate = new ArrayList<>();
|
||||
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
|
||||
lDate.add(sd.format(dBegin));
|
||||
Calendar calBegin = Calendar.getInstance();
|
||||
// 使用给定的 Date 设置此 Calendar 的时间
|
||||
calBegin.setTime(dBegin);
|
||||
Calendar calEnd = Calendar.getInstance();
|
||||
// 使用给定的 Date 设置此 Calendar 的时间
|
||||
calEnd.setTime(dEnd);
|
||||
// 测试此日期是否在指定日期之后
|
||||
while (dEnd.after(calBegin.getTime())) {
|
||||
// 根据日历的规则,为给定的日历字段添加或减去指定的时间量
|
||||
calBegin.add(Calendar.DAY_OF_MONTH, 1);
|
||||
lDate.add(sd.format(calBegin.getTime()));
|
||||
}
|
||||
return lDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得日期所在年的下一年同一天<br />
|
||||
* 注:若参数date为空,则取得第当前年所对应的下一年
|
||||
*
|
||||
* @param date
|
||||
* @return
|
||||
*/
|
||||
public static Date getNextYearDay(Date date) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
if (date != null) {
|
||||
cal.setTime(date);
|
||||
}
|
||||
cal.add(Calendar.YEAR, 1);
|
||||
return cal.getTime();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取指定天开始时间
|
||||
*
|
||||
* @param date 日期
|
||||
* @return 获得该日期的开始
|
||||
*/
|
||||
public static Date getDayBegin(Date date) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
setCalender(calendar, 0, 0, 0, 0);
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定小时开始时间
|
||||
* @param date 日期
|
||||
* @return 指定小时开始时间
|
||||
*/
|
||||
public static Date getHourBegin(Date date) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
setCalender(calendar, calendar.get(Calendar.HOUR), 0, 0, 0);
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定小时结束时间
|
||||
* @param date 日期
|
||||
* @return 指定小时结束时间
|
||||
*/
|
||||
public static Date getHourEnd(Date date) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
setCalender(calendar, calendar.get(Calendar.HOUR), 59, 59, 999);
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当天开始时间
|
||||
*
|
||||
* @return 获得该日期的开始
|
||||
*/
|
||||
public static Date getDayBegin() {
|
||||
return getDayBegin(new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定天结束时间
|
||||
*
|
||||
* @param date 日期
|
||||
* @return 获得该日期的结束
|
||||
*/
|
||||
public static Date getDayEnd(Date date) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
setCalender(calendar, 23, 59, 59, 999);
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定天结束时间
|
||||
*
|
||||
* @param date 日期
|
||||
* @return 获得该日期的结束
|
||||
*/
|
||||
public static Date getDayEnd2(Date date) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
setCalender(calendar, 23, 59, 59, 000);
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期遍历接口
|
||||
* @param startDate 开始日期 yyyy-MM-dd
|
||||
* @param endDate 结束日期 yyyy-MM-dd
|
||||
* @param consumer 执行器回调
|
||||
*/
|
||||
public static void dayForEach(String startDate, String endDate, Consumer<String> consumer) {
|
||||
if (StringUtils.isEmpty(startDate) || StringUtils.isEmpty(endDate) || null == consumer) {
|
||||
return;
|
||||
}
|
||||
Date current = parse(startDate, "yyyy-MM-dd");
|
||||
Date end = parse(endDate, "yyyy-MM-dd");
|
||||
while (!current.after(end)) {
|
||||
consumer.accept(format(current, "yyyy-MM-dd"));
|
||||
current = addDate(current, Calendar.DATE, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
package fun.asgc.neutrino.proxy.core.util;
|
||||
|
||||
import fun.asgc.neutrino.proxy.core.base.InternalException;
|
||||
import fun.asgc.neutrino.proxy.core.base.MetaDataConstant;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
public class FileUtil {
|
||||
|
||||
/**
|
||||
* 根据文件路径获取输入流
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
public static InputStream getInputStream(String path) throws FileNotFoundException {
|
||||
if (StringUtils.isEmpty(path)) {
|
||||
throw new NullPointerException("path 不能为空!");
|
||||
}
|
||||
if (path.startsWith(MetaDataConstant.CLASSPATH_RESOURCE_IDENTIFIER)) {
|
||||
String subPath = path.substring(MetaDataConstant.CLASSPATH_RESOURCE_IDENTIFIER.length());
|
||||
return FileUtil.class.getResourceAsStream(subPath);
|
||||
}
|
||||
return new FileInputStream(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件路径获取输出流
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
public static OutputStream getOutputStream(String path) throws FileNotFoundException {
|
||||
if (StringUtils.isEmpty(path)) {
|
||||
throw new NullPointerException("path 不能为空!");
|
||||
}
|
||||
if (path.startsWith(MetaDataConstant.CLASSPATH_RESOURCE_IDENTIFIER)) {
|
||||
throw new InternalException("不支持路径以'" + MetaDataConstant.CLASSPATH_IDENTIFIER + "'开头");
|
||||
}
|
||||
return new FileOutputStream(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取文件内容
|
||||
* @param path
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public static String readContentAsString(String path) {
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(getInputStream(path)))){
|
||||
return br.lines().collect(Collectors.joining("\n"));
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取文件内容
|
||||
* @param in
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public static String readContentAsString(InputStream in) {
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(in))){
|
||||
return br.lines().collect(Collectors.joining("\n"));
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取文件内容
|
||||
* @param path
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public static List<String> readContentAsStringList(String path) {
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(getInputStream(path)))){
|
||||
return br.lines().collect(Collectors.toList());
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取字节内容
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
public static byte[] readBytes(String path) {
|
||||
try (InputStream in = getInputStream(path)){
|
||||
return readBytes(in);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] readBytes(File file) {
|
||||
try (InputStream in = new FileInputStream(file)){
|
||||
return readBytes(in);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] readBytes(InputStream in) throws IOException {
|
||||
byte[] bytes = new byte[1024];
|
||||
int length = 0;
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
while ((length = in.read(bytes)) != -1) {
|
||||
baos.write(bytes, 0, length);
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
public static void write(String path, String content) {
|
||||
// try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(path), StandardCharsets.UTF_8)){
|
||||
// writer.write(content);
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(getOutputStream(path)))){
|
||||
bw.write(content);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static File getDirectory(String path) {
|
||||
if (path.endsWith("/./")) {
|
||||
path = path.substring(0, path.length() - 2);
|
||||
}
|
||||
File file = new File(path);
|
||||
if (file.isDirectory() || path.endsWith("/")) {
|
||||
return file;
|
||||
}
|
||||
return file.getParentFile();
|
||||
}
|
||||
|
||||
public static void makeDirs(String path) {
|
||||
try {
|
||||
File file = getDirectory(path);
|
||||
if (null != file && !file.exists()) {
|
||||
file.mkdirs();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
public static File save(String path, String fileName, String content) {
|
||||
if (!path.endsWith("/")) {
|
||||
path += "/";
|
||||
}
|
||||
makeDirs(path);
|
||||
write(path + fileName, content);
|
||||
return new File(path + "/" + fileName);
|
||||
}
|
||||
|
||||
public static void unzipJar(String destinationDir, String jarPath) throws IOException {
|
||||
File file = new File(jarPath);
|
||||
JarFile jar = new JarFile(file);
|
||||
for (Enumeration<JarEntry> enums = jar.entries(); enums.hasMoreElements();) {
|
||||
JarEntry entry = (JarEntry) enums.nextElement();
|
||||
String fileName = destinationDir + File.separator + entry.getName();
|
||||
File f = new File(fileName);
|
||||
if (fileName.endsWith("/")) {
|
||||
f.mkdirs();
|
||||
}
|
||||
}
|
||||
for (Enumeration<JarEntry> enums = jar.entries(); enums.hasMoreElements();) {
|
||||
JarEntry entry = (JarEntry) enums.nextElement();
|
||||
String fileName = destinationDir + File.separator + entry.getName();
|
||||
File f = new File(fileName);
|
||||
if (!fileName.endsWith("/")) {
|
||||
InputStream is = jar.getInputStream(entry);
|
||||
FileOutputStream fos = new FileOutputStream(f);
|
||||
while (is.available() > 0) {
|
||||
fos.write(is.read());
|
||||
}
|
||||
fos.close();
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String getFileSuffix(String path) {
|
||||
if (StringUtils.isBlank(path)) {
|
||||
return "";
|
||||
}
|
||||
int index = path.lastIndexOf(".");
|
||||
if (index >= 0) {
|
||||
return path.substring(index);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package fun.asgc.neutrino.proxy.core.util;
|
||||
|
||||
import fun.asgc.neutrino.proxy.core.base.CodeBlock;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
public class LockUtil {
|
||||
|
||||
/**
|
||||
* 双重校验处理
|
||||
* @param isLock
|
||||
* @param lock
|
||||
* @param lockProcess
|
||||
*/
|
||||
public static void doubleCheckProcess(BooleanSupplier isLock, Object lock, CodeBlock lockProcess) throws Exception {
|
||||
if (isLock.getAsBoolean()) {
|
||||
synchronized (lock) {
|
||||
if (isLock.getAsBoolean()) {
|
||||
lockProcess.execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 双重校验处理
|
||||
* @param isLock
|
||||
* @param lock
|
||||
* @param lockProcess
|
||||
*/
|
||||
public static void doubleCheckProcessForNoException(BooleanSupplier isLock, Object lock, CodeBlock lockProcess) {
|
||||
try {
|
||||
doubleCheckProcess(isLock, lock, lockProcess);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 双重校验处理
|
||||
* @param isLock
|
||||
* @param lock
|
||||
* @param lockProcess
|
||||
* @param nonLockProcess
|
||||
*/
|
||||
public static <T> T doubleCheckProcess(BooleanSupplier isLock, Object lock, CodeBlock lockProcess, Supplier<T> nonLockProcess) throws Exception {
|
||||
doubleCheckProcess(isLock, lock, lockProcess);
|
||||
return nonLockProcess.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 双重校验处理
|
||||
* @param isLock
|
||||
* @param lock
|
||||
* @param lockProcess
|
||||
* @param nonLockProcess
|
||||
*/
|
||||
public static <T> T doubleCheckProcessForNoException(BooleanSupplier isLock, Object lock, CodeBlock lockProcess, Supplier<T> nonLockProcess) {
|
||||
doubleCheckProcessForNoException(isLock, lock, lockProcess);
|
||||
return nonLockProcess.get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,580 @@
|
||||
package fun.asgc.neutrino.proxy.core.util;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.lang.Pair;
|
||||
import com.google.common.collect.Lists;
|
||||
import fun.asgc.neutrino.proxy.core.type.TypeMatchInfo;
|
||||
import fun.asgc.neutrino.proxy.core.type.TypeMatchers;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
public class TypeUtil {
|
||||
|
||||
/**
|
||||
* 严格意义上的基本数据类型
|
||||
*/
|
||||
private static final Set<Class<?>> strictBasicType = new HashSet<Class<?>>() {
|
||||
{
|
||||
this.add(byte.class);
|
||||
this.add(short.class);
|
||||
this.add(int.class);
|
||||
this.add(long.class);
|
||||
this.add(float.class);
|
||||
this.add(double.class);
|
||||
this.add(char.class);
|
||||
this.add(boolean.class);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 一般意义上的基本数据类型
|
||||
*/
|
||||
private static final Set<Class<?>> normalBasicType = new HashSet<Class<?>>() {
|
||||
{
|
||||
this.addAll(strictBasicType);
|
||||
|
||||
this.add(Byte.class);
|
||||
this.add(Short.class);
|
||||
this.add(Integer.class);
|
||||
this.add(Long.class);
|
||||
this.add(Float.class);
|
||||
this.add(Double.class);
|
||||
this.add(Character.class);
|
||||
this.add(Boolean.class);
|
||||
this.add(String.class);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 基本类型的映射
|
||||
*/
|
||||
private static final Map<Class<?>, Class<?>> basicTypeMap = new HashMap<Class<?>, Class<?>>() {
|
||||
{
|
||||
this.put(byte.class, byte.class);
|
||||
this.put(short.class, short.class);
|
||||
this.put(int.class, int.class);
|
||||
this.put(long.class, long.class);
|
||||
this.put(float.class, float.class);
|
||||
this.put(double.class, double.class);
|
||||
this.put(char.class, char.class);
|
||||
this.put(boolean.class, boolean.class);
|
||||
|
||||
this.put(Byte.class, byte.class);
|
||||
this.put(Short.class, short.class);
|
||||
this.put(Integer.class, int.class);
|
||||
this.put(Long.class, long.class);
|
||||
this.put(Float.class, float.class);
|
||||
this.put(Double.class, double.class);
|
||||
this.put(Character.class, char.class);
|
||||
this.put(Boolean.class, boolean.class);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 包装类型的映射
|
||||
*/
|
||||
private static final Map<Class<?>, Class<?>> wrapTypeMap = new HashMap<Class<?>, Class<?>>() {
|
||||
{
|
||||
this.put(byte.class, Byte.class);
|
||||
this.put(short.class, Short.class);
|
||||
this.put(int.class, Integer.class);
|
||||
this.put(long.class, Long.class);
|
||||
this.put(float.class, Float.class);
|
||||
this.put(double.class, Double.class);
|
||||
this.put(char.class, Character.class);
|
||||
this.put(boolean.class, Boolean.class);
|
||||
|
||||
this.put(Byte.class, Byte.class);
|
||||
this.put(Short.class, Short.class);
|
||||
this.put(Integer.class, Integer.class);
|
||||
this.put(Long.class, Long.class);
|
||||
this.put(Float.class, Float.class);
|
||||
this.put(Double.class, Double.class);
|
||||
this.put(Character.class, Character.class);
|
||||
this.put(Boolean.class, Boolean.class);
|
||||
|
||||
this.put(String.class, String.class);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 基本类型列表(用于计算类型提升距离)
|
||||
*/
|
||||
public static final List<Class<?>> basicTypeList = Lists.newArrayList(
|
||||
boolean.class, Boolean.class, byte.class, Byte.class, short.class, Short.class, char.class, Character.class,
|
||||
int.class, Integer.class, long.class, Long.class, float.class, Float.class, double.class, Double.class
|
||||
);
|
||||
|
||||
/**
|
||||
* 默认值
|
||||
*/
|
||||
private static final Map<Class<?>, Object> defaultValueMap = new HashMap<Class<?>, Object>() {
|
||||
{
|
||||
this.put(byte.class, 0);
|
||||
this.put(short.class, 0);
|
||||
this.put(int.class, 0);
|
||||
this.put(long.class, 0);
|
||||
this.put(float.class, 0);
|
||||
this.put(double.class, 0);
|
||||
this.put(char.class, 0);
|
||||
this.put(boolean.class, false);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 默认的类型匹配器
|
||||
*/
|
||||
private static final TypeMatchers defaultTypeMatchers = new TypeMatchers();
|
||||
|
||||
/**
|
||||
* 获取字段类型
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public static Class<?> getFieldType(Field field) {
|
||||
return field.getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* 字段类型匹配
|
||||
* @param field
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static boolean fieldTypeMatch(Field field, Class<?> clazz) {
|
||||
return getFieldType(field) == clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是严格基本类型
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static boolean isStrictBasicType(Class<?> clazz) {
|
||||
return strictBasicType.contains(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是严格基本类型
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public static boolean isStrictBasicType(Field field) {
|
||||
return isStrictBasicType(getFieldType(field));
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是一般基本类型
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static boolean isNormalBasicType(Class<?> clazz) {
|
||||
return normalBasicType.contains(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是数字
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static boolean isNumber(Class<?> clazz) {
|
||||
return Number.class.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是一般基本类型
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public static boolean isNormalBasicType(Field field) {
|
||||
return isNormalBasicType(getFieldType(field));
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是包装类型
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static boolean isWrapType(Class<?> clazz) {
|
||||
return !isStrictBasicType(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是包装类型
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public static boolean isWrapType(Field field) {
|
||||
return !isStrictBasicType(field);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是byte类型
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public static boolean isByte(Field field) {
|
||||
return isByte(getFieldType(field));
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是byte类型
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static boolean isByte(Class clazz) {
|
||||
return clazz == byte.class || clazz == Byte.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是short类型
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public static boolean isShort(Field field) {
|
||||
return isShort(getFieldType(field));
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是short类型
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static boolean isShort(Class clazz) {
|
||||
return clazz == short.class || clazz == Short.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是integer类型
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public static boolean isInteger(Field field) {
|
||||
return isInteger(getFieldType(field));
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是integer类型
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static boolean isInteger(Class clazz) {
|
||||
return clazz == int.class || clazz == Integer.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是long类型
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public static boolean isLong(Field field) {
|
||||
return isLong(getFieldType(field));
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是long类型
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static boolean isLong(Class<?> clazz) {
|
||||
return clazz == long.class || clazz == Long.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是float类型
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public static boolean isFloat(Field field) {
|
||||
return isFloat(getFieldType(field));
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是float类型
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static boolean isFloat(Class<?> clazz) {
|
||||
return clazz == float.class || clazz == Float.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是double类型
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public static boolean isDouble(Field field) {
|
||||
return isDouble(getFieldType(field));
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是double类型
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static boolean isDouble(Class<?> clazz) {
|
||||
return clazz == double.class || clazz == Double.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是char类型
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public static boolean isChar(Field field) {
|
||||
Class<?> clazz = getFieldType(field);
|
||||
return clazz == char.class || clazz == Character.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是boolean类型
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public static boolean isBoolean(Field field) {
|
||||
Class<?> clazz = getFieldType(field);
|
||||
return clazz == boolean.class || clazz == Boolean.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是String类型
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public static boolean isString(Field field) {
|
||||
return isString(getFieldType(field));
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是String类型
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static boolean isString(Class clazz) {
|
||||
return clazz == String.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是日期类型
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public static boolean isDate(Field field) {
|
||||
return isDate(getFieldType(field));
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是日期类型
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static boolean isDate(Class<?> clazz) {
|
||||
return clazz == Date.class || clazz == java.sql.Date.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是布尔值
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static boolean isBoolean(Class<?> clazz) {
|
||||
return clazz == boolean.class || clazz == Boolean.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是字符
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static boolean isChar(Class<?> clazz) {
|
||||
return clazz == char.class || clazz == Character.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是map类型
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static boolean isMap(Class<?> clazz) {
|
||||
return Map.class.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取包装类型
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static Class<?> getWrapType(Class<?> clazz) {
|
||||
if (isStrictBasicType(clazz)) {
|
||||
return wrapTypeMap.get(clazz);
|
||||
}
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取包装类型
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public static Class<?> getWrapType(Field field) {
|
||||
return getWrapType(getFieldType(field));
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是超类
|
||||
* @param superClass
|
||||
* @param childClass
|
||||
* @return
|
||||
*/
|
||||
public static boolean isSupper(Class<?> superClass, Class<?> childClass) {
|
||||
return superClass.isAssignableFrom(childClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取简单类名
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static String getSimpleName(Class<?> clazz) {
|
||||
return clazz.getSimpleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取包名
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static String getPackageName(Class<?> clazz) {
|
||||
return clazz.getPackage().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取默认变量名
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static String getDefaultVariableName(Class<?> clazz) {
|
||||
String name = getSimpleName(clazz);
|
||||
return name.substring(0, 1).toLowerCase() + name.substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取默认值
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static Object getDefaultValue(Class<?> clazz) {
|
||||
return defaultValueMap.get(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是集合类型
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static boolean isCollection(Class<?> clazz) {
|
||||
return Collection.class.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否可列举
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static boolean isListable(Class<?> clazz) {
|
||||
return clazz.isArray() || isCollection(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是list
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static boolean isList(Class<?> clazz) {
|
||||
return List.class.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* list转成其他形式
|
||||
* @param list
|
||||
* @param targetType
|
||||
* @return
|
||||
*/
|
||||
public static Object listTo(List list, Class<?> targetType) {
|
||||
if (null == list) {
|
||||
return null;
|
||||
}
|
||||
if (isList(targetType)) {
|
||||
return list;
|
||||
}
|
||||
// 数组
|
||||
if (targetType.isArray()) {
|
||||
return list.toArray();
|
||||
}
|
||||
// set
|
||||
if (Set.class.isAssignableFrom(targetType)) {
|
||||
return list.stream().collect(Collectors.toSet());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取继承层级
|
||||
* 此处假定继承层级最多为100层,避免计算太过耗时
|
||||
* @param superClass
|
||||
* @param childClass
|
||||
* @return
|
||||
*/
|
||||
public static int getInheritLevel(Class<?> superClass, Class<?> childClass) {
|
||||
if (!isSupper(superClass, childClass)) {
|
||||
return -1;
|
||||
}
|
||||
List<Pair<Class<?>, Integer>> list = new LinkedList<>();
|
||||
list.add(Pair.of(childClass, 0));
|
||||
while (CollectionUtil.isNotEmpty(list) && list.get(0).getKey() != superClass && list.get(0).getValue() < 100) {
|
||||
Pair<Class<?>, Integer> current = list.remove(0);
|
||||
Class<?> clazz = current.getKey();
|
||||
int level = current.getValue();
|
||||
if (null != clazz.getSuperclass()) {
|
||||
list.add(Pair.of(clazz.getSuperclass(), level + 1));
|
||||
}
|
||||
if (null != clazz.getInterfaces() && clazz.getInterfaces().length > 0) {
|
||||
for (Class<?> inter : clazz.getInterfaces()) {
|
||||
list.add(Pair.of(inter, level + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (list.isEmpty()) {
|
||||
return 100;
|
||||
}
|
||||
return Math.min(list.get(0).getValue(), 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算一个类型的值是否可以赋值给指定类型的匹配信息
|
||||
* @param fieldType
|
||||
* @param valueType
|
||||
* @return
|
||||
*/
|
||||
public static TypeMatchInfo typeMatch(Class<?> fieldType, Class<?> valueType) {
|
||||
Assert.notNull(fieldType, "字段类型不能为空!");
|
||||
Assert.notNull(valueType, "值类型不能为空!");
|
||||
return new TypeMatchInfo(fieldType, valueType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 类型转换
|
||||
* @param value
|
||||
* @param targetType
|
||||
* @return
|
||||
*/
|
||||
public static <T> T conversion(Object value, Class<T> targetType) {
|
||||
return (T)defaultTypeMatchers.conversion(value, targetType);
|
||||
}
|
||||
}
|
||||
@@ -13,8 +13,35 @@
|
||||
|
||||
<artifactId>neutrino-proxy-server</artifactId>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.noear</groupId>
|
||||
<artifactId>solon-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.noear</groupId>
|
||||
<artifactId>mybatis-plus-solon-plugin</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.noear</groupId>
|
||||
<artifactId>mybatis-pagehelper-solon-plugin</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.noear</groupId>
|
||||
<artifactId>activerecord-solon-plugin</artifactId>
|
||||
</dependency>
|
||||
<!--orika-->
|
||||
<dependency>
|
||||
<groupId>fun.asgc</groupId>
|
||||
<artifactId>orika-solon-plugin</artifactId>
|
||||
<version>2.2.2</version>
|
||||
</dependency>
|
||||
<!--job-->
|
||||
<dependency>
|
||||
<groupId>fun.asgc</groupId>
|
||||
<artifactId>job-solon-plugin</artifactId>
|
||||
<version>2.2.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>fun.asgc.neutrino</groupId>
|
||||
<artifactId>neutrino-proxy-core</artifactId>
|
||||
@@ -23,17 +50,14 @@
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<version>3.39.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid</artifactId>
|
||||
<version>1.1.24</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.29</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.zaxxer</groupId>
|
||||
<artifactId>HikariCP</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
+9
-28
@@ -1,30 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package fun.asgc.neutrino.proxy.server;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.EnableJob;
|
||||
import fun.asgc.neutrino.core.annotation.NeutrinoApplication;
|
||||
import fun.asgc.neutrino.core.context.NeutrinoLauncher;
|
||||
import fun.asgc.solon.extend.job.annotation.EnableJob;
|
||||
import org.noear.solon.Solon;
|
||||
import org.noear.solon.annotation.SolonMain;
|
||||
import org.noear.solon.web.cors.CrossFilter;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -32,11 +11,13 @@ import fun.asgc.neutrino.core.context.NeutrinoLauncher;
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@EnableJob
|
||||
@NeutrinoApplication
|
||||
@SolonMain
|
||||
public class ProxyServer {
|
||||
|
||||
public static void main(String[] args) {
|
||||
NeutrinoLauncher.run(ProxyServer.class, args);
|
||||
Solon.start(ProxyServer.class, args, app -> {
|
||||
// 跨域支持。加-1 优先级更高
|
||||
app.filter(-1, new CrossFilter().allowedOrigins("*"));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+33
-63
@@ -19,20 +19,22 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.base.rest;
|
||||
package fun.asgc.neutrino.proxy.server.base.db;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import fun.asgc.neutrino.core.annotation.PreLoad;
|
||||
import fun.asgc.neutrino.core.db.template.JdbcTemplate;
|
||||
import fun.asgc.neutrino.core.util.*;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.config.DbConfig;
|
||||
import com.jfinal.plugin.activerecord.Db;
|
||||
import fun.asgc.neutrino.proxy.core.util.Assert;
|
||||
import fun.asgc.neutrino.proxy.core.util.FileUtil;
|
||||
import fun.asgc.neutrino.proxy.server.constant.DbTypeEnum;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.sqlite.SQLiteConfig;
|
||||
import org.sqlite.SQLiteDataSource;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Init;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
import org.noear.solon.core.event.AppLoadEndEvent;
|
||||
import org.noear.solon.core.event.EventListener;
|
||||
|
||||
import java.sql.DriverManager;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -41,43 +43,48 @@ import java.util.List;
|
||||
* @date: 2022/7/31
|
||||
*/
|
||||
@Slf4j
|
||||
@PreLoad("init")
|
||||
public class DBInitialize {
|
||||
@Component
|
||||
public class DBInitialize implements EventListener<AppLoadEndEvent> {
|
||||
private static List<String> initDataTableNameList = Lists.newArrayList("user", "license", "port_pool", "port_mapping", "job_info");
|
||||
private static DbConfig dbConfig;
|
||||
private static JdbcTemplate jdbcTemplate;
|
||||
@Inject
|
||||
private DbConfig dbConfig;
|
||||
|
||||
private static DbTypeEnum dbTypeEnum;
|
||||
private DbTypeEnum dbTypeEnum;
|
||||
|
||||
public static void init() throws Exception {
|
||||
dbConfig = ConfigUtil.getYmlConfig(DbConfig.class);
|
||||
@Init
|
||||
public void init() throws Throwable {
|
||||
Assert.notNull(dbConfig.getType(), "neutrino.data.db.type不能为空!");
|
||||
dbTypeEnum = DbTypeEnum.of(dbConfig.getType());
|
||||
Assert.notNull(dbTypeEnum, "neutrino.data.db.type取值异常!");
|
||||
|
||||
log.info("{}数据库初始化...", dbConfig.getType());
|
||||
jdbcTemplate = getJdbcTemplate();
|
||||
initDBStructure();
|
||||
initDBData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(AppLoadEndEvent appLoadEndEvent) throws Throwable {
|
||||
// TODO 该事件有50%的概率不触发
|
||||
System.out.println("11");
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化数据库结构
|
||||
*/
|
||||
private static void initDBStructure() throws Exception {
|
||||
private void initDBStructure() throws Exception {
|
||||
List<String> lines = FileUtil.readContentAsStringList(String.format("classpath:/sql/%s/init-structure.sql", dbConfig.getType()));
|
||||
if (CollectionUtil.isEmpty(lines)) {
|
||||
return;
|
||||
}
|
||||
String sql = "";
|
||||
for (String line : lines) {
|
||||
if (StringUtil.isEmpty(line) || StringUtil.isEmpty(line.trim()) || line.trim().startsWith("#")) {
|
||||
if (StrUtil.isEmpty(line) || StrUtil.isEmpty(line.trim()) || line.trim().startsWith("#")) {
|
||||
continue;
|
||||
}
|
||||
sql += "\r\n" + line.trim();
|
||||
if (sql.endsWith(";")) {
|
||||
log.debug("初始化数据库表 sql:{}", sql);
|
||||
jdbcTemplate.update(sql);
|
||||
Db.update(sql);
|
||||
sql = "";
|
||||
}
|
||||
}
|
||||
@@ -85,15 +92,17 @@ public class DBInitialize {
|
||||
|
||||
/**
|
||||
* 初始化数据
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
private static void initDBData() throws Exception {
|
||||
private void initDBData() throws Exception {
|
||||
if (CollectionUtil.isEmpty(initDataTableNameList)) {
|
||||
return;
|
||||
}
|
||||
for (String tableName : initDataTableNameList) {
|
||||
// 表里没有数据的时候,才进行初始化操作
|
||||
int count = jdbcTemplate.queryForInt(String.format("select count(1) from `%s`", tableName));
|
||||
|
||||
int count = Db.queryInt(String.format("select count(1) from `%s`", tableName));
|
||||
if (count > 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -103,55 +112,16 @@ public class DBInitialize {
|
||||
}
|
||||
String sql = "";
|
||||
for (String line : lines) {
|
||||
if (StringUtil.isEmpty(line) || StringUtil.isEmpty(line.trim()) || line.trim().startsWith("#")) {
|
||||
if (StrUtil.isEmpty(line) || StrUtil.isEmpty(line.trim()) || line.trim().startsWith("#")) {
|
||||
continue;
|
||||
}
|
||||
sql += "\r\n" + line.trim();
|
||||
if (sql.endsWith(";")) {
|
||||
log.debug("初始化数据[table={}] sql:{}", tableName, sql);
|
||||
jdbcTemplate.update(sql);
|
||||
Db.update(sql);
|
||||
sql = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取jdbcTemplate实例
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
private static JdbcTemplate getJdbcTemplate() throws Exception {
|
||||
return LockUtil.doubleCheckProcess(
|
||||
() -> null == jdbcTemplate,
|
||||
DBInitialize.class,
|
||||
() -> {
|
||||
if (DbTypeEnum.SQLITE == dbTypeEnum) {
|
||||
//建立一个数据库名data.db的连接,如果不存在就在当前目录下创建之
|
||||
DriverManager.getConnection(dbConfig.getUrl());
|
||||
// 创建数据源
|
||||
SQLiteDataSource dataSource = new SQLiteDataSource();
|
||||
dataSource.setUrl(dbConfig.getUrl());
|
||||
dataSource.setJournalMode(SQLiteConfig.JournalMode.WAL.getValue());
|
||||
// 创建jdbcTemplate
|
||||
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
} else if (DbTypeEnum.MYSQL == dbTypeEnum) {
|
||||
DruidDataSource dataSource = new DruidDataSource();
|
||||
dataSource.setDriverClassName(dbConfig.getDriverClass());
|
||||
dataSource.setUrl(dbConfig.getUrl());
|
||||
dataSource.setInitialSize(5);
|
||||
dataSource.setMinIdle(5);
|
||||
dataSource.setMaxActive(20);
|
||||
dataSource.setMaxWait(60000);
|
||||
dataSource.setPoolPreparedStatements(true);
|
||||
dataSource.setUsername(dbConfig.getUsername());
|
||||
dataSource.setPassword(dbConfig.getPassword());
|
||||
|
||||
// 创建jdbcTemplate
|
||||
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
},
|
||||
() -> jdbcTemplate
|
||||
);
|
||||
}
|
||||
}
|
||||
+9
-12
@@ -19,13 +19,12 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.base.rest.config;
|
||||
package fun.asgc.neutrino.proxy.server.base.db;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Configuration;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.annotation.Value;
|
||||
import fun.asgc.neutrino.proxy.server.constant.DbTypeEnum;
|
||||
import lombok.Data;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
|
||||
/**
|
||||
* sqlite数据库配置
|
||||
@@ -33,35 +32,33 @@ import lombok.Data;
|
||||
* @date: 2022/7/31
|
||||
*/
|
||||
@Data
|
||||
@NonIntercept
|
||||
@Configuration(prefix = "neutrino.data.db")
|
||||
@Component
|
||||
public class DbConfig {
|
||||
/**
|
||||
* 数据库类型
|
||||
* {@link DbTypeEnum}
|
||||
*/
|
||||
@Value("type")
|
||||
@Inject("${neutrino.data.db.type}")
|
||||
private String type;
|
||||
/**
|
||||
* 连接url
|
||||
*/
|
||||
@Value("url")
|
||||
@Inject("${neutrino.data.db.url}")
|
||||
private String url;
|
||||
/**
|
||||
* 驱动类
|
||||
*/
|
||||
@Value("driver-class")
|
||||
@Inject("${neutrino.data.db.driver-class}")
|
||||
private String driverClass;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
@Value("username")
|
||||
@Inject("${neutrino.data.db.username}")
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
@Value("password")
|
||||
@Inject("${neutrino.data.db.password}")
|
||||
private String password;
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
package fun.asgc.neutrino.proxy.server.base.db;
|
||||
|
||||
import com.baomidou.mybatisplus.core.MybatisConfiguration;
|
||||
import com.baomidou.mybatisplus.core.MybatisSqlSessionFactoryBuilder;
|
||||
import com.baomidou.mybatisplus.core.config.GlobalConfig;
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import fun.asgc.neutrino.proxy.server.constant.DbTypeEnum;
|
||||
import org.apache.ibatis.solon.annotation.Db;
|
||||
import org.noear.solon.annotation.Bean;
|
||||
import org.noear.solon.annotation.Configuration;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
import org.sqlite.SQLiteConfig;
|
||||
import org.sqlite.SQLiteDataSource;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2023/3/10
|
||||
*/
|
||||
@Configuration
|
||||
public class DbConfiguration {
|
||||
|
||||
@Bean(value = "db", typed = true)
|
||||
public DataSource dataSource(@Inject DbConfig dbConfig) {
|
||||
DbTypeEnum dbTypeEnum = DbTypeEnum.of(dbConfig.getType());
|
||||
if (DbTypeEnum.SQLITE == dbTypeEnum) {
|
||||
SQLiteDataSource dataSource = new SQLiteDataSource();
|
||||
dataSource.setUrl(dbConfig.getUrl());
|
||||
dataSource.setJournalMode(SQLiteConfig.JournalMode.WAL.getValue());
|
||||
return dataSource;
|
||||
} else if (DbTypeEnum.MYSQL == dbTypeEnum) {
|
||||
HikariDataSource dataSource = new HikariDataSource();
|
||||
dataSource.setDriverClassName(dbConfig.getDriverClass());
|
||||
dataSource.setJdbcUrl(dbConfig.getUrl());
|
||||
dataSource.setMinimumIdle(5);
|
||||
dataSource.setMaximumPoolSize(20);
|
||||
dataSource.setMaxLifetime(60000);
|
||||
// dataSource.setInitialSize(5);
|
||||
// dataSource.setMinIdle(5);
|
||||
// dataSource.setMaxActive(20);
|
||||
// dataSource.setMaxWait(60000);
|
||||
// dataSource.setPoolPreparedStatements(true);
|
||||
dataSource.setUsername(dbConfig.getUsername());
|
||||
dataSource.setPassword(dbConfig.getPassword());
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public void db1_ext(@Db("db") GlobalConfig globalConfig) {
|
||||
MetaObjectHandler metaObjectHandler = new MetaObjectHandlerImpl();
|
||||
globalConfig.setMetaObjectHandler(metaObjectHandler);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public void db1_ext2(@Db("db") MybatisConfiguration config){
|
||||
config.getTypeHandlerRegistry().register("fun.asgc.neutrino.proxy.server.dal");
|
||||
config.setDefaultEnumTypeHandler(null);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MybatisSqlSessionFactoryBuilder factoryBuilderNew(){
|
||||
return new MybatisSqlSessionFactoryBuilderImpl();
|
||||
}
|
||||
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package fun.asgc.neutrino.proxy.server.base.db;
|
||||
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import org.apache.ibatis.reflection.MetaObject;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2023/3/10
|
||||
*/
|
||||
public class MetaObjectHandlerImpl implements MetaObjectHandler {
|
||||
@Override
|
||||
public void insertFill(MetaObject metaObject) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFill(MetaObject metaObject) {
|
||||
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package fun.asgc.neutrino.proxy.server.base.db;
|
||||
|
||||
import com.baomidou.mybatisplus.core.MybatisSqlSessionFactoryBuilder;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2023/3/10
|
||||
*/
|
||||
public class MybatisSqlSessionFactoryBuilderImpl extends MybatisSqlSessionFactoryBuilder {
|
||||
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
package fun.asgc.neutrino.proxy.server.base.page;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/6
|
||||
*/
|
||||
@Data
|
||||
public class PageInfo<T> implements Serializable {
|
||||
private static final long serialVersionUID = 8545996863226528797L;
|
||||
private List<T> records;
|
||||
private Long total;
|
||||
private Integer size;
|
||||
private Integer current;
|
||||
|
||||
public PageInfo() {
|
||||
this.records = Collections.emptyList();
|
||||
this.total = 0L;
|
||||
this.size = 10;
|
||||
this.current = 1;
|
||||
}
|
||||
|
||||
public PageInfo(Integer current, Integer size) {
|
||||
this(current, size, 0L);
|
||||
}
|
||||
|
||||
public PageInfo(Integer current, Integer size, Long total) {
|
||||
this.records = Collections.emptyList();
|
||||
this.total = 0L;
|
||||
this.size = 10;
|
||||
this.current = 1;
|
||||
if ((long)current > 1L) {
|
||||
this.current = current;
|
||||
}
|
||||
|
||||
this.size = size;
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
public Long getPages() {
|
||||
if ((long)this.getSize() == 0L) {
|
||||
return 0L;
|
||||
} else {
|
||||
Long pages = this.getTotal() / (long)this.getSize();
|
||||
if (this.getTotal() % (long)this.getSize() != 0L) {
|
||||
pages = pages + 1L;
|
||||
}
|
||||
|
||||
return pages;
|
||||
}
|
||||
}
|
||||
|
||||
public Long getTotal() {
|
||||
return this.total;
|
||||
}
|
||||
|
||||
public Integer getSize() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
public boolean hasPrevious() {
|
||||
return (long)this.current > 1L;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return (long)this.current < this.getPages();
|
||||
}
|
||||
|
||||
public List<T> getRecords() {
|
||||
return this.records;
|
||||
}
|
||||
|
||||
public PageInfo<T> setRecords(List<T> records) {
|
||||
this.records = records;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PageInfo<T> setTotal(Long total) {
|
||||
this.total = total;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PageInfo<T> setSize(Integer size) {
|
||||
this.size = size;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getCurrent() {
|
||||
return this.current;
|
||||
}
|
||||
|
||||
public PageInfo<T> setCurrent(Integer current) {
|
||||
this.current = current;
|
||||
return this;
|
||||
}
|
||||
|
||||
public static <T> PageInfo<T> of(List<T> records, Long total, Integer current, Integer size) {
|
||||
PageInfo<T> pageInfo = new PageInfo();
|
||||
pageInfo.setRecords(records);
|
||||
pageInfo.setTotal(total);
|
||||
pageInfo.setCurrent(current);
|
||||
pageInfo.setSize(size);
|
||||
return pageInfo;
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package fun.asgc.neutrino.proxy.server.base.page;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/6
|
||||
*/
|
||||
@Data
|
||||
public class PageQuery implements Serializable {
|
||||
/**
|
||||
* 当前页
|
||||
*/
|
||||
private int current = 1;
|
||||
/**
|
||||
* 分页大小
|
||||
*/
|
||||
private int size = 10;
|
||||
}
|
||||
+5
-37
@@ -1,29 +1,8 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.base.proxy;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Configuration;
|
||||
import fun.asgc.neutrino.core.annotation.Value;
|
||||
import lombok.Data;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
|
||||
/**
|
||||
* 服务端代理配置
|
||||
@@ -31,48 +10,37 @@ import lombok.Data;
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@Data
|
||||
@Configuration(prefix = "neutrino.proxy")
|
||||
@Component
|
||||
public class ProxyConfig {
|
||||
/**
|
||||
* 传输协议相关配置
|
||||
*/
|
||||
@Inject("${neutrino.proxy.protocol}")
|
||||
private Protocol protocol;
|
||||
/**
|
||||
* 服务端配置
|
||||
*/
|
||||
@Inject("${neutrino.proxy.server}")
|
||||
private Server server;
|
||||
|
||||
@Data
|
||||
public static class Protocol {
|
||||
@Value("max-frame-length")
|
||||
private Integer maxFrameLength;
|
||||
@Value("length-field-offset")
|
||||
private Integer lengthFieldOffset;
|
||||
@Value("length-field-length")
|
||||
private Integer lengthFieldLength;
|
||||
@Value("initial-bytes-to-strip")
|
||||
private Integer initialBytesToStrip;
|
||||
@Value("length-adjustment")
|
||||
private Integer lengthAdjustment;
|
||||
@Value("read-idle-time")
|
||||
private Integer readIdleTime;
|
||||
@Value("write-idle-time")
|
||||
private Integer writeIdleTime;
|
||||
@Value("all-idle-time-seconds")
|
||||
private Integer allIdleTimeSeconds;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Server {
|
||||
@Value("port")
|
||||
private Integer port;
|
||||
@Value("ssl-port")
|
||||
private Integer sslPort;
|
||||
@Value("key-store-password")
|
||||
private String keyStorePassword;
|
||||
@Value("key-manager-password")
|
||||
private String keyManagerPassword;
|
||||
@Value("jks-path")
|
||||
private String jksPath;
|
||||
}
|
||||
|
||||
|
||||
+32
-36
@@ -1,51 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.base.proxy;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Bean;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Order;
|
||||
import fun.asgc.neutrino.core.base.DefaultDispatcher;
|
||||
import fun.asgc.neutrino.core.base.Dispatcher;
|
||||
import fun.asgc.neutrino.core.base.Ordered;
|
||||
import fun.asgc.neutrino.core.util.BeanManager;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyDataTypeEnum;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessage;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessageHandler;
|
||||
import fun.asgc.neutrino.proxy.core.dispatcher.DefaultDispatcher;
|
||||
import fun.asgc.neutrino.proxy.core.dispatcher.Dispatcher;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import org.noear.solon.Solon;
|
||||
import org.noear.solon.annotation.Bean;
|
||||
import org.noear.solon.annotation.Configuration;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
import org.noear.solon.core.AopContext;
|
||||
import org.noear.solon.core.bean.LifecycleBean;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 代理配置
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/8
|
||||
*/
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
@Component
|
||||
public class ProxyConfiguration {
|
||||
@Configuration
|
||||
public class ProxyConfiguration implements LifecycleBean {
|
||||
|
||||
@Bean
|
||||
public Dispatcher<ChannelHandlerContext, ProxyMessage> dispatcher() {
|
||||
return new DefaultDispatcher<>("消息调度器",
|
||||
BeanManager.getBeanListBySuperClass(ProxyMessageHandler.class),
|
||||
proxyMessage -> ProxyDataTypeEnum.of((int)proxyMessage.getType()) == null ? null : ProxyDataTypeEnum.of((int)proxyMessage.getType()).getName());
|
||||
@Override
|
||||
public void start() throws Throwable {
|
||||
List<ProxyMessageHandler> list = Solon.context().getBeansOfType(ProxyMessageHandler.class);
|
||||
Dispatcher<ChannelHandlerContext, ProxyMessage> dispatcher = new DefaultDispatcher<>("消息调度器", list,
|
||||
proxyMessage -> ProxyDataTypeEnum.of((int)proxyMessage.getType()) == null ?
|
||||
null : ProxyDataTypeEnum.of((int)proxyMessage.getType()).getName());
|
||||
|
||||
Solon.context().wrapAndPut(Dispatcher.class, dispatcher);
|
||||
}
|
||||
|
||||
@Bean("serverBossGroup")
|
||||
public NioEventLoopGroup serverBossGroup() {
|
||||
return new NioEventLoopGroup();
|
||||
}
|
||||
|
||||
@Bean("serverWorkerGroup")
|
||||
public NioEventLoopGroup serverWorkerGroup() {
|
||||
return new NioEventLoopGroup();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -35,4 +35,6 @@ import java.lang.annotation.Target;
|
||||
@Target({ElementType.METHOD})
|
||||
public @interface Authorization {
|
||||
boolean login() default true;
|
||||
|
||||
boolean onlyAdmin() default false;
|
||||
}
|
||||
|
||||
+2
@@ -24,6 +24,7 @@ package fun.asgc.neutrino.proxy.server.base.rest;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.noear.solon.core.handle.Action;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@@ -51,4 +52,5 @@ public class SystemContext {
|
||||
* 接收请求时间
|
||||
*/
|
||||
private Date receiveTime;
|
||||
private Action action;
|
||||
}
|
||||
|
||||
-75
@@ -1,75 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.base.rest.config;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import fun.asgc.neutrino.core.annotation.*;
|
||||
import fun.asgc.neutrino.core.base.Ordered;
|
||||
import fun.asgc.neutrino.core.db.template.JdbcTemplate;
|
||||
import fun.asgc.neutrino.proxy.server.constant.DbTypeEnum;
|
||||
import org.sqlite.SQLiteConfig;
|
||||
import org.sqlite.SQLiteDataSource;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* 系统配置
|
||||
*author: aoshiguchen
|
||||
* @date: 2022/8/1
|
||||
*/
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
@Component
|
||||
public class RestConfiguration {
|
||||
@Autowired
|
||||
private DbConfig dbConfig;
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
DbTypeEnum dbTypeEnum = DbTypeEnum.of(dbConfig.getType());
|
||||
if (DbTypeEnum.SQLITE == dbTypeEnum) {
|
||||
SQLiteDataSource dataSource = new SQLiteDataSource();
|
||||
dataSource.setUrl(dbConfig.getUrl());
|
||||
dataSource.setJournalMode(SQLiteConfig.JournalMode.WAL.getValue());
|
||||
return dataSource;
|
||||
} else if (DbTypeEnum.MYSQL == dbTypeEnum) {
|
||||
DruidDataSource dataSource = new DruidDataSource();
|
||||
dataSource.setDriverClassName(dbConfig.getDriverClass());
|
||||
dataSource.setUrl(dbConfig.getUrl());
|
||||
dataSource.setInitialSize(5);
|
||||
dataSource.setMinIdle(5);
|
||||
dataSource.setMaxActive(20);
|
||||
dataSource.setMaxWait(60000);
|
||||
dataSource.setPoolPreparedStatements(true);
|
||||
dataSource.setUsername(dbConfig.getUsername());
|
||||
dataSource.setPassword(dbConfig.getPassword());
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JdbcTemplate jdbcTemplate() {
|
||||
return new JdbcTemplate(dataSource());
|
||||
}
|
||||
|
||||
}
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.base.rest.config;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Configuration;
|
||||
import fun.asgc.neutrino.core.web.config.WebMvcConfigurer;
|
||||
import fun.asgc.neutrino.core.web.interceptor.ExceptionHandlerRegistry;
|
||||
import fun.asgc.neutrino.core.web.interceptor.InterceptorRegistry;
|
||||
import fun.asgc.neutrino.core.web.interceptor.RestControllerAdviceHandler;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.interceptor.*;
|
||||
|
||||
/**
|
||||
* web配置
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/7/30
|
||||
*/
|
||||
@Configuration
|
||||
public class WebConfigurerAdapter implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(new BaseAuthInterceptor())
|
||||
.addPathPatterns("/**").excludePathPatterns("/**/*.html", "/**/*.js", "/**/*.ico");
|
||||
registry.addInterceptor(new CorsInterceptor());
|
||||
registry.addInterceptor(new VisitLogInterceptor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestControllerAdviceHandler adviceHandler() {
|
||||
return new GlobalAdviceHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addExceptionHandler(ExceptionHandlerRegistry registry) {
|
||||
registry.addExceptionHandler(new GlobalExceptionHandler());
|
||||
}
|
||||
}
|
||||
+75
-64
@@ -1,84 +1,95 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.base.rest.interceptor;
|
||||
|
||||
import fun.asgc.neutrino.core.util.BeanManager;
|
||||
import fun.asgc.neutrino.core.util.HttpUtil;
|
||||
import fun.asgc.neutrino.core.util.StringUtil;
|
||||
import fun.asgc.neutrino.core.web.context.HttpContextHolder;
|
||||
import fun.asgc.neutrino.core.web.context.HttpRequestWrapper;
|
||||
import fun.asgc.neutrino.core.web.context.HttpResponseWrapper;
|
||||
import fun.asgc.neutrino.core.web.interceptor.HandlerInterceptor;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.*;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.annotation.OnlyAdmin;
|
||||
import fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
|
||||
import fun.asgc.neutrino.proxy.server.constant.ExceptionConstant;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
|
||||
import fun.asgc.neutrino.proxy.server.service.UserService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.noear.solon.Solon;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.core.handle.Action;
|
||||
import org.noear.solon.core.handle.Context;
|
||||
import org.noear.solon.core.handle.Handler;
|
||||
import org.noear.solon.core.route.RouterInterceptor;
|
||||
import org.noear.solon.core.route.RouterInterceptorChain;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 鉴权拦截器
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/7/30
|
||||
* @date: 2023/3/9
|
||||
*/
|
||||
public class BaseAuthInterceptor implements HandlerInterceptor {
|
||||
@Slf4j
|
||||
@Component
|
||||
public class BaseAuthInterceptor implements RouterInterceptor {
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpRequestWrapper requestParser, HttpResponseWrapper responseWrapper, String route, Method targetMethod) throws Exception {
|
||||
SystemContext systemContext = new SystemContext();
|
||||
SystemContextHolder.set(systemContext);
|
||||
systemContext.setIp(HttpUtil.getIP(HttpContextHolder.getChannelHandlerContext(), requestParser));
|
||||
@Override
|
||||
public void doIntercept(Context ctx, Handler mainHandler, RouterInterceptorChain chain) throws Throwable {
|
||||
if (!(mainHandler instanceof Action)) {
|
||||
chain.doIntercept(ctx, mainHandler);
|
||||
return;
|
||||
}
|
||||
Action action = (Action) mainHandler;
|
||||
Method targetMethod = action.method().getMethod();
|
||||
|
||||
Authorization authorization = targetMethod.getAnnotation(Authorization.class);
|
||||
if (null == authorization || authorization.login()) {
|
||||
String authorize = requestParser.getHeaderValue("Authorize");
|
||||
if (StringUtil.isEmpty(authorize)) {
|
||||
throw ServiceException.create(ExceptionConstant.USER_NOT_LOGIN);
|
||||
}
|
||||
UserDO userDO = BeanManager.getBean(UserService.class).findByToken(authorize);
|
||||
if (null == userDO) {
|
||||
throw ServiceException.create(ExceptionConstant.USER_NOT_LOGIN);
|
||||
}
|
||||
if (EnableStatusEnum.DISABLE.getStatus().equals(userDO.getEnable())) {
|
||||
throw ServiceException.create(ExceptionConstant.USER_DISABLE);
|
||||
}
|
||||
if (targetMethod.isAnnotationPresent(OnlyAdmin.class) && !userDO.getLoginName().equals("admin")) {
|
||||
throw ServiceException.create(ExceptionConstant.NO_PERMISSION_VISIT);
|
||||
}
|
||||
SystemContext systemContext = new SystemContext();
|
||||
SystemContextHolder.set(systemContext);
|
||||
systemContext.setIp(ctx.realIp());
|
||||
|
||||
systemContext.setToken(authorize);
|
||||
systemContext.setUser(userDO);
|
||||
Authorization authorization = targetMethod.getAnnotation(Authorization.class);
|
||||
if (null == authorization || authorization.login()) {
|
||||
String authorize = ctx.header("Authorize");
|
||||
if (StrUtil.isEmpty(authorize)) {
|
||||
throw ServiceException.create(ExceptionConstant.USER_NOT_LOGIN);
|
||||
}
|
||||
UserDO userDO = Solon.context().getBean(UserService.class).findByToken(authorize);
|
||||
if (null == userDO) {
|
||||
throw ServiceException.create(ExceptionConstant.USER_NOT_LOGIN);
|
||||
}
|
||||
if (EnableStatusEnum.DISABLE.getStatus().equals(userDO.getEnable())) {
|
||||
throw ServiceException.create(ExceptionConstant.USER_DISABLE);
|
||||
}
|
||||
if (null != authorization && authorization.onlyAdmin() && !userDO.getLoginName().equals("admin")) {
|
||||
throw ServiceException.create(ExceptionConstant.NO_PERMISSION_VISIT);
|
||||
}
|
||||
|
||||
// token续期
|
||||
BeanManager.getBean(UserService.class).updateTokenExpirationTime(authorize);
|
||||
}
|
||||
systemContext.setToken(authorize);
|
||||
systemContext.setUser(userDO);
|
||||
|
||||
return true;
|
||||
}
|
||||
// token续期
|
||||
Solon.context().getBean(UserService.class).updateTokenExpirationTime(authorize);
|
||||
}
|
||||
chain.doIntercept(ctx, mainHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpRequestWrapper requestParser, HttpResponseWrapper responseWrapper, String route, Method targetMethod) {
|
||||
SystemContextHolder.remove();
|
||||
}
|
||||
@Override
|
||||
public Object postResult(Context ctx, Object result) throws Throwable {
|
||||
SystemContextHolder.remove();
|
||||
if (result instanceof ResponseBody) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (result instanceof Throwable) {
|
||||
log.error("全局异常", (Throwable) result);
|
||||
|
||||
if (result instanceof ServiceException) {
|
||||
ServiceException exception = (ServiceException) result;
|
||||
return new ResponseBody<>()
|
||||
.setCode(exception.getCode())
|
||||
.setMsg(exception.getMsg());
|
||||
}
|
||||
|
||||
return new ResponseBody<>()
|
||||
.setCode(ExceptionConstant.SYSTEM_ERROR.getCode())
|
||||
.setMsg(ExceptionConstant.SYSTEM_ERROR.getMsg())
|
||||
.setStack(ExceptionUtils.getStackTrace((Throwable) result));
|
||||
}
|
||||
|
||||
return new ResponseBody<>()
|
||||
.setCode(0)
|
||||
.setData(result);
|
||||
}
|
||||
}
|
||||
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.base.rest.interceptor;
|
||||
|
||||
import fun.asgc.neutrino.core.web.context.HttpRequestWrapper;
|
||||
import fun.asgc.neutrino.core.web.context.HttpResponseWrapper;
|
||||
import fun.asgc.neutrino.core.web.interceptor.HandlerInterceptor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 处理跨域问题
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/7/30
|
||||
*/
|
||||
public class CorsInterceptor implements HandlerInterceptor {
|
||||
|
||||
@Override
|
||||
public void postHandle(HttpRequestWrapper requestParser, HttpResponseWrapper responseWrapper, String route, Method targetMethod, Object result) throws Exception {
|
||||
responseWrapper.headers().add("Access-Control-Allow-Origin", "*");
|
||||
responseWrapper.headers().add("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
|
||||
responseWrapper.headers().add("Access-Control-Max-Age", "86400");
|
||||
responseWrapper.headers().add("Access-Control-Allow-Headers", "*");
|
||||
responseWrapper.headers().add("Access-Control-Allow-Credentials", "true");
|
||||
responseWrapper.headers().add("XDomainRequestAllowed", "1");
|
||||
responseWrapper.headers().add("Access-Control-Allow-Headers","Authorize, Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type");
|
||||
responseWrapper.headers().add("Access-Control-Allow-Credentials", "true");
|
||||
}
|
||||
|
||||
}
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.base.rest.interceptor;
|
||||
|
||||
import fun.asgc.neutrino.core.web.context.HttpRequestWrapper;
|
||||
import fun.asgc.neutrino.core.web.context.HttpResponseWrapper;
|
||||
import fun.asgc.neutrino.core.web.interceptor.RestControllerAdviceHandler;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.ResponseBody;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 全局返回处理
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/7/31
|
||||
*/
|
||||
public class GlobalAdviceHandler implements RestControllerAdviceHandler {
|
||||
|
||||
@Override
|
||||
public Object advice(HttpRequestWrapper requestParser, HttpResponseWrapper responseWrapper, String route, Method targetMethod, Object res) {
|
||||
if (res instanceof ResponseBody) {
|
||||
return res;
|
||||
}
|
||||
return new ResponseBody<>()
|
||||
.setCode(0)
|
||||
.setData(res);
|
||||
}
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package fun.asgc.neutrino.proxy.server.base.rest.interceptor;
|
||||
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.ResponseBody;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.ServiceException;
|
||||
import fun.asgc.neutrino.proxy.server.constant.ExceptionConstant;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.core.handle.Context;
|
||||
import org.noear.solon.core.handle.Filter;
|
||||
import org.noear.solon.core.handle.FilterChain;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2023/3/9
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class GlobalExceptionFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void doFilter(Context ctx, FilterChain chain) throws Throwable {
|
||||
try {
|
||||
chain.doFilter(ctx);
|
||||
} catch (Throwable e) {
|
||||
log.error("全局异常", e);
|
||||
|
||||
if (e instanceof ServiceException) {
|
||||
ServiceException serviceException = (ServiceException) e;
|
||||
ctx.render(new ResponseBody<>()
|
||||
.setCode(serviceException.getCode())
|
||||
.setMsg(serviceException.getMsg()));
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.render(new ResponseBody<>()
|
||||
.setCode(ExceptionConstant.SYSTEM_ERROR.getCode())
|
||||
.setMsg(ExceptionConstant.SYSTEM_ERROR.getMsg())
|
||||
.setStack(ExceptionUtils.getStackTrace(e)));
|
||||
}
|
||||
}
|
||||
}
|
||||
-53
@@ -1,53 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.base.rest.interceptor;
|
||||
|
||||
import fun.asgc.neutrino.core.web.context.HttpRequestWrapper;
|
||||
import fun.asgc.neutrino.core.web.context.HttpResponseWrapper;
|
||||
import fun.asgc.neutrino.core.web.interceptor.RestControllerExceptionHandler;
|
||||
import fun.asgc.neutrino.proxy.server.constant.ExceptionConstant;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.ResponseBody;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.ServiceException;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
|
||||
/**
|
||||
* 全局异常处理
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/7/31
|
||||
*/
|
||||
public class GlobalExceptionHandler implements RestControllerExceptionHandler {
|
||||
|
||||
@Override
|
||||
public Object handle(HttpRequestWrapper requestParser, HttpResponseWrapper responseWrapper, Throwable e) {
|
||||
if (e instanceof ServiceException) {
|
||||
ServiceException serviceException = (ServiceException)e;
|
||||
return new ResponseBody<>()
|
||||
.setCode(serviceException.getCode())
|
||||
.setMsg(serviceException.getMsg());
|
||||
}
|
||||
return new ResponseBody<>()
|
||||
.setCode(ExceptionConstant.SYSTEM_ERROR.getCode())
|
||||
.setMsg(ExceptionConstant.SYSTEM_ERROR.getMsg())
|
||||
.setStack(ExceptionUtils.getStackTrace(e));
|
||||
}
|
||||
|
||||
}
|
||||
+31
-54
@@ -1,70 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.base.rest.interceptor;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import fun.asgc.neutrino.core.web.context.HttpRequestWrapper;
|
||||
import fun.asgc.neutrino.core.web.context.HttpResponseWrapper;
|
||||
import fun.asgc.neutrino.core.web.interceptor.HandlerInterceptor;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.SystemContextHolder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.core.handle.Action;
|
||||
import org.noear.solon.core.handle.Context;
|
||||
import org.noear.solon.core.handle.Handler;
|
||||
import org.noear.solon.core.route.RouterInterceptor;
|
||||
import org.noear.solon.core.route.RouterInterceptorChain;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 访问日志拦截器
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/14
|
||||
* @date: 2023/3/12
|
||||
*/
|
||||
@Slf4j
|
||||
public class VisitLogInterceptor implements HandlerInterceptor {
|
||||
@Component(index = 1)
|
||||
public class VisitLogInterceptor implements RouterInterceptor {
|
||||
@Override
|
||||
public void doIntercept(Context ctx, Handler mainHandler, RouterInterceptorChain chain) throws Throwable {
|
||||
if (!(mainHandler instanceof Action)) {
|
||||
chain.doIntercept(ctx, mainHandler);
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpRequestWrapper requestParser, HttpResponseWrapper responseWrapper, String route, Method targetMethod) throws Exception {
|
||||
if (null != SystemContextHolder.getContext()) {
|
||||
SystemContextHolder.getContext().setReceiveTime(new Date());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
Date startTime = new Date();
|
||||
try {
|
||||
chain.doIntercept(ctx, mainHandler);
|
||||
} finally {
|
||||
Date now = new Date();
|
||||
long elapsedTime = now.getTime() - startTime.getTime();
|
||||
log.info("\n-----------------------------------------------------------------接口请求日志:\n{} url:{} 执行耗时:{}\n请求体参数:{}\n响应结果:{}\n客户端IP:{}\n",
|
||||
ctx.method(), ctx.path(), getElapsedTimeStr(elapsedTime),
|
||||
JSONObject.toJSONString(ctx.paramMap()),
|
||||
JSONObject.toJSONString(JSONObject.toJSONString(ctx.result)),
|
||||
ctx.realIp()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postHandle(HttpRequestWrapper requestParser, HttpResponseWrapper responseWrapper, String route, Method targetMethod, Object result) throws Exception {
|
||||
if (null == SystemContextHolder.getContext() || null == SystemContextHolder.getContext().getReceiveTime()) {
|
||||
return;
|
||||
}
|
||||
Date receiveTime = SystemContextHolder.getContext().getReceiveTime();
|
||||
Date now = new Date();
|
||||
long elapsedTime = now.getTime() - receiveTime.getTime();
|
||||
log.info("\n-----------------------------------------------------------------接口请求日志:\n{} url:{} 执行耗时:{}\nURL参数:{}\n请求体参数:{}\n响应结果:{}\n客户端IP:{}\n",
|
||||
requestParser.getMethod().name(), requestParser.getUrl(), getElapsedTimeStr(elapsedTime),
|
||||
requestParser.getQueryString(),
|
||||
requestParser.getContentAsString(),
|
||||
JSONObject.toJSONString(result),
|
||||
SystemContextHolder.getIp()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* 获取耗时描述
|
||||
* @param elapsedTime
|
||||
* @return
|
||||
@@ -77,4 +53,5 @@ public class VisitLogInterceptor implements HandlerInterceptor {
|
||||
}
|
||||
return String.format("%.2f分钟", (elapsedTime * 1.0) / 1000 / 60);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+12
-13
@@ -21,33 +21,32 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.controller;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.core.web.annotation.GetMapping;
|
||||
import fun.asgc.neutrino.core.web.annotation.RequestMapping;
|
||||
import fun.asgc.neutrino.core.web.annotation.RestController;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.ClientConnectRecordListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.ClientConnectRecordListRes;
|
||||
import fun.asgc.neutrino.proxy.server.service.ClientConnectRecordService;
|
||||
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.noear.solon.annotation.Controller;
|
||||
import org.noear.solon.annotation.Get;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
import org.noear.solon.annotation.Mapping;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/26
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@RequestMapping("client-connect-record")
|
||||
@RestController
|
||||
@Mapping("/client-connect-record")
|
||||
@Controller
|
||||
public class ClientConnectRecordController {
|
||||
@Autowired
|
||||
@Inject
|
||||
private ClientConnectRecordService clientConnectRecordService;
|
||||
|
||||
@GetMapping("page")
|
||||
public Page<ClientConnectRecordListRes> page(PageQuery pageQuery, ClientConnectRecordListReq req) {
|
||||
@Get
|
||||
@Mapping("/page")
|
||||
public PageInfo<ClientConnectRecordListRes> page(PageQuery pageQuery, ClientConnectRecordListReq req) {
|
||||
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
|
||||
return clientConnectRecordService.page(pageQuery, req);
|
||||
}
|
||||
|
||||
+16
-10
@@ -21,37 +21,43 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.controller;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.web.annotation.*;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.Authorization;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.LoginReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.LoginRes;
|
||||
import fun.asgc.neutrino.proxy.server.service.UserService;
|
||||
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
|
||||
import org.noear.solon.annotation.*;
|
||||
import org.noear.solon.core.handle.Context;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/7/31
|
||||
*/
|
||||
@NonIntercept
|
||||
@RequestMapping
|
||||
@RestController
|
||||
@Controller
|
||||
public class IndexController {
|
||||
@Autowired
|
||||
@Inject
|
||||
private UserService userService;
|
||||
|
||||
@Authorization(login = false)
|
||||
@PostMapping("login")
|
||||
public LoginRes login(@RequestBody LoginReq req) {
|
||||
@Get
|
||||
@Mapping("/")
|
||||
public void home(Context ctx) {
|
||||
ctx.forward("/index.html");
|
||||
}
|
||||
|
||||
@Authorization(login = false)
|
||||
@Post
|
||||
@Mapping("/login")
|
||||
public LoginRes login(LoginReq req) {
|
||||
ParamCheckUtil.checkNotEmpty(req.getLoginName(), "loginName");
|
||||
ParamCheckUtil.checkNotEmpty(req.getLoginPassword(), "loginPassword");
|
||||
|
||||
return userService.login(req);
|
||||
}
|
||||
|
||||
@PostMapping("logout")
|
||||
@Post
|
||||
@Mapping("/logout")
|
||||
public void logout() {
|
||||
userService.logout();
|
||||
}
|
||||
|
||||
+31
-23
@@ -21,18 +21,22 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.controller;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.core.web.annotation.*;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.annotation.OnlyAdmin;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.*;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.*;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.Authorization;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.JobInfoExecuteReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.JobInfoListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.JobInfoUpdateEnableStatusReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.JobInfoUpdateReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.JobInfoExecuteRes;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.JobInfoListRes;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.JobInfoUpdateEnableStatusRes;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.JobInfoUpdateRes;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.JobInfoDO;
|
||||
import fun.asgc.neutrino.proxy.server.service.JobInfoService;
|
||||
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.noear.solon.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -42,44 +46,48 @@ import java.util.List;
|
||||
* @date: 2022/9/5
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@RequestMapping("job-info")
|
||||
@RestController
|
||||
@Mapping("/job-info")
|
||||
@Controller
|
||||
public class JobInfoController {
|
||||
@Autowired
|
||||
@Inject
|
||||
private JobInfoService jobInfoService;
|
||||
|
||||
@GetMapping("page")
|
||||
public Page<JobInfoListRes> page(PageQuery pageQuery, JobInfoListReq req) {
|
||||
@Get
|
||||
@Mapping("/page")
|
||||
public PageInfo<JobInfoListRes> page(PageQuery pageQuery, JobInfoListReq req) {
|
||||
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
|
||||
return jobInfoService.page(pageQuery, req);
|
||||
}
|
||||
|
||||
@GetMapping("findList")
|
||||
@Get
|
||||
@Mapping("/findList")
|
||||
public List<JobInfoDO> findList() {
|
||||
return jobInfoService.findList();
|
||||
}
|
||||
|
||||
@OnlyAdmin
|
||||
@PostMapping("update/enable-status")
|
||||
public JobInfoUpdateEnableStatusRes updateEnableStatus(@RequestBody JobInfoUpdateEnableStatusReq req) {
|
||||
@Post
|
||||
@Mapping("/update/enable-status")
|
||||
@Authorization(onlyAdmin = true)
|
||||
public JobInfoUpdateEnableStatusRes updateEnableStatus(JobInfoUpdateEnableStatusReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotNull(req.getId(), "id");
|
||||
ParamCheckUtil.checkNotNull(req.getEnable(), "enable");
|
||||
return jobInfoService.updateEnableStatus(req);
|
||||
}
|
||||
|
||||
@OnlyAdmin
|
||||
@PostMapping("execute")
|
||||
public JobInfoExecuteRes execute(@RequestBody JobInfoExecuteReq req) {
|
||||
@Post
|
||||
@Mapping("/execute")
|
||||
@Authorization(onlyAdmin = true)
|
||||
public JobInfoExecuteRes execute(JobInfoExecuteReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotNull(req.getId(), "id");
|
||||
|
||||
return jobInfoService.execute(req);
|
||||
}
|
||||
|
||||
@PostMapping("update")
|
||||
public JobInfoUpdateRes update(@RequestBody JobInfoUpdateReq req) {
|
||||
@Post
|
||||
@Mapping("/update")
|
||||
public JobInfoUpdateRes update(JobInfoUpdateReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
|
||||
return jobInfoService.update(req);
|
||||
|
||||
+14
-13
@@ -21,16 +21,17 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.controller;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.core.web.annotation.*;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.*;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.*;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.JobLogListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.JobLogListRes;
|
||||
import fun.asgc.neutrino.proxy.server.service.JobLogService;
|
||||
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.noear.solon.annotation.Controller;
|
||||
import org.noear.solon.annotation.Get;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
import org.noear.solon.annotation.Mapping;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -38,15 +39,15 @@ import lombok.extern.slf4j.Slf4j;
|
||||
* @date: 2022/9/25
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@RequestMapping("job-log")
|
||||
@RestController
|
||||
@Mapping("/job-log")
|
||||
@Controller
|
||||
public class JobLogController {
|
||||
@Autowired
|
||||
@Inject
|
||||
private JobLogService jobLogService;
|
||||
|
||||
@GetMapping("page")
|
||||
public Page<JobLogListRes> page(PageQuery pageQuery, JobLogListReq req) {
|
||||
@Get
|
||||
@Mapping("/page")
|
||||
public PageInfo<JobLogListRes> page(PageQuery pageQuery, JobLogListReq req) {
|
||||
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
|
||||
return jobLogService.page(pageQuery, req);
|
||||
}
|
||||
|
||||
+44
-41
@@ -21,19 +21,14 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.controller;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.core.web.annotation.*;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.annotation.OnlyAdmin;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.LicenseCreateReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.LicenseListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.LicenseUpdateEnableStatusReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.LicenseUpdateReq;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.Authorization;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.*;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.*;
|
||||
import fun.asgc.neutrino.proxy.server.service.LicenseService;
|
||||
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
|
||||
import org.noear.solon.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -42,29 +37,29 @@ import java.util.List;
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/6
|
||||
*/
|
||||
@NonIntercept
|
||||
@RequestMapping("license")
|
||||
@RestController
|
||||
@Mapping("/license")
|
||||
@Controller
|
||||
public class LicenseController {
|
||||
|
||||
@Autowired
|
||||
@Inject
|
||||
private LicenseService licenseService;
|
||||
|
||||
@GetMapping("page")
|
||||
public Page<LicenseListRes> page(PageQuery pageQuery, LicenseListReq req) {
|
||||
@Get
|
||||
@Mapping("/page")
|
||||
public PageInfo<LicenseListRes> page(PageQuery pageQuery, LicenseListReq req) {
|
||||
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
|
||||
|
||||
return licenseService.page(pageQuery, req);
|
||||
}
|
||||
|
||||
@GetMapping("list")
|
||||
@Mapping("/list")
|
||||
public List<LicenseListRes> list(LicenseListReq req) {
|
||||
return licenseService.list(req);
|
||||
}
|
||||
|
||||
@OnlyAdmin
|
||||
@PostMapping("create")
|
||||
public LicenseCreateRes create(@RequestBody LicenseCreateReq req) {
|
||||
@Post
|
||||
@Mapping("/create")
|
||||
@Authorization(onlyAdmin = true)
|
||||
public LicenseCreateRes create(LicenseCreateReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotEmpty(req.getName(), "name");
|
||||
ParamCheckUtil.checkNotNull(req.getUserId(), "userId");
|
||||
@@ -72,9 +67,10 @@ public class LicenseController {
|
||||
return licenseService.create(req);
|
||||
}
|
||||
|
||||
@OnlyAdmin
|
||||
@PostMapping("update")
|
||||
public LicenseUpdateRes update(@RequestBody LicenseUpdateReq req) {
|
||||
@Post
|
||||
@Mapping("/update")
|
||||
@Authorization(onlyAdmin = true)
|
||||
public LicenseUpdateRes update(LicenseUpdateReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotNull(req.getId(), "id");
|
||||
ParamCheckUtil.checkNotEmpty(req.getName(), "name");
|
||||
@@ -82,16 +78,19 @@ public class LicenseController {
|
||||
return licenseService.update(req);
|
||||
}
|
||||
|
||||
@GetMapping("detail")
|
||||
public LicenseDetailRes detail(@RequestParam("id") Integer id) {
|
||||
ParamCheckUtil.checkNotNull(id, "id");
|
||||
@Post
|
||||
@Mapping("/detail")
|
||||
public LicenseDetailRes detail(LicenseDetailReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotNull(req.getId(), "id");
|
||||
|
||||
return licenseService.detail(id);
|
||||
return licenseService.detail(req.getId());
|
||||
}
|
||||
|
||||
@OnlyAdmin
|
||||
@PostMapping("update/enable-status")
|
||||
public LicenseUpdateEnableStatusRes updateEnableStatus(@RequestBody LicenseUpdateEnableStatusReq req) {
|
||||
@Post
|
||||
@Mapping("/update/enable-status")
|
||||
@Authorization(onlyAdmin = true)
|
||||
public LicenseUpdateEnableStatusRes updateEnableStatus(LicenseUpdateEnableStatusReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotNull(req.getId(), "id");
|
||||
ParamCheckUtil.checkNotNull(req.getEnable(), "enable");
|
||||
@@ -99,20 +98,24 @@ public class LicenseController {
|
||||
return licenseService.updateEnableStatus(req);
|
||||
}
|
||||
|
||||
@OnlyAdmin
|
||||
@PostMapping("delete")
|
||||
public void delete(@RequestParam("id") Integer id) {
|
||||
ParamCheckUtil.checkNotNull(id, "id");
|
||||
@Post
|
||||
@Mapping("/delete")
|
||||
@Authorization(onlyAdmin = true)
|
||||
public void delete(LicenseDeleteReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotNull(req.getId(), "id");
|
||||
|
||||
licenseService.delete(id);
|
||||
licenseService.delete(req.getId());
|
||||
}
|
||||
|
||||
@OnlyAdmin
|
||||
@PostMapping("reset")
|
||||
public void reset(@RequestParam("id") Integer id) {
|
||||
ParamCheckUtil.checkNotNull(id, "id");
|
||||
@Post
|
||||
@Mapping("/reset")
|
||||
@Authorization(onlyAdmin = true)
|
||||
public void reset(LicenseResetReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotNull(req.getId(), "id");
|
||||
|
||||
licenseService.reset(id);
|
||||
licenseService.reset(req.getId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+31
-50
@@ -1,60 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.controller;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.core.web.annotation.*;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.PortMappingCreateReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.PortMappingListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.PortMappingUpdateEnableStatusReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.PortMappingUpdateReq;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.*;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.*;
|
||||
import fun.asgc.neutrino.proxy.server.service.PortMappingService;
|
||||
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
|
||||
import org.noear.solon.annotation.*;
|
||||
|
||||
/**
|
||||
* 端口映射
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/8
|
||||
*/
|
||||
@NonIntercept
|
||||
@RequestMapping("port-mapping")
|
||||
@RestController
|
||||
@Mapping("/port-mapping")
|
||||
@Controller
|
||||
public class PortMappingController {
|
||||
@Autowired
|
||||
@Inject
|
||||
private PortMappingService portMappingService;
|
||||
|
||||
@GetMapping("page")
|
||||
public Page<PortMappingListRes> page(PageQuery pageQuery, PortMappingListReq req) {
|
||||
@Get
|
||||
@Mapping("/page")
|
||||
public PageInfo<PortMappingListRes> page(PageQuery pageQuery, PortMappingListReq req) {
|
||||
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
|
||||
|
||||
return portMappingService.page(pageQuery, req);
|
||||
}
|
||||
|
||||
@PostMapping("create")
|
||||
public PortMappingCreateRes create(@RequestBody PortMappingCreateReq req) {
|
||||
@Post
|
||||
@Mapping("/create")
|
||||
public PortMappingCreateRes create(PortMappingCreateReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotNull(req.getLicenseId(), "licenseId");
|
||||
ParamCheckUtil.checkNotNull(req.getServerPort(), "serverPort");
|
||||
@@ -64,22 +39,26 @@ public class PortMappingController {
|
||||
return portMappingService.create(req);
|
||||
}
|
||||
|
||||
@PostMapping("update")
|
||||
public PortMappingUpdateRes update(@RequestBody PortMappingUpdateReq req) {
|
||||
@Post
|
||||
@Mapping("/update")
|
||||
public PortMappingUpdateRes update(PortMappingUpdateReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
|
||||
return portMappingService.update(req);
|
||||
}
|
||||
|
||||
@GetMapping("detail")
|
||||
public PortMappingDetailRes detail(@RequestParam("id") Integer id) {
|
||||
ParamCheckUtil.checkNotNull(id, "id");
|
||||
@Get
|
||||
@Mapping("/detail")
|
||||
public PortMappingDetailRes detail(PortMappingDetailReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotNull(req.getId(), "id");
|
||||
|
||||
return portMappingService.detail(id);
|
||||
return portMappingService.detail(req.getId());
|
||||
}
|
||||
|
||||
@PostMapping("update/enable-status")
|
||||
public PortMappingUpdateEnableStatusRes updateEnableStatus(@RequestBody PortMappingUpdateEnableStatusReq req) {
|
||||
@Post
|
||||
@Mapping("/update/enable-status")
|
||||
public PortMappingUpdateEnableStatusRes updateEnableStatus(PortMappingUpdateEnableStatusReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotNull(req.getId(), "id");
|
||||
ParamCheckUtil.checkNotNull(req.getEnable(), "enable");
|
||||
@@ -87,10 +66,12 @@ public class PortMappingController {
|
||||
return portMappingService.updateEnableStatus(req);
|
||||
}
|
||||
|
||||
@PostMapping("delete")
|
||||
public void delete(@RequestParam("id") Integer id) {
|
||||
ParamCheckUtil.checkNotNull(id, "id");
|
||||
@Post
|
||||
@Mapping("/delete")
|
||||
public void delete(PortMappingDeleteReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotNull(req.getId(), "id");
|
||||
|
||||
portMappingService.delete(id);
|
||||
portMappingService.delete(req.getId());
|
||||
}
|
||||
}
|
||||
|
||||
+28
-24
@@ -21,13 +21,11 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.controller;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.core.web.annotation.*;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.annotation.OnlyAdmin;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.Authorization;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.PortPoolCreateReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.PortPoolDeleteReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.PortPoolListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.PortPoolUpdateEnableStatusReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.PortPoolCreateRes;
|
||||
@@ -35,6 +33,7 @@ import fun.asgc.neutrino.proxy.server.controller.res.PortPoolListRes;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.PortPoolUpdateEnableStatusRes;
|
||||
import fun.asgc.neutrino.proxy.server.service.PortPoolService;
|
||||
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
|
||||
import org.noear.solon.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -43,37 +42,40 @@ import java.util.List;
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/7
|
||||
*/
|
||||
@NonIntercept
|
||||
@RequestMapping("port-pool")
|
||||
@RestController
|
||||
@Mapping("/port-pool")
|
||||
@Controller
|
||||
public class PortPoolController {
|
||||
@Autowired
|
||||
@Inject
|
||||
private PortPoolService portPoolService;
|
||||
|
||||
@GetMapping("page")
|
||||
public Page<PortPoolListRes> page(PageQuery pageQuery, PortPoolListReq req) {
|
||||
@Get
|
||||
@Mapping("/page")
|
||||
public PageInfo<PortPoolListRes> page(PageQuery pageQuery, PortPoolListReq req) {
|
||||
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
|
||||
|
||||
return portPoolService.page(pageQuery, req);
|
||||
}
|
||||
|
||||
@GetMapping("list")
|
||||
@Get
|
||||
@Mapping("/list")
|
||||
public List<PortPoolListRes> list(PortPoolListReq req) {
|
||||
return portPoolService.list(req);
|
||||
}
|
||||
|
||||
@OnlyAdmin
|
||||
@PostMapping("create")
|
||||
public PortPoolCreateRes create(@RequestBody PortPoolCreateReq req) {
|
||||
@Post
|
||||
@Mapping("/create")
|
||||
@Authorization(onlyAdmin = true)
|
||||
public PortPoolCreateRes create(PortPoolCreateReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotNull(req.getPort(), "port");
|
||||
|
||||
return portPoolService.create(req);
|
||||
}
|
||||
|
||||
@OnlyAdmin
|
||||
@PostMapping("update/enable-status")
|
||||
public PortPoolUpdateEnableStatusRes updateEnableStatus(@RequestBody PortPoolUpdateEnableStatusReq req) {
|
||||
@Post
|
||||
@Mapping("/update/enable-status")
|
||||
@Authorization(onlyAdmin = true)
|
||||
public PortPoolUpdateEnableStatusRes updateEnableStatus(PortPoolUpdateEnableStatusReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotNull(req.getId(), "id");
|
||||
ParamCheckUtil.checkNotNull(req.getEnable(), "enable");
|
||||
@@ -81,11 +83,13 @@ public class PortPoolController {
|
||||
return portPoolService.updateEnableStatus(req);
|
||||
}
|
||||
|
||||
@OnlyAdmin
|
||||
@PostMapping("delete")
|
||||
public void delete(@RequestParam("id") Integer id) {
|
||||
ParamCheckUtil.checkNotNull(id, "id");
|
||||
@Post
|
||||
@Mapping("/delete")
|
||||
@Authorization(onlyAdmin = true)
|
||||
public void delete(PortPoolDeleteReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotNull(req.getId(), "id");
|
||||
|
||||
portPoolService.delete(id);
|
||||
portPoolService.delete(req.getId());
|
||||
}
|
||||
}
|
||||
|
||||
+17
-37
@@ -1,33 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.controller;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.core.web.annotation.GetMapping;
|
||||
import fun.asgc.neutrino.core.web.annotation.RequestMapping;
|
||||
import fun.asgc.neutrino.core.web.annotation.RestController;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.LicenseFlowReportReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.UserFlowReportReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.LicenseFlowReportRes;
|
||||
@@ -35,18 +9,21 @@ import fun.asgc.neutrino.proxy.server.controller.res.ReportDataViewRes;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.UserFlowReportRes;
|
||||
import fun.asgc.neutrino.proxy.server.service.ReportService;
|
||||
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
|
||||
import org.noear.solon.annotation.Controller;
|
||||
import org.noear.solon.annotation.Get;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
import org.noear.solon.annotation.Mapping;
|
||||
|
||||
/**
|
||||
* 报表管理
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/9/12
|
||||
*/
|
||||
@NonIntercept
|
||||
@RequestMapping("report")
|
||||
@RestController
|
||||
@Mapping("/report")
|
||||
@Controller
|
||||
public class ReportController {
|
||||
|
||||
@Autowired
|
||||
@Inject
|
||||
private ReportService reportService;
|
||||
|
||||
/**
|
||||
@@ -62,7 +39,8 @@ public class ReportController {
|
||||
* 4、点击历史流量:下方展示历史流量折线图。筛选项:日/月 日期选择:日(展示最近30天,最多跨30日),月(展示最近12个月,最多跨12个月)
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("data-view")
|
||||
@Get
|
||||
@Mapping("/data-view")
|
||||
public ReportDataViewRes dataView() {
|
||||
return new ReportDataViewRes()
|
||||
.setUserOnlineNumber(2).setEnableUserNumber(3).setUserNumber(5)
|
||||
@@ -78,8 +56,9 @@ public class ReportController {
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("user/flow-report/page")
|
||||
public Page<UserFlowReportRes> userFlowReportPage(PageQuery pageQuery, UserFlowReportReq req) {
|
||||
@Get
|
||||
@Mapping("/user/flow-report/page")
|
||||
public PageInfo<UserFlowReportRes> userFlowReportPage(PageQuery pageQuery, UserFlowReportReq req) {
|
||||
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
|
||||
|
||||
return reportService.userFlowReportPage(pageQuery, req);
|
||||
@@ -91,8 +70,9 @@ public class ReportController {
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("license/flow-report/page")
|
||||
public Page<LicenseFlowReportRes> licenseFlowReportPage(PageQuery pageQuery, LicenseFlowReportReq req) {
|
||||
@Get
|
||||
@Mapping("/license/flow-report/page")
|
||||
public PageInfo<LicenseFlowReportRes> licenseFlowReportPage(PageQuery pageQuery, LicenseFlowReportReq req) {
|
||||
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
|
||||
|
||||
return reportService.licenseFlowReportPage(pageQuery, req);
|
||||
|
||||
+41
-34
@@ -21,13 +21,10 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.controller;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.core.web.annotation.*;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.Authorization;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.SystemContextHolder;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.annotation.OnlyAdmin;
|
||||
import fun.asgc.neutrino.proxy.server.constant.ExceptionConstant;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.*;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.*;
|
||||
@@ -36,6 +33,7 @@ import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
|
||||
import fun.asgc.neutrino.proxy.server.service.UserService;
|
||||
import fun.asgc.neutrino.proxy.server.util.Md5Util;
|
||||
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
|
||||
import org.noear.solon.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -44,36 +42,39 @@ import java.util.List;
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/7/31
|
||||
*/
|
||||
@NonIntercept
|
||||
@RequestMapping("user")
|
||||
@RestController
|
||||
@Mapping("/user")
|
||||
@Controller
|
||||
public class UserController {
|
||||
@Autowired
|
||||
@Inject
|
||||
private UserService userService;
|
||||
@Autowired
|
||||
@Inject
|
||||
private UserMapper userMapper;
|
||||
|
||||
@GetMapping("page")
|
||||
public Page<UserListRes> page(PageQuery pageQuery, UserListReq req) {
|
||||
@Get
|
||||
@Mapping("/page")
|
||||
public PageInfo<UserListRes> page(PageQuery pageQuery, UserListReq req) {
|
||||
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
|
||||
|
||||
return userService.page(pageQuery, req);
|
||||
}
|
||||
|
||||
@GetMapping("list")
|
||||
@Get
|
||||
@Mapping("/list")
|
||||
public List<UserListRes> list(UserListReq req) {
|
||||
|
||||
return userService.list(req);
|
||||
}
|
||||
|
||||
@GetMapping("info")
|
||||
@Get
|
||||
@Mapping("/info")
|
||||
public UserInfoRes info(UserInfoReq req) {
|
||||
return userService.info(req);
|
||||
}
|
||||
|
||||
@OnlyAdmin
|
||||
@PostMapping("update/enable-status")
|
||||
public UserUpdateEnableStatusRes updateEnableStatus(@RequestBody UserUpdateEnableStatusReq req) {
|
||||
@Post
|
||||
@Mapping("/update/enable-status")
|
||||
@Authorization(onlyAdmin = true)
|
||||
public UserUpdateEnableStatusRes updateEnableStatus(UserUpdateEnableStatusReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotNull(req.getId(), "id");
|
||||
ParamCheckUtil.checkNotNull(req.getEnable(), "enable");
|
||||
@@ -81,9 +82,10 @@ public class UserController {
|
||||
return userService.updateEnableStatus(req);
|
||||
}
|
||||
|
||||
@OnlyAdmin
|
||||
@PostMapping("create")
|
||||
public UserCreateRes create(@RequestBody UserCreateReq req) {
|
||||
@Post
|
||||
@Mapping("/create")
|
||||
@Authorization(onlyAdmin = true)
|
||||
public UserCreateRes create(UserCreateReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotEmpty(req.getName(), "name");
|
||||
ParamCheckUtil.checkNotEmpty(req.getLoginName(), "loginName");
|
||||
@@ -91,9 +93,10 @@ public class UserController {
|
||||
return userService.create(req);
|
||||
}
|
||||
|
||||
@OnlyAdmin
|
||||
@PostMapping("update")
|
||||
public UserUpdateRes update(@RequestBody UserUpdateReq req) {
|
||||
@Post
|
||||
@Mapping("/update")
|
||||
@Authorization(onlyAdmin = true)
|
||||
public UserUpdateRes update(UserUpdateReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotNull(req.getId(), "id");
|
||||
ParamCheckUtil.checkNotEmpty(req.getName(), "name");
|
||||
@@ -102,9 +105,10 @@ public class UserController {
|
||||
return userService.update(req);
|
||||
}
|
||||
|
||||
@OnlyAdmin
|
||||
@PostMapping("update/password")
|
||||
public UserUpdatePasswordRes updatePassword(@RequestBody UserUpdatePasswordReq req) {
|
||||
@Post
|
||||
@Mapping("/update/password")
|
||||
@Authorization(onlyAdmin = true)
|
||||
public UserUpdatePasswordRes updatePassword(UserUpdatePasswordReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotNull(req.getId(), "id");
|
||||
ParamCheckUtil.checkNotEmpty(req.getLoginPassword(), "loginPassword");
|
||||
@@ -113,8 +117,9 @@ public class UserController {
|
||||
return userService.updatePassword(req);
|
||||
}
|
||||
|
||||
@PostMapping("current-user/update/password")
|
||||
public UserUpdatePasswordRes currentUserUpdatePassword(@RequestBody UserUpdatePasswordReq req) {
|
||||
@Post
|
||||
@Mapping("/current-user/update/password")
|
||||
public UserUpdatePasswordRes currentUserUpdatePassword(UserUpdatePasswordReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotEmpty(req.getOldLoginPassword(), "oldLoginPassword");
|
||||
ParamCheckUtil.checkNotEmpty(req.getLoginPassword(), "loginPassword");
|
||||
@@ -128,11 +133,13 @@ public class UserController {
|
||||
return userService.updatePassword(req);
|
||||
}
|
||||
|
||||
@OnlyAdmin
|
||||
@PostMapping("delete")
|
||||
public void delete(@RequestParam("id") Integer id) {
|
||||
ParamCheckUtil.checkNotNull(id, "id");
|
||||
@Post
|
||||
@Mapping("/delete")
|
||||
@Authorization(onlyAdmin = true)
|
||||
public void delete(UserDeleteReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotNull(req.getId(), "id");
|
||||
|
||||
userService.delete(id);
|
||||
userService.delete(req.getId());
|
||||
}
|
||||
}
|
||||
|
||||
+12
-13
@@ -21,31 +21,30 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.controller;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.core.web.annotation.GetMapping;
|
||||
import fun.asgc.neutrino.core.web.annotation.RequestMapping;
|
||||
import fun.asgc.neutrino.core.web.annotation.RestController;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.UserLoginRecordListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.UserLoginRecordListRes;
|
||||
import fun.asgc.neutrino.proxy.server.service.UserLoginRecordService;
|
||||
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
|
||||
import org.noear.solon.annotation.Controller;
|
||||
import org.noear.solon.annotation.Get;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
import org.noear.solon.annotation.Mapping;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/20
|
||||
*/
|
||||
@NonIntercept
|
||||
@RequestMapping("user-login-record")
|
||||
@RestController
|
||||
@Mapping("/user-login-record")
|
||||
@Controller
|
||||
public class UserLoginRecordController {
|
||||
@Autowired
|
||||
@Inject
|
||||
private UserLoginRecordService userLoginRecordService;
|
||||
|
||||
@GetMapping("page")
|
||||
public Page<UserLoginRecordListRes> page(PageQuery pageQuery, UserLoginRecordListReq req) {
|
||||
@Get
|
||||
@Mapping("/page")
|
||||
public PageInfo<UserLoginRecordListRes> page(PageQuery pageQuery, UserLoginRecordListReq req) {
|
||||
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
|
||||
|
||||
return userLoginRecordService.page(pageQuery, req);
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package fun.asgc.neutrino.proxy.server.controller.req;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* license删除请求
|
||||
* @author: aoshiguchen
|
||||
* @date: 2023/3/11
|
||||
*/
|
||||
@Data
|
||||
public class LicenseDeleteReq {
|
||||
private Integer id;
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package fun.asgc.neutrino.proxy.server.controller.req;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2023/3/11
|
||||
*/
|
||||
@Data
|
||||
public class LicenseDetailReq {
|
||||
private Integer id;
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package fun.asgc.neutrino.proxy.server.controller.req;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2023/3/11
|
||||
*/
|
||||
@Data
|
||||
public class LicenseResetReq {
|
||||
private Integer id;
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package fun.asgc.neutrino.proxy.server.controller.req;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2023/3/11
|
||||
*/
|
||||
@Data
|
||||
public class PortMappingDeleteReq {
|
||||
private Integer id;
|
||||
}
|
||||
+1
-1
@@ -30,5 +30,5 @@ import lombok.Data;
|
||||
*/
|
||||
@Data
|
||||
public class PortMappingDetailReq {
|
||||
|
||||
private Integer id;
|
||||
}
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package fun.asgc.neutrino.proxy.server.controller.req;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2023/3/11
|
||||
*/
|
||||
@Data
|
||||
public class PortPoolDeleteReq {
|
||||
private Integer id;
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package fun.asgc.neutrino.proxy.server.controller.req;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2023/3/11
|
||||
*/
|
||||
@Data
|
||||
public class UserDeleteReq {
|
||||
private Integer id;
|
||||
}
|
||||
-23
@@ -1,27 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.controller.res;
|
||||
|
||||
import fun.asgc.neutrino.core.db.annotation.Id;
|
||||
import fun.asgc.neutrino.proxy.server.constant.OnlineStatusEnum;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
@@ -36,7 +14,6 @@ import java.util.Date;
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
public class LicenseListRes {
|
||||
@Id
|
||||
private Integer id;
|
||||
/**
|
||||
* 名称
|
||||
|
||||
-23
@@ -1,27 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.controller.res;
|
||||
|
||||
import fun.asgc.neutrino.core.db.annotation.Id;
|
||||
import fun.asgc.neutrino.proxy.server.constant.OnlineStatusEnum;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
@@ -36,7 +14,6 @@ import java.util.Date;
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
public class PortMappingDetailRes {
|
||||
@Id
|
||||
private Integer id;
|
||||
/**
|
||||
* licenseId
|
||||
|
||||
-22
@@ -1,27 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.controller.res;
|
||||
|
||||
import fun.asgc.neutrino.core.db.annotation.Id;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
|
||||
+12
-17
@@ -1,26 +1,21 @@
|
||||
package fun.asgc.neutrino.proxy.server.dal;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.aop.Intercept;
|
||||
import fun.asgc.neutrino.core.db.annotation.ResultType;
|
||||
import fun.asgc.neutrino.core.db.annotation.Select;
|
||||
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.ClientConnectRecordListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.ClientConnectRecordListRes;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.ClientConnectRecordDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/23
|
||||
*/
|
||||
@Intercept(ignoreGlobal = true)
|
||||
@Component
|
||||
public interface ClientConnectRecordMapper extends SqlMapper {
|
||||
|
||||
void add(ClientConnectRecordDO clientConnectRecordDO);
|
||||
|
||||
@ResultType(ClientConnectRecordListRes.class)
|
||||
@Select("select * from client_connect_record order by id desc")
|
||||
void page(Page page, ClientConnectRecordListReq req);
|
||||
@Mapper
|
||||
public interface ClientConnectRecordMapper extends BaseMapper<ClientConnectRecordDO> {
|
||||
default void clean(Date date) {
|
||||
this.delete(new LambdaQueryWrapper<ClientConnectRecordDO>()
|
||||
.lt(ClientConnectRecordDO::getCreateTime, date)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
-57
@@ -1,57 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.aop.Intercept;
|
||||
import fun.asgc.neutrino.core.db.annotation.Delete;
|
||||
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/9/17
|
||||
*/
|
||||
@Intercept(ignoreGlobal = true)
|
||||
@Component
|
||||
public interface DataCleanMapper extends SqlMapper {
|
||||
|
||||
@Delete("delete from `job_log` where create_time < ?")
|
||||
void cleanJobLog(Date date);
|
||||
|
||||
@Delete("delete from `user_login_record` where create_time < ?")
|
||||
void cleanUserLoginRecord(Date date);
|
||||
|
||||
@Delete("delete from `client_connect_record` where create_time < ?")
|
||||
void cleanClientConnectRecord(Date date);
|
||||
|
||||
@Delete("delete from `flow_report_minute` where create_time < ?")
|
||||
void cleanFlowMinuteReport(Date date);
|
||||
|
||||
@Delete("delete from `flow_report_hour` where create_time < ?")
|
||||
void cleanFlowHourReport(Date date);
|
||||
|
||||
@Delete("delete from `flow_report_day` where create_time < ?")
|
||||
void cleanFlowDayReport(Date date);
|
||||
|
||||
}
|
||||
+21
-25
@@ -21,36 +21,32 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Param;
|
||||
import fun.asgc.neutrino.core.aop.Intercept;
|
||||
import fun.asgc.neutrino.core.db.annotation.Delete;
|
||||
import fun.asgc.neutrino.core.db.annotation.Insert;
|
||||
import fun.asgc.neutrino.core.db.annotation.ResultType;
|
||||
import fun.asgc.neutrino.core.db.annotation.Select;
|
||||
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportDayDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/28
|
||||
*/
|
||||
@Intercept(ignoreGlobal = true)
|
||||
@Component
|
||||
public interface FlowReportDayMapper extends SqlMapper {
|
||||
@Select("select * from flow_report_day where license_id = :licenseId and date_str = :dateStr")
|
||||
FlowReportDayDO findOne(@Param("licenseId") Integer licenseId, @Param("dateStr") String dateStr);
|
||||
@Mapper
|
||||
public interface FlowReportDayMapper extends BaseMapper<FlowReportDayDO> {
|
||||
default void clean(Date date) {
|
||||
this.delete(new LambdaQueryWrapper<FlowReportDayDO>()
|
||||
.lt(FlowReportDayDO::getCreateTime, date)
|
||||
);
|
||||
}
|
||||
|
||||
@Insert("insert into flow_report_day(`user_id`,`license_id`,`write_bytes`,`read_bytes`,`date`,`date_str`,`create_time`) values(:userId,:licenseId,:writeBytes,:readBytes,:date,:dateStr,:createTime)")
|
||||
void add(FlowReportDayDO flowReportDayDO);
|
||||
default void deleteByDateStr(String dateStr) {
|
||||
this.delete(new LambdaQueryWrapper<FlowReportDayDO>()
|
||||
.eq(FlowReportDayDO::getDateStr, dateStr)
|
||||
);
|
||||
}
|
||||
|
||||
@Delete("delete from flow_report_day where date_str = :dateStr")
|
||||
void deleteByDateStr(@Param("dateStr") String dateStr);
|
||||
|
||||
@ResultType(FlowReportDayDO.class)
|
||||
@Select("select * from flow_report_day where date >= :startDate and date <= :endDate")
|
||||
List<FlowReportDayDO> findListByDateRange(@Param("startDate") Date startDate, @Param("endDate") Date endDate);
|
||||
default List<FlowReportDayDO> findListByDateRange(Date startDate, Date endDate) {
|
||||
return this.selectList(new LambdaQueryWrapper<FlowReportDayDO>()
|
||||
.le(FlowReportDayDO::getDate, startDate)
|
||||
.gt(FlowReportDayDO::getDate, endDate)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+21
-25
@@ -21,37 +21,33 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Param;
|
||||
import fun.asgc.neutrino.core.aop.Intercept;
|
||||
import fun.asgc.neutrino.core.db.annotation.Delete;
|
||||
import fun.asgc.neutrino.core.db.annotation.Insert;
|
||||
import fun.asgc.neutrino.core.db.annotation.ResultType;
|
||||
import fun.asgc.neutrino.core.db.annotation.Select;
|
||||
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportHourDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/28
|
||||
*/
|
||||
@Intercept(ignoreGlobal = true)
|
||||
@Component
|
||||
public interface FlowReportHourMapper extends SqlMapper {
|
||||
@Select("select * from flow_report_hour where license_id = :licenseId and date_str = :dateStr")
|
||||
FlowReportHourDO findOne(@Param("licenseId") Integer licenseId, @Param("dateStr") String dateStr);
|
||||
@Mapper
|
||||
public interface FlowReportHourMapper extends BaseMapper<FlowReportHourDO> {
|
||||
default void clean(Date date) {
|
||||
this.delete(new LambdaQueryWrapper<FlowReportHourDO>()
|
||||
.lt(FlowReportHourDO::getCreateTime, date)
|
||||
);
|
||||
}
|
||||
|
||||
@Insert("insert into flow_report_hour(`user_id`,`license_id`,`write_bytes`,`read_bytes`,`date`,`date_str`,`create_time`) values(:userId,:licenseId,:writeBytes,:readBytes,:date,:dateStr,:createTime)")
|
||||
void add(FlowReportHourDO flowReportHourDO);
|
||||
default void deleteByDateStr(String dateStr) {
|
||||
this.delete(new LambdaQueryWrapper<FlowReportHourDO>()
|
||||
.eq(FlowReportHourDO::getDateStr, dateStr)
|
||||
);
|
||||
}
|
||||
|
||||
@Delete("delete from flow_report_hour where date_str = :dateStr")
|
||||
void deleteByDateStr(@Param("dateStr") String dateStr);
|
||||
|
||||
@ResultType(FlowReportHourDO.class)
|
||||
@Select("select * from flow_report_hour where date >= :startDate and date <= :endDate")
|
||||
List<FlowReportHourDO> findListByDateRange(@Param("startDate") Date startDate, @Param("endDate") Date endDate);
|
||||
default List<FlowReportHourDO> findListByDateRange(Date startDate, Date endDate) {
|
||||
return this.selectList(new LambdaQueryWrapper<FlowReportHourDO>()
|
||||
.ge(FlowReportHourDO::getDateStr, startDate)
|
||||
.le(FlowReportHourDO::getDateStr, endDate)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+22
-24
@@ -21,37 +21,35 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Param;
|
||||
import fun.asgc.neutrino.core.aop.Intercept;
|
||||
import fun.asgc.neutrino.core.db.annotation.Insert;
|
||||
import fun.asgc.neutrino.core.db.annotation.ResultType;
|
||||
import fun.asgc.neutrino.core.db.annotation.Select;
|
||||
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportMinuteDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/24
|
||||
*/
|
||||
@Intercept(ignoreGlobal = true)
|
||||
@Component
|
||||
public interface FlowReportMinuteMapper extends SqlMapper {
|
||||
@Select("select * from flow_report_minute where license_id = :licenseId and date = :date")
|
||||
FlowReportMinuteDO findOne(@Param("licenseId") Integer licenseId, @Param("date") String date);
|
||||
@Mapper
|
||||
public interface FlowReportMinuteMapper extends BaseMapper<FlowReportMinuteDO> {
|
||||
default void clean(Date date) {
|
||||
this.delete(new LambdaQueryWrapper<FlowReportMinuteDO>()
|
||||
.lt(FlowReportMinuteDO::getCreateTime, date)
|
||||
);
|
||||
}
|
||||
|
||||
@ResultType(FlowReportMinuteDO.class)
|
||||
@Select("select * from flow_report_minute where license_id in (:licenseIds) and date = :date")
|
||||
List<FlowReportMinuteDO> findList(@Param("licenseIds") Set<Integer> licenseIds, @Param("date") String date);
|
||||
default List<FlowReportMinuteDO> findList(Set<Integer> licenseIds, String date) {
|
||||
return this.selectList(new LambdaQueryWrapper<FlowReportMinuteDO>()
|
||||
.in(FlowReportMinuteDO::getLicenseId, licenseIds)
|
||||
.eq(FlowReportMinuteDO::getDate, date)
|
||||
);
|
||||
}
|
||||
|
||||
@ResultType(FlowReportMinuteDO.class)
|
||||
@Select("select * from flow_report_minute where date >= :startDate and date <= :endDate")
|
||||
List<FlowReportMinuteDO> findListByDateRange(@Param("startDate") Date startDate, @Param("endDate") Date endDate);
|
||||
default List<FlowReportMinuteDO> findListByDateRange(Date startDate, Date endDate) {
|
||||
return this.selectList(new LambdaQueryWrapper<FlowReportMinuteDO>()
|
||||
.ge(FlowReportMinuteDO::getDate, startDate)
|
||||
.le(FlowReportMinuteDO::getDate, endDate)
|
||||
);
|
||||
}
|
||||
|
||||
@Insert("insert into flow_report_minute(`user_id`,`license_id`,`write_bytes`,`read_bytes`,`date`,`date_str`,`create_time`) values(:userId,:licenseId,:writeBytes,:readBytes,:date,:dateStr,:createTime)")
|
||||
void add(FlowReportMinuteDO flowReportMinuteDO);
|
||||
}
|
||||
|
||||
+10
-21
@@ -21,28 +21,17 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Param;
|
||||
import fun.asgc.neutrino.core.aop.Intercept;
|
||||
import fun.asgc.neutrino.core.db.annotation.Delete;
|
||||
import fun.asgc.neutrino.core.db.annotation.Insert;
|
||||
import fun.asgc.neutrino.core.db.annotation.Select;
|
||||
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportMonthDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/28
|
||||
*/
|
||||
@Intercept(ignoreGlobal = true)
|
||||
@Component
|
||||
public interface FlowReportMonthMapper extends SqlMapper {
|
||||
@Select("select * from flow_report_month where license_id = :licenseId and date_str = :dateStr")
|
||||
FlowReportMonthDO findOne(@Param("licenseId") Integer licenseId, @Param("dateStr") String dateStr);
|
||||
@Mapper
|
||||
public interface FlowReportMonthMapper extends BaseMapper<FlowReportMonthDO> {
|
||||
|
||||
@Insert("insert into flow_report_month(`user_id`,`license_id`,`write_bytes`,`read_bytes`,`date`,`date_str`,`create_time`) values(:userId,:licenseId,:writeBytes,:readBytes,:date,:dateStr,:createTime)")
|
||||
void add(FlowReportMonthDO flowReportMonthDO);
|
||||
|
||||
@Delete("delete from flow_report_month where date_str = :dateStr")
|
||||
void deleteByDateStr(@Param("dateStr") String dateStr);
|
||||
default void deleteByDateStr(String dateStr) {
|
||||
this.delete(new LambdaQueryWrapper<FlowReportMonthDO>()
|
||||
.eq(FlowReportMonthDO::getDateStr, dateStr)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+19
-31
@@ -21,43 +21,31 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Param;
|
||||
import fun.asgc.neutrino.core.aop.Intercept;
|
||||
import fun.asgc.neutrino.core.db.annotation.ResultType;
|
||||
import fun.asgc.neutrino.core.db.annotation.Select;
|
||||
import fun.asgc.neutrino.core.db.annotation.Update;
|
||||
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.JobInfoListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.JobInfoListRes;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.JobInfoDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/9/5
|
||||
*/
|
||||
@Intercept(ignoreGlobal = true)
|
||||
@Component
|
||||
public interface JobInfoMapper extends SqlMapper {
|
||||
@Mapper
|
||||
public interface JobInfoMapper extends BaseMapper<JobInfoDO> {
|
||||
|
||||
@ResultType(JobInfoListRes.class)
|
||||
@Select("select * from job_info")
|
||||
void page(Page page, JobInfoListReq req);
|
||||
default JobInfoDO findById(Integer id) {
|
||||
return this.selectById(id);
|
||||
}
|
||||
|
||||
@Select("select * from job_info where id = ?")
|
||||
JobInfoDO findById(Integer id);
|
||||
default void updateEnableStatus(Integer id, Integer enable, Date updateTime) {
|
||||
this.update(null, new LambdaUpdateWrapper<JobInfoDO>()
|
||||
.eq(JobInfoDO::getId, id)
|
||||
.set(JobInfoDO::getEnable, enable)
|
||||
.set(JobInfoDO::getUpdateTime, updateTime)
|
||||
);
|
||||
}
|
||||
|
||||
@Update("update `job_info` set enable = :enable,update_time = :updateTime where id = :id")
|
||||
void updateEnableStatus(@Param("id") Integer id, @Param("enable") Integer enable, @Param("updateTime") Date updateTime);
|
||||
|
||||
@ResultType(JobInfoDO.class)
|
||||
@Select("select * from job_info")
|
||||
List<JobInfoDO> findList();
|
||||
|
||||
void update(JobInfoDO jobInfoDO);
|
||||
default List<JobInfoDO> findList() {
|
||||
return this.selectList(new LambdaQueryWrapper<>());
|
||||
}
|
||||
}
|
||||
|
||||
+12
-26
@@ -21,39 +21,25 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Param;
|
||||
import fun.asgc.neutrino.core.aop.Intercept;
|
||||
import fun.asgc.neutrino.core.db.annotation.Insert;
|
||||
import fun.asgc.neutrino.core.db.annotation.ResultType;
|
||||
import fun.asgc.neutrino.core.db.annotation.Select;
|
||||
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.JobInfoListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.JobLogListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.JobInfoListRes;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.JobLogListRes;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.JobInfoDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.JobLogDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/9/5
|
||||
*/
|
||||
@Intercept(ignoreGlobal = true)
|
||||
@Component
|
||||
public interface JobLogMapper extends SqlMapper {
|
||||
@Mapper
|
||||
public interface JobLogMapper extends BaseMapper<JobLogDO> {
|
||||
|
||||
@Insert("insert into job_log(`job_id`,`handler`,`param`,`code`,`msg`,`alarm_status`,`create_time`) values(:jobId,:handler,:param,:code,:msg,:alarmStatus,:createTime)")
|
||||
void add(JobLogDO jobLog);
|
||||
|
||||
@ResultType(JobLogListRes.class)
|
||||
@Select("select * from job_log order by create_time desc")
|
||||
void page(Page page, JobLogListReq req);
|
||||
|
||||
@ResultType(JobLogListRes.class)
|
||||
@Select("select * from job_log where job_id = :jobId order by create_time desc")
|
||||
void pageByJobId(Page page, JobLogListReq req);
|
||||
default void clean(Date date) {
|
||||
this.delete(new LambdaQueryWrapper<JobLogDO>()
|
||||
.lt(JobLogDO::getCreateTime, date)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+74
-63
@@ -21,18 +21,11 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Param;
|
||||
import fun.asgc.neutrino.core.aop.Intercept;
|
||||
import fun.asgc.neutrino.core.db.annotation.Delete;
|
||||
import fun.asgc.neutrino.core.db.annotation.ResultType;
|
||||
import fun.asgc.neutrino.core.db.annotation.Select;
|
||||
import fun.asgc.neutrino.core.db.annotation.Update;
|
||||
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.LicenseListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.LicenseListRes;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.LicenseDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@@ -43,68 +36,86 @@ import java.util.Set;
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/6
|
||||
*/
|
||||
@Intercept(ignoreGlobal = true)
|
||||
@Component
|
||||
public interface LicenseMapper extends SqlMapper {
|
||||
@Mapper
|
||||
public interface LicenseMapper extends BaseMapper<LicenseDO> {
|
||||
|
||||
/**
|
||||
* 查询license分页
|
||||
* @param page
|
||||
* @param req
|
||||
*/
|
||||
void page(Page page, LicenseListReq req);
|
||||
default List<LicenseDO> listAll() {
|
||||
return this.selectList(new LambdaQueryWrapper<>());
|
||||
}
|
||||
|
||||
@ResultType(LicenseListRes.class)
|
||||
@Select("select * from license where enable = 1")
|
||||
List<LicenseListRes> list();
|
||||
default List<LicenseDO> listByUserId(Integer userId) {
|
||||
return this.selectList(new LambdaQueryWrapper<LicenseDO>()
|
||||
.eq(LicenseDO::getUserId, userId)
|
||||
);
|
||||
}
|
||||
|
||||
@ResultType(LicenseDO.class)
|
||||
@Select("select * from license")
|
||||
List<LicenseDO> listAll();
|
||||
default void updateEnableStatus(Integer id, Integer enable, Date updateTime) {
|
||||
this.update(null, new LambdaUpdateWrapper<LicenseDO>()
|
||||
.eq(LicenseDO::getId, id)
|
||||
.set(LicenseDO::getEnable, enable)
|
||||
.set(LicenseDO::getUpdateTime, updateTime)
|
||||
);
|
||||
}
|
||||
|
||||
@ResultType(LicenseDO.class)
|
||||
@Select("select * from `license` where user_id = :userId")
|
||||
List<LicenseDO> listByUserId(@Param("userId") Integer userId);
|
||||
default void updateOnlineStatus(Integer id, Integer isOnline, Date updateTime) {
|
||||
this.update(null, new LambdaUpdateWrapper<LicenseDO>()
|
||||
.eq(LicenseDO::getId, id)
|
||||
.set(LicenseDO::getIsOnline, isOnline)
|
||||
.set(LicenseDO::getUpdateTime, updateTime)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增license
|
||||
* @param license
|
||||
*/
|
||||
int add(LicenseDO license);
|
||||
default void updateOnlineStatus(Integer isOnline, Date updateTime) {
|
||||
this.update(null, new LambdaUpdateWrapper<LicenseDO>()
|
||||
.set(LicenseDO::getIsOnline, updateTime)
|
||||
.set(LicenseDO::getUpdateTime, updateTime)
|
||||
);
|
||||
}
|
||||
|
||||
@Update("update `license` set enable = :enable, update_time = :updateTime where id = :id")
|
||||
void updateEnableStatus(@Param("id") Integer id, @Param("enable") Integer enable, @Param("updateTime") Date updateTime);
|
||||
default void reset(Integer id, String key, Date updateTime) {
|
||||
this.update(null, new LambdaUpdateWrapper<LicenseDO>()
|
||||
.eq(LicenseDO::getId, id)
|
||||
.set(LicenseDO::getKey, key)
|
||||
.set(LicenseDO::getUpdateTime, updateTime)
|
||||
);
|
||||
}
|
||||
|
||||
@Update("update `license` set is_online = :isOnline, update_time = :updateTime where id = :id")
|
||||
void updateOnlineStatus(@Param("id") Integer id, @Param("isOnline") Integer isOnline, @Param("updateTime") Date updateTime);
|
||||
default LicenseDO findById(Integer id) {
|
||||
return this.selectById(id);
|
||||
}
|
||||
|
||||
@Update("update `license` set is_online = :isOnline, update_time = :updateTime")
|
||||
void updateOnlineStatus(@Param("isOnline") Integer isOnline, @Param("updateTime") Date updateTime);
|
||||
default void update(Integer id, String name, Date updateTime) {
|
||||
this.update(null, new LambdaUpdateWrapper<LicenseDO>()
|
||||
.eq(LicenseDO::getId, id)
|
||||
.set(LicenseDO::getName, name)
|
||||
.set(LicenseDO::getUpdateTime, updateTime)
|
||||
);
|
||||
}
|
||||
|
||||
@Update("update `license` set `key` = :key,update_time = :updateTime where id = :id")
|
||||
void reset(@Param("id") Integer id, @Param("key") String key, @Param("updateTime") Date updateTime);
|
||||
default List<LicenseDO> findByIds(Set<Integer> ids) {
|
||||
return selectBatchIds(ids);
|
||||
}
|
||||
|
||||
@Delete("delete from `license` where id = ?")
|
||||
void delete(Integer id);
|
||||
default LicenseDO checkRepeat(Integer userId, String name) {
|
||||
return this.selectOne(new LambdaQueryWrapper<LicenseDO>()
|
||||
.eq(LicenseDO::getUserId, userId)
|
||||
.eq(LicenseDO::getName, name)
|
||||
.last("limit 1")
|
||||
);
|
||||
}
|
||||
|
||||
@Select("select * from `license` where id = ?")
|
||||
LicenseDO findById(Integer id);
|
||||
default LicenseDO checkRepeat(Integer userId, String name, Set<Integer> excludeIds) {
|
||||
return this.selectOne(new LambdaQueryWrapper<LicenseDO>()
|
||||
.eq(LicenseDO::getUserId, userId)
|
||||
.eq(LicenseDO::getName, name)
|
||||
.notIn(LicenseDO::getId, excludeIds)
|
||||
.last("limit 1")
|
||||
);
|
||||
}
|
||||
|
||||
@Update("update `license` set name = :name, update_time = :updateTime where id = :id")
|
||||
void update(@Param("id") Integer id, @Param("name") String name, @Param("updateTime") Date updateTime);
|
||||
|
||||
@ResultType(LicenseDO.class)
|
||||
@Select("select * from `license` where id in (:ids)")
|
||||
List<LicenseDO> findByIds(@Param("ids")Set<Integer> ids);
|
||||
|
||||
@ResultType(LicenseDO.class)
|
||||
@Select("select * from `license` where user_id = :userId and name =:name limit 0,1")
|
||||
LicenseDO checkRepeat(@Param("userId") Integer userId, @Param("name") String name);
|
||||
|
||||
@ResultType(LicenseDO.class)
|
||||
@Select("select * from `license` where user_id = :userId and name =:name and id not in (:excludeIds) limit 0,1")
|
||||
LicenseDO checkRepeat(@Param("userId") Integer userId, @Param("name") String name, @Param("excludeIds") Set<Integer> excludeIds);
|
||||
|
||||
@Select("select * from `license` where `key` = ?")
|
||||
LicenseDO findByKey(String licenseKey);
|
||||
default LicenseDO findByKey(String licenseKey) {
|
||||
return selectOne(new LambdaQueryWrapper<LicenseDO>()
|
||||
.eq(LicenseDO::getKey, licenseKey)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+62
-70
@@ -1,38 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Param;
|
||||
import fun.asgc.neutrino.core.aop.Intercept;
|
||||
import fun.asgc.neutrino.core.db.annotation.Delete;
|
||||
import fun.asgc.neutrino.core.db.annotation.ResultType;
|
||||
import fun.asgc.neutrino.core.db.annotation.Select;
|
||||
import fun.asgc.neutrino.core.db.annotation.Update;
|
||||
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.PortMappingListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.PortMappingListRes;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.PortMappingDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@@ -43,51 +17,69 @@ import java.util.Set;
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/8
|
||||
*/
|
||||
@Intercept(ignoreGlobal = true)
|
||||
@Component
|
||||
public interface PortMappingMapper extends SqlMapper {
|
||||
@Mapper
|
||||
public interface PortMappingMapper extends BaseMapper<PortMappingDO> {
|
||||
|
||||
@ResultType(PortMappingListRes.class)
|
||||
@Select("select * from port_mapping")
|
||||
void page(Page page, PortMappingListReq req);
|
||||
default PortMappingDO findById(Integer id) {
|
||||
return this.selectById(id);
|
||||
}
|
||||
|
||||
void add(PortMappingDO portMappingDO);
|
||||
default void updateEnableStatus(Integer id, Integer enable, Date updateTime) {
|
||||
this.update(null, new LambdaUpdateWrapper<PortMappingDO>()
|
||||
.eq(PortMappingDO::getId, id)
|
||||
.set(PortMappingDO::getEnable, enable)
|
||||
.set(PortMappingDO::getUpdateTime, updateTime)
|
||||
);
|
||||
}
|
||||
|
||||
void update(PortMappingDO portMappingDO);
|
||||
default PortMappingDO findByPort(Integer port, Set<Integer> excludeIds) {
|
||||
return this.selectOne(new LambdaQueryWrapper<PortMappingDO>()
|
||||
.eq(PortMappingDO::getServerPort, port)
|
||||
.notIn(!CollectionUtil.isEmpty(excludeIds), PortMappingDO::getId, excludeIds)
|
||||
.last("limit 1")
|
||||
);
|
||||
}
|
||||
|
||||
@Select("select * from port_mapping where id = ?")
|
||||
PortMappingDO findById(Integer id);
|
||||
default List<PortMappingDO> findEnableListByLicenseId(Integer licenseId) {
|
||||
return this.selectList(new LambdaQueryWrapper<PortMappingDO>()
|
||||
.eq(PortMappingDO::getLicenseId, licenseId)
|
||||
.eq(PortMappingDO::getEnable, EnableStatusEnum.ENABLE.getStatus())
|
||||
);
|
||||
}
|
||||
|
||||
@Update("update `port_mapping` set enable = :enable,update_time = :updateTime where id = :id")
|
||||
void updateEnableStatus(@Param("id") Integer id, @Param("enable") Integer enable, @Param("updateTime") Date updateTime);
|
||||
default List<PortMappingDO> findListByServerPort(Integer serverPort) {
|
||||
return this.selectList(new LambdaQueryWrapper<PortMappingDO>()
|
||||
.eq(PortMappingDO::getServerPort, serverPort)
|
||||
);
|
||||
}
|
||||
|
||||
@Delete("delete from `port_mapping` where id = ?")
|
||||
void delete(Integer id);
|
||||
default List<PortMappingDO> findListByLicenseId(Integer licenseId) {
|
||||
return this.selectList(new LambdaQueryWrapper<PortMappingDO>()
|
||||
.eq(PortMappingDO::getLicenseId, licenseId)
|
||||
);
|
||||
}
|
||||
|
||||
@Select("select * from port_mapping where server_port = ?")
|
||||
PortMappingDO findByPort(Integer port);
|
||||
default void updateOnlineStatus(Integer licenseId,Integer serverPort, Integer isOnline, Date updateTime) {
|
||||
this.update(null, new LambdaUpdateWrapper<PortMappingDO>()
|
||||
.eq(PortMappingDO::getLicenseId, licenseId)
|
||||
.eq(PortMappingDO::getServerPort, serverPort)
|
||||
.set(PortMappingDO::getIsOnline, isOnline)
|
||||
.set(PortMappingDO::getUpdateTime, updateTime)
|
||||
);
|
||||
}
|
||||
|
||||
@Select("select * from port_mapping where server_port = :port and id not in (:excludeIds)")
|
||||
PortMappingDO findByPort(@Param("port") Integer port, @Param("excludeIds") Set<Integer> excludeIds);
|
||||
default void updateOnlineStatus(Integer licenseId, Integer isOnline, Date updateTime) {
|
||||
this.update(null, new LambdaUpdateWrapper<PortMappingDO>()
|
||||
.eq(PortMappingDO::getLicenseId, licenseId)
|
||||
.set(PortMappingDO::getIsOnline, isOnline)
|
||||
.set(PortMappingDO::getUpdateTime, updateTime)
|
||||
);
|
||||
}
|
||||
|
||||
@ResultType(PortMappingDO.class)
|
||||
@Select("select * from port_mapping where license_id = ? and enable = 1")
|
||||
List<PortMappingDO> findEnableListByLicenseId(Integer licenseId);
|
||||
|
||||
@ResultType(PortMappingDO.class)
|
||||
@Select("select * from port_mapping where server_port = :serverPort")
|
||||
List<PortMappingDO> findListByServerPort(@Param("serverPort") Integer serverPort);
|
||||
|
||||
@ResultType(PortMappingDO.class)
|
||||
@Select("select * from port_mapping where license_id = ?")
|
||||
List<PortMappingDO> findListByLicenseId(Integer licenseId);
|
||||
|
||||
@Update("update `port_mapping` set is_online = :isOnline,update_time = :updateTime where license_id = :licenseId and server_port = :serverPort")
|
||||
void updateOnlineStatus(@Param("licenseId") Integer licenseId, @Param("serverPort") Integer serverPort, @Param("isOnline") Integer isOnline, @Param("updateTime") Date updateTime);
|
||||
|
||||
@Update("update `port_mapping` set is_online = :isOnline,update_time = :updateTime where license_id = :licenseId")
|
||||
void updateOnlineStatus(@Param("licenseId") Integer licenseId, @Param("isOnline") Integer isOnline, @Param("updateTime") Date updateTime);
|
||||
|
||||
@Update("update `port_mapping` set is_online = :isOnline,update_time = :updateTime")
|
||||
void updateOnlineStatus(@Param("isOnline") Integer isOnline, @Param("updateTime") Date updateTime);
|
||||
default void updateOnlineStatus(Integer isOnline, Date updateTime) {
|
||||
this.update(null, new LambdaUpdateWrapper<PortMappingDO>()
|
||||
.set(PortMappingDO::getIsOnline, isOnline)
|
||||
.set(PortMappingDO::getUpdateTime, updateTime)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+21
-33
@@ -21,48 +21,36 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Param;
|
||||
import fun.asgc.neutrino.core.aop.Intercept;
|
||||
import fun.asgc.neutrino.core.db.annotation.*;
|
||||
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.PortPoolListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.PortPoolListRes;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.PortPoolDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/7
|
||||
*/
|
||||
@Intercept(ignoreGlobal = true)
|
||||
@Component
|
||||
public interface PortPoolMapper extends SqlMapper {
|
||||
@Mapper
|
||||
public interface PortPoolMapper extends BaseMapper<PortPoolDO> {
|
||||
default void updateEnableStatus(Integer id, Integer enable, Date updateTime) {
|
||||
this.update(null, new LambdaUpdateWrapper<PortPoolDO>()
|
||||
.eq(PortPoolDO::getId, id)
|
||||
.set(PortPoolDO::getEnable, enable)
|
||||
.set(PortPoolDO::getUpdateTime, updateTime)
|
||||
);
|
||||
}
|
||||
|
||||
@ResultType(PortPoolListRes.class)
|
||||
@Select("select * from port_pool")
|
||||
void page(Page<PortPoolListRes> page, PortPoolListReq req);
|
||||
default PortPoolDO findByPort(Integer port) {
|
||||
return this.selectOne(new LambdaQueryWrapper<PortPoolDO>()
|
||||
.eq(PortPoolDO::getPort, port)
|
||||
);
|
||||
}
|
||||
|
||||
@ResultType(PortPoolListRes.class)
|
||||
@Select("select * from port_pool where enable = 1")
|
||||
List<PortPoolListRes> list();
|
||||
|
||||
@Insert("insert into port_pool(`port`,`enable`,`create_time`,`update_time`) values(:port,:enable,:createTime,:updateTime)")
|
||||
void add(PortPoolDO portPool);
|
||||
|
||||
@Update("update `port_pool` set enable = :enable, update_time = :updateTime where id = :id")
|
||||
void updateEnableStatus(@Param("id") Integer id, @Param("enable") Integer enable, @Param("updateTime") Date updateTime);
|
||||
|
||||
@Delete("delete from `port_pool` where id = ?")
|
||||
void delete(Integer id);
|
||||
|
||||
@Select("select * from port_pool where port = ? limit 0,1")
|
||||
PortPoolDO findByPort(Integer port);
|
||||
|
||||
@Select("select * from port_pool where id = ?")
|
||||
PortPoolDO findById(Integer id);
|
||||
default PortPoolDO findById(Integer id) {
|
||||
return this.selectById(id);
|
||||
}
|
||||
}
|
||||
|
||||
+12
-23
@@ -21,34 +21,23 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.aop.Intercept;
|
||||
import fun.asgc.neutrino.core.db.annotation.Insert;
|
||||
import fun.asgc.neutrino.core.db.annotation.ResultType;
|
||||
import fun.asgc.neutrino.core.db.annotation.Select;
|
||||
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.UserLoginRecordListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.UserLoginRecordListRes;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.UserLoginRecordDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/2
|
||||
*/
|
||||
@Intercept(ignoreGlobal = true)
|
||||
@Component
|
||||
public interface UserLoginRecordMapper extends SqlMapper {
|
||||
/**
|
||||
* 新增用户登录日志
|
||||
* @param userLoginRecord
|
||||
* @return
|
||||
*/
|
||||
@Insert("insert into `user_login_record`(`user_id`,`ip`,`token`,`type`,`create_time`) values(:userId,:ip,:token,:type,:createTime)")
|
||||
int add(UserLoginRecordDO userLoginRecord);
|
||||
|
||||
@ResultType(UserLoginRecordListRes.class)
|
||||
@Select("select * from user_login_record order by create_time desc")
|
||||
void page(Page page, UserLoginRecordListReq req);
|
||||
@Mapper
|
||||
public interface UserLoginRecordMapper extends BaseMapper<UserLoginRecordDO> {
|
||||
default void clean(Date date) {
|
||||
this.delete(new LambdaQueryWrapper<UserLoginRecordDO>()
|
||||
.lt(UserLoginRecordDO::getCreateTime, date)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+33
-57
@@ -1,35 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Param;
|
||||
import fun.asgc.neutrino.core.aop.Intercept;
|
||||
import fun.asgc.neutrino.core.db.annotation.*;
|
||||
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.UserListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.UserListRes;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
|
||||
import org.apache.ibatis.annotations.Insert;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@@ -40,49 +16,49 @@ import java.util.Set;
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/1
|
||||
*/
|
||||
@Intercept(ignoreGlobal = true)
|
||||
@Component
|
||||
public interface UserMapper extends SqlMapper {
|
||||
@Mapper
|
||||
public interface UserMapper extends BaseMapper<UserDO> {
|
||||
|
||||
/**
|
||||
* 根据登录名查询用户记录
|
||||
* @param loginName
|
||||
* @return
|
||||
*/
|
||||
@Select("select * from user where login_name = ?")
|
||||
UserDO findByLoginName(String loginName);
|
||||
default UserDO findByLoginName(String loginName) {
|
||||
return selectOne(new LambdaQueryWrapper<UserDO>()
|
||||
.eq(UserDO::getLoginName, loginName)
|
||||
.last("limit 1")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据id查询单条记录
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@Select("select * from user where id = ?")
|
||||
UserDO findById(Integer id);
|
||||
default UserDO findById(Integer id) {
|
||||
return selectById(id);
|
||||
}
|
||||
|
||||
@ResultType(UserDO.class)
|
||||
@Select("select * from user where id in (:ids)")
|
||||
List<UserDO> findByIds(@Param("ids") Set<Integer> ids);
|
||||
default List<UserDO> findByIds(Set<Integer> ids) {
|
||||
return selectBatchIds(ids);
|
||||
}
|
||||
|
||||
@ResultType(UserListRes.class)
|
||||
@Select("select * from user")
|
||||
void page(Page page, UserListReq req);
|
||||
default void updateEnableStatus(Integer id, Integer enable, Date updateTime) {
|
||||
this.update(null, new LambdaUpdateWrapper<UserDO>()
|
||||
.eq(UserDO::getId, id)
|
||||
.set(UserDO::getEnable, enable)
|
||||
.set(UserDO::getUpdateTime, updateTime)
|
||||
);
|
||||
}
|
||||
|
||||
@ResultType(UserListRes.class)
|
||||
@Select("select * from user where enable = 1")
|
||||
List<UserListRes> list();
|
||||
|
||||
@Update("update `user` set enable = :enable,update_time = :updateTime where id = :id")
|
||||
void updateEnableStatus(@Param("id") Integer id, @Param("enable") Integer enable, @Param("updateTime")Date updateTime);
|
||||
|
||||
@Delete("delete from `user` where id = ?")
|
||||
void delete(Integer id);
|
||||
|
||||
@Update("update `user` set name = :name,login_name = :loginName,update_time = :updateTime where id = :id")
|
||||
void update(UserDO userDO);
|
||||
|
||||
@Update("update `user` set login_password = :loginPassword,update_time = :updateTime where id = :id")
|
||||
void updateLoginPassword(@Param("id") Integer id, @Param("loginPassword") String loginPassword, @Param("updateTime")Date updateTime);
|
||||
default void updateLoginPassword(Integer id, String loginPassword, Date updateTime) {
|
||||
this.update(null, new LambdaUpdateWrapper<UserDO>()
|
||||
.eq(UserDO::getId, id)
|
||||
.set(UserDO::getLoginPassword, loginPassword)
|
||||
.set(UserDO::getUpdateTime, updateTime)
|
||||
);
|
||||
}
|
||||
|
||||
@Insert("insert into user(`name`,`login_name`,`login_password`,`enable`,`create_time`,`update_time`) values(:name,:loginName,:loginPassword,:enable,:createTime,:updateTime)")
|
||||
void add(UserDO user);
|
||||
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
package fun.asgc.neutrino.proxy.server.dal;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Param;
|
||||
import fun.asgc.neutrino.core.aop.Intercept;
|
||||
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.UserFlowReportRes;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2023/1/18
|
||||
*/
|
||||
@Intercept(ignoreGlobal = true)
|
||||
@Component
|
||||
public interface UserReportMapper extends SqlMapper {
|
||||
|
||||
void userFlowReportPage(Page<UserFlowReportRes> page, @Param("todayBegin") Date todayBegin, @Param("todayEnd") Date todayEnd);
|
||||
|
||||
}
|
||||
+28
-25
@@ -21,13 +21,11 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Param;
|
||||
import fun.asgc.neutrino.core.aop.Intercept;
|
||||
import fun.asgc.neutrino.core.db.annotation.Delete;
|
||||
import fun.asgc.neutrino.core.db.annotation.Update;
|
||||
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.UserTokenDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@@ -36,17 +34,8 @@ import java.util.Date;
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/1
|
||||
*/
|
||||
@Intercept(ignoreGlobal = true)
|
||||
@Component
|
||||
public interface UserTokenMapper extends SqlMapper {
|
||||
/**
|
||||
* 新增用户token
|
||||
* 支持注解 + xml配置2种方式
|
||||
* @param userToken
|
||||
* @return
|
||||
*/
|
||||
// @Insert("insert into `user_token`(`token`,`user_id`,`expiration_time`,`create_time`,`update_time`) values (:token,:userId,:expirationTime,:createTime,:updateTime)")
|
||||
int add(UserTokenDO userToken);
|
||||
@Mapper
|
||||
public interface UserTokenMapper extends BaseMapper<UserTokenDO> {
|
||||
|
||||
/**
|
||||
* 根据token查询单条记录
|
||||
@@ -55,23 +44,37 @@ public interface UserTokenMapper extends SqlMapper {
|
||||
* @param time
|
||||
* @return
|
||||
*/
|
||||
// @Select("select * from user_token where token = ? and expiration_time > ?")
|
||||
UserTokenDO findByAvailableToken(String token, Date date);
|
||||
default UserTokenDO findByAvailableToken(String token, Date date) {
|
||||
return selectOne(new LambdaQueryWrapper<UserTokenDO>()
|
||||
.eq(UserTokenDO::getToken, token)
|
||||
.gt(UserTokenDO::getExpirationTime, date)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据token删除记录
|
||||
* @param token
|
||||
*/
|
||||
@Delete("delete from user_token where token = ?")
|
||||
void deleteByToken(String token);
|
||||
default void deleteByToken(String token) {
|
||||
this.delete(new LambdaQueryWrapper<UserTokenDO>()
|
||||
.eq(UserTokenDO::getToken, token)
|
||||
);
|
||||
}
|
||||
|
||||
@Update("update user_token set expiration_time = :expirationTime where token = :token")
|
||||
void updateTokenExpirationTime(@Param("token") String token, @Param("expirationTime") Date expirationTime);
|
||||
default void updateTokenExpirationTime(String token, Date expirationTime) {
|
||||
this.update(null, new LambdaUpdateWrapper<UserTokenDO>()
|
||||
.eq(UserTokenDO::getToken, token)
|
||||
.set(UserTokenDO::getExpirationTime, expirationTime)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据userId删除token
|
||||
* @param userId
|
||||
*/
|
||||
@Delete("delete from user_token where user_id = ?")
|
||||
void deleteByUserId(Integer userId);
|
||||
default void deleteByUserId(Integer userId) {
|
||||
this.delete(new LambdaQueryWrapper<UserTokenDO>()
|
||||
.eq(UserTokenDO::getUserId, userId)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-4
@@ -1,7 +1,8 @@
|
||||
package fun.asgc.neutrino.proxy.server.dal.entity;
|
||||
|
||||
import fun.asgc.neutrino.core.db.annotation.Id;
|
||||
import fun.asgc.neutrino.core.db.annotation.Table;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
@@ -15,9 +16,9 @@ import java.util.Date;
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
@Table("client_connect_record")
|
||||
@TableName("client_connect_record")
|
||||
public class ClientConnectRecordDO {
|
||||
@Id
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
private String ip;
|
||||
private Integer licenseId;
|
||||
|
||||
+5
-4
@@ -21,8 +21,9 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal.entity;
|
||||
|
||||
import fun.asgc.neutrino.core.db.annotation.Id;
|
||||
import fun.asgc.neutrino.core.db.annotation.Table;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
@@ -36,9 +37,9 @@ import java.util.Date;
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
@Table("flow_report_day")
|
||||
@TableName("flow_report_day")
|
||||
public class FlowReportDayDO {
|
||||
@Id
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
/**
|
||||
* 用户ID
|
||||
|
||||
+5
-4
@@ -21,8 +21,9 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal.entity;
|
||||
|
||||
import fun.asgc.neutrino.core.db.annotation.Id;
|
||||
import fun.asgc.neutrino.core.db.annotation.Table;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
@@ -36,9 +37,9 @@ import java.util.Date;
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
@Table("flow_report_hour")
|
||||
@TableName("flow_report_hour")
|
||||
public class FlowReportHourDO {
|
||||
@Id
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
/**
|
||||
* 用户ID
|
||||
|
||||
+5
-4
@@ -21,8 +21,9 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal.entity;
|
||||
|
||||
import fun.asgc.neutrino.core.db.annotation.Id;
|
||||
import fun.asgc.neutrino.core.db.annotation.Table;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
@@ -36,9 +37,9 @@ import java.util.Date;
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
@Table("flow_report_minute")
|
||||
@TableName("flow_report_minute")
|
||||
public class FlowReportMinuteDO {
|
||||
@Id
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
/**
|
||||
* 用户ID
|
||||
|
||||
+5
-4
@@ -21,8 +21,9 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal.entity;
|
||||
|
||||
import fun.asgc.neutrino.core.db.annotation.Id;
|
||||
import fun.asgc.neutrino.core.db.annotation.Table;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
@@ -36,9 +37,9 @@ import java.util.Date;
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
@Table("flow_report_month")
|
||||
@TableName("flow_report_month")
|
||||
public class FlowReportMonthDO {
|
||||
@Id
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
/**
|
||||
* 用户ID
|
||||
|
||||
+7
-4
@@ -21,8 +21,10 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal.entity;
|
||||
|
||||
import fun.asgc.neutrino.core.db.annotation.Id;
|
||||
import fun.asgc.neutrino.core.db.annotation.Table;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
@@ -37,11 +39,12 @@ import java.util.Date;
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
@Table("job_info")
|
||||
@TableName("job_info")
|
||||
public class JobInfoDO {
|
||||
@Id
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
private String cron;
|
||||
@TableField("`desc`")
|
||||
private String desc;
|
||||
private String alarmEmail;
|
||||
private String alarmDing;
|
||||
|
||||
+5
-4
@@ -21,8 +21,9 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal.entity;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.db.annotation.Table;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
@@ -37,9 +38,9 @@ import java.util.Date;
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
@Table("job_log")
|
||||
@TableName("job_log")
|
||||
public class JobLogDO {
|
||||
@Autowired
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
private Integer jobId;
|
||||
private String handler;
|
||||
|
||||
+7
-4
@@ -21,8 +21,10 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal.entity;
|
||||
|
||||
import fun.asgc.neutrino.core.db.annotation.Id;
|
||||
import fun.asgc.neutrino.core.db.annotation.Table;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import fun.asgc.neutrino.proxy.server.constant.OnlineStatusEnum;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
@@ -38,9 +40,9 @@ import java.util.Date;
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
@Table("license")
|
||||
@TableName("license")
|
||||
public class LicenseDO {
|
||||
@Id
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
/**
|
||||
* 名称
|
||||
@@ -49,6 +51,7 @@ public class LicenseDO {
|
||||
/**
|
||||
* licenseKey
|
||||
*/
|
||||
@TableField("`key`")
|
||||
private String key;
|
||||
/**
|
||||
* 用户ID
|
||||
|
||||
+5
-4
@@ -21,8 +21,9 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal.entity;
|
||||
|
||||
import fun.asgc.neutrino.core.db.annotation.Id;
|
||||
import fun.asgc.neutrino.core.db.annotation.Table;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import fun.asgc.neutrino.proxy.server.constant.OnlineStatusEnum;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
@@ -38,9 +39,9 @@ import java.util.Date;
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
@Table("port_mapping")
|
||||
@TableName("port_mapping")
|
||||
public class PortMappingDO {
|
||||
@Id
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
/**
|
||||
* licenseId
|
||||
|
||||
+5
-4
@@ -21,8 +21,9 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal.entity;
|
||||
|
||||
import fun.asgc.neutrino.core.db.annotation.Id;
|
||||
import fun.asgc.neutrino.core.db.annotation.Table;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
@@ -37,9 +38,9 @@ import java.util.Date;
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
@Table("port_pool")
|
||||
@TableName("port_pool")
|
||||
public class PortPoolDO {
|
||||
@Id
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
/**
|
||||
* 端口
|
||||
|
||||
+5
-4
@@ -21,8 +21,9 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal.entity;
|
||||
|
||||
import fun.asgc.neutrino.core.db.annotation.Id;
|
||||
import fun.asgc.neutrino.core.db.annotation.Table;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@@ -35,9 +36,9 @@ import java.util.Date;
|
||||
*/
|
||||
@ToString
|
||||
@Data
|
||||
@Table("user")
|
||||
@TableName("user")
|
||||
public class UserDO {
|
||||
@Id
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
/**
|
||||
* 用户名
|
||||
|
||||
+5
-4
@@ -12,8 +12,9 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal.entity;
|
||||
|
||||
import fun.asgc.neutrino.core.db.annotation.Id;
|
||||
import fun.asgc.neutrino.core.db.annotation.Table;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
@@ -28,7 +29,7 @@ import java.util.Date;
|
||||
@ToString
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Table("user_login_record")
|
||||
@TableName("user_login_record")
|
||||
public class UserLoginRecordDO {
|
||||
/**
|
||||
* 类型 - 登录
|
||||
@@ -39,7 +40,7 @@ public class UserLoginRecordDO {
|
||||
*/
|
||||
public static final Integer TYPE_LOGOUT = 2;
|
||||
|
||||
@Id
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
/**
|
||||
* 用户ID
|
||||
|
||||
+5
-4
@@ -21,8 +21,9 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.dal.entity;
|
||||
|
||||
import fun.asgc.neutrino.core.db.annotation.Id;
|
||||
import fun.asgc.neutrino.core.db.annotation.Table;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
@@ -37,10 +38,10 @@ import java.util.Date;
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
@Data
|
||||
@Table("user_token")
|
||||
@TableName("user_token")
|
||||
public class UserTokenDO {
|
||||
|
||||
@Id
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
/**
|
||||
* token
|
||||
|
||||
+25
-38
@@ -1,38 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.job;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.quartz.IJobHandler;
|
||||
import fun.asgc.neutrino.core.quartz.annotation.JobHandler;
|
||||
import fun.asgc.neutrino.core.util.DateUtil;
|
||||
import fun.asgc.neutrino.proxy.server.dal.DataCleanMapper;
|
||||
import fun.asgc.neutrino.proxy.core.util.DateUtil;
|
||||
import fun.asgc.neutrino.proxy.server.dal.*;
|
||||
import fun.asgc.solon.extend.job.IJobHandler;
|
||||
import fun.asgc.solon.extend.job.annotation.JobHandler;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
@@ -44,13 +22,9 @@ import java.util.Date;
|
||||
* @date: 2022/9/17
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
@JobHandler(name = "DataCleanJob", cron = "0 0 1 * * ?")
|
||||
public class DataCleanJob implements IJobHandler {
|
||||
@Autowired
|
||||
private DataCleanMapper dataCleanMapper;
|
||||
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
/**
|
||||
* Job日志保存天数
|
||||
*/
|
||||
@@ -76,6 +50,19 @@ public class DataCleanJob implements IJobHandler {
|
||||
* 流量统计天报表记录保留天数
|
||||
*/
|
||||
private static final Integer FLOW_DAY_REPORT_KEEP_DAYS = 400;
|
||||
@Inject
|
||||
private JobLogMapper jobLogMapper;
|
||||
@Inject
|
||||
private UserLoginRecordMapper userLoginRecordMapper;
|
||||
@Inject
|
||||
private ClientConnectRecordMapper clientConnectRecordMapper;
|
||||
@Inject
|
||||
private FlowReportMinuteMapper flowReportMinuteMapper;
|
||||
@Inject
|
||||
private FlowReportHourMapper flowReportHourMapper;
|
||||
@Inject
|
||||
private FlowReportDayMapper flowReportDayMapper;
|
||||
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
@Override
|
||||
public void execute(String s) throws Exception {
|
||||
@@ -84,37 +71,37 @@ public class DataCleanJob implements IJobHandler {
|
||||
{
|
||||
Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getJobLogKeepDays());
|
||||
log.info("清理调度管理日志 date:{}", sdf.format(date));
|
||||
dataCleanMapper.cleanJobLog(date);
|
||||
jobLogMapper.clean(date);
|
||||
}
|
||||
|
||||
{
|
||||
Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getUserLoginRecordKeepDays());
|
||||
log.info("清理用户登录日志 date:{}", sdf.format(date));
|
||||
dataCleanMapper.cleanUserLoginRecord(date);
|
||||
userLoginRecordMapper.clean(date);
|
||||
}
|
||||
|
||||
{
|
||||
Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getClientConnectRecordKeepDays());
|
||||
log.info("清理客户端连接日志 date:{}", sdf.format(date));
|
||||
dataCleanMapper.cleanClientConnectRecord(date);
|
||||
clientConnectRecordMapper.clean(date);
|
||||
}
|
||||
|
||||
{
|
||||
Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getFlowMinuteReportKeepDays());
|
||||
log.info("清理流通统计分钟报表日志 date:{}", sdf.format(date));
|
||||
dataCleanMapper.cleanFlowMinuteReport(date);
|
||||
flowReportMinuteMapper.clean(date);
|
||||
}
|
||||
|
||||
{
|
||||
Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getFlowHourReportKeepDays());
|
||||
log.info("清理流通统计小时报表日志 date:{}", sdf.format(date));
|
||||
dataCleanMapper.cleanFlowHourReport(date);
|
||||
flowReportHourMapper.clean(date);
|
||||
}
|
||||
|
||||
{
|
||||
Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getFlowDayReportKeepDays());
|
||||
log.info("清理流通统计日报表日志 date:{}", sdf.format(date));
|
||||
dataCleanMapper.cleanFlowDayReport(date);
|
||||
flowReportDayMapper.clean(date);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-26
@@ -1,31 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.job;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.quartz.IJobHandler;
|
||||
import fun.asgc.neutrino.core.quartz.annotation.JobHandler;
|
||||
import fun.asgc.solon.extend.job.IJobHandler;
|
||||
import fun.asgc.solon.extend.job.annotation.JobHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.noear.solon.annotation.Component;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -33,7 +11,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||
* @date: 2022/9/4
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
@JobHandler(name = "DemoJob", cron = "0/10 * * * * ?", param = "{\"a\":1}")
|
||||
public class DemoJob implements IJobHandler {
|
||||
|
||||
+12
-14
@@ -21,13 +21,8 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.job;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.quartz.IJobHandler;
|
||||
import fun.asgc.neutrino.core.quartz.annotation.JobHandler;
|
||||
import fun.asgc.neutrino.core.util.CollectionUtil;
|
||||
import fun.asgc.neutrino.core.util.DateUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import fun.asgc.neutrino.proxy.core.util.DateUtil;
|
||||
import fun.asgc.neutrino.proxy.server.dal.FlowReportDayMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.FlowReportHourMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.FlowReportMinuteMapper;
|
||||
@@ -35,7 +30,11 @@ import fun.asgc.neutrino.proxy.server.dal.LicenseMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportDayDO;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportHourDO;
|
||||
import fun.asgc.neutrino.proxy.server.service.FlowReportService;
|
||||
import fun.asgc.solon.extend.job.IJobHandler;
|
||||
import fun.asgc.solon.extend.job.annotation.JobHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -44,19 +43,18 @@ import java.util.*;
|
||||
* @date: 2022/10/28
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
@JobHandler(name = "FlowReportForDayJob", cron = "0 0 1 * * ?", param = "")
|
||||
public class FlowReportForDayJob implements IJobHandler {
|
||||
@Autowired
|
||||
@Inject
|
||||
private FlowReportService flowReportService;
|
||||
@Autowired
|
||||
@Inject
|
||||
private LicenseMapper licenseMapper;
|
||||
@Autowired
|
||||
@Inject
|
||||
private FlowReportMinuteMapper flowReportMinuteMapper;
|
||||
@Autowired
|
||||
@Inject
|
||||
private FlowReportHourMapper flowReportHourMapper;
|
||||
@Autowired
|
||||
@Inject
|
||||
private FlowReportDayMapper flowReportDayMapper;
|
||||
|
||||
@Override
|
||||
@@ -97,7 +95,7 @@ public class FlowReportForDayJob implements IJobHandler {
|
||||
}
|
||||
|
||||
for (FlowReportDayDO item : map.values()) {
|
||||
flowReportDayMapper.add(item);
|
||||
flowReportDayMapper.insert(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-34
@@ -1,40 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.job;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.quartz.IJobHandler;
|
||||
import fun.asgc.neutrino.core.quartz.annotation.JobHandler;
|
||||
import fun.asgc.neutrino.core.util.CollectionUtil;
|
||||
import fun.asgc.neutrino.core.util.DateUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import fun.asgc.neutrino.proxy.core.util.DateUtil;
|
||||
import fun.asgc.neutrino.proxy.server.dal.FlowReportHourMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.FlowReportMinuteMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.LicenseMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportHourDO;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportMinuteDO;
|
||||
import fun.asgc.neutrino.proxy.server.service.FlowReportService;
|
||||
import fun.asgc.solon.extend.job.IJobHandler;
|
||||
import fun.asgc.solon.extend.job.annotation.JobHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -43,17 +21,16 @@ import java.util.*;
|
||||
* @date: 2022/10/28
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
@JobHandler(name = "FlowReportForHourJob", cron = "0 0 */1 * * ?", param = "")
|
||||
public class FlowReportForHourJob implements IJobHandler {
|
||||
@Autowired
|
||||
@Inject
|
||||
private FlowReportService flowReportService;
|
||||
@Autowired
|
||||
@Inject
|
||||
private LicenseMapper licenseMapper;
|
||||
@Autowired
|
||||
@Inject
|
||||
private FlowReportMinuteMapper flowReportMinuteMapper;
|
||||
@Autowired
|
||||
@Inject
|
||||
private FlowReportHourMapper flowReportHourMapper;
|
||||
|
||||
@Override
|
||||
@@ -94,7 +71,7 @@ public class FlowReportForHourJob implements IJobHandler {
|
||||
}
|
||||
|
||||
for (FlowReportHourDO item : map.values()) {
|
||||
flowReportHourMapper.add(item);
|
||||
flowReportHourMapper.insert(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-33
@@ -1,39 +1,17 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.job;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.quartz.IJobHandler;
|
||||
import fun.asgc.neutrino.core.quartz.annotation.JobHandler;
|
||||
import fun.asgc.neutrino.core.util.CollectionUtil;
|
||||
import fun.asgc.neutrino.core.util.DateUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import fun.asgc.neutrino.proxy.core.util.DateUtil;
|
||||
import fun.asgc.neutrino.proxy.server.dal.FlowReportMinuteMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.LicenseMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportMinuteDO;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.LicenseDO;
|
||||
import fun.asgc.neutrino.proxy.server.service.FlowReportService;
|
||||
import fun.asgc.solon.extend.job.IJobHandler;
|
||||
import fun.asgc.solon.extend.job.annotation.JobHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
@@ -45,16 +23,15 @@ import java.util.stream.Collectors;
|
||||
* @date: 2022/10/24
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
@JobHandler(name = "FlowReportForMinuteJob", cron = "0 */1 * * * ?", param = "")
|
||||
public class FlowReportForMinuteJob implements IJobHandler {
|
||||
|
||||
@Autowired
|
||||
@Inject
|
||||
private FlowReportService flowReportService;
|
||||
@Autowired
|
||||
@Inject
|
||||
private LicenseMapper licenseMapper;
|
||||
@Autowired
|
||||
@Inject
|
||||
private FlowReportMinuteMapper flowReportMinuteMapper;
|
||||
|
||||
@Override
|
||||
@@ -86,7 +63,7 @@ public class FlowReportForMinuteJob implements IJobHandler {
|
||||
flowReportMinuteDO.setDate(date);
|
||||
flowReportMinuteDO.setDateStr(dateStr);
|
||||
flowReportMinuteDO.setCreateTime(now);
|
||||
flowReportMinuteMapper.add(flowReportMinuteDO);
|
||||
flowReportMinuteMapper.insert(flowReportMinuteDO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
-36
@@ -1,38 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.job;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.quartz.IJobHandler;
|
||||
import fun.asgc.neutrino.core.quartz.annotation.JobHandler;
|
||||
import fun.asgc.neutrino.core.util.CollectionUtil;
|
||||
import fun.asgc.neutrino.core.util.DateUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import fun.asgc.neutrino.proxy.core.util.DateUtil;
|
||||
import fun.asgc.neutrino.proxy.server.dal.*;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportDayDO;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.FlowReportMonthDO;
|
||||
import fun.asgc.neutrino.proxy.server.service.FlowReportService;
|
||||
import fun.asgc.solon.extend.job.IJobHandler;
|
||||
import fun.asgc.solon.extend.job.annotation.JobHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -41,21 +19,20 @@ import java.util.*;
|
||||
* @date: 2022/10/28
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
@JobHandler(name = "FlowReportForMonthJob", cron = "0 10 0 1 * ?", param = "")
|
||||
public class FlowReportForMonthJob implements IJobHandler {
|
||||
@Autowired
|
||||
@Inject
|
||||
private FlowReportService flowReportService;
|
||||
@Autowired
|
||||
@Inject
|
||||
private LicenseMapper licenseMapper;
|
||||
@Autowired
|
||||
@Inject
|
||||
private FlowReportMinuteMapper flowReportMinuteMapper;
|
||||
@Autowired
|
||||
@Inject
|
||||
private FlowReportHourMapper flowReportHourMapper;
|
||||
@Autowired
|
||||
@Inject
|
||||
private FlowReportDayMapper flowReportDayMapper;
|
||||
@Autowired
|
||||
@Inject
|
||||
private FlowReportMonthMapper flowReportMonthMapper;
|
||||
|
||||
@Override
|
||||
@@ -96,7 +73,7 @@ public class FlowReportForMonthJob implements IJobHandler {
|
||||
}
|
||||
|
||||
for (FlowReportMonthDO item : map.values()) {
|
||||
flowReportMonthMapper.add(item);
|
||||
flowReportMonthMapper.insert(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+24
-55
@@ -1,36 +1,8 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package fun.asgc.neutrino.proxy.server.proxy.core;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Bean;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.context.ApplicationRunner;
|
||||
import fun.asgc.neutrino.core.context.Environment;
|
||||
import fun.asgc.neutrino.core.util.FileUtil;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessageDecoder;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessageEncoder;
|
||||
import fun.asgc.neutrino.proxy.core.util.FileUtil;
|
||||
import fun.asgc.neutrino.proxy.server.base.proxy.ProxyConfig;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
@@ -41,8 +13,15 @@ import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
import io.netty.handler.timeout.IdleStateHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
import org.noear.solon.core.event.AppLoadEndEvent;
|
||||
import org.noear.solon.core.event.EventListener;
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyStore;
|
||||
|
||||
@@ -52,24 +31,29 @@ import java.security.KeyStore;
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
public class ProxyServerRunner implements ApplicationRunner {
|
||||
@Autowired
|
||||
public class ProxyServerRunner implements EventListener<AppLoadEndEvent> {
|
||||
@Inject
|
||||
private ProxyConfig proxyConfig;
|
||||
@Autowired("serverBossGroup")
|
||||
@Inject("serverBossGroup")
|
||||
private NioEventLoopGroup serverBossGroup;
|
||||
@Autowired("serverWorkerGroup")
|
||||
@Inject("serverWorkerGroup")
|
||||
private NioEventLoopGroup serverWorkerGroup;
|
||||
@Autowired
|
||||
private Environment environment;
|
||||
|
||||
@Inject("${neutrino.proxy.server.port}")
|
||||
private Integer port;
|
||||
@Inject("${neutrino.proxy.server.ssl-port}")
|
||||
private Integer sslPort;
|
||||
@Inject("${neutrino.proxy.server.jks-path}")
|
||||
private String jksPath;
|
||||
@Inject("${neutrino.proxy.server.key-store-password}")
|
||||
private String keyStorePassword;
|
||||
@Inject("${neutrino.proxy.server.key-manager-password}")
|
||||
private String keyManagerPassword;
|
||||
@Override
|
||||
public void run(String[] args) {
|
||||
public void onEvent(AppLoadEndEvent appLoadEndEvent) throws Throwable {
|
||||
startProxyServer();
|
||||
startProxyServerForSSL();
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动代理服务
|
||||
*/
|
||||
@@ -83,7 +67,6 @@ public class ProxyServerRunner implements ApplicationRunner {
|
||||
}
|
||||
});
|
||||
try {
|
||||
Integer port = environment.getMainArgsForInteger("neutrino.proxy.server.port", proxyConfig.getServer().getPort());
|
||||
bootstrap.bind(port).sync();
|
||||
log.info("代理服务启动,端口:{}", port);
|
||||
} catch (Exception e) {
|
||||
@@ -92,7 +75,6 @@ public class ProxyServerRunner implements ApplicationRunner {
|
||||
}
|
||||
|
||||
private void startProxyServerForSSL() {
|
||||
Integer sslPort = environment.getMainArgsForInteger("neutrino.proxy.server.ssl-port", proxyConfig.getServer().getSslPort());
|
||||
if (null == sslPort) {
|
||||
return;
|
||||
}
|
||||
@@ -115,15 +97,12 @@ public class ProxyServerRunner implements ApplicationRunner {
|
||||
|
||||
private ChannelHandler createSslHandler() {
|
||||
try {
|
||||
String jksPath = environment.getMainArgsForString("neutrino.proxy.server.jks-path", proxyConfig.getServer().getJksPath());
|
||||
InputStream jksInputStream = FileUtil.getInputStream(jksPath);
|
||||
SSLContext serverContext = SSLContext.getInstance("TLS");
|
||||
final KeyStore ks = KeyStore.getInstance("JKS");
|
||||
|
||||
String keyStorePassword = environment.getMainArgsForString("neutrino.proxy.server.key-store-password", proxyConfig.getServer().getKeyStorePassword());
|
||||
ks.load(jksInputStream, keyStorePassword.toCharArray());
|
||||
final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||
String keyManagerPassword = environment.getMainArgsForString("neutrino.proxy.server.key-manager-password", proxyConfig.getServer().getKeyManagerPassword());
|
||||
kmf.init(ks, keyManagerPassword.toCharArray());
|
||||
TrustManager[] trustManagers = null;
|
||||
|
||||
@@ -149,14 +128,4 @@ public class ProxyServerRunner implements ApplicationRunner {
|
||||
ch.pipeline().addLast(new IdleStateHandler(proxyConfig.getProtocol().getReadIdleTime(), proxyConfig.getProtocol().getWriteIdleTime(), proxyConfig.getProtocol().getAllIdleTimeSeconds()));
|
||||
ch.pipeline().addLast(new ServerChannelHandler());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public NioEventLoopGroup serverBossGroup() {
|
||||
return new NioEventLoopGroup();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public NioEventLoopGroup serverWorkerGroup() {
|
||||
return new NioEventLoopGroup();
|
||||
}
|
||||
}
|
||||
|
||||
+7
-7
@@ -22,11 +22,9 @@
|
||||
|
||||
package fun.asgc.neutrino.proxy.server.proxy.core;
|
||||
|
||||
import fun.asgc.neutrino.core.base.Dispatcher;
|
||||
import fun.asgc.neutrino.core.util.BeanManager;
|
||||
import fun.asgc.neutrino.core.util.ChannelUtil;
|
||||
import fun.asgc.neutrino.proxy.core.Constants;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessage;
|
||||
import fun.asgc.neutrino.proxy.core.dispatcher.Dispatcher;
|
||||
import fun.asgc.neutrino.proxy.server.constant.ClientConnectTypeEnum;
|
||||
import fun.asgc.neutrino.proxy.server.constant.SuccessCodeEnum;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.ClientConnectRecordDO;
|
||||
@@ -38,7 +36,9 @@ import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.handler.timeout.IdleStateEvent;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.noear.solon.Solon;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
@@ -51,7 +51,7 @@ public class ServerChannelHandler extends SimpleChannelInboundHandler<ProxyMessa
|
||||
private static volatile Dispatcher<ChannelHandlerContext, ProxyMessage> dispatcher;
|
||||
|
||||
public ServerChannelHandler() {
|
||||
dispatcher = BeanManager.getBean(Dispatcher.class);
|
||||
dispatcher = Solon.context().getBean(Dispatcher.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -87,9 +87,9 @@ public class ServerChannelHandler extends SimpleChannelInboundHandler<ProxyMessa
|
||||
} else {
|
||||
CmdChannelAttachInfo cmdChannelAttachInfo = ProxyUtil.getAttachInfo(ctx.channel());
|
||||
if (null != cmdChannelAttachInfo) {
|
||||
BeanManager.getBean(ProxyMutualService.class).offline(cmdChannelAttachInfo);
|
||||
BeanManager.getBean(ClientConnectRecordService.class).add(new ClientConnectRecordDO()
|
||||
.setIp(ChannelUtil.getIP(ctx.channel()))
|
||||
Solon.context().getBean(ProxyMutualService.class).offline(cmdChannelAttachInfo);
|
||||
Solon.context().getBean(ClientConnectRecordService.class).add(new ClientConnectRecordDO()
|
||||
.setIp(((InetSocketAddress)ctx.channel().remoteAddress()).getAddress().getHostAddress())
|
||||
.setLicenseId(cmdChannelAttachInfo.getLicenseId())
|
||||
.setType(ClientConnectTypeEnum.DISCONNECT.getType())
|
||||
.setMsg("")
|
||||
|
||||
+4
-26
@@ -1,29 +1,6 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package fun.asgc.neutrino.proxy.server.proxy.core;
|
||||
|
||||
import fun.asgc.neutrino.core.util.BeanManager;
|
||||
import fun.asgc.neutrino.core.util.StringUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import fun.asgc.neutrino.proxy.core.Constants;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessage;
|
||||
import fun.asgc.neutrino.proxy.server.proxy.domain.VisitorChannelAttachInfo;
|
||||
@@ -34,6 +11,7 @@ import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import org.noear.solon.Solon;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
@@ -72,7 +50,7 @@ public class VisitorChannelHandler extends SimpleChannelInboundHandler<ByteBuf>
|
||||
|
||||
// 增加流量计数
|
||||
VisitorChannelAttachInfo visitorChannelAttachInfo = ProxyUtil.getAttachInfo(visitorChannel);
|
||||
BeanManager.getBean(FlowReportService.class).addWriteByte(visitorChannelAttachInfo.getLicenseId(), bytes.length);
|
||||
Solon.context().getBean(FlowReportService.class).addWriteByte(visitorChannelAttachInfo.getLicenseId(), bytes.length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +66,7 @@ public class VisitorChannelHandler extends SimpleChannelInboundHandler<ByteBuf>
|
||||
} else {
|
||||
String visitorId = newVisitorId();
|
||||
String lanInfo = ProxyUtil.getClientLanInfoByServerPort(sa.getPort());
|
||||
if (StringUtil.isEmpty(lanInfo)) {
|
||||
if (StrUtil.isEmpty(lanInfo)) {
|
||||
ctx.channel().close();
|
||||
} else {
|
||||
// 用户连接到代理服务器时,设置用户连接不可读,等待代理后端服务器连接成功后再改变为可读状态
|
||||
|
||||
+1
-22
@@ -1,27 +1,6 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.proxy.domain;
|
||||
|
||||
import fun.asgc.neutrino.core.util.CollectionUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.PortMappingDO;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
+16
-18
@@ -22,13 +22,9 @@
|
||||
|
||||
package fun.asgc.neutrino.proxy.server.proxy.handler;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Match;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.util.ChannelUtil;
|
||||
import fun.asgc.neutrino.core.util.StringUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import fun.asgc.neutrino.proxy.core.*;
|
||||
import fun.asgc.neutrino.proxy.core.dispatcher.Match;
|
||||
import fun.asgc.neutrino.proxy.server.base.proxy.ProxyConfig;
|
||||
import fun.asgc.neutrino.proxy.server.constant.ClientConnectTypeEnum;
|
||||
import fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
|
||||
@@ -43,7 +39,10 @@ import fun.asgc.neutrino.proxy.server.util.ProxyUtil;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
@@ -52,36 +51,35 @@ import java.util.Date;
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Match(type = Constants.ProxyDataTypeName.AUTH)
|
||||
@Component
|
||||
public class ProxyMessageAuthHandler implements ProxyMessageHandler {
|
||||
@Autowired
|
||||
@Inject
|
||||
private ProxyConfig proxyConfig;
|
||||
@Autowired
|
||||
@Inject
|
||||
private LicenseService licenseService;
|
||||
@Autowired
|
||||
@Inject
|
||||
private UserService userService;
|
||||
@Autowired
|
||||
@Inject
|
||||
private PortMappingService portMappingService;
|
||||
@Autowired
|
||||
@Inject
|
||||
private ProxyMutualService proxyMutualService;
|
||||
@Autowired
|
||||
@Inject
|
||||
private FlowReportService flowReportService;
|
||||
@Autowired
|
||||
@Inject
|
||||
private ClientConnectRecordService clientConnectRecordService;
|
||||
@Autowired
|
||||
@Inject
|
||||
private LicenseMapper licenseMapper;
|
||||
@Autowired
|
||||
@Inject
|
||||
private VisitorChannelService visitorChannelService;
|
||||
|
||||
@Override
|
||||
public void handle(ChannelHandlerContext ctx, ProxyMessage proxyMessage) {
|
||||
String ip = ChannelUtil.getIP(ctx.channel());
|
||||
String ip = ((InetSocketAddress)ctx.channel().remoteAddress()).getAddress().getHostAddress();
|
||||
Date now = new Date();
|
||||
|
||||
String licenseKey = proxyMessage.getInfo();
|
||||
if (StringUtil.isEmpty(licenseKey)) {
|
||||
if (StrUtil.isEmpty(licenseKey)) {
|
||||
ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "license不能为空!", licenseKey));
|
||||
clientConnectRecordService.add(new ClientConnectRecordDO()
|
||||
.setIp(ip)
|
||||
|
||||
+7
-32
@@ -1,33 +1,8 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package fun.asgc.neutrino.proxy.server.proxy.handler;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Match;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.util.StringUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import fun.asgc.neutrino.proxy.core.*;
|
||||
import fun.asgc.neutrino.proxy.core.dispatcher.Match;
|
||||
import fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.LicenseDO;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
|
||||
@@ -37,26 +12,26 @@ import fun.asgc.neutrino.proxy.server.util.ProxyUtil;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@NonIntercept
|
||||
@Match(type = Constants.ProxyDataTypeName.CONNECT)
|
||||
@Component
|
||||
public class ProxyMessageConnectHandler implements ProxyMessageHandler {
|
||||
|
||||
@Autowired
|
||||
@Inject
|
||||
private LicenseService licenseService;
|
||||
@Autowired
|
||||
@Inject
|
||||
private UserService userService;
|
||||
|
||||
@Override
|
||||
public void handle(ChannelHandlerContext ctx, ProxyMessage proxyMessage) {
|
||||
String info = proxyMessage.getInfo();
|
||||
if (StringUtil.isEmpty(info)) {
|
||||
if (StrUtil.isEmpty(info)) {
|
||||
ctx.channel().writeAndFlush(ProxyMessage.buildErrMessage(ExceptionEnum.CONNECT_FAILED, "info不能为空!"));
|
||||
ctx.channel().close();
|
||||
return;
|
||||
|
||||
+2
-26
@@ -1,46 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package fun.asgc.neutrino.proxy.server.proxy.handler;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Match;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.proxy.core.Constants;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyDataTypeEnum;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessage;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessageHandler;
|
||||
import fun.asgc.neutrino.proxy.core.dispatcher.Match;
|
||||
import fun.asgc.neutrino.proxy.server.util.ProxyUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import org.noear.solon.annotation.Component;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@NonIntercept
|
||||
@Match(type = Constants.ProxyDataTypeName.DISCONNECT)
|
||||
@Component
|
||||
public class ProxyMessageDisconnectHandler implements ProxyMessageHandler {
|
||||
|
||||
+2
-26
@@ -1,42 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package fun.asgc.neutrino.proxy.server.proxy.handler;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Match;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.proxy.core.Constants;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyDataTypeEnum;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessage;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessageHandler;
|
||||
import fun.asgc.neutrino.proxy.core.dispatcher.Match;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import org.noear.solon.annotation.Component;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@NonIntercept
|
||||
@Match(type = Constants.ProxyDataTypeName.HEARTBEAT)
|
||||
@Component
|
||||
public class ProxyMessageHeartbeatHandler implements ProxyMessageHandler {
|
||||
|
||||
+4
-28
@@ -1,48 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package fun.asgc.neutrino.proxy.server.proxy.handler;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Match;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.util.BeanManager;
|
||||
import fun.asgc.neutrino.proxy.core.Constants;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyDataTypeEnum;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessage;
|
||||
import fun.asgc.neutrino.proxy.core.ProxyMessageHandler;
|
||||
import fun.asgc.neutrino.proxy.core.dispatcher.Match;
|
||||
import fun.asgc.neutrino.proxy.server.proxy.domain.VisitorChannelAttachInfo;
|
||||
import fun.asgc.neutrino.proxy.server.service.FlowReportService;
|
||||
import fun.asgc.neutrino.proxy.server.util.ProxyUtil;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import org.noear.solon.Solon;
|
||||
import org.noear.solon.annotation.Component;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@NonIntercept
|
||||
@Match(type = Constants.ProxyDataTypeName.TRANSFER)
|
||||
@Component
|
||||
public class ProxyMessageTransferHandler implements ProxyMessageHandler {
|
||||
@@ -57,7 +33,7 @@ public class ProxyMessageTransferHandler implements ProxyMessageHandler {
|
||||
|
||||
// 增加流量计数
|
||||
VisitorChannelAttachInfo visitorChannelAttachInfo = ProxyUtil.getAttachInfo(visitorChannel);
|
||||
BeanManager.getBean(FlowReportService.class).addReadByte(visitorChannelAttachInfo.getLicenseId(), proxyMessage.getData().length);
|
||||
Solon.context().getBean(FlowReportService.class).addReadByte(visitorChannelAttachInfo.getLicenseId(), proxyMessage.getData().length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+29
-44
@@ -1,32 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.service;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.core.util.CollectionUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.SystemContextHolder;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.ClientConnectRecordListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.ClientConnectRecordListRes;
|
||||
@@ -37,6 +17,10 @@ import fun.asgc.neutrino.proxy.server.dal.entity.ClientConnectRecordDO;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.LicenseDO;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import ma.glasnost.orika.MapperFacade;
|
||||
import org.apache.ibatis.solon.annotation.Db;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -49,40 +33,41 @@ import java.util.stream.Collectors;
|
||||
* @date: 2022/11/23
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
public class ClientConnectRecordService {
|
||||
@Autowired
|
||||
@Inject
|
||||
private MapperFacade mapperFacade;
|
||||
@Db
|
||||
private ClientConnectRecordMapper clientConnectRecordMapper;
|
||||
@Autowired
|
||||
@Db
|
||||
private LicenseMapper licenseMapper;
|
||||
@Autowired
|
||||
@Db
|
||||
private UserMapper userMapper;
|
||||
|
||||
public void add(ClientConnectRecordDO clientConnectRecordDO) {
|
||||
clientConnectRecordMapper.add(clientConnectRecordDO);
|
||||
clientConnectRecordMapper.insert(clientConnectRecordDO);
|
||||
}
|
||||
|
||||
public Page<ClientConnectRecordListRes> page(PageQuery pageQuery, ClientConnectRecordListReq req) {
|
||||
Page<ClientConnectRecordListRes> page = Page.create(pageQuery);
|
||||
clientConnectRecordMapper.page(page, req);
|
||||
if (CollectionUtil.isEmpty(page.getRecords())) {
|
||||
return page;
|
||||
}
|
||||
Set<Integer> licenseIds = page.getRecords().stream().map(ClientConnectRecordListRes::getLicenseId).collect(Collectors.toSet());
|
||||
if (CollectionUtil.isEmpty(licenseIds)) {
|
||||
return page;
|
||||
public PageInfo<ClientConnectRecordListRes> page(PageQuery pageQuery, ClientConnectRecordListReq req) {
|
||||
Page<ClientConnectRecordListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
|
||||
List<ClientConnectRecordDO> list = clientConnectRecordMapper.selectList(new LambdaQueryWrapper<ClientConnectRecordDO>()
|
||||
.orderByDesc(ClientConnectRecordDO::getId)
|
||||
);
|
||||
List<ClientConnectRecordListRes> respList = mapperFacade.mapAsList(list, ClientConnectRecordListRes.class);
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
|
||||
}
|
||||
Set<Integer> licenseIds = respList.stream().map(ClientConnectRecordListRes::getLicenseId).collect(Collectors.toSet());
|
||||
List<LicenseDO> licenseList = licenseMapper.findByIds(licenseIds);
|
||||
if (CollectionUtil.isEmpty(licenseList)) {
|
||||
return page;
|
||||
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
|
||||
}
|
||||
Set<Integer> userIds = licenseList.stream().map(LicenseDO::getUserId).collect(Collectors.toSet());
|
||||
List<UserDO> userList = userMapper.findByIds(userIds);
|
||||
Map<Integer, LicenseDO> licenseMap = licenseList.stream().collect(Collectors.toMap(LicenseDO::getId, Function.identity()));
|
||||
Map<Integer, UserDO> userMap = userList.stream().collect(Collectors.toMap(UserDO::getId, Function.identity()));
|
||||
boolean isAdmin = SystemContextHolder.isAdmin();
|
||||
page.getRecords().forEach(item -> {
|
||||
respList.forEach(item -> {
|
||||
LicenseDO license = licenseMap.get(item.getLicenseId());
|
||||
if (null == license) {
|
||||
return;
|
||||
@@ -99,6 +84,6 @@ public class ClientConnectRecordService {
|
||||
item.setMsg("******");
|
||||
}
|
||||
});
|
||||
return page;
|
||||
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
|
||||
}
|
||||
}
|
||||
|
||||
+2
-4
@@ -21,10 +21,9 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.service;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.util.LockUtil;
|
||||
import fun.asgc.neutrino.proxy.core.util.LockUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.noear.solon.annotation.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -36,7 +35,6 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
* @date: 2022/10/26
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
public class FlowReportService {
|
||||
private Map<Integer/*licenseId*/, AtomicInteger/*writeByte*/> writeByteMap = new HashMap<>();
|
||||
|
||||
+36
-44
@@ -1,45 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.service;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.google.common.collect.Lists;
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.core.quartz.IJobSource;
|
||||
import fun.asgc.neutrino.core.quartz.JobExecutor;
|
||||
import fun.asgc.neutrino.core.quartz.JobInfo;
|
||||
import fun.asgc.neutrino.core.util.BeanManager;
|
||||
import fun.asgc.neutrino.core.util.CollectionUtil;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
|
||||
import fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
|
||||
import fun.asgc.neutrino.proxy.server.constant.ExceptionConstant;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.*;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.*;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.JobInfoExecuteReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.JobInfoListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.JobInfoUpdateEnableStatusReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.JobInfoUpdateReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.JobInfoExecuteRes;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.JobInfoListRes;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.JobInfoUpdateEnableStatusRes;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.JobInfoUpdateRes;
|
||||
import fun.asgc.neutrino.proxy.server.dal.JobInfoMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.JobInfoDO;
|
||||
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
|
||||
import fun.asgc.solon.extend.job.IJobSource;
|
||||
import fun.asgc.solon.extend.job.JobInfo;
|
||||
import fun.asgc.solon.extend.job.impl.JobExecutor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import ma.glasnost.orika.MapperFacade;
|
||||
import org.apache.ibatis.solon.annotation.Db;
|
||||
import org.noear.solon.Solon;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@@ -50,17 +39,20 @@ import java.util.List;
|
||||
* @date: 2022/9/5
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
public class JobInfoService implements IJobSource {
|
||||
|
||||
@Autowired
|
||||
@Inject
|
||||
private MapperFacade mapperFacade;
|
||||
@Db
|
||||
private JobInfoMapper jobInfoMapper;
|
||||
|
||||
public Page<JobInfoListRes> page(PageQuery pageQuery, JobInfoListReq req) {
|
||||
Page<JobInfoListRes> page = Page.create(pageQuery);
|
||||
jobInfoMapper.page(page, req);
|
||||
return page;
|
||||
public PageInfo<JobInfoListRes> page(PageQuery pageQuery, JobInfoListReq req) {
|
||||
Page<JobInfoListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
|
||||
List<JobInfoDO> list = jobInfoMapper.selectList(new LambdaQueryWrapper<JobInfoDO>()
|
||||
.orderByAsc(JobInfoDO::getId)
|
||||
);
|
||||
List<JobInfoListRes> respList = mapperFacade.mapAsList(list, JobInfoListRes.class);
|
||||
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
|
||||
}
|
||||
|
||||
public List<JobInfoDO> findList() {
|
||||
@@ -73,7 +65,7 @@ public class JobInfoService implements IJobSource {
|
||||
ParamCheckUtil.checkNotNull(jobInfoDO, ExceptionConstant.JOB_INFO_NOT_EXIST);
|
||||
jobInfoMapper.updateEnableStatus(req.getId(), req.getEnable(), new Date());
|
||||
if (EnableStatusEnum.ENABLE.getStatus().equals(req.getEnable())) {
|
||||
BeanManager.getBean(JobExecutor.class).add(new JobInfo()
|
||||
Solon.context().getBean(JobExecutor.class).add(new JobInfo()
|
||||
.setId(String.valueOf(jobInfoDO.getId()))
|
||||
.setName(jobInfoDO.getHandler())
|
||||
.setDesc(jobInfoDO.getDesc())
|
||||
@@ -82,13 +74,13 @@ public class JobInfoService implements IJobSource {
|
||||
.setEnable(true)
|
||||
);
|
||||
} else {
|
||||
BeanManager.getBean(JobExecutor.class).remove(String.valueOf(req.getId()));
|
||||
Solon.context().getBean(JobExecutor.class).remove(String.valueOf(req.getId()));
|
||||
}
|
||||
return new JobInfoUpdateEnableStatusRes();
|
||||
}
|
||||
|
||||
public JobInfoExecuteRes execute(JobInfoExecuteReq req) {
|
||||
BeanManager.getBean(JobExecutor.class).trigger(String.valueOf(req.getId()), req.getParam());
|
||||
Solon.context().getBean(JobExecutor.class).trigger(String.valueOf(req.getId()), req.getParam());
|
||||
return new JobInfoExecuteRes();
|
||||
}
|
||||
|
||||
@@ -125,7 +117,7 @@ public class JobInfoService implements IJobSource {
|
||||
jobInfo.setParam(req.getParam());
|
||||
jobInfo.setUpdateTime(new Date());
|
||||
|
||||
jobInfoMapper.update( jobInfo);
|
||||
jobInfoMapper.updateById(jobInfo);
|
||||
return new JobInfoUpdateRes();
|
||||
}
|
||||
}
|
||||
|
||||
+24
-21
@@ -21,23 +21,26 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.service;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.core.quartz.IJobCallback;
|
||||
import fun.asgc.neutrino.core.quartz.JobInfo;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.JobInfoListReq;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.JobLogListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.JobInfoListRes;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.JobLogListRes;
|
||||
import fun.asgc.neutrino.proxy.server.dal.JobLogMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.JobLogDO;
|
||||
import fun.asgc.solon.extend.job.IJobCallback;
|
||||
import fun.asgc.solon.extend.job.JobInfo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import ma.glasnost.orika.MapperFacade;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.apache.ibatis.solon.annotation.Db;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -45,10 +48,11 @@ import java.util.Date;
|
||||
* @date: 2022/9/4
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
public class JobLogService implements IJobCallback {
|
||||
@Autowired
|
||||
@Inject
|
||||
private MapperFacade mapperFacade;
|
||||
@Db
|
||||
private JobLogMapper jobLogMapper;
|
||||
|
||||
@Override
|
||||
@@ -63,7 +67,7 @@ public class JobLogService implements IJobCallback {
|
||||
msg = "执行异常:\r\n" + ExceptionUtils.getStackTrace(throwable);
|
||||
code = -1;
|
||||
}
|
||||
jobLogMapper.add(new JobLogDO()
|
||||
jobLogMapper.insert(new JobLogDO()
|
||||
.setJobId(Integer.valueOf(jobInfo.getId()))
|
||||
.setHandler(jobInfo.getName())
|
||||
.setParam(param)
|
||||
@@ -74,15 +78,14 @@ public class JobLogService implements IJobCallback {
|
||||
);
|
||||
}
|
||||
|
||||
public Page<JobLogListRes> page(PageQuery pageQuery, JobLogListReq req) {
|
||||
Page<JobLogListRes> page = Page.create(pageQuery);
|
||||
|
||||
if(req.getJobId() != null && req.getJobId() > 0){
|
||||
jobLogMapper.pageByJobId(page, req);
|
||||
} else {
|
||||
jobLogMapper.page(page, req);
|
||||
}
|
||||
return page;
|
||||
public PageInfo<JobLogListRes> page(PageQuery pageQuery, JobLogListReq req) {
|
||||
Page<JobLogListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
|
||||
List<JobLogDO> list = jobLogMapper.selectList(new LambdaQueryWrapper<JobLogDO>()
|
||||
.eq(null != req.getJobId(), JobLogDO::getJobId, req.getJobId())
|
||||
.orderByDesc(JobLogDO::getId)
|
||||
);
|
||||
List<JobLogListRes> respList = mapperFacade.mapAsList(list, JobLogListRes.class);
|
||||
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+47
-44
@@ -1,31 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.service;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.google.common.collect.Sets;
|
||||
import fun.asgc.neutrino.core.annotation.*;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.core.util.CollectionUtil;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.SystemContextHolder;
|
||||
import fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
|
||||
import fun.asgc.neutrino.proxy.server.constant.ExceptionConstant;
|
||||
@@ -40,6 +22,11 @@ import fun.asgc.neutrino.proxy.server.dal.UserMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.LicenseDO;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
|
||||
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
|
||||
import ma.glasnost.orika.MapperFacade;
|
||||
import org.apache.ibatis.solon.annotation.Db;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
import org.noear.solon.core.Lifecycle;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
@@ -50,25 +37,31 @@ import java.util.stream.Collectors;
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/6
|
||||
*/
|
||||
@NonIntercept
|
||||
@Component
|
||||
public class LicenseService {
|
||||
|
||||
@Autowired
|
||||
public class LicenseService implements Lifecycle {
|
||||
@Inject
|
||||
private MapperFacade mapperFacade;
|
||||
@Db
|
||||
private LicenseMapper licenseMapper;
|
||||
@Autowired
|
||||
@Db
|
||||
private UserMapper userMapper;
|
||||
@Autowired
|
||||
@Inject
|
||||
private VisitorChannelService visitorChannelService;
|
||||
|
||||
public Page<LicenseListRes> page(PageQuery pageQuery, LicenseListReq req) {
|
||||
Page<LicenseListRes> page = Page.create(pageQuery);
|
||||
licenseMapper.page(page, req);
|
||||
if (!CollectionUtil.isEmpty(page.getRecords())) {
|
||||
Set<Integer> userIds = page.getRecords().stream().map(LicenseListRes::getUserId).collect(Collectors.toSet());
|
||||
public PageInfo<LicenseListRes> page(PageQuery pageQuery, LicenseListReq req) {
|
||||
Page<LicenseListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
|
||||
List<LicenseDO> list = licenseMapper.selectList(new LambdaQueryWrapper<LicenseDO>()
|
||||
.orderByAsc(LicenseDO::getId)
|
||||
);
|
||||
List<LicenseListRes> respList = mapperFacade.mapAsList(list, LicenseListRes.class);
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
|
||||
}
|
||||
if (!CollectionUtil.isEmpty(respList)) {
|
||||
Set<Integer> userIds = respList.stream().map(LicenseListRes::getUserId).collect(Collectors.toSet());
|
||||
List<UserDO> userList = userMapper.findByIds(userIds);
|
||||
Map<Integer, UserDO> userMap = userList.stream().collect(Collectors.toMap(UserDO::getId, Function.identity()));
|
||||
for (LicenseListRes item : page.getRecords()) {
|
||||
for (LicenseListRes item : respList) {
|
||||
UserDO userDO = userMap.get(item.getUserId());
|
||||
if (null != userDO) {
|
||||
item.setUserName(userDO.getName());
|
||||
@@ -76,11 +69,14 @@ public class LicenseService {
|
||||
item.setKey(desensitization(item.getUserId(), item.getKey()));
|
||||
}
|
||||
}
|
||||
return page;
|
||||
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
|
||||
}
|
||||
|
||||
public List<LicenseListRes> list(LicenseListReq req) {
|
||||
List<LicenseListRes> licenseList = licenseMapper.list();
|
||||
List<LicenseDO> list = licenseMapper.selectList(new LambdaQueryWrapper<LicenseDO>()
|
||||
.eq(LicenseDO::getEnable, EnableStatusEnum.ENABLE.getStatus())
|
||||
);
|
||||
List<LicenseListRes> licenseList = mapperFacade.mapAsList(list, LicenseListRes.class);
|
||||
if (!CollectionUtil.isEmpty(licenseList)) {
|
||||
Set<Integer> userIds = licenseList.stream().map(LicenseListRes::getUserId).collect(Collectors.toSet());
|
||||
List<UserDO> userList = userMapper.findByIds(userIds);
|
||||
@@ -108,7 +104,7 @@ public class LicenseService {
|
||||
String key = UUID.randomUUID().toString().replaceAll("-", "");
|
||||
Date now = new Date();
|
||||
|
||||
licenseMapper.add(new LicenseDO()
|
||||
licenseMapper.insert(new LicenseDO()
|
||||
.setName(req.getName())
|
||||
.setKey(key)
|
||||
.setUserId(req.getUserId())
|
||||
@@ -171,7 +167,7 @@ public class LicenseService {
|
||||
* @param id
|
||||
*/
|
||||
public void delete(Integer id) {
|
||||
licenseMapper.delete(id);
|
||||
licenseMapper.deleteById(id);
|
||||
// 更新VisitorChannel
|
||||
visitorChannelService.updateVisitorChannelByLicenseId(id, EnableStatusEnum.DISABLE.getStatus());
|
||||
}
|
||||
@@ -209,9 +205,16 @@ public class LicenseService {
|
||||
/**
|
||||
* 服务端项目停止、启动时,更新在线状态为离线
|
||||
*/
|
||||
@Init
|
||||
@Destroy
|
||||
public void destroy() {
|
||||
@Override
|
||||
public void start() throws Throwable {
|
||||
licenseMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务端项目停止、启动时,更新在线状态为离线
|
||||
*/
|
||||
@Override
|
||||
public void stop() throws Throwable {
|
||||
licenseMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date());
|
||||
}
|
||||
}
|
||||
|
||||
+45
-52
@@ -1,31 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.service;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.google.common.collect.Sets;
|
||||
import fun.asgc.neutrino.core.annotation.*;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.core.util.CollectionUtil;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.SystemContextHolder;
|
||||
import fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
|
||||
import fun.asgc.neutrino.proxy.server.constant.ExceptionConstant;
|
||||
@@ -44,6 +26,11 @@ import fun.asgc.neutrino.proxy.server.dal.entity.PortMappingDO;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.PortPoolDO;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
|
||||
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
|
||||
import ma.glasnost.orika.MapperFacade;
|
||||
import org.apache.ibatis.solon.annotation.Db;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
import org.noear.solon.core.Lifecycle;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@@ -57,39 +44,40 @@ import java.util.stream.Collectors;
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/8
|
||||
*/
|
||||
@NonIntercept
|
||||
@Component
|
||||
public class PortMappingService {
|
||||
@Autowired
|
||||
public class PortMappingService implements Lifecycle {
|
||||
@Inject
|
||||
private MapperFacade mapperFacade;
|
||||
@Db
|
||||
private PortMappingMapper portMappingMapper;
|
||||
@Autowired
|
||||
@Db
|
||||
private LicenseMapper licenseMapper;
|
||||
@Autowired
|
||||
@Db
|
||||
private UserMapper userMapper;
|
||||
@Autowired
|
||||
@Db
|
||||
private PortPoolMapper portPoolMapper;
|
||||
@Autowired
|
||||
@Inject
|
||||
private VisitorChannelService visitorChannelService;
|
||||
|
||||
public Page<PortMappingListRes> page(PageQuery pageQuery, PortMappingListReq req) {
|
||||
Page<PortMappingListRes> page = Page.create(pageQuery);
|
||||
portMappingMapper.page(page, req);
|
||||
if (CollectionUtil.isEmpty(page.getRecords())) {
|
||||
return page;
|
||||
}
|
||||
Set<Integer> licenseIds = page.getRecords().stream().map(PortMappingListRes::getLicenseId).collect(Collectors.toSet());
|
||||
if (CollectionUtil.isEmpty(licenseIds)) {
|
||||
return page;
|
||||
public PageInfo<PortMappingListRes> page(PageQuery pageQuery, PortMappingListReq req) {
|
||||
Page<PortMappingListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
|
||||
List<PortMappingDO> list = portMappingMapper.selectList(new LambdaQueryWrapper<PortMappingDO>()
|
||||
.orderByAsc(PortMappingDO::getId)
|
||||
);
|
||||
List<PortMappingListRes> respList = mapperFacade.mapAsList(list, PortMappingListRes.class);
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
|
||||
}
|
||||
Set<Integer> licenseIds = respList.stream().map(PortMappingListRes::getLicenseId).collect(Collectors.toSet());
|
||||
List<LicenseDO> licenseList = licenseMapper.findByIds(licenseIds);
|
||||
if (CollectionUtil.isEmpty(licenseList)) {
|
||||
return page;
|
||||
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
|
||||
}
|
||||
Set<Integer> userIds = licenseList.stream().map(LicenseDO::getUserId).collect(Collectors.toSet());
|
||||
List<UserDO> userList = userMapper.findByIds(userIds);
|
||||
Map<Integer, LicenseDO> licenseMap = licenseList.stream().collect(Collectors.toMap(LicenseDO::getId, Function.identity()));
|
||||
Map<Integer, UserDO> userMap = userList.stream().collect(Collectors.toMap(UserDO::getId, Function.identity()));
|
||||
page.getRecords().forEach(item -> {
|
||||
respList.forEach(item -> {
|
||||
LicenseDO license = licenseMap.get(item.getLicenseId());
|
||||
if (null == license) {
|
||||
return;
|
||||
@@ -102,7 +90,7 @@ public class PortMappingService {
|
||||
}
|
||||
item.setUserName(user.getName());
|
||||
});
|
||||
return page;
|
||||
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
|
||||
}
|
||||
|
||||
public PortMappingCreateRes create(PortMappingCreateReq req) {
|
||||
@@ -114,7 +102,7 @@ public class PortMappingService {
|
||||
}
|
||||
PortPoolDO portPoolDO = portPoolMapper.findByPort(req.getServerPort());
|
||||
ParamCheckUtil.checkNotNull(portPoolDO, ExceptionConstant.PORT_NOT_EXIST);
|
||||
ParamCheckUtil.checkExpression(null == portMappingMapper.findByPort(req.getServerPort()), ExceptionConstant.PORT_CANNOT_REPEAT_MAPPING, req.getServerPort());
|
||||
ParamCheckUtil.checkExpression(null == portMappingMapper.findByPort(req.getServerPort(), null), ExceptionConstant.PORT_CANNOT_REPEAT_MAPPING, req.getServerPort());
|
||||
|
||||
|
||||
Date now = new Date();
|
||||
@@ -127,7 +115,7 @@ public class PortMappingService {
|
||||
portMappingDO.setEnable(EnableStatusEnum.ENABLE.getStatus());
|
||||
portMappingDO.setCreateTime(now);
|
||||
portMappingDO.setUpdateTime(now);
|
||||
portMappingMapper.add(portMappingDO);
|
||||
portMappingMapper.insert(portMappingDO);
|
||||
// 更新VisitorChannel
|
||||
visitorChannelService.addVisitorChannelByPortMapping(portMappingDO);
|
||||
return new PortMappingCreateRes();
|
||||
@@ -156,7 +144,7 @@ public class PortMappingService {
|
||||
portMappingDO.setClientPort(req.getClientPort());
|
||||
portMappingDO.setUpdateTime(new Date());
|
||||
portMappingDO.setEnable(EnableStatusEnum.ENABLE.getStatus());
|
||||
portMappingMapper.update(portMappingDO);
|
||||
portMappingMapper.updateById(portMappingDO);
|
||||
// 更新VisitorChannel
|
||||
visitorChannelService.updateVisitorChannelByPortMapping(oldPortMappingDO, portMappingDO);
|
||||
return new PortMappingUpdateRes();
|
||||
@@ -198,7 +186,6 @@ public class PortMappingService {
|
||||
LicenseDO licenseDO = licenseMapper.findById(portMappingDO.getLicenseId());
|
||||
ParamCheckUtil.checkNotNull(licenseDO, ExceptionConstant.LICENSE_NOT_EXIST);
|
||||
if (!SystemContextHolder.isAdmin()) {
|
||||
// 临时处理,如果当前用户不是管理员,则操作userId不能为1
|
||||
ParamCheckUtil.checkExpression(!licenseDO.getUserId().equals(1), ExceptionConstant.NO_PERMISSION_VISIT);
|
||||
}
|
||||
|
||||
@@ -225,7 +212,7 @@ public class PortMappingService {
|
||||
ParamCheckUtil.checkExpression(!licenseDO.getUserId().equals(1), ExceptionConstant.NO_PERMISSION_VISIT);
|
||||
}
|
||||
|
||||
portMappingMapper.delete(id);
|
||||
portMappingMapper.deleteById(id);
|
||||
|
||||
// 更新VisitorChannel
|
||||
visitorChannelService.removeVisitorChannelByPortMapping(portMappingDO);
|
||||
@@ -243,10 +230,16 @@ public class PortMappingService {
|
||||
/**
|
||||
* 服务端项目停止、启动时,更新在线状态为离线
|
||||
*/
|
||||
@Init
|
||||
@Destroy
|
||||
public void destroy() {
|
||||
@Override
|
||||
public void start() throws Throwable {
|
||||
portMappingMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务端项目停止、启动时,更新在线状态为离线
|
||||
*/
|
||||
@Override
|
||||
public void stop() throws Throwable {
|
||||
portMappingMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date());
|
||||
}
|
||||
}
|
||||
|
||||
+26
-16
@@ -21,11 +21,11 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.service;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
|
||||
import fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
|
||||
import fun.asgc.neutrino.proxy.server.constant.ExceptionConstant;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.PortPoolCreateReq;
|
||||
@@ -37,6 +37,10 @@ import fun.asgc.neutrino.proxy.server.controller.res.PortPoolUpdateEnableStatusR
|
||||
import fun.asgc.neutrino.proxy.server.dal.PortPoolMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.PortPoolDO;
|
||||
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
|
||||
import ma.glasnost.orika.MapperFacade;
|
||||
import org.apache.ibatis.solon.annotation.Db;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@@ -46,23 +50,29 @@ import java.util.List;
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/7
|
||||
*/
|
||||
@NonIntercept
|
||||
@Component
|
||||
public class PortPoolService {
|
||||
|
||||
@Autowired
|
||||
@Inject
|
||||
private MapperFacade mapperFacade;
|
||||
@Db
|
||||
private PortPoolMapper portPoolMapper;
|
||||
@Autowired
|
||||
@Inject
|
||||
private VisitorChannelService visitorChannelService;
|
||||
|
||||
public Page<PortPoolListRes> page(PageQuery pageQuery, PortPoolListReq req) {
|
||||
Page<PortPoolListRes> page = Page.create(pageQuery);
|
||||
portPoolMapper.page(page, req);
|
||||
return page;
|
||||
public PageInfo<PortPoolListRes> page(PageQuery pageQuery, PortPoolListReq req) {
|
||||
Page<PortPoolListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
|
||||
List<PortPoolDO> list = portPoolMapper.selectList(new LambdaQueryWrapper<PortPoolDO>()
|
||||
.orderByAsc(PortPoolDO::getId)
|
||||
);
|
||||
List<PortPoolListRes> respList = mapperFacade.mapAsList(list, PortPoolListRes.class);
|
||||
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
|
||||
}
|
||||
|
||||
public List<PortPoolListRes> list(PortPoolListReq req) {
|
||||
return portPoolMapper.list();
|
||||
List<PortPoolDO> list = portPoolMapper.selectList(new LambdaQueryWrapper<PortPoolDO>()
|
||||
.eq(PortPoolDO::getEnable, EnableStatusEnum.ENABLE.getStatus())
|
||||
);
|
||||
return mapperFacade.mapAsList(list, PortPoolListRes.class);
|
||||
}
|
||||
|
||||
public PortPoolCreateRes create(PortPoolCreateReq req) {
|
||||
@@ -71,7 +81,7 @@ public class PortPoolService {
|
||||
|
||||
Date now = new Date();
|
||||
|
||||
portPoolMapper.add(new PortPoolDO()
|
||||
portPoolMapper.insert(new PortPoolDO()
|
||||
.setPort(req.getPort())
|
||||
.setEnable(EnableStatusEnum.ENABLE.getStatus())
|
||||
.setCreateTime(now)
|
||||
@@ -98,7 +108,7 @@ public class PortPoolService {
|
||||
PortPoolDO portPoolDO = portPoolMapper.findById(id);
|
||||
ParamCheckUtil.checkNotNull(portPoolDO, ExceptionConstant.PORT_NOT_EXIST);
|
||||
|
||||
portPoolMapper.delete(id);
|
||||
portPoolMapper.deleteById(id);
|
||||
|
||||
// 更新visitorChannel
|
||||
visitorChannelService.updateVisitorChannelByPortPool(portPoolDO.getPort(), EnableStatusEnum.DISABLE.getStatus());
|
||||
|
||||
+4
-6
@@ -21,14 +21,13 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.service;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.proxy.server.constant.OnlineStatusEnum;
|
||||
import fun.asgc.neutrino.proxy.server.dal.LicenseMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.PortMappingMapper;
|
||||
import fun.asgc.neutrino.proxy.server.proxy.domain.CmdChannelAttachInfo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.ibatis.solon.annotation.Db;
|
||||
import org.noear.solon.annotation.Component;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@@ -38,12 +37,11 @@ import java.util.Date;
|
||||
* @date: 2022/9/3
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
public class ProxyMutualService {
|
||||
@Autowired
|
||||
@Db
|
||||
private PortMappingMapper portMappingMapper;
|
||||
@Autowired
|
||||
@Db
|
||||
private LicenseMapper licenseMapper;
|
||||
|
||||
/**
|
||||
|
||||
+5
-33
@@ -1,57 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.service;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.LicenseFlowReportReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.UserFlowReportReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.LicenseFlowReportRes;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.UserFlowReportRes;
|
||||
import fun.asgc.neutrino.proxy.server.dal.UserReportMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.noear.solon.annotation.Component;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/12/23
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
public class ReportService {
|
||||
|
||||
@Autowired
|
||||
private UserReportMapper userReportMapper;
|
||||
|
||||
/**
|
||||
* 用户流量报表分页
|
||||
* @param pageQuery
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
public Page<UserFlowReportRes> userFlowReportPage(PageQuery pageQuery, UserFlowReportReq req) {
|
||||
public PageInfo<UserFlowReportRes> userFlowReportPage(PageQuery pageQuery, UserFlowReportReq req) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
@@ -62,7 +34,7 @@ public class ReportService {
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
public Page<LicenseFlowReportRes> licenseFlowReportPage(PageQuery pageQuery, LicenseFlowReportReq req) {
|
||||
public PageInfo<LicenseFlowReportRes> licenseFlowReportPage(PageQuery pageQuery, LicenseFlowReportReq req) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
+30
-37
@@ -1,37 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.service;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.core.util.CollectionUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.UserLoginRecordListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.UserLoginRecordListRes;
|
||||
import fun.asgc.neutrino.proxy.server.dal.UserLoginRecordMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.UserMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.UserLoginRecordDO;
|
||||
import ma.glasnost.orika.MapperFacade;
|
||||
import org.apache.ibatis.solon.annotation.Db;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -44,28 +29,36 @@ import java.util.stream.Collectors;
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/10/20
|
||||
*/
|
||||
@NonIntercept
|
||||
@Component
|
||||
public class UserLoginRecordService {
|
||||
@Autowired
|
||||
@Inject
|
||||
private MapperFacade mapperFacade;
|
||||
@Db
|
||||
private UserLoginRecordMapper userLoginRecordMapper;
|
||||
@Autowired
|
||||
@Db
|
||||
private UserMapper userMapper;
|
||||
|
||||
public Page<UserLoginRecordListRes> page(PageQuery pageQuery, UserLoginRecordListReq req) {
|
||||
Page<UserLoginRecordListRes> page = Page.create(pageQuery);
|
||||
userLoginRecordMapper.page(page, req);
|
||||
if (!CollectionUtil.isEmpty(page.getRecords())) {
|
||||
Set<Integer> userIds = page.getRecords().stream().map(UserLoginRecordListRes::getUserId).collect(Collectors.toSet());
|
||||
public PageInfo<UserLoginRecordListRes> page(PageQuery pageQuery, UserLoginRecordListReq req) {
|
||||
Page<UserLoginRecordListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
|
||||
List<UserLoginRecordDO> list = userLoginRecordMapper.selectList(new LambdaQueryWrapper<UserLoginRecordDO>()
|
||||
.orderByDesc(UserLoginRecordDO::getCreateTime)
|
||||
);
|
||||
List<UserLoginRecordListRes> respList = mapperFacade.mapAsList(list, UserLoginRecordListRes.class);
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
|
||||
}
|
||||
|
||||
if (!CollectionUtil.isEmpty(respList)) {
|
||||
Set<Integer> userIds = respList.stream().map(UserLoginRecordListRes::getUserId).collect(Collectors.toSet());
|
||||
List<UserDO> userList = userMapper.findByIds(userIds);
|
||||
Map<Integer, UserDO> userMap = userList.stream().collect(Collectors.toMap(UserDO::getId, Function.identity()));
|
||||
for (UserLoginRecordListRes item : page.getRecords()) {
|
||||
for (UserLoginRecordListRes item : respList) {
|
||||
UserDO userDO = userMap.get(item.getUserId());
|
||||
if (null != userDO) {
|
||||
item.setUserName(userDO.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
return page;
|
||||
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
|
||||
}
|
||||
}
|
||||
|
||||
+40
-52
@@ -1,32 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.service;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.core.util.DateUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import fun.asgc.neutrino.proxy.core.util.DateUtil;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
|
||||
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.ServiceException;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.SystemContextHolder;
|
||||
import fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
|
||||
@@ -41,6 +21,10 @@ import fun.asgc.neutrino.proxy.server.dal.entity.UserLoginRecordDO;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.UserTokenDO;
|
||||
import fun.asgc.neutrino.proxy.server.util.Md5Util;
|
||||
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
|
||||
import ma.glasnost.orika.MapperFacade;
|
||||
import org.apache.ibatis.solon.annotation.Db;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
@@ -52,17 +36,18 @@ import java.util.UUID;
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/7/31
|
||||
*/
|
||||
@NonIntercept
|
||||
@Component
|
||||
public class UserService {
|
||||
private static final String DEFAULT_PASSWORD = "123456";
|
||||
@Autowired
|
||||
@Inject
|
||||
private MapperFacade mapperFacade;
|
||||
@Db
|
||||
private UserMapper userMapper;
|
||||
@Autowired
|
||||
@Db
|
||||
private UserTokenMapper userTokenMapper;
|
||||
@Autowired
|
||||
@Db
|
||||
private UserLoginRecordMapper userLoginRecordMapper;
|
||||
@Autowired
|
||||
@Inject
|
||||
private VisitorChannelService visitorChannelService;
|
||||
|
||||
public LoginRes login(LoginReq req) {
|
||||
@@ -79,7 +64,7 @@ public class UserService {
|
||||
Date expirationTime = DateUtil.addDate(now, Calendar.HOUR, 1);
|
||||
|
||||
// 缓存token
|
||||
userTokenMapper.add(new UserTokenDO()
|
||||
userTokenMapper.insert(new UserTokenDO()
|
||||
.setToken(token)
|
||||
.setUserId(userDO.getId())
|
||||
.setExpirationTime(expirationTime)
|
||||
@@ -88,7 +73,7 @@ public class UserService {
|
||||
);
|
||||
|
||||
// 新增用户登录日志
|
||||
userLoginRecordMapper.add(new UserLoginRecordDO()
|
||||
userLoginRecordMapper.insert(new UserLoginRecordDO()
|
||||
.setUserId(userDO.getId())
|
||||
.setIp(SystemContextHolder.getIp())
|
||||
.setToken(token)
|
||||
@@ -106,7 +91,7 @@ public class UserService {
|
||||
userTokenMapper.deleteByToken(SystemContextHolder.getToken());
|
||||
|
||||
// 新增用户登录日志
|
||||
userLoginRecordMapper.add(new UserLoginRecordDO()
|
||||
userLoginRecordMapper.insert(new UserLoginRecordDO()
|
||||
.setUserId(SystemContextHolder.getUser().getId())
|
||||
.setIp(SystemContextHolder.getIp())
|
||||
.setToken(SystemContextHolder.getToken())
|
||||
@@ -134,15 +119,21 @@ public class UserService {
|
||||
userTokenMapper.updateTokenExpirationTime(token, expirationTime);
|
||||
}
|
||||
|
||||
public Page<UserListRes> page(PageQuery pageQuery, UserListReq req) {
|
||||
Page<UserListRes> page = Page.create(pageQuery);
|
||||
userMapper.page(page, req);
|
||||
return page;
|
||||
public PageInfo<UserListRes> page(PageQuery pageQuery, UserListReq req) {
|
||||
Page<UserListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
|
||||
List<UserDO> list = userMapper.selectList(new LambdaQueryWrapper<UserDO>()
|
||||
.orderByAsc(UserDO::getId)
|
||||
);
|
||||
List<UserListRes> respList = mapperFacade.mapAsList(list, UserListRes.class);
|
||||
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
|
||||
}
|
||||
|
||||
public List<UserListRes> list(UserListReq req) {
|
||||
List<UserListRes> list = userMapper.list();
|
||||
return list;
|
||||
List<UserDO> userDOList = userMapper.selectList(new LambdaQueryWrapper<UserDO>()
|
||||
.eq(UserDO::getEnable, EnableStatusEnum.ENABLE.getStatus())
|
||||
.orderByAsc(UserDO::getId)
|
||||
);
|
||||
return mapperFacade.mapAsList(userDOList, UserListRes.class);
|
||||
}
|
||||
|
||||
public UserInfoRes info(UserInfoReq req) {
|
||||
@@ -170,8 +161,6 @@ public class UserService {
|
||||
}
|
||||
|
||||
public UserCreateRes create(UserCreateReq req) {
|
||||
|
||||
|
||||
Date now = new Date();
|
||||
UserDO userDO = new UserDO();
|
||||
userDO.setName(req.getName());
|
||||
@@ -180,18 +169,17 @@ public class UserService {
|
||||
userDO.setEnable(EnableStatusEnum.ENABLE.getStatus());
|
||||
userDO.setCreateTime(now);
|
||||
userDO.setUpdateTime(now);
|
||||
userMapper.add(userDO);
|
||||
|
||||
userMapper.insert(userDO);
|
||||
return new UserCreateRes();
|
||||
}
|
||||
|
||||
public UserUpdateRes update(UserUpdateReq req) {
|
||||
UserDO userDO = new UserDO();
|
||||
userDO.setId(req.getId());
|
||||
userDO.setName(req.getName());
|
||||
userDO.setLoginName(req.getLoginName());
|
||||
userDO.setUpdateTime(new Date());
|
||||
userMapper.update(userDO);
|
||||
userMapper.update(null, new LambdaUpdateWrapper<UserDO>()
|
||||
.eq(UserDO::getId, req.getId())
|
||||
.set(UserDO::getName, req.getName())
|
||||
.set(UserDO::getLoginName, req.getLoginName())
|
||||
.set(UserDO::getUpdateTime, new Date())
|
||||
);
|
||||
return new UserUpdateRes();
|
||||
}
|
||||
|
||||
@@ -210,7 +198,7 @@ public class UserService {
|
||||
}
|
||||
|
||||
public void delete(Integer id) {
|
||||
userMapper.delete(id);
|
||||
userMapper.deleteById(id);
|
||||
// 更新VisitorChannel
|
||||
visitorChannelService.updateVisitorChannelByUserId(id, EnableStatusEnum.DISABLE.getStatus());
|
||||
}
|
||||
|
||||
+11
-33
@@ -1,32 +1,8 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.service;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.util.CollectionUtil;
|
||||
import fun.asgc.neutrino.proxy.core.Constants;
|
||||
import fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
|
||||
import fun.asgc.neutrino.proxy.server.dal.LicenseMapper;
|
||||
@@ -49,6 +25,9 @@ import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.ibatis.solon.annotation.Db;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
|
||||
import java.net.BindException;
|
||||
import java.util.List;
|
||||
@@ -60,22 +39,21 @@ import java.util.stream.Collectors;
|
||||
* @date: 2023/2/5
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
public class VisitorChannelService {
|
||||
@Autowired("serverBossGroup")
|
||||
@Inject("serverBossGroup")
|
||||
private NioEventLoopGroup serverBossGroup;
|
||||
@Autowired("serverWorkerGroup")
|
||||
@Inject("serverWorkerGroup")
|
||||
private NioEventLoopGroup serverWorkerGroup;
|
||||
@Autowired
|
||||
@Inject
|
||||
private ProxyMutualService proxyMutualService;
|
||||
@Autowired
|
||||
@Db
|
||||
private UserMapper userMapper;
|
||||
@Autowired
|
||||
@Db
|
||||
private LicenseMapper licenseMapper;
|
||||
@Autowired
|
||||
@Db
|
||||
private PortMappingMapper portMappingMapper;
|
||||
@Autowired
|
||||
@Db
|
||||
private PortPoolMapper portPoolMapper;
|
||||
|
||||
/**
|
||||
|
||||
+3
-24
@@ -1,27 +1,6 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.util;
|
||||
|
||||
import fun.asgc.neutrino.core.util.StringUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import fun.asgc.neutrino.proxy.server.constant.ExceptionConstant;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.ServiceException;
|
||||
|
||||
@@ -43,7 +22,7 @@ public class ParamCheckUtil {
|
||||
}
|
||||
|
||||
public static void checkNotEmpty(String str, String name) {
|
||||
if (StringUtil.isEmpty(str)) {
|
||||
if (StrUtil.isEmpty(str)) {
|
||||
throw ServiceException.create(ExceptionConstant.PARAMS_NOT_EMPTY, name);
|
||||
}
|
||||
}
|
||||
@@ -80,7 +59,7 @@ public class ParamCheckUtil {
|
||||
}
|
||||
|
||||
public static void checkNotEmpty(String str, ExceptionConstant constant, Object... params) {
|
||||
if (StringUtil.isEmpty(str)) {
|
||||
if (StrUtil.isEmpty(str)) {
|
||||
throw ServiceException.create(constant, params);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-25
@@ -1,29 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.util;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.google.common.collect.Sets;
|
||||
import fun.asgc.neutrino.core.util.ChannelUtil;
|
||||
import fun.asgc.neutrino.core.util.CollectionUtil;
|
||||
import fun.asgc.neutrino.proxy.core.ChannelAttribute;
|
||||
import fun.asgc.neutrino.proxy.server.proxy.domain.CmdChannelAttachInfo;
|
||||
import fun.asgc.neutrino.proxy.server.proxy.domain.ProxyMapping;
|
||||
@@ -134,7 +112,7 @@ public class ProxyUtil {
|
||||
CmdChannelAttachInfo cmdChannelAttachInfo = getAttachInfo(cmdChannel);
|
||||
if (null == cmdChannelAttachInfo) {
|
||||
cmdChannelAttachInfo = new CmdChannelAttachInfo()
|
||||
.setIp(ChannelUtil.getIP(cmdChannel))
|
||||
.setIp(((InetSocketAddress)cmdChannel.remoteAddress()).getAddress().getHostAddress())
|
||||
.setLicenseId(licenseId)
|
||||
.setVisitorChannelMap(new HashMap<>(16))
|
||||
.setServerPorts(Sets.newHashSet());
|
||||
@@ -213,7 +191,7 @@ public class ProxyUtil {
|
||||
.setLanInfo(lanInfo)
|
||||
.setServerPort(serverPort)
|
||||
.setLicenseId(cmdChannelAttachInfo.getLicenseId())
|
||||
.setIp(ChannelUtil.getIP(visitorChannel))
|
||||
.setIp(((InetSocketAddress)visitorChannel.remoteAddress()).getAddress().getHostAddress())
|
||||
);
|
||||
userChannelMapLock.writeLock().lock();
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
server:
|
||||
port: 8888
|
||||
|
||||
neutrino:
|
||||
proxy:
|
||||
protocol:
|
||||
max-frame-length: 2097152
|
||||
length-field-offset: 0
|
||||
length-field-length: 4
|
||||
initial-bytes-to-strip: 0
|
||||
length-adjustment: 0
|
||||
read-idle-time: 40
|
||||
write-idle-time: 10
|
||||
all-idle-time-seconds: 0
|
||||
server:
|
||||
port: 9000
|
||||
ssl-port: 9002
|
||||
key-store-password: 123456
|
||||
key-manager-password: 123456
|
||||
jks-path: classpath:/test.jks
|
||||
data:
|
||||
db:
|
||||
type: sqlite
|
||||
url: jdbc:sqlite:data.db
|
||||
driver-class: org.sqlite.JDBC
|
||||
username:
|
||||
password:
|
||||
|
||||
#添加MIME印射(如果有需要?)
|
||||
#是否启用静态文件服务。(可不配,默认为启用)
|
||||
solon.staticfiles.enable: true
|
||||
#静态文件的304缓存时长。(可不配,默认为10分钟)
|
||||
solon.staticfiles.maxAge: 600
|
||||
#添加静态目录映射。(按需选择)#v1.11.0 后支持
|
||||
solon.staticfiles.mappings:
|
||||
- path: "/"
|
||||
repository: "./neutrino-proxy-admin/dist/" #2.添加资源路径(仓库只能是目录)
|
||||
|
||||
mybatis.db:
|
||||
typeAliases: #支持包名 或 类名(大写开头 或 *)//支持 ** 或 * 占位符
|
||||
- "fun.asgc.neutrino.proxy.server.dal.entity"
|
||||
mappers: #支持包名 或 类名(大写开头 或 *)或 xml(.xml结尾)//支持 ** 或 * 占位符
|
||||
- "classpath:mapper/*.xml"
|
||||
- "fun.asgc.neutrino.proxy.server.dal"
|
||||
configuration: #扩展配置(要与 MybatisConfiguration 类的属性一一对应)
|
||||
cacheEnabled: false
|
||||
mapUnderscoreToCamelCase: true
|
||||
globalConfig: #全局配置(要与 GlobalConfig 类的属性一一对应)
|
||||
banner: true
|
||||
@@ -1,38 +0,0 @@
|
||||
neutrino:
|
||||
application:
|
||||
name: neutrino-proxy-server
|
||||
http:
|
||||
enable: true
|
||||
port: 8888
|
||||
context-path: /
|
||||
max-content-length-desc: 128K
|
||||
static-resource:
|
||||
locations:
|
||||
- "neutrino-proxy-admin/dist/"
|
||||
|
||||
proxy:
|
||||
protocol:
|
||||
max-frame-length: 2097152
|
||||
length-field-offset: 0
|
||||
length-field-length: 4
|
||||
initial-bytes-to-strip: 0
|
||||
length-adjustment: 0
|
||||
read-idle-time: 40
|
||||
write-idle-time: 10
|
||||
all-idle-time-seconds: 0
|
||||
server:
|
||||
port: 9000
|
||||
ssl-port: 9002
|
||||
key-store-password: 123456
|
||||
key-manager-password: 123456
|
||||
jks-path: classpath:/test.jks
|
||||
data:
|
||||
db:
|
||||
type: sqlite
|
||||
url: jdbc:sqlite:data.db
|
||||
driver-class: org.sqlite.JDBC
|
||||
# type: mysql
|
||||
# url: jdbc:mysql://103.163.47.16:3306/neutrino-proxy?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useAffectedRows=true&useSSL=false
|
||||
# driver-class: com.mysql.jdbc.Driver
|
||||
# username: "******"
|
||||
# password: "******"
|
||||
@@ -1,7 +0,0 @@
|
||||
<mapper namespace = "fun.asgc.neutrino.proxy.server.dal.ClientConnectRecordMapper">
|
||||
|
||||
<update id="add">
|
||||
insert into client_connect_record(`ip`,`license_id`,`type`, `msg`, `code`, `err`, `create_time`)
|
||||
values(:ip,:licenseId,:type,:msg,:code,:err,:createTime)
|
||||
</update>
|
||||
</mapper>
|
||||
@@ -1,8 +0,0 @@
|
||||
<mapper namespace = "fun.asgc.neutrino.proxy.server.dal.JobInfoMapper">
|
||||
|
||||
<update id="update">
|
||||
update `job_info`
|
||||
set cron = :cron,desc = :desc,alarm_email=:alarmEmail,alarm_ding=:alarmDing,param=:param,update_time=:updateTime
|
||||
where id =:id
|
||||
</update>
|
||||
</mapper>
|
||||
@@ -1,12 +0,0 @@
|
||||
<mapper namespace = "fun.asgc.neutrino.proxy.server.dal.LicenseMapper">
|
||||
|
||||
<select id="page" resultType="fun.asgc.neutrino.proxy.server.controller.res.LicenseListRes">
|
||||
select * from `license`
|
||||
</select>
|
||||
|
||||
<insert id="add">
|
||||
insert into `license`(`name`,`key`,`user_id`,`is_online`,`enable`,`create_time`,`update_time`)
|
||||
values (:name, :key, :userId, :isOnline, :enable, :createTime, :updateTime)
|
||||
</insert>
|
||||
|
||||
</mapper>
|
||||
@@ -1,13 +0,0 @@
|
||||
<mapper namespace = "fun.asgc.neutrino.proxy.server.dal.PortMappingMapper">
|
||||
|
||||
<insert id="add">
|
||||
insert into `port_mapping`(`license_id`,`server_port`,`client_ip`,`client_port`,`is_online`,`enable`,`create_time`,`update_time`)
|
||||
values (:licenseId, :serverPort, :clientIp, :clientPort, :isOnline, :enable, :createTime, :updateTime)
|
||||
</insert>
|
||||
|
||||
<update id="update">
|
||||
update `port_mapping`
|
||||
set license_id = :licenseId,server_port = :serverPort,client_ip=:clientIp,client_port=:clientPort,update_time=:updateTime
|
||||
where id =:id
|
||||
</update>
|
||||
</mapper>
|
||||
@@ -1,14 +0,0 @@
|
||||
<mapper namespace = "fun.asgc.neutrino.proxy.server.dal.UserReportMapper">
|
||||
|
||||
<select id="userFlowReportPage" resultType="fun.asgc.neutrino.proxy.server.controller.res.UserFlowReportRes">
|
||||
SELECT
|
||||
u.id AS userId,
|
||||
u.NAME AS userName,
|
||||
IFNULL( SUM( frm.write_bytes ), 0 ) AS historyWriteBytes,
|
||||
IFNULL( SUM( frm.read_bytes ), 0 ) AS historyReadBytes
|
||||
FROM `user` u
|
||||
LEFT JOIN flow_report_month frm ON u.id = frm.user_id
|
||||
GROUP BY u.id
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -1,12 +0,0 @@
|
||||
<mapper namespace = "fun.asgc.neutrino.proxy.server.dal.UserTokenMapper">
|
||||
|
||||
<insert id = "add">
|
||||
insert into `user_token`(`token`,`user_id`,`expiration_time`,`create_time`,`update_time`)
|
||||
values (:token, :userId, :expirationTime, :createTime, :updateTime)
|
||||
</insert>
|
||||
|
||||
<select id = "findByAvailableToken">
|
||||
select * from user_token where token = ? and expiration_time > ?
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 66 KiB |
@@ -1,3 +0,0 @@
|
||||
function hello() {
|
||||
alert("hello");
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>测试页面</title>
|
||||
<script type="application/javascript" src="js/test.js"></script>
|
||||
<script type="application/javascript">
|
||||
hello();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h2>hello,欢迎来到<span stype="color:red;">中微子代理</span></h2>
|
||||
</body>
|
||||
</html>
|
||||
@@ -4,6 +4,13 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.noear</groupId>
|
||||
<artifactId>solon-parent</artifactId>
|
||||
<version>2.2.2</version>
|
||||
<relativePath />
|
||||
</parent>
|
||||
|
||||
<groupId>fun.asgc.neutrino</groupId>
|
||||
<artifactId>neutrino-proxy</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
@@ -14,6 +21,8 @@
|
||||
<module>neutrino-proxy-core</module>
|
||||
<module>neutrino-proxy-client</module>
|
||||
<module>neutrino-proxy-server</module>
|
||||
<module>_solon_plugin/job-solon-plugin</module>
|
||||
<module>_solon_plugin/orika-solon-plugin</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
@@ -25,7 +34,7 @@
|
||||
<java.version>1.8</java.version>
|
||||
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
|
||||
<maven-flatten.version>1.1.0</maven-flatten.version>
|
||||
<org.projectlombok.version>1.16.14</org.projectlombok.version>
|
||||
<org.projectlombok.version>1.18.4</org.projectlombok.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
@@ -48,12 +57,12 @@
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.0</version>
|
||||
<version>${org.projectlombok.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<version>1.25</version>
|
||||
<version>1.33</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
@@ -81,6 +90,21 @@
|
||||
<artifactId>commons-fileupload</artifactId>
|
||||
<version>1.3.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<version>3.39.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.49</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.zaxxer</groupId>
|
||||
<artifactId>HikariCP</artifactId>
|
||||
<version>4.0.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
@@ -129,6 +153,7 @@
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
|
||||
+15
-1
@@ -34,4 +34,18 @@
|
||||
# Bug
|
||||
- windows环境下直接运行发布版的jar包,日志输出乱码
|
||||
- 部份用户windows环境下启动客户端,扫描类个数为0个
|
||||
- 代理mysql时,使用未开启远程访问的账号走代理访问mysql,代理客户端出现断开现象
|
||||
- 代理mysql时,使用未开启远程访问的账号走代理访问mysql,代理客户端出现断开现象
|
||||
|
||||
# 2.x规划
|
||||
- 全面重构:底层更换为Solon + Mybatis Plus
|
||||
- 规范协议:代理协议规范化,方便后续更好扩展、支持不同语言客户端接入
|
||||
- 端口池优化:支持为license设置独占端口。方便后续开发jetbrains插件、solon插件
|
||||
- 精细化控制:支持针对用户限速、限流
|
||||
- 参考鹊桥,增加对域名的支持
|
||||
- MGT增加服务端维护
|
||||
- 支持调整服务端端口
|
||||
- 支持重启
|
||||
- 支持查看服务端日志
|
||||
- 支持证书上传下载
|
||||
- 支持客户端版本管理
|
||||
- 支持原生编译
|
||||
Reference in New Issue
Block a user