41 changed files with 648 additions and 226 deletions
@ -0,0 +1,59 @@ |
|||||
|
<template> |
||||
|
<div v-if="showRef"> |
||||
|
<div class="pl-1 truncate">{{ $t('progress.tip') }} {{ messageRef }}</div> |
||||
|
<q-linear-progress size="20px" :value="percentageRef" color="primary" rounded v-bind="attrs"> </q-linear-progress> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import { ref, useAttrs, onMounted } from 'vue'; |
||||
|
import { axios, Environment } from '@/platform'; |
||||
|
|
||||
|
const props = defineProps({ |
||||
|
dataUrl: { type: String, default: '' }, |
||||
|
interval: { type: Number, default: 1000 }, |
||||
|
}); |
||||
|
const attrs = useAttrs(); |
||||
|
|
||||
|
const showRef = ref(false); |
||||
|
const percentageRef = ref(0.2); |
||||
|
const messageRef = ref(''); |
||||
|
let executeProgressInterval; |
||||
|
|
||||
|
const refreshProgress = () => { |
||||
|
axios |
||||
|
.get(Environment.apiContextPath(props.dataUrl)) |
||||
|
.then((response) => { |
||||
|
const progressInfo = response.data; |
||||
|
percentageRef.value = progressInfo.currentWeight / progressInfo.totalWeight; |
||||
|
messageRef.value = progressInfo.messageKey; |
||||
|
if (percentageRef.value >= 1) { |
||||
|
clearInterval(executeProgressInterval); |
||||
|
showRef.value = false; |
||||
|
} |
||||
|
}) |
||||
|
.catch(() => { |
||||
|
clearInterval(executeProgressInterval); |
||||
|
showRef.value = false; |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const start = () => { |
||||
|
showRef.value = true; |
||||
|
executeProgressInterval = setInterval(refreshProgress, props.interval); |
||||
|
}; |
||||
|
|
||||
|
onMounted(() => { |
||||
|
axios |
||||
|
.get(Environment.apiContextPath(props.dataUrl)) |
||||
|
.then((response) => { |
||||
|
start(); |
||||
|
}) |
||||
|
.catch(() => { |
||||
|
showRef.value = false; |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
defineExpose({ |
||||
|
start, |
||||
|
}); |
||||
|
</script> |
@ -1,13 +1,15 @@ |
|||||
package io.sc.platform.csv.exporter; |
package io.sc.platform.csv.exporter; |
||||
|
|
||||
|
import io.sc.platform.core.support.ProgressInfo; |
||||
import io.sc.platform.jdbc.exporter.DataExporter; |
import io.sc.platform.jdbc.exporter.DataExporter; |
||||
import io.sc.platform.jdbc.exporter.support.DataExportConfigure; |
import io.sc.platform.jdbc.exporter.support.DataExportConfigure; |
||||
|
|
||||
import javax.sql.DataSource; |
import javax.sql.DataSource; |
||||
|
import java.util.Locale; |
||||
|
|
||||
public class CsvExporter implements DataExporter { |
public class CsvExporter implements DataExporter { |
||||
@Override |
@Override |
||||
public void export(DataSource dataSource, DataExportConfigure configure) { |
public void export(DataSource dataSource, DataExportConfigure configure, ProgressInfo progressInfo, Locale locale) { |
||||
|
|
||||
} |
} |
||||
} |
} |
||||
|
@ -0,0 +1,70 @@ |
|||||
|
<template> |
||||
|
<div v-if="showRef"> |
||||
|
<div class="pl-1 truncate">{{ $t('progress.tip') }} {{ messageRef }}</div> |
||||
|
<q-linear-progress size="20px" :value="percentageRef" color="primary" rounded v-bind="attrs"> </q-linear-progress> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import { ref, useAttrs, onMounted } from 'vue'; |
||||
|
import { axios, Environment } from 'platform-core'; |
||||
|
|
||||
|
const props = defineProps({ |
||||
|
dataUrl: { type: String, default: '' }, |
||||
|
interval: { type: Number, default: 1000 }, |
||||
|
}); |
||||
|
const attrs = useAttrs(); |
||||
|
|
||||
|
const showRef = ref(false); |
||||
|
const percentageRef = ref(0); |
||||
|
const messageRef = ref(''); |
||||
|
let executeProgressInterval; |
||||
|
|
||||
|
const refreshProgress = () => { |
||||
|
axios |
||||
|
.get(Environment.apiContextPath(props.dataUrl)) |
||||
|
.then((response) => { |
||||
|
if (response?.data?.running) { |
||||
|
const progressInfo = response.data; |
||||
|
percentageRef.value = progressInfo.currentWeight / progressInfo.totalWeight; |
||||
|
messageRef.value = progressInfo.messageKey; |
||||
|
if (percentageRef.value >= 1) { |
||||
|
stop(); |
||||
|
} |
||||
|
} else { |
||||
|
stop(); |
||||
|
} |
||||
|
}) |
||||
|
.catch(() => { |
||||
|
stop(); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const start = () => { |
||||
|
showRef.value = true; |
||||
|
percentageRef.value = 0; |
||||
|
executeProgressInterval = setInterval(refreshProgress, props.interval); |
||||
|
}; |
||||
|
|
||||
|
const stop = () => { |
||||
|
clearInterval(executeProgressInterval); |
||||
|
showRef.value = false; |
||||
|
}; |
||||
|
|
||||
|
onMounted(() => { |
||||
|
axios |
||||
|
.get(Environment.apiContextPath(props.dataUrl)) |
||||
|
.then((response) => { |
||||
|
if (response?.data?.running) { |
||||
|
start(); |
||||
|
} |
||||
|
}) |
||||
|
.catch(() => { |
||||
|
stop(); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
defineExpose({ |
||||
|
start, |
||||
|
stop, |
||||
|
}); |
||||
|
</script> |
@ -0,0 +1,75 @@ |
|||||
|
<template> |
||||
|
<q-btn icon="bi-database-down" :label="$t('export')" outline no-caps v-bind="attrs" :loading="showRef" :percentage="percentageRef"> |
||||
|
<!-- <template #loading> |
||||
|
<div class="justify-between"> |
||||
|
<q-icon :name="attrs.icon"></q-icon> |
||||
|
<span>正在执行...</span> |
||||
|
<q-btn v-if="showRef" icon="bi-info" title="show detail" dense rounded flat @click.stop.prevent="() => {}"></q-btn> |
||||
|
</div> |
||||
|
</template> --> |
||||
|
</q-btn> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import { ref, useAttrs, onMounted } from 'vue'; |
||||
|
import { axios, Environment } from 'platform-core'; |
||||
|
|
||||
|
const props = defineProps({ |
||||
|
dataUrl: { type: String, default: '' }, |
||||
|
interval: { type: Number, default: 1000 }, |
||||
|
}); |
||||
|
const attrs = useAttrs(); |
||||
|
|
||||
|
const showRef = ref(false); |
||||
|
const percentageRef = ref(0); |
||||
|
const messageRef = ref(''); |
||||
|
let executeProgressInterval; |
||||
|
|
||||
|
const refreshProgress = () => { |
||||
|
axios |
||||
|
.get(Environment.apiContextPath(props.dataUrl)) |
||||
|
.then((response) => { |
||||
|
if (response?.data?.running) { |
||||
|
const progressInfo = response.data; |
||||
|
percentageRef.value = (progressInfo.currentWeight / progressInfo.totalWeight) * 100; |
||||
|
messageRef.value = progressInfo.messageKey; |
||||
|
if (percentageRef.value >= 100) { |
||||
|
stop(); |
||||
|
} |
||||
|
} else { |
||||
|
stop(); |
||||
|
} |
||||
|
}) |
||||
|
.catch(() => { |
||||
|
stop(); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const start = () => { |
||||
|
showRef.value = true; |
||||
|
percentageRef.value = 0; |
||||
|
executeProgressInterval = setInterval(refreshProgress, props.interval); |
||||
|
}; |
||||
|
|
||||
|
const stop = () => { |
||||
|
clearInterval(executeProgressInterval); |
||||
|
showRef.value = false; |
||||
|
}; |
||||
|
|
||||
|
onMounted(() => { |
||||
|
axios |
||||
|
.get(Environment.apiContextPath(props.dataUrl)) |
||||
|
.then((response) => { |
||||
|
if (response?.data?.running) { |
||||
|
start(); |
||||
|
} |
||||
|
}) |
||||
|
.catch(() => { |
||||
|
stop(); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
defineExpose({ |
||||
|
start, |
||||
|
stop, |
||||
|
}); |
||||
|
</script> |
@ -0,0 +1,43 @@ |
|||||
|
package io.sc.platform.jdbc.controller; |
||||
|
|
||||
|
import io.sc.platform.core.support.ProgressInfo; |
||||
|
import io.sc.platform.jdbc.controller.support.ExporterThread; |
||||
|
import io.sc.platform.jdbc.exporter.exception.ExporterNotRunningException; |
||||
|
import io.sc.platform.jdbc.exporter.exception.ExporterRunningException; |
||||
|
import io.sc.platform.jdbc.exporter.support.DataExportConfigure; |
||||
|
import io.sc.platform.jdbc.service.JdbcExportService; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
import java.util.Locale; |
||||
|
|
||||
|
@RestController |
||||
|
@RequestMapping("/api/jdbc/export") |
||||
|
public class JdbcExportWebController { |
||||
|
@Autowired private JdbcExportService jdbcExportService; |
||||
|
private ExporterThread thread =null; |
||||
|
|
||||
|
@PostMapping("export") |
||||
|
public void export(@RequestBody DataExportConfigure configure, Locale locale) throws Exception { |
||||
|
//检查有当前用户启动的执行线程是否正在运行
|
||||
|
if(thread!=null && thread.isAlive()){ |
||||
|
throw new ExporterRunningException(); |
||||
|
} |
||||
|
//启动新线程
|
||||
|
thread =new ExporterThread(jdbcExportService,configure,locale); |
||||
|
thread.start(); |
||||
|
} |
||||
|
|
||||
|
@GetMapping("traceExecuteProgress") |
||||
|
public ProgressInfo traceExecuteProgress(Locale locale) throws Exception{ |
||||
|
if(thread!=null && thread.isAlive()){ |
||||
|
if(thread.getException()!=null){ |
||||
|
throw thread.getException(); |
||||
|
} |
||||
|
return thread.getProgressInfo(); |
||||
|
}else{ |
||||
|
return ProgressInfo.notRunning(); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,39 @@ |
|||||
|
package io.sc.platform.jdbc.controller.support; |
||||
|
|
||||
|
import io.sc.platform.core.support.ProgressInfo; |
||||
|
import io.sc.platform.jdbc.exporter.support.DataExportConfigure; |
||||
|
import io.sc.platform.jdbc.service.JdbcExportService; |
||||
|
import org.slf4j.Logger; |
||||
|
import org.slf4j.LoggerFactory; |
||||
|
|
||||
|
import java.util.Locale; |
||||
|
|
||||
|
public class ExporterThread extends Thread { |
||||
|
private Logger log = LoggerFactory.getLogger(ExporterThread.class); |
||||
|
private JdbcExportService jdbcExportService; |
||||
|
private DataExportConfigure exportConfigure; |
||||
|
private Locale locale; |
||||
|
private volatile ProgressInfo progressInfo =new ProgressInfo(100,0); |
||||
|
private Exception exception; |
||||
|
|
||||
|
public ExporterThread(JdbcExportService jdbcExportService,DataExportConfigure exportConfigure, Locale locale){ |
||||
|
this.jdbcExportService =jdbcExportService; |
||||
|
this.exportConfigure =exportConfigure; |
||||
|
this.locale =locale; |
||||
|
} |
||||
|
@Override |
||||
|
public void run() { |
||||
|
try { |
||||
|
jdbcExportService.export(exportConfigure,progressInfo,locale); |
||||
|
} catch (Exception e) { |
||||
|
this.exception =e; |
||||
|
log.error("",e); |
||||
|
} |
||||
|
} |
||||
|
public ProgressInfo getProgressInfo(){ |
||||
|
return progressInfo; |
||||
|
} |
||||
|
public Exception getException() { |
||||
|
return exception; |
||||
|
} |
||||
|
} |
@ -0,0 +1,5 @@ |
|||||
|
package io.sc.platform.jdbc.exporter.exception; |
||||
|
|
||||
|
public class ExporterNotRunningException extends RuntimeException { |
||||
|
|
||||
|
} |
@ -0,0 +1,5 @@ |
|||||
|
package io.sc.platform.jdbc.exporter.exception; |
||||
|
|
||||
|
public class ExporterRunningException extends RuntimeException { |
||||
|
|
||||
|
} |
@ -1,6 +0,0 @@ |
|||||
package io.sc.platform.jdbc.exporter.support; |
|
||||
|
|
||||
public enum ExportMode { |
|
||||
SINGLE_FILE, // 单文件
|
|
||||
MULTI_FILE; // 多文件(每个表一个文件)
|
|
||||
} |
|
@ -0,0 +1,10 @@ |
|||||
|
package io.sc.platform.jdbc.service; |
||||
|
|
||||
|
import io.sc.platform.core.support.ProgressInfo; |
||||
|
import io.sc.platform.jdbc.exporter.support.DataExportConfigure; |
||||
|
|
||||
|
import java.util.Locale; |
||||
|
|
||||
|
public interface JdbcExportService { |
||||
|
public void export(DataExportConfigure configure, ProgressInfo progressInfo, Locale locale) throws Exception; |
||||
|
} |
@ -0,0 +1,43 @@ |
|||||
|
package io.sc.platform.jdbc.service.impl; |
||||
|
|
||||
|
import io.sc.platform.core.support.ProgressInfo; |
||||
|
import io.sc.platform.jdbc.exporter.DataExporter; |
||||
|
import io.sc.platform.jdbc.exporter.support.DataExportConfigure; |
||||
|
import io.sc.platform.jdbc.service.DatasourceService; |
||||
|
import io.sc.platform.jdbc.service.JdbcExportService; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.util.StringUtils; |
||||
|
|
||||
|
import javax.sql.DataSource; |
||||
|
import java.util.Date; |
||||
|
import java.util.Locale; |
||||
|
|
||||
|
@Service |
||||
|
public class JdbcExportServiceImpl implements JdbcExportService { |
||||
|
@Autowired private DatasourceService datasourceService; |
||||
|
|
||||
|
@Override |
||||
|
public void export(DataExportConfigure configure, ProgressInfo progressInfo, Locale locale) throws Exception { |
||||
|
if(configure==null){ |
||||
|
return; |
||||
|
} |
||||
|
progressInfo.setRunning(true); |
||||
|
DataSource dataSource =null; |
||||
|
if(StringUtils.hasText(configure.getDatasource())){ |
||||
|
dataSource =datasourceService.getDatasource(configure.getDatasource()); |
||||
|
}else{ |
||||
|
dataSource =datasourceService.getDefaultDatasource(); |
||||
|
} |
||||
|
|
||||
|
progressInfo.setStartDatetime(new Date()); |
||||
|
progressInfo.setTotalWeight(100); |
||||
|
|
||||
|
DataExporter dataExporter =DataExporter.newInstance(); |
||||
|
dataExporter.export(dataSource,configure,progressInfo,locale); |
||||
|
|
||||
|
//执行完毕
|
||||
|
progressInfo.setCompletedDatetime(new Date()); |
||||
|
progressInfo.setCurrentWeight(progressInfo.getTotalWeight()); |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue