|
@@ -8,8 +8,10 @@ import lombok.Getter;
|
|
import lombok.SneakyThrows;
|
|
import lombok.SneakyThrows;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import org.hswebframework.ezorm.core.param.QueryParam;
|
|
import org.hswebframework.ezorm.core.param.QueryParam;
|
|
-import org.hswebframework.ezorm.core.param.TermType;
|
|
|
|
import org.hswebframework.ezorm.rdb.exception.DuplicateKeyException;
|
|
import org.hswebframework.ezorm.rdb.exception.DuplicateKeyException;
|
|
|
|
+import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository;
|
|
|
|
+import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult;
|
|
|
|
+import org.hswebframework.reactor.excel.ReactorExcel;
|
|
import org.hswebframework.web.api.crud.entity.PagerResult;
|
|
import org.hswebframework.web.api.crud.entity.PagerResult;
|
|
import org.hswebframework.web.api.crud.entity.QueryParamEntity;
|
|
import org.hswebframework.web.api.crud.entity.QueryParamEntity;
|
|
import org.hswebframework.web.authorization.Authentication;
|
|
import org.hswebframework.web.authorization.Authentication;
|
|
@@ -21,23 +23,21 @@ import org.hswebframework.web.authorization.annotation.SaveAction;
|
|
import org.hswebframework.web.bean.FastBeanCopier;
|
|
import org.hswebframework.web.bean.FastBeanCopier;
|
|
import org.hswebframework.web.crud.web.reactive.ReactiveServiceCrudController;
|
|
import org.hswebframework.web.crud.web.reactive.ReactiveServiceCrudController;
|
|
import org.hswebframework.web.exception.BusinessException;
|
|
import org.hswebframework.web.exception.BusinessException;
|
|
-import org.jetlinks.community.device.entity.DeviceProductEntity;
|
|
|
|
|
|
+import org.jetlinks.community.device.entity.*;
|
|
import org.jetlinks.community.device.entity.excel.DeviceInstanceImportExportEntity;
|
|
import org.jetlinks.community.device.entity.excel.DeviceInstanceImportExportEntity;
|
|
import org.jetlinks.community.device.enums.DeviceState;
|
|
import org.jetlinks.community.device.enums.DeviceState;
|
|
import org.jetlinks.community.device.service.LocalDeviceProductService;
|
|
import org.jetlinks.community.device.service.LocalDeviceProductService;
|
|
|
|
+import org.jetlinks.community.device.web.excel.DeviceExcelInfo;
|
|
|
|
+import org.jetlinks.community.device.web.excel.DeviceWrapper;
|
|
import org.jetlinks.community.io.excel.ImportExportService;
|
|
import org.jetlinks.community.io.excel.ImportExportService;
|
|
-import org.jetlinks.core.device.DeviceConfigKey;
|
|
|
|
|
|
+import org.jetlinks.community.io.utils.FileUtils;
|
|
import org.jetlinks.core.device.DeviceOperator;
|
|
import org.jetlinks.core.device.DeviceOperator;
|
|
|
|
+import org.jetlinks.core.device.DeviceProductOperator;
|
|
import org.jetlinks.core.device.DeviceRegistry;
|
|
import org.jetlinks.core.device.DeviceRegistry;
|
|
-import org.jetlinks.community.device.entity.DeviceInstanceEntity;
|
|
|
|
-import org.jetlinks.community.device.entity.DeviceOperationLogEntity;
|
|
|
|
-import org.jetlinks.community.device.entity.DevicePropertiesEntity;
|
|
|
|
import org.jetlinks.community.device.response.*;
|
|
import org.jetlinks.community.device.response.*;
|
|
import org.jetlinks.community.device.service.LocalDeviceInstanceService;
|
|
import org.jetlinks.community.device.service.LocalDeviceInstanceService;
|
|
-import org.jetlinks.community.device.timeseries.DeviceTimeSeriesMetric;
|
|
|
|
import org.jetlinks.community.timeseries.TimeSeriesManager;
|
|
import org.jetlinks.community.timeseries.TimeSeriesManager;
|
|
import org.jetlinks.community.timeseries.TimeSeriesMetric;
|
|
import org.jetlinks.community.timeseries.TimeSeriesMetric;
|
|
-import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
import org.springframework.core.io.buffer.DataBufferFactory;
|
|
import org.springframework.core.io.buffer.DataBufferFactory;
|
|
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
|
|
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
|
|
import org.springframework.http.HttpHeaders;
|
|
import org.springframework.http.HttpHeaders;
|
|
@@ -48,13 +48,16 @@ import org.springframework.web.bind.annotation.*;
|
|
import reactor.core.publisher.Flux;
|
|
import reactor.core.publisher.Flux;
|
|
import reactor.core.publisher.Mono;
|
|
import reactor.core.publisher.Mono;
|
|
import reactor.core.scheduler.Schedulers;
|
|
import reactor.core.scheduler.Schedulers;
|
|
|
|
+import reactor.util.function.Tuple2;
|
|
|
|
+import reactor.util.function.Tuples;
|
|
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.IOException;
|
|
-import java.io.OutputStream;
|
|
|
|
import java.net.URLEncoder;
|
|
import java.net.URLEncoder;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.nio.charset.StandardCharsets;
|
|
|
|
+import java.util.Collections;
|
|
import java.util.Map;
|
|
import java.util.Map;
|
|
|
|
+import java.util.function.Function;
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
@RestController
|
|
@RestController
|
|
@@ -76,37 +79,57 @@ public class DeviceInstanceController implements
|
|
|
|
|
|
private final ImportExportService importExportService;
|
|
private final ImportExportService importExportService;
|
|
|
|
|
|
- public DeviceInstanceController(LocalDeviceInstanceService service, TimeSeriesManager timeSeriesManager, DeviceRegistry registry, LocalDeviceProductService productService, ImportExportService importExportService) {
|
|
|
|
|
|
+ private final ReactiveRepository<DeviceTagEntity, String> tagRepository;
|
|
|
|
+
|
|
|
|
+ @SuppressWarnings("all")
|
|
|
|
+ public DeviceInstanceController(LocalDeviceInstanceService service,
|
|
|
|
+ TimeSeriesManager timeSeriesManager,
|
|
|
|
+ DeviceRegistry registry,
|
|
|
|
+ LocalDeviceProductService productService,
|
|
|
|
+ ImportExportService importExportService,
|
|
|
|
+ ReactiveRepository<DeviceTagEntity, String> tagRepository) {
|
|
this.service = service;
|
|
this.service = service;
|
|
this.timeSeriesManager = timeSeriesManager;
|
|
this.timeSeriesManager = timeSeriesManager;
|
|
this.registry = registry;
|
|
this.registry = registry;
|
|
this.productService = productService;
|
|
this.productService = productService;
|
|
this.importExportService = importExportService;
|
|
this.importExportService = importExportService;
|
|
|
|
+ this.tagRepository = tagRepository;
|
|
}
|
|
}
|
|
|
|
|
|
- @GetMapping({
|
|
|
|
- "/all-info/{id:.+}", //todo 即将删除
|
|
|
|
- "/{id:.+}/detail"
|
|
|
|
- })
|
|
|
|
|
|
+
|
|
|
|
+ //获取设备详情
|
|
|
|
+ @GetMapping("/{id:.+}/detail")
|
|
|
|
+ @QueryAction
|
|
|
|
+ public Mono<DeviceDetail> getDeviceDetailInfo(@PathVariable String id) {
|
|
|
|
+ return service.getDeviceDetail(id);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //获取设备运行状态
|
|
|
|
+ @GetMapping("/{id:.+}/state")
|
|
@QueryAction
|
|
@QueryAction
|
|
- public Mono<DeviceAllInfoResponse> getDeviceAllInfo(@PathVariable String id) {
|
|
|
|
- return service.getDeviceAllInfo(id);
|
|
|
|
|
|
+ public Mono<DeviceState> getDeviceState(@PathVariable String id) {
|
|
|
|
+ return service.getDeviceState(id);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ //已弃用 下一个版本删除
|
|
@GetMapping("/info/{id:.+}")
|
|
@GetMapping("/info/{id:.+}")
|
|
@QueryAction
|
|
@QueryAction
|
|
|
|
+ @Deprecated
|
|
public Mono<DeviceInfo> getDeviceInfoById(@PathVariable String id) {
|
|
public Mono<DeviceInfo> getDeviceInfoById(@PathVariable String id) {
|
|
return service.getDeviceInfoById(id);
|
|
return service.getDeviceInfoById(id);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ //已弃用 下一个版本删除
|
|
@GetMapping("/run-info/{id:.+}")
|
|
@GetMapping("/run-info/{id:.+}")
|
|
@QueryAction
|
|
@QueryAction
|
|
|
|
+ @Deprecated
|
|
public Mono<DeviceRunInfo> getRunDeviceInfoById(@PathVariable String id) {
|
|
public Mono<DeviceRunInfo> getRunDeviceInfoById(@PathVariable String id) {
|
|
return service.getDeviceRunInfo(id);
|
|
return service.getDeviceRunInfo(id);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
@PostMapping({
|
|
@PostMapping({
|
|
- "/deploy/{deviceId:.+}",//todo 即将移除
|
|
|
|
|
|
+ "/deploy/{deviceId:.+}",//todo 已弃用 下一个版本删除
|
|
"/{deviceId:.+}/deploy"
|
|
"/{deviceId:.+}/deploy"
|
|
})
|
|
})
|
|
@SaveAction
|
|
@SaveAction
|
|
@@ -115,7 +138,7 @@ public class DeviceInstanceController implements
|
|
}
|
|
}
|
|
|
|
|
|
@PostMapping({
|
|
@PostMapping({
|
|
- "/cancelDeploy/{deviceId:.+}", //todo 即将移除
|
|
|
|
|
|
+ "/cancelDeploy/{deviceId:.+}", //todo 已弃用 下一个版本删除
|
|
"/{deviceId:.+}/undeploy"
|
|
"/{deviceId:.+}/undeploy"
|
|
})
|
|
})
|
|
@SaveAction
|
|
@SaveAction
|
|
@@ -123,7 +146,7 @@ public class DeviceInstanceController implements
|
|
return service.cancelDeploy(deviceId);
|
|
return service.cancelDeploy(deviceId);
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
|
|
+ //断开连接
|
|
@PostMapping("/{deviceId:.+}/disconnect")
|
|
@PostMapping("/{deviceId:.+}/disconnect")
|
|
@SaveAction
|
|
@SaveAction
|
|
public Mono<Boolean> disconnect(@PathVariable String deviceId) {
|
|
public Mono<Boolean> disconnect(@PathVariable String deviceId) {
|
|
@@ -133,6 +156,7 @@ public class DeviceInstanceController implements
|
|
.singleOrEmpty();
|
|
.singleOrEmpty();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ //添加设备
|
|
@PostMapping
|
|
@PostMapping
|
|
public Mono<DeviceInstanceEntity> add(@RequestBody Mono<DeviceInstanceEntity> payload) {
|
|
public Mono<DeviceInstanceEntity> add(@RequestBody Mono<DeviceInstanceEntity> payload) {
|
|
return payload.flatMap(entity -> service.insert(Mono.just(entity))
|
|
return payload.flatMap(entity -> service.insert(Mono.just(entity))
|
|
@@ -140,6 +164,7 @@ public class DeviceInstanceController implements
|
|
.thenReturn(entity));
|
|
.thenReturn(entity));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ //批量发布,激活设备
|
|
@GetMapping(value = "/deploy", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
|
@GetMapping(value = "/deploy", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
|
@SaveAction
|
|
@SaveAction
|
|
public Flux<DeviceDeployResult> deployAll(QueryParamEntity query) {
|
|
public Flux<DeviceDeployResult> deployAll(QueryParamEntity query) {
|
|
@@ -175,18 +200,21 @@ public class DeviceInstanceController implements
|
|
return service.getDeviceLatestProperties(deviceId);
|
|
return service.getDeviceLatestProperties(deviceId);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ //获取最新的设备属性
|
|
@GetMapping("/{deviceId:.+}/properties/latest")
|
|
@GetMapping("/{deviceId:.+}/properties/latest")
|
|
@QueryAction
|
|
@QueryAction
|
|
public Flux<DevicePropertiesEntity> getDeviceLatestProperties(@PathVariable String deviceId) {
|
|
public Flux<DevicePropertiesEntity> getDeviceLatestProperties(@PathVariable String deviceId) {
|
|
return service.getDeviceLatestProperties(deviceId);
|
|
return service.getDeviceLatestProperties(deviceId);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ //获取单个最新的设备属性
|
|
@GetMapping("/{deviceId:.+}/property/{property:.+}")
|
|
@GetMapping("/{deviceId:.+}/property/{property:.+}")
|
|
@QueryAction
|
|
@QueryAction
|
|
public Mono<DevicePropertiesEntity> getDeviceLatestProperty(@PathVariable String deviceId, @PathVariable String property) {
|
|
public Mono<DevicePropertiesEntity> getDeviceLatestProperty(@PathVariable String deviceId, @PathVariable String property) {
|
|
return service.getDeviceLatestProperty(deviceId, property);
|
|
return service.getDeviceLatestProperty(deviceId, property);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ //获取设备事件数据
|
|
@GetMapping("/{deviceId:.+}/event/{eventId}")
|
|
@GetMapping("/{deviceId:.+}/event/{eventId}")
|
|
@QueryAction
|
|
@QueryAction
|
|
public Mono<PagerResult<Map<String, Object>>> queryPagerByDeviceEvent(QueryParamEntity queryParam,
|
|
public Mono<PagerResult<Map<String, Object>>> queryPagerByDeviceEvent(QueryParamEntity queryParam,
|
|
@@ -209,6 +237,59 @@ public class DeviceInstanceController implements
|
|
return service.queryDeviceLog(deviceId, entity);
|
|
return service.queryDeviceLog(deviceId, entity);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ //删除标签
|
|
|
|
+ @DeleteMapping("/{deviceId}/tag/{tagId:.+}")
|
|
|
|
+ @SaveAction
|
|
|
|
+ public Mono<Void> deleteDeviceTag(@PathVariable String deviceId,
|
|
|
|
+ @PathVariable String tagId) {
|
|
|
|
+ return tagRepository.createDelete()
|
|
|
|
+ .where(DeviceTagEntity::getDeviceId, deviceId)
|
|
|
|
+ .and(DeviceTagEntity::getId, tagId)
|
|
|
|
+ .execute()
|
|
|
|
+ .then();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 获取设备全部标签
|
|
|
|
+ * <pre>
|
|
|
|
+ * GET /device/instance/{deviceId}/tags
|
|
|
|
+ *
|
|
|
|
+ * [
|
|
|
|
+ * {
|
|
|
|
+ * "id":"id",
|
|
|
|
+ * "key":"",
|
|
|
|
+ * "value":"",
|
|
|
|
+ * "name":""
|
|
|
|
+ * }
|
|
|
|
+ * ]
|
|
|
|
+ * </pre>
|
|
|
|
+ *
|
|
|
|
+ * @param deviceId 设备ID
|
|
|
|
+ * @return 设备标签列表
|
|
|
|
+ */
|
|
|
|
+ @GetMapping("/{deviceId}/tags")
|
|
|
|
+ @SaveAction
|
|
|
|
+ public Flux<DeviceTagEntity> getDeviceTags(@PathVariable String deviceId) {
|
|
|
|
+ return tagRepository.createQuery()
|
|
|
|
+ .where(DeviceTagEntity::getDeviceId, deviceId)
|
|
|
|
+ .fetch();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //保存设备标签
|
|
|
|
+ @PatchMapping("/{deviceId}/tag")
|
|
|
|
+ @SaveAction
|
|
|
|
+ public Mono<Void> saveDeviceTag(@PathVariable String deviceId,
|
|
|
|
+ @RequestBody Flux<DeviceTagEntity> tags) {
|
|
|
|
+ return tags
|
|
|
|
+ .doOnNext(tag -> {
|
|
|
|
+ tag.setId(deviceId.concat(":").concat(tag.getKey()));
|
|
|
|
+ tag.setDeviceId(deviceId);
|
|
|
|
+ tag.tryValidate();
|
|
|
|
+ })
|
|
|
|
+ .as(tagRepository::save)
|
|
|
|
+ .then();
|
|
|
|
+ }
|
|
|
|
+
|
|
//已废弃
|
|
//已废弃
|
|
@GetMapping("/operation/log")
|
|
@GetMapping("/operation/log")
|
|
@QueryAction
|
|
@QueryAction
|
|
@@ -265,6 +346,111 @@ public class DeviceInstanceController implements
|
|
|
|
|
|
DataBufferFactory bufferFactory = new DefaultDataBufferFactory();
|
|
DataBufferFactory bufferFactory = new DefaultDataBufferFactory();
|
|
|
|
|
|
|
|
+ //按产品型号导入数据
|
|
|
|
+ @GetMapping(value = "/{productId}/import", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
|
|
|
+ @SaveAction
|
|
|
|
+ public Flux<ImportDeviceInstanceResult> doBatchImportByProduct(@PathVariable String productId,
|
|
|
|
+ @RequestParam String fileUrl) {
|
|
|
|
+
|
|
|
|
+ return registry.getProduct(productId)
|
|
|
|
+ .flatMap(DeviceProductOperator::getMetadata)
|
|
|
|
+ .map(metadata -> new DeviceWrapper(metadata.getTags()))
|
|
|
|
+ .defaultIfEmpty(DeviceWrapper.empty)
|
|
|
|
+ .flatMapMany(wrapper -> importExportService
|
|
|
|
+ .getInputStream(fileUrl)
|
|
|
|
+ .flatMapMany(inputStream -> ReactorExcel.read(inputStream, FileUtils.getExtension(fileUrl), wrapper)))
|
|
|
|
+ .map(info -> {
|
|
|
|
+ DeviceInstanceEntity entity = FastBeanCopier.copy(info, new DeviceInstanceEntity());
|
|
|
|
+ entity.setProductId(productId);
|
|
|
|
+ if (StringUtils.isEmpty(entity.getId())) {
|
|
|
|
+ throw new BusinessException("设备ID不能为空");
|
|
|
|
+ }
|
|
|
|
+ return Tuples.of(entity, info.getTags());
|
|
|
|
+ })
|
|
|
|
+ .buffer(100)//每100条数据保存一次
|
|
|
|
+ .publishOn(Schedulers.single())
|
|
|
|
+ .concatMap(buffer ->
|
|
|
|
+ Mono.zip(
|
|
|
|
+ service.save(Flux.fromIterable(buffer).map(Tuple2::getT1)),
|
|
|
|
+ tagRepository
|
|
|
|
+ .save(Flux.fromIterable(buffer).flatMapIterable(Tuple2::getT2))
|
|
|
|
+ .defaultIfEmpty(SaveResult.of(0, 0))
|
|
|
|
+ ))
|
|
|
|
+ .map(res -> ImportDeviceInstanceResult.success(res.getT1()))
|
|
|
|
+ .onErrorResume(err -> Mono.just(ImportDeviceInstanceResult.error(err)));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //获取导入模版
|
|
|
|
+ @GetMapping("/{productId}/template.{format}")
|
|
|
|
+ @QueryAction
|
|
|
|
+ public Mono<Void> downloadExportTemplate(ServerHttpResponse response,
|
|
|
|
+ QueryParamEntity parameter,
|
|
|
|
+ @PathVariable String format,
|
|
|
|
+ @PathVariable String productId) throws IOException {
|
|
|
|
+ response.getHeaders().set(HttpHeaders.CONTENT_DISPOSITION,
|
|
|
|
+ "attachment; filename=".concat(URLEncoder.encode("设备导入模版." + format, StandardCharsets.UTF_8.displayName())));
|
|
|
|
+ return Authentication
|
|
|
|
+ .currentReactive()
|
|
|
|
+ .flatMap(auth -> {
|
|
|
|
+ parameter.setPaging(false);
|
|
|
|
+ parameter.toNestQuery(q -> q.is(DeviceInstanceEntity::getProductId, productId));
|
|
|
|
+ return registry.getProduct(productId)
|
|
|
|
+ .flatMap(DeviceProductOperator::getMetadata)
|
|
|
|
+ .map(meta -> DeviceExcelInfo.getTemplateHeaderMapping(meta.getTags()))
|
|
|
|
+ .defaultIfEmpty(DeviceExcelInfo.getTemplateHeaderMapping(Collections.emptyList()))
|
|
|
|
+ .flatMapMany(headers ->
|
|
|
|
+ ReactorExcel.<DeviceExcelInfo>writer(format)
|
|
|
|
+ .headers(headers)
|
|
|
|
+ .converter(DeviceExcelInfo::toMap)
|
|
|
|
+ .writeBuffer(Flux.empty()))
|
|
|
|
+ .doOnError(err -> log.error(err.getMessage(), err))
|
|
|
|
+ .map(bufferFactory::wrap)
|
|
|
|
+ .as(response::writeWith);
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //按照型号导出数据
|
|
|
|
+ @GetMapping("/{productId}/export.{format}")
|
|
|
|
+ @QueryAction
|
|
|
|
+ public Mono<Void> export(ServerHttpResponse response,
|
|
|
|
+ QueryParamEntity parameter,
|
|
|
|
+ @PathVariable String format,
|
|
|
|
+ @PathVariable String productId) throws IOException {
|
|
|
|
+ response.getHeaders().set(HttpHeaders.CONTENT_DISPOSITION,
|
|
|
|
+ "attachment; filename=".concat(URLEncoder.encode("设备实例." + format, StandardCharsets.UTF_8.displayName())));
|
|
|
|
+ parameter.setPaging(false);
|
|
|
|
+ parameter.toNestQuery(q -> q.is(DeviceInstanceEntity::getProductId, productId));
|
|
|
|
+ return registry.getProduct(productId)
|
|
|
|
+ .flatMap(DeviceProductOperator::getMetadata)
|
|
|
|
+ .map(meta -> DeviceExcelInfo.getExportHeaderMapping(meta.getTags()))
|
|
|
|
+ .defaultIfEmpty(DeviceExcelInfo.getExportHeaderMapping(Collections.emptyList()))
|
|
|
|
+ .flatMapMany(headers ->
|
|
|
|
+ ReactorExcel.<DeviceExcelInfo>writer(format)
|
|
|
|
+ .headers(headers)
|
|
|
|
+ .converter(DeviceExcelInfo::toMap)
|
|
|
|
+ .writeBuffer(
|
|
|
|
+ service.query(parameter)
|
|
|
|
+ .map(entity -> FastBeanCopier.copy(entity, new DeviceExcelInfo()))
|
|
|
|
+ .buffer(200)
|
|
|
|
+ .flatMap(list -> {
|
|
|
|
+ Map<String, DeviceExcelInfo> importInfo = list
|
|
|
|
+ .stream()
|
|
|
|
+ .collect(Collectors.toMap(DeviceExcelInfo::getId, Function.identity()));
|
|
|
|
+ return tagRepository.createQuery()
|
|
|
|
+ .where()
|
|
|
|
+ .in(DeviceTagEntity::getDeviceId, importInfo.keySet())
|
|
|
|
+ .fetch()
|
|
|
|
+ .collect(Collectors.groupingBy(DeviceTagEntity::getDeviceId))
|
|
|
|
+ .flatMapIterable(Map::entrySet)
|
|
|
|
+ .doOnNext(entry -> importInfo.get(entry.getKey()).setTags(entry.getValue()))
|
|
|
|
+ .thenMany(Flux.fromIterable(list));
|
|
|
|
+ })
|
|
|
|
+ , 512 * 1024))//缓冲512k
|
|
|
|
+ .doOnError(err -> log.error(err.getMessage(), err))
|
|
|
|
+ .map(bufferFactory::wrap)
|
|
|
|
+ .as(response::writeWith);
|
|
|
|
+ }
|
|
|
|
+
|
|
@PostMapping("/export")
|
|
@PostMapping("/export")
|
|
@QueryAction
|
|
@QueryAction
|
|
@SneakyThrows
|
|
@SneakyThrows
|