Commit c495fa5bc6814d91b37a22a7ec8e0b90f1086310
1 parent
0657018b
fix: generate excel and save it. fix schedule bug
Showing
24 changed files
with
591 additions
and
209 deletions
1 | package org.thingsboard.server.controller.yunteng; | 1 | package org.thingsboard.server.controller.yunteng; |
2 | 2 | ||
3 | import io.swagger.annotations.Api; | 3 | import io.swagger.annotations.Api; |
4 | +import io.swagger.annotations.ApiOperation; | ||
4 | import lombok.RequiredArgsConstructor; | 5 | import lombok.RequiredArgsConstructor; |
5 | import org.quartz.SchedulerException; | 6 | import org.quartz.SchedulerException; |
6 | import org.springframework.security.access.prepost.PreAuthorize; | 7 | import org.springframework.security.access.prepost.PreAuthorize; |
@@ -37,6 +38,7 @@ public class YtReportFormConfigController extends BaseController { | @@ -37,6 +38,7 @@ public class YtReportFormConfigController extends BaseController { | ||
37 | private final YtReportFormConfigService reportFormConfigService; | 38 | private final YtReportFormConfigService reportFormConfigService; |
38 | 39 | ||
39 | @GetMapping(params = {PAGE_SIZE, PAGE}) | 40 | @GetMapping(params = {PAGE_SIZE, PAGE}) |
41 | + @ApiOperation("分页") | ||
40 | public YtPageData<ReportFormConfigDTO> page( | 42 | public YtPageData<ReportFormConfigDTO> page( |
41 | @RequestParam(PAGE_SIZE) int pageSize, | 43 | @RequestParam(PAGE_SIZE) int pageSize, |
42 | @RequestParam(PAGE) int page, | 44 | @RequestParam(PAGE) int page, |
@@ -62,9 +64,10 @@ public class YtReportFormConfigController extends BaseController { | @@ -62,9 +64,10 @@ public class YtReportFormConfigController extends BaseController { | ||
62 | } | 64 | } |
63 | 65 | ||
64 | @PostMapping | 66 | @PostMapping |
67 | + @ApiOperation("新增") | ||
65 | public ResponseResult<ReportFormConfigDTO> saveReportFromConfig( | 68 | public ResponseResult<ReportFormConfigDTO> saveReportFromConfig( |
66 | @Validated({AddGroup.class}) @RequestBody ReportFormConfigDTO configDTO) | 69 | @Validated({AddGroup.class}) @RequestBody ReportFormConfigDTO configDTO) |
67 | - throws ThingsboardException, SchedulerException { | 70 | + throws ThingsboardException, SchedulerException { |
68 | if (StringUtils.isNotEmpty(configDTO.getId())) { | 71 | if (StringUtils.isNotEmpty(configDTO.getId())) { |
69 | throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); | 72 | throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); |
70 | } | 73 | } |
@@ -72,30 +75,43 @@ public class YtReportFormConfigController extends BaseController { | @@ -72,30 +75,43 @@ public class YtReportFormConfigController extends BaseController { | ||
72 | } | 75 | } |
73 | 76 | ||
74 | @PutMapping | 77 | @PutMapping |
78 | + @ApiOperation("编辑") | ||
75 | public ResponseResult<ReportFormConfigDTO> updateReportFromConfig( | 79 | public ResponseResult<ReportFormConfigDTO> updateReportFromConfig( |
76 | @Validated({UpdateGroup.class}) @RequestBody ReportFormConfigDTO configDTO) | 80 | @Validated({UpdateGroup.class}) @RequestBody ReportFormConfigDTO configDTO) |
77 | - throws ThingsboardException, SchedulerException { | 81 | + throws ThingsboardException, SchedulerException { |
78 | return saveOrUpdate(configDTO); | 82 | return saveOrUpdate(configDTO); |
79 | } | 83 | } |
80 | 84 | ||
81 | @PutMapping("/{id}/{status}") | 85 | @PutMapping("/{id}/{status}") |
86 | + @ApiOperation("修改状态") | ||
82 | public ResponseResult<ReportFormConfigDTO> updateStatusById( | 87 | public ResponseResult<ReportFormConfigDTO> updateStatusById( |
83 | - @PathVariable String id, @PathVariable Integer status) throws ThingsboardException, SchedulerException { | 88 | + @PathVariable String id, @PathVariable Integer status) |
89 | + throws ThingsboardException, SchedulerException { | ||
84 | return ResponseResult.success( | 90 | return ResponseResult.success( |
85 | reportFormConfigService.updateStatusById( | 91 | reportFormConfigService.updateStatusById( |
86 | getCurrentUser().getCurrentTenantId(), status, id)); | 92 | getCurrentUser().getCurrentTenantId(), status, id)); |
87 | } | 93 | } |
88 | 94 | ||
89 | @DeleteMapping | 95 | @DeleteMapping |
96 | + @ApiOperation("删除") | ||
90 | public ResponseResult<Boolean> deleteReportFormConfig( | 97 | public ResponseResult<Boolean> deleteReportFormConfig( |
91 | - @Validated({DeleteGroup.class}) @RequestBody DeleteDTO deleteDTO) { | 98 | + @Validated({DeleteGroup.class}) @RequestBody DeleteDTO deleteDTO) throws SchedulerException { |
92 | return reportFormConfigService.deleteReportFormConfig(deleteDTO) | 99 | return reportFormConfigService.deleteReportFormConfig(deleteDTO) |
93 | ? ResponseResult.success(FastIotConstants.StateValue.DELETE_SUCCESS) | 100 | ? ResponseResult.success(FastIotConstants.StateValue.DELETE_SUCCESS) |
94 | : ResponseResult.failed(FastIotConstants.StateValue.DELETE_FAILED); | 101 | : ResponseResult.failed(FastIotConstants.StateValue.DELETE_FAILED); |
95 | } | 102 | } |
96 | 103 | ||
104 | + @GetMapping("/{id}") | ||
105 | + @ApiOperation("获取报表配置信息") | ||
106 | + public ResponseResult<ReportFormConfigDTO> getReportFormConfig(@PathVariable String id) | ||
107 | + throws ThingsboardException, SchedulerException { | ||
108 | + return ResponseResult.success( | ||
109 | + reportFormConfigService.findReportFormConfigById( | ||
110 | + id, getCurrentUser().getCurrentTenantId())); | ||
111 | + } | ||
112 | + | ||
97 | private ResponseResult<ReportFormConfigDTO> saveOrUpdate(ReportFormConfigDTO configDTO) | 113 | private ResponseResult<ReportFormConfigDTO> saveOrUpdate(ReportFormConfigDTO configDTO) |
98 | - throws ThingsboardException, SchedulerException { | 114 | + throws ThingsboardException, SchedulerException { |
99 | configDTO.setTenantId(getCurrentUser().getCurrentTenantId()); | 115 | configDTO.setTenantId(getCurrentUser().getCurrentTenantId()); |
100 | ReportFormConfigDTO newDTO = reportFormConfigService.saveOrUpdateReportFormConfig(configDTO); | 116 | ReportFormConfigDTO newDTO = reportFormConfigService.saveOrUpdateReportFormConfig(configDTO); |
101 | return ResponseResult.success(newDTO); | 117 | return ResponseResult.success(newDTO); |
1 | package org.thingsboard.server.common.data.yunteng.core.utils; | 1 | package org.thingsboard.server.common.data.yunteng.core.utils; |
2 | 2 | ||
3 | - | ||
4 | import org.springframework.http.ResponseEntity; | 3 | import org.springframework.http.ResponseEntity; |
5 | import org.springframework.web.multipart.MultipartFile; | 4 | import org.springframework.web.multipart.MultipartFile; |
6 | import org.thingsboard.server.common.data.yunteng.dto.FileUploadResponse; | 5 | import org.thingsboard.server.common.data.yunteng.dto.FileUploadResponse; |
7 | 6 | ||
8 | import javax.servlet.http.HttpServletRequest; | 7 | import javax.servlet.http.HttpServletRequest; |
9 | import javax.servlet.http.HttpServletResponse; | 8 | import javax.servlet.http.HttpServletResponse; |
9 | +import java.io.InputStream; | ||
10 | 10 | ||
11 | public interface FileStorageService { | 11 | public interface FileStorageService { |
12 | 12 | ||
@@ -26,4 +26,6 @@ public interface FileStorageService { | @@ -26,4 +26,6 @@ public interface FileStorageService { | ||
26 | */ | 26 | */ |
27 | ResponseEntity<?> download( | 27 | ResponseEntity<?> download( |
28 | String fileName, HttpServletRequest request, HttpServletResponse response); | 28 | String fileName, HttpServletRequest request, HttpServletResponse response); |
29 | + | ||
30 | + String uploadFile(String fileName, String contentType, InputStream inputStream) throws Exception; | ||
29 | } | 31 | } |
@@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.yunteng.dto.FileUploadResponse; | @@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.yunteng.dto.FileUploadResponse; | ||
22 | import javax.servlet.http.HttpServletRequest; | 22 | import javax.servlet.http.HttpServletRequest; |
23 | import javax.servlet.http.HttpServletResponse; | 23 | import javax.servlet.http.HttpServletResponse; |
24 | import java.io.IOException; | 24 | import java.io.IOException; |
25 | +import java.io.InputStream; | ||
25 | import java.net.MalformedURLException; | 26 | import java.net.MalformedURLException; |
26 | import java.nio.file.Files; | 27 | import java.nio.file.Files; |
27 | import java.nio.file.Path; | 28 | import java.nio.file.Path; |
@@ -58,26 +59,7 @@ public class LocalFileStorageService implements FileStorageService { | @@ -58,26 +59,7 @@ public class LocalFileStorageService implements FileStorageService { | ||
58 | String fileName = StringUtils.cleanPath(Objects.requireNonNull(file.getOriginalFilename())); | 59 | String fileName = StringUtils.cleanPath(Objects.requireNonNull(file.getOriginalFilename())); |
59 | 60 | ||
60 | try { | 61 | try { |
61 | - // random fileName if needed | ||
62 | - if (fileStorageProperties.isRandomFileName()) { | ||
63 | - if (fileName.contains(".")) { | ||
64 | - fileName = | ||
65 | - RandomStringUtils.randomAlphabetic(15) | ||
66 | - + fileName.substring(fileName.lastIndexOf(".")); | ||
67 | - } else { | ||
68 | - fileName = RandomStringUtils.randomAlphabetic(15); | ||
69 | - } | ||
70 | - } | ||
71 | - // Check if the file's name contains invalid characters | ||
72 | - if (fileName.contains("..")) { | ||
73 | - throw new FileStorageException(ErrorMessage.STORE_FILE_FAILED); | ||
74 | - } | ||
75 | - | ||
76 | - // Copy file to the target location (Replacing existing file with the same name) | ||
77 | - Path targetLocation = this.fileStorageLocation.resolve(fileName); | ||
78 | - Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING); | ||
79 | - | ||
80 | - return fileName; | 62 | + return storeFileByInputStream(fileName, file.getInputStream()); |
81 | } catch (IOException ex) { | 63 | } catch (IOException ex) { |
82 | throw new FileStorageException(ErrorMessage.STORE_FILE_FAILED); | 64 | throw new FileStorageException(ErrorMessage.STORE_FILE_FAILED); |
83 | } | 65 | } |
@@ -136,4 +118,37 @@ public class LocalFileStorageService implements FileStorageService { | @@ -136,4 +118,37 @@ public class LocalFileStorageService implements FileStorageService { | ||
136 | "attachment; filename=\"" + resource.getFilename() + "\"") | 118 | "attachment; filename=\"" + resource.getFilename() + "\"") |
137 | .body(resource); | 119 | .body(resource); |
138 | } | 120 | } |
121 | + | ||
122 | + @Override | ||
123 | + public String uploadFile(String fileName, String contentType, InputStream inputStream) | ||
124 | + throws IOException { | ||
125 | + String name = storeFileByInputStream(fileName, inputStream); | ||
126 | + String ossStaticPath = | ||
127 | + ServletUriComponentsBuilder.fromCurrentContextPath().toUriString() + ossFileUrl; | ||
128 | + ossStaticPath = ossStaticPath.replace("**", name); | ||
129 | + return ossStaticPath; | ||
130 | + } | ||
131 | + | ||
132 | + private String storeFileByInputStream(String fileName, InputStream inputStream) | ||
133 | + throws IOException { | ||
134 | + // random fileName if needed | ||
135 | + if (fileStorageProperties.isRandomFileName()) { | ||
136 | + if (fileName.contains(".")) { | ||
137 | + fileName = | ||
138 | + RandomStringUtils.randomAlphabetic(15) + fileName.substring(fileName.lastIndexOf(".")); | ||
139 | + } else { | ||
140 | + fileName = RandomStringUtils.randomAlphabetic(15); | ||
141 | + } | ||
142 | + } | ||
143 | + // Check if the file's name contains invalid characters | ||
144 | + if (fileName.contains("..")) { | ||
145 | + throw new FileStorageException(ErrorMessage.STORE_FILE_FAILED); | ||
146 | + } | ||
147 | + | ||
148 | + // Copy file to the target location (Replacing existing file with the same name) | ||
149 | + Path targetLocation = this.fileStorageLocation.resolve(fileName); | ||
150 | + Files.copy(inputStream, targetLocation, StandardCopyOption.REPLACE_EXISTING); | ||
151 | + | ||
152 | + return fileName; | ||
153 | + } | ||
139 | } | 154 | } |
1 | package org.thingsboard.server.common.data.yunteng.core.utils; | 1 | package org.thingsboard.server.common.data.yunteng.core.utils; |
2 | 2 | ||
3 | import io.minio.*; | 3 | import io.minio.*; |
4 | +import io.minio.errors.*; | ||
4 | import lombok.extern.slf4j.Slf4j; | 5 | import lombok.extern.slf4j.Slf4j; |
5 | import okhttp3.OkHttpClient; | 6 | import okhttp3.OkHttpClient; |
6 | import org.apache.commons.lang3.RandomStringUtils; | 7 | import org.apache.commons.lang3.RandomStringUtils; |
@@ -22,8 +23,10 @@ import org.thingsboard.server.common.data.yunteng.dto.FileUploadResponse; | @@ -22,8 +23,10 @@ import org.thingsboard.server.common.data.yunteng.dto.FileUploadResponse; | ||
22 | import javax.net.ssl.*; | 23 | import javax.net.ssl.*; |
23 | import javax.servlet.http.HttpServletRequest; | 24 | import javax.servlet.http.HttpServletRequest; |
24 | import javax.servlet.http.HttpServletResponse; | 25 | import javax.servlet.http.HttpServletResponse; |
26 | +import java.io.IOException; | ||
25 | import java.io.InputStream; | 27 | import java.io.InputStream; |
26 | import java.io.OutputStream; | 28 | import java.io.OutputStream; |
29 | +import java.security.InvalidKeyException; | ||
27 | import java.security.KeyManagementException; | 30 | import java.security.KeyManagementException; |
28 | import java.security.NoSuchAlgorithmException; | 31 | import java.security.NoSuchAlgorithmException; |
29 | import java.security.SecureRandom; | 32 | import java.security.SecureRandom; |
@@ -36,7 +39,7 @@ import java.util.Objects; | @@ -36,7 +39,7 @@ import java.util.Objects; | ||
36 | public class MinioFileStorageService implements FileStorageService { | 39 | public class MinioFileStorageService implements FileStorageService { |
37 | 40 | ||
38 | private final MinioFileStorageProperties fileStorageProperties; | 41 | private final MinioFileStorageProperties fileStorageProperties; |
39 | - private MinioClient minioClient; | 42 | + private final MinioClient minioClient; |
40 | 43 | ||
41 | @Autowired | 44 | @Autowired |
42 | public MinioFileStorageService(MinioFileStorageProperties fileStorageProperties) | 45 | public MinioFileStorageService(MinioFileStorageProperties fileStorageProperties) |
@@ -53,36 +56,47 @@ public class MinioFileStorageService implements FileStorageService { | @@ -53,36 +56,47 @@ public class MinioFileStorageService implements FileStorageService { | ||
53 | checkBucket(); | 56 | checkBucket(); |
54 | } | 57 | } |
55 | 58 | ||
59 | + public static OkHttpClient getUnsafeOkHttpClient() throws KeyManagementException { | ||
60 | + try { | ||
61 | + final TrustManager[] trustAllCerts = | ||
62 | + new TrustManager[] { | ||
63 | + new X509TrustManager() { | ||
64 | + @Override | ||
65 | + public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {} | ||
66 | + | ||
67 | + @Override | ||
68 | + public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {} | ||
69 | + | ||
70 | + @Override | ||
71 | + public X509Certificate[] getAcceptedIssuers() { | ||
72 | + return new X509Certificate[] {}; | ||
73 | + } | ||
74 | + } | ||
75 | + }; | ||
76 | + | ||
77 | + final SSLContext sslContext = SSLContext.getInstance("SSL"); | ||
78 | + sslContext.init(null, trustAllCerts, new SecureRandom()); | ||
79 | + final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); | ||
80 | + OkHttpClient.Builder builder = new OkHttpClient.Builder(); | ||
81 | + builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]); | ||
82 | + | ||
83 | + builder.hostnameVerifier((s, sslSession) -> true); | ||
84 | + return builder.build(); | ||
85 | + | ||
86 | + } catch (NoSuchAlgorithmException e) { | ||
87 | + e.printStackTrace(); | ||
88 | + } | ||
89 | + return null; | ||
90 | + } | ||
91 | + | ||
56 | // 储存文件 | 92 | // 储存文件 |
57 | public String storeFile(MultipartFile file) { | 93 | public String storeFile(MultipartFile file) { |
58 | // Normalize file name | 94 | // Normalize file name |
59 | String fileName = StringUtils.cleanPath(Objects.requireNonNull(file.getOriginalFilename())); | 95 | String fileName = StringUtils.cleanPath(Objects.requireNonNull(file.getOriginalFilename())); |
60 | // random fileName if needed | 96 | // random fileName if needed |
61 | - if (fileStorageProperties.isRandomFileName()) { | ||
62 | - if (fileName.contains(".")) { | ||
63 | - fileName = | ||
64 | - RandomStringUtils.randomAlphabetic(15) + fileName.substring(fileName.lastIndexOf(".")); | ||
65 | - } else { | ||
66 | - fileName = RandomStringUtils.randomAlphabetic(15); | ||
67 | - } | ||
68 | - } | ||
69 | - // Check if the file's name contains invalid characters | ||
70 | - if (fileName.contains("..")) { | ||
71 | - throw new FileStorageException(ErrorMessage.STORE_FILE_FAILED); | ||
72 | - } | ||
73 | - | ||
74 | // 储存 | 97 | // 储存 |
75 | try { | 98 | try { |
76 | - checkBucket(); | ||
77 | - PutObjectArgs build = | ||
78 | - PutObjectArgs.builder() | ||
79 | - .bucket(fileStorageProperties.getBucketName()) | ||
80 | - .object(fileName) | ||
81 | - .contentType(file.getContentType()) | ||
82 | - .stream(file.getInputStream(), file.getInputStream().available(), -1) | ||
83 | - .build(); | ||
84 | - minioClient.putObject(build); | ||
85 | - return fileName; | 99 | + return storeFileByInputStream(fileName, file.getContentType(), file.getInputStream()); |
86 | } catch (Exception ex) { | 100 | } catch (Exception ex) { |
87 | ex.printStackTrace(); | 101 | ex.printStackTrace(); |
88 | throw new FileStorageException(ErrorMessage.STORE_FILE_FAILED); | 102 | throw new FileStorageException(ErrorMessage.STORE_FILE_FAILED); |
@@ -122,7 +136,7 @@ public class MinioFileStorageService implements FileStorageService { | @@ -122,7 +136,7 @@ public class MinioFileStorageService implements FileStorageService { | ||
122 | .object(fileName) | 136 | .object(fileName) |
123 | .build()); | 137 | .build()); |
124 | // 获取输出流 | 138 | // 获取输出流 |
125 | - OutputStream outputStream = response.getOutputStream(); ) { | 139 | + OutputStream outputStream = response.getOutputStream()) { |
126 | // 清空 | 140 | // 清空 |
127 | response.reset(); | 141 | response.reset(); |
128 | // 写入流 | 142 | // 写入流 |
@@ -141,6 +155,16 @@ public class MinioFileStorageService implements FileStorageService { | @@ -141,6 +155,16 @@ public class MinioFileStorageService implements FileStorageService { | ||
141 | } | 155 | } |
142 | } | 156 | } |
143 | 157 | ||
158 | + @Override | ||
159 | + public String uploadFile(String fileName, String contentType, InputStream inputStream) | ||
160 | + throws IOException { | ||
161 | + try { | ||
162 | + return getPath(storeFileByInputStream(fileName, contentType, inputStream)); | ||
163 | + } catch (Exception e) { | ||
164 | + throw new IOException(e.getMessage()); | ||
165 | + } | ||
166 | + } | ||
167 | + | ||
144 | // 检查储存桶情况 | 168 | // 检查储存桶情况 |
145 | private void checkBucket() { | 169 | private void checkBucket() { |
146 | try { | 170 | try { |
@@ -181,37 +205,32 @@ public class MinioFileStorageService implements FileStorageService { | @@ -181,37 +205,32 @@ public class MinioFileStorageService implements FileStorageService { | ||
181 | .concat(fileName); | 205 | .concat(fileName); |
182 | } | 206 | } |
183 | 207 | ||
184 | - public static OkHttpClient getUnsafeOkHttpClient() throws KeyManagementException { | ||
185 | - try { | ||
186 | - final TrustManager[] trustAllCerts = | ||
187 | - new TrustManager[] { | ||
188 | - new X509TrustManager() { | ||
189 | - @Override | ||
190 | - public void checkClientTrusted(X509Certificate[] x509Certificates, String s){} | ||
191 | - | ||
192 | - @Override | ||
193 | - public void checkServerTrusted(X509Certificate[] x509Certificates, String s){} | ||
194 | - | ||
195 | - @Override | ||
196 | - public X509Certificate[] getAcceptedIssuers() { | ||
197 | - return new X509Certificate[] {}; | ||
198 | - } | ||
199 | - } | ||
200 | - }; | ||
201 | - | ||
202 | - final SSLContext sslContext = SSLContext.getInstance("SSL"); | ||
203 | - sslContext.init(null, trustAllCerts, new SecureRandom()); | ||
204 | - final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); | ||
205 | - OkHttpClient.Builder builder = new OkHttpClient.Builder(); | ||
206 | - builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]); | ||
207 | - | ||
208 | - builder.hostnameVerifier( | ||
209 | - (s, sslSession) -> true); | ||
210 | - return builder.build(); | ||
211 | - | ||
212 | - } catch (NoSuchAlgorithmException e) { | ||
213 | - e.printStackTrace(); | 208 | + private String storeFileByInputStream( |
209 | + String fileName, String contentType, InputStream inputStream) | ||
210 | + throws ServerException, InsufficientDataException, ErrorResponseException, IOException, | ||
211 | + NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, | ||
212 | + XmlParserException, InternalException { | ||
213 | + if (fileStorageProperties.isRandomFileName()) { | ||
214 | + if (!fileName.contains(".")) { | ||
215 | + fileName = RandomStringUtils.randomAlphabetic(15); | ||
216 | + } else { | ||
217 | + fileName = | ||
218 | + RandomStringUtils.randomAlphabetic(15) + fileName.substring(fileName.lastIndexOf(".")); | ||
219 | + } | ||
214 | } | 220 | } |
215 | - return null; | 221 | + // Check if the file's name contains invalid characters |
222 | + if (fileName.contains("..")) { | ||
223 | + throw new FileStorageException(ErrorMessage.STORE_FILE_FAILED); | ||
224 | + } | ||
225 | + checkBucket(); | ||
226 | + PutObjectArgs build = | ||
227 | + PutObjectArgs.builder() | ||
228 | + .bucket(fileStorageProperties.getBucketName()) | ||
229 | + .object(fileName) | ||
230 | + .contentType(contentType) | ||
231 | + .stream(inputStream, inputStream.available(), -1) | ||
232 | + .build(); | ||
233 | + minioClient.putObject(build); | ||
234 | + return fileName; | ||
216 | } | 235 | } |
217 | } | 236 | } |
@@ -26,6 +26,8 @@ public class ReportFormConfigDTO extends TenantDTO { | @@ -26,6 +26,8 @@ public class ReportFormConfigDTO extends TenantDTO { | ||
26 | @NotEmpty(message = "组织不能为空或空字符串", groups = AddGroup.class) | 26 | @NotEmpty(message = "组织不能为空或空字符串", groups = AddGroup.class) |
27 | private String organizationId; | 27 | private String organizationId; |
28 | 28 | ||
29 | + private OrganizationDTO organizationDTO; | ||
30 | + | ||
29 | /** 执行方式:0立即执行 1定时执行 */ | 31 | /** 执行方式:0立即执行 1定时执行 */ |
30 | @ApiModelProperty(value = "执行方式", required = true) | 32 | @ApiModelProperty(value = "执行方式", required = true) |
31 | @NotNull(message = "执行方式不能为空", groups = AddGroup.class) | 33 | @NotNull(message = "执行方式不能为空", groups = AddGroup.class) |
@@ -39,15 +41,11 @@ public class ReportFormConfigDTO extends TenantDTO { | @@ -39,15 +41,11 @@ public class ReportFormConfigDTO extends TenantDTO { | ||
39 | @Size(message = "至少需要一个执行设备及属性", min = 1,groups = AddGroup.class) | 41 | @Size(message = "至少需要一个执行设备及属性", min = 1,groups = AddGroup.class) |
40 | private List<ExecuteAttributesDTO> executeAttributes; | 42 | private List<ExecuteAttributesDTO> executeAttributes; |
41 | 43 | ||
42 | - /** 属性性质:0共有属性 1全部属性 */ | ||
43 | - @ApiModelProperty(value = "属性性质", required = true) | ||
44 | - @NotNull(message = "属性性质不能为空", groups = AddGroup.class) | ||
45 | - private Integer attributeNature; | ||
46 | 44 | ||
47 | - /** 数据对比:0历史数据 1环比 2同比 */ | ||
48 | - @ApiModelProperty(value = "数据对比", required = true) | ||
49 | - @NotNull(message = "数据对比不能为空", groups = AddGroup.class) | ||
50 | - private Integer dataCompare; | 45 | + /** 数据类型:0历史数据 1聚合数据 */ |
46 | + @ApiModelProperty(value = "数据类型:0原始数据 1聚合数据", required = true) | ||
47 | + @NotNull(message = "数据类型不能为空", groups = AddGroup.class) | ||
48 | + private Integer dataType; | ||
51 | 49 | ||
52 | /** 数据周期:单位毫秒 */ | 50 | /** 数据周期:单位毫秒 */ |
53 | @ApiModelProperty(value = "开始时间", required = true) | 51 | @ApiModelProperty(value = "开始时间", required = true) |
common/data/src/main/java/org/thingsboard/server/common/data/yunteng/dto/report/BasicData.java
0 → 100644
1 | +package org.thingsboard.server.common.data.yunteng.dto.report; | ||
2 | + | ||
3 | +import lombok.Data; | ||
4 | +import org.jetbrains.annotations.NotNull; | ||
5 | + | ||
6 | +@Data | ||
7 | +public class BasicData implements Comparable<BasicData> { | ||
8 | + private final Object value; | ||
9 | + | ||
10 | + private final long ts; | ||
11 | + | ||
12 | + public BasicData(long ts, Object value) { | ||
13 | + super(); | ||
14 | + this.ts = ts; | ||
15 | + this.value = value; | ||
16 | + } | ||
17 | + | ||
18 | + @Override | ||
19 | + public int compareTo(@NotNull BasicData o) { | ||
20 | + return Long.compare(ts, o.ts); | ||
21 | + } | ||
22 | +} |
common/data/src/main/java/org/thingsboard/server/common/data/yunteng/dto/report/ChartReportDTO.java
0 → 100644
1 | +package org.thingsboard.server.common.data.yunteng.dto.report; | ||
2 | + | ||
3 | +import lombok.Data; | ||
4 | + | ||
5 | +import java.util.List; | ||
6 | + | ||
7 | +/** 报表导出:Echarts图表展示数据 */ | ||
8 | +@Data | ||
9 | +public class ChartReportDTO { | ||
10 | + /** 报表查询:开始时间 */ | ||
11 | + private Long startTs; | ||
12 | + | ||
13 | + /** 报表查询:结束时间 */ | ||
14 | + private Long endTs; | ||
15 | + | ||
16 | + /** 查询返回的数据 */ | ||
17 | + private List<ReportDataSourceDTO> data; | ||
18 | +} |
1 | +package org.thingsboard.server.common.data.yunteng.dto.report; | ||
2 | + | ||
3 | +import lombok.Data; | ||
4 | + | ||
5 | +import java.util.List; | ||
6 | + | ||
7 | +/** 基础报表数据 */ | ||
8 | +@Data | ||
9 | +public class ReportDataSourceDTO { | ||
10 | + | ||
11 | + /** 采集属性 */ | ||
12 | + private String attribute; | ||
13 | + | ||
14 | + /** 采集的数据 */ | ||
15 | + private List<BasicData> data; | ||
16 | +} |
@@ -4,12 +4,17 @@ import io.swagger.annotations.ApiModel; | @@ -4,12 +4,17 @@ import io.swagger.annotations.ApiModel; | ||
4 | import io.swagger.annotations.ApiModelProperty; | 4 | import io.swagger.annotations.ApiModelProperty; |
5 | import lombok.Data; | 5 | import lombok.Data; |
6 | 6 | ||
7 | +import java.util.List; | ||
8 | + | ||
7 | @Data | 9 | @Data |
8 | @ApiModel(value = "执行设备及属性") | 10 | @ApiModel(value = "执行设备及属性") |
9 | public class ExecuteAttributesDTO { | 11 | public class ExecuteAttributesDTO { |
10 | @ApiModelProperty(value = "执行设备", required = true) | 12 | @ApiModelProperty(value = "执行设备", required = true) |
11 | private String device; | 13 | private String device; |
12 | 14 | ||
15 | + @ApiModelProperty(value = "设备名称", required = true) | ||
16 | + private String name; | ||
17 | + | ||
13 | @ApiModelProperty(value = "执行属性", required = true) | 18 | @ApiModelProperty(value = "执行属性", required = true) |
14 | - private String attribute; | 19 | + private List<String> attributes; |
15 | } | 20 | } |
@@ -3,21 +3,22 @@ package org.thingsboard.server.common.data.yunteng.dto.request; | @@ -3,21 +3,22 @@ package org.thingsboard.server.common.data.yunteng.dto.request; | ||
3 | import io.swagger.annotations.ApiModel; | 3 | import io.swagger.annotations.ApiModel; |
4 | import io.swagger.annotations.ApiModelProperty; | 4 | import io.swagger.annotations.ApiModelProperty; |
5 | import lombok.Data; | 5 | import lombok.Data; |
6 | +import org.thingsboard.server.common.data.kv.Aggregation; | ||
6 | 7 | ||
7 | @Data | 8 | @Data |
8 | @ApiModel(value = "查询条件") | 9 | @ApiModel(value = "查询条件") |
9 | public class QueryConditionDTO { | 10 | public class QueryConditionDTO { |
10 | - @ApiModelProperty("聚合间隔:单位毫秒") | ||
11 | - private Long interval; | 11 | + @ApiModelProperty("聚合间隔:单位毫秒,默认0") |
12 | + private Long interval = 0L; | ||
12 | 13 | ||
13 | - @ApiModelProperty("查询的最大数量:该参数仅在'agg'参数设置为'NONE'的情况下使用") | ||
14 | - private Integer limit; | 14 | + @ApiModelProperty("查询的最大数量:该参数仅在'agg'参数设置为'NONE'的情况下使用,默认100") |
15 | + private Integer limit = 100; | ||
15 | 16 | ||
16 | @ApiModelProperty("聚合条件:AVG, COUNT, MAX, MIN, NONE, SUM") | 17 | @ApiModelProperty("聚合条件:AVG, COUNT, MAX, MIN, NONE, SUM") |
17 | - private String agg; | 18 | + private Aggregation agg; |
18 | 19 | ||
19 | - @ApiModelProperty("排序:ASC, DESC") | ||
20 | - private String orderBy; | 20 | + @ApiModelProperty("排序:ASC, DESC 默认DESC") |
21 | + private String orderBy = "DESC"; | ||
21 | 22 | ||
22 | @ApiModelProperty("启用/禁用遥测值到字符串的转换。默认情况下启用转换。设置参数为'true'以禁用转换") | 23 | @ApiModelProperty("启用/禁用遥测值到字符串的转换。默认情况下启用转换。设置参数为'true'以禁用转换") |
23 | private boolean useStrictDataTypes; | 24 | private boolean useStrictDataTypes; |
@@ -8,8 +8,8 @@ public enum StatusEnum { | @@ -8,8 +8,8 @@ public enum StatusEnum { | ||
8 | ONLINE("在线", 1), | 8 | ONLINE("在线", 1), |
9 | ENABLE("启用", 1), | 9 | ENABLE("启用", 1), |
10 | DISABLE("禁用", 0), | 10 | DISABLE("禁用", 0), |
11 | - NORMAL("正常", 0), | ||
12 | - PAUSE("暂停", 1), | 11 | + NORMAL("正常", 1), |
12 | + PAUSE("暂停", 0), | ||
13 | FAIL("失败", 0), | 13 | FAIL("失败", 0), |
14 | SUCCESS("成功", 1), | 14 | SUCCESS("成功", 1), |
15 | RUNNING("运行中",2), | 15 | RUNNING("运行中",2), |
1 | package org.thingsboard.server.common.data.yunteng.utils; | 1 | package org.thingsboard.server.common.data.yunteng.utils; |
2 | 2 | ||
3 | import com.alibaba.excel.EasyExcel; | 3 | import com.alibaba.excel.EasyExcel; |
4 | +import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; | ||
4 | import org.apache.commons.lang3.StringUtils; | 5 | import org.apache.commons.lang3.StringUtils; |
5 | import org.springframework.beans.BeanUtils; | 6 | import org.springframework.beans.BeanUtils; |
6 | 7 | ||
7 | import javax.servlet.http.HttpServletResponse; | 8 | import javax.servlet.http.HttpServletResponse; |
9 | +import java.io.ByteArrayOutputStream; | ||
8 | import java.io.IOException; | 10 | import java.io.IOException; |
9 | import java.net.URLEncoder; | 11 | import java.net.URLEncoder; |
10 | import java.nio.charset.StandardCharsets; | 12 | import java.nio.charset.StandardCharsets; |
@@ -15,7 +17,6 @@ import java.util.List; | @@ -15,7 +17,6 @@ import java.util.List; | ||
15 | 17 | ||
16 | public class ExcelUtil { | 18 | public class ExcelUtil { |
17 | private ExcelUtil() {} | 19 | private ExcelUtil() {} |
18 | - | ||
19 | public static void exportExcel( | 20 | public static void exportExcel( |
20 | HttpServletResponse response, | 21 | HttpServletResponse response, |
21 | String fileName, | 22 | String fileName, |
@@ -52,4 +53,15 @@ public class ExcelUtil { | @@ -52,4 +53,15 @@ public class ExcelUtil { | ||
52 | 53 | ||
53 | exportExcel(response, fileName, sheetName, targetList, targetClass); | 54 | exportExcel(response, fileName, sheetName, targetList, targetClass); |
54 | } | 55 | } |
56 | + | ||
57 | + public static ByteArrayOutputStream noModelWrite(String fileName, List<List<String>> heads, List<?> data) { | ||
58 | + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); | ||
59 | + EasyExcel.write(byteArrayOutputStream) | ||
60 | + .head(heads) | ||
61 | + .sheet(fileName) | ||
62 | + // 自适应列宽 | ||
63 | + .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) | ||
64 | + .doWrite(data); | ||
65 | + return byteArrayOutputStream; | ||
66 | + } | ||
55 | } | 67 | } |
@@ -64,7 +64,7 @@ public abstract class AbstractQuartzJob implements Job { | @@ -64,7 +64,7 @@ public abstract class AbstractQuartzJob implements Job { | ||
64 | long runMs = | 64 | long runMs = |
65 | sysJobLog.getEndTime().toInstant(ZoneOffset.of("+8")).toEpochMilli() | 65 | sysJobLog.getEndTime().toInstant(ZoneOffset.of("+8")).toEpochMilli() |
66 | - startTime.toInstant(ZoneOffset.of("+8")).toEpochMilli(); | 66 | - startTime.toInstant(ZoneOffset.of("+8")).toEpochMilli(); |
67 | - sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时:" + runMs + "毫秒"); | 67 | + sysJobLog.setJobMessage(" 总共耗时:" + runMs + "毫秒"); |
68 | if (e != null) { | 68 | if (e != null) { |
69 | sysJobLog.setStatus(StatusEnum.FAIL.getIndex()); | 69 | sysJobLog.setStatus(StatusEnum.FAIL.getIndex()); |
70 | String errorMsg = StringUtils.substring(e.getMessage(), 0, 2000); | 70 | String errorMsg = StringUtils.substring(e.getMessage(), 0, 2000); |
1 | package org.thingsboard.server.dao.util.yunteng; | 1 | package org.thingsboard.server.dao.util.yunteng; |
2 | 2 | ||
3 | import org.apache.commons.lang3.StringUtils; | 3 | import org.apache.commons.lang3.StringUtils; |
4 | +import org.thingsboard.server.common.data.yunteng.dto.ReportGenerateRecordDTO; | ||
4 | import org.thingsboard.server.common.data.yunteng.enums.JobGroupEnum; | 5 | import org.thingsboard.server.common.data.yunteng.enums.JobGroupEnum; |
5 | import org.thingsboard.server.common.data.yunteng.utils.SpringBeanUtils; | 6 | import org.thingsboard.server.common.data.yunteng.utils.SpringBeanUtils; |
6 | import org.thingsboard.server.dao.yunteng.entities.SysJob; | 7 | import org.thingsboard.server.dao.yunteng.entities.SysJob; |
@@ -22,13 +23,16 @@ public class JobInvokeUtil { | @@ -22,13 +23,16 @@ public class JobInvokeUtil { | ||
22 | String invokeTarget = sysJob.getInvokeTarget(); | 23 | String invokeTarget = sysJob.getInvokeTarget(); |
23 | String beanName = getBeanName(invokeTarget); | 24 | String beanName = getBeanName(invokeTarget); |
24 | String methodName = getMethodName(invokeTarget); | 25 | String methodName = getMethodName(invokeTarget); |
26 | + String reportGenerateRecordId = null; | ||
25 | if (StringUtils.isNotEmpty(sysJob.getSourceId()) | 27 | if (StringUtils.isNotEmpty(sysJob.getSourceId()) |
26 | && sysJob.getJobGroup().equals(JobGroupEnum.REPORT.toString())) { | 28 | && sysJob.getJobGroup().equals(JobGroupEnum.REPORT.toString())) { |
27 | // 写入报表生成记录 | 29 | // 写入报表生成记录 |
28 | - SpringBeanUtils.getBean(YtReportGenerateRecordService.class) | ||
29 | - .generateReportRecord(sysJob.getSourceId(), sysJob.getTenantId(), sysJob.getId()); | 30 | + ReportGenerateRecordDTO dto = |
31 | + SpringBeanUtils.getBean(YtReportGenerateRecordService.class) | ||
32 | + .generateReportRecord(sysJob.getSourceId(), sysJob.getTenantId(), sysJob.getId()); | ||
33 | + reportGenerateRecordId = dto.getId(); | ||
30 | } | 34 | } |
31 | - List<Object[]> methodParams = getMethodParams(invokeTarget); | 35 | + List<Object[]> methodParams = getMethodParams(invokeTarget, reportGenerateRecordId); |
32 | Object bean; | 36 | Object bean; |
33 | if (!isValidClassName(beanName)) { | 37 | if (!isValidClassName(beanName)) { |
34 | bean = SpringBeanUtils.getBean(beanName); | 38 | bean = SpringBeanUtils.getBean(beanName); |
@@ -96,11 +100,14 @@ public class JobInvokeUtil { | @@ -96,11 +100,14 @@ public class JobInvokeUtil { | ||
96 | * @param invokeTarget 目标字符串 | 100 | * @param invokeTarget 目标字符串 |
97 | * @return method方法相关参数列表 | 101 | * @return method方法相关参数列表 |
98 | */ | 102 | */ |
99 | - public static List<Object[]> getMethodParams(String invokeTarget) { | 103 | + public static List<Object[]> getMethodParams(String invokeTarget, String reportGenerateRecordId) { |
100 | String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")"); | 104 | String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")"); |
101 | if (StringUtils.isEmpty(methodStr)) { | 105 | if (StringUtils.isEmpty(methodStr)) { |
102 | return null; | 106 | return null; |
103 | } | 107 | } |
108 | + if (reportGenerateRecordId != null) { | ||
109 | + methodStr += ",\"" + reportGenerateRecordId + "\""; | ||
110 | + } | ||
104 | String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)"); | 111 | String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)"); |
105 | List<Object[]> classs = new LinkedList<>(); | 112 | List<Object[]> classs = new LinkedList<>(); |
106 | for (String methodParam : methodParams) { | 113 | for (String methodParam : methodParams) { |
1 | package org.thingsboard.server.dao.util.yunteng.task; | 1 | package org.thingsboard.server.dao.util.yunteng.task; |
2 | 2 | ||
3 | +import com.google.common.util.concurrent.FutureCallback; | ||
4 | +import com.google.common.util.concurrent.Futures; | ||
5 | +import com.google.common.util.concurrent.MoreExecutors; | ||
6 | +import lombok.RequiredArgsConstructor; | ||
7 | +import lombok.extern.slf4j.Slf4j; | ||
8 | +import org.jetbrains.annotations.NotNull; | ||
9 | +import org.springframework.http.HttpStatus; | ||
10 | +import org.springframework.http.ResponseEntity; | ||
3 | import org.springframework.stereotype.Component; | 11 | import org.springframework.stereotype.Component; |
12 | +import org.springframework.web.context.request.async.DeferredResult; | ||
13 | +import org.thingsboard.common.util.JacksonUtil; | ||
14 | +import org.thingsboard.server.common.data.id.DeviceId; | ||
15 | +import org.thingsboard.server.common.data.id.TenantId; | ||
16 | +import org.thingsboard.server.common.data.kv.*; | ||
17 | +import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants; | ||
18 | +import org.thingsboard.server.common.data.yunteng.core.utils.FileStorageService; | ||
19 | +import org.thingsboard.server.common.data.yunteng.dto.ReportFormConfigDTO; | ||
20 | +import org.thingsboard.server.common.data.yunteng.dto.ReportGenerateRecordDTO; | ||
21 | +import org.thingsboard.server.common.data.yunteng.dto.report.BasicData; | ||
22 | +import org.thingsboard.server.common.data.yunteng.dto.request.ExecuteAttributesDTO; | ||
23 | +import org.thingsboard.server.common.data.yunteng.dto.request.QueryConditionDTO; | ||
24 | +import org.thingsboard.server.common.data.yunteng.enums.StatusEnum; | ||
25 | +import org.thingsboard.server.common.data.yunteng.utils.ExcelUtil; | ||
26 | +import org.thingsboard.server.dao.timeseries.TimeseriesService; | ||
27 | +import org.thingsboard.server.dao.yunteng.service.YtReportFormConfigService; | ||
28 | +import org.thingsboard.server.dao.yunteng.service.YtReportGenerateRecordService; | ||
29 | + | ||
30 | +import java.io.ByteArrayInputStream; | ||
31 | +import java.io.ByteArrayOutputStream; | ||
32 | +import java.io.InputStream; | ||
33 | +import java.sql.Timestamp; | ||
34 | +import java.time.format.DateTimeFormatter; | ||
35 | +import java.util.*; | ||
36 | +import java.util.stream.Collectors; | ||
4 | 37 | ||
5 | @Component("reportTask") | 38 | @Component("reportTask") |
39 | +@RequiredArgsConstructor | ||
40 | +@Slf4j | ||
6 | public class ReportTask { | 41 | public class ReportTask { |
7 | - public void multipleParams(String s, Boolean b, Long l, Double d, Integer i) | ||
8 | - { | ||
9 | - System.out.println("执行多参方法: s="+s+"b="+b+"l="+l+"d"+d+"i="+i); | ||
10 | - } | 42 | + private static final String CONTENT_TYPE = |
43 | + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; | ||
44 | + private final YtReportFormConfigService ytReportFormConfigService; | ||
45 | + private final TimeseriesService tsService; | ||
46 | + private final FileStorageService fileStorageService; | ||
47 | + private final YtReportGenerateRecordService ytReportGenerateRecordService; | ||
11 | 48 | ||
12 | - public void params(String params) throws InterruptedException { | ||
13 | - System.out.println("==========================执行有参方法:" + params+"======================="); | ||
14 | - Thread.sleep(100); | ||
15 | - } | 49 | + public void multipleParams(String s, Boolean b, Long l, Double d, Integer i) { |
50 | + System.out.println("执行多参方法: s=" + s + "b=" + b + "l=" + l + "d" + d + "i=" + i); | ||
51 | + } | ||
52 | + | ||
53 | + public void params(String params) throws InterruptedException { | ||
54 | + System.out.println("==========================执行有参方法:" + params + "======================="); | ||
55 | + Thread.sleep(100); | ||
56 | + } | ||
16 | 57 | ||
17 | - public void noParams() throws InterruptedException { | ||
18 | - System.out.println("=========================执行无参方法======================================"); | 58 | + public void noParams() throws InterruptedException { |
59 | + System.out.println("=========================执行无参方法======================================"); | ||
60 | + } | ||
61 | + | ||
62 | + public void generateReport(String reportId, String reportGenerateRecordId) { | ||
63 | + ReportFormConfigDTO formConfigDTO = | ||
64 | + ytReportFormConfigService.findReportFormConfigById(reportId); | ||
65 | + // 关联设备 | ||
66 | + List<ExecuteAttributesDTO> dtoList = formConfigDTO.getExecuteAttributes(); | ||
67 | + if (!dtoList.isEmpty()) { | ||
68 | + if (dtoList.size() == FastIotConstants.MagicNumber.ONE) { | ||
69 | + try { | ||
70 | + ExecuteAttributesDTO attributesDTO = dtoList.get(0); | ||
71 | + getTsKv(formConfigDTO, attributesDTO, reportGenerateRecordId); | ||
72 | + | ||
73 | + } catch (Exception e) { | ||
74 | + log.error(e.getMessage()); | ||
75 | + } | ||
76 | + } else { | ||
77 | + for (ExecuteAttributesDTO dto : dtoList) { | ||
78 | + getTsKv(formConfigDTO, dto, reportGenerateRecordId); | ||
79 | + } | ||
80 | + } | ||
19 | } | 81 | } |
82 | + } | ||
83 | + | ||
84 | + private void getTsKv( | ||
85 | + ReportFormConfigDTO formConfigDTO, ExecuteAttributesDTO dto, String reportGenerateRecordId) { | ||
86 | + Long startTs = formConfigDTO.getStartTs(); | ||
87 | + Long endTs = formConfigDTO.getEndTs(); | ||
88 | + QueryConditionDTO queryCondition = formConfigDTO.getQueryCondition(); | ||
89 | + boolean useStrictDataTypes = queryCondition.isUseStrictDataTypes(); | ||
90 | + Long interval = queryCondition.getInterval(); | ||
91 | + int limit = queryCondition.getLimit(); | ||
92 | + Aggregation agg = queryCondition.getAgg(); | ||
93 | + String orderBy = queryCondition.getOrderBy(); | ||
94 | + List<String> keys = dto.getAttributes(); | ||
95 | + DeviceId entityId = DeviceId.fromString(dto.getDevice()); | ||
96 | + String reportTenantId = formConfigDTO.getTenantId(); | ||
97 | + TenantId tenantId = TenantId.fromUUID(UUID.fromString(reportTenantId)); | ||
98 | + final DeferredResult<ResponseEntity> result = new DeferredResult<>(); | ||
99 | + List<ReadTsKvQuery> queries = | ||
100 | + keys.stream() | ||
101 | + .map(key -> new BaseReadTsKvQuery(key, startTs, endTs, interval, limit, agg, orderBy)) | ||
102 | + .collect(Collectors.toList()); | ||
20 | 103 | ||
21 | - public void generateReport(String reportId){ | ||
22 | - System.out.println("===========================执行报表生成:"+ reportId +"===================================="); | 104 | + Futures.addCallback( |
105 | + tsService.findAll(tenantId, entityId, queries), | ||
106 | + getTsKvListCallback( | ||
107 | + result, | ||
108 | + useStrictDataTypes, | ||
109 | + formConfigDTO.getName(), | ||
110 | + dto.getName(), | ||
111 | + reportGenerateRecordId, | ||
112 | + reportTenantId), | ||
113 | + MoreExecutors.directExecutor()); | ||
114 | + } | ||
115 | + | ||
116 | + private FutureCallback<List<TsKvEntry>> getTsKvListCallback( | ||
117 | + final DeferredResult<ResponseEntity> response, | ||
118 | + Boolean useStrictDataTypes, | ||
119 | + String reportFormName, | ||
120 | + String deviceName, | ||
121 | + String reportGenerateRecordId, | ||
122 | + String tenantId) { | ||
123 | + return new FutureCallback<>() { | ||
124 | + @Override | ||
125 | + public void onSuccess(List<TsKvEntry> data) { | ||
126 | + Map<String, List<BasicData>> result = new LinkedHashMap<>(); | ||
127 | + for (TsKvEntry entry : data) { | ||
128 | + Object value = useStrictDataTypes ? getKvValue(entry) : entry.getValueAsString(); | ||
129 | + result | ||
130 | + .computeIfAbsent(entry.getKey(), k -> new ArrayList<>()) | ||
131 | + .add(new BasicData(entry.getTs(), value)); | ||
132 | + } | ||
133 | + response.setResult(new ResponseEntity<>(result, HttpStatus.OK)); | ||
134 | + generateExcel(deviceName, reportFormName, result, reportGenerateRecordId, tenantId); | ||
135 | + } | ||
136 | + | ||
137 | + @Override | ||
138 | + public void onFailure(@NotNull Throwable e) { | ||
139 | + log.error("Failed to fetch historical data", e); | ||
140 | + } | ||
141 | + }; | ||
142 | + } | ||
143 | + | ||
144 | + private Object getKvValue(KvEntry entry) { | ||
145 | + if (entry.getDataType() == DataType.JSON) { | ||
146 | + Optional<String> json = entry.getJsonValue(); | ||
147 | + return json.map(JacksonUtil::toJsonNode).orElse(null); | ||
23 | } | 148 | } |
149 | + return entry.getValue(); | ||
150 | + } | ||
24 | 151 | ||
152 | + private void generateExcel( | ||
153 | + String deviceName, | ||
154 | + String reportFormName, | ||
155 | + Map<String, List<BasicData>> result, | ||
156 | + String reportGenerateRecordId, | ||
157 | + String tenantId) { | ||
158 | + List<List<String>> heads = new ArrayList<>(); | ||
159 | + List<List<Object>> values = new ArrayList<>(); | ||
160 | + int firstKey = 0; | ||
161 | + for (String key : result.keySet()) { | ||
162 | + List<String> headValue = new ArrayList<>(); | ||
163 | + headValue.add(deviceName); | ||
164 | + headValue.add(key + "采集值"); | ||
165 | + List<String> tsValue = new ArrayList<>(); | ||
166 | + tsValue.add(deviceName); | ||
167 | + tsValue.add(key + "采集时间"); | ||
168 | + heads.add(headValue); | ||
169 | + heads.add(tsValue); | ||
170 | + List<BasicData> basicData = result.get(key); | ||
171 | + for (int i = 0; i < basicData.size(); i++) { | ||
172 | + BasicData item = basicData.get(i); | ||
173 | + List<Object> listValue; | ||
174 | + if (firstKey == 0) { | ||
175 | + listValue = new ArrayList<>(); | ||
176 | + } else { | ||
177 | + listValue = values.get(i); | ||
178 | + } | ||
179 | + Object value = item.getValue(); | ||
180 | + listValue.add(value); | ||
181 | + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); | ||
182 | + Timestamp t = new Timestamp(item.getTs()); | ||
183 | + listValue.add(t.toLocalDateTime().format(dtf)); | ||
184 | + if (firstKey == 0) { | ||
185 | + values.add(listValue); | ||
186 | + } | ||
187 | + } | ||
188 | + firstKey++; | ||
189 | + } | ||
190 | + ByteArrayOutputStream byteArrayOutputStream = | ||
191 | + ExcelUtil.noModelWrite(reportFormName, heads, values); | ||
192 | + String fileName = reportFormName + System.currentTimeMillis() + ".xlsx"; | ||
193 | + int status = StatusEnum.SUCCESS.getIndex(); | ||
194 | + InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); | ||
195 | + String response = null; | ||
196 | + try { | ||
197 | + response = fileStorageService.uploadFile(fileName, CONTENT_TYPE, inputStream); | ||
198 | + } catch (Exception e) { | ||
199 | + log.error(e.getMessage()); | ||
200 | + } | ||
201 | + ReportGenerateRecordDTO recordDTO = | ||
202 | + ytReportGenerateRecordService.findReportGenerateRecordById( | ||
203 | + reportGenerateRecordId, tenantId); | ||
204 | + if (null != recordDTO) { | ||
205 | + if (response != null) { | ||
206 | + recordDTO.setReportPath(response); | ||
207 | + } else { | ||
208 | + status = StatusEnum.FAIL.getIndex(); | ||
209 | + } | ||
210 | + recordDTO.setExecuteStatus(status); | ||
211 | + ytReportGenerateRecordService.saveOrUpdateReportGenerateRecord(recordDTO); | ||
212 | + } | ||
213 | + } | ||
25 | } | 214 | } |
@@ -33,11 +33,8 @@ public class ReportFormConfig extends TenantBaseEntity { | @@ -33,11 +33,8 @@ public class ReportFormConfig extends TenantBaseEntity { | ||
33 | @TableField(typeHandler = JacksonTypeHandler.class) | 33 | @TableField(typeHandler = JacksonTypeHandler.class) |
34 | private JsonNode executeAttributes; | 34 | private JsonNode executeAttributes; |
35 | 35 | ||
36 | - /** 属性性质:0共有属性 1全部属性 */ | ||
37 | - private Integer attributeNature; | ||
38 | - | ||
39 | - /** 数据对比:0历史数据 1环比 2同比 */ | ||
40 | - private Integer dataCompare; | 36 | + /** 数据对比:0原始数据 1聚合数据 */ |
37 | + private Integer dataType; | ||
41 | 38 | ||
42 | /** 查询开始时间:单位毫秒 */ | 39 | /** 查询开始时间:单位毫秒 */ |
43 | private Long startTs; | 40 | private Long startTs; |
@@ -31,7 +31,7 @@ public class SysJob extends TenantBaseEntity { | @@ -31,7 +31,7 @@ public class SysJob extends TenantBaseEntity { | ||
31 | /** 是否并发执行(0允许 1禁止) */ | 31 | /** 是否并发执行(0允许 1禁止) */ |
32 | private Integer concurrent; | 32 | private Integer concurrent; |
33 | 33 | ||
34 | - /** 任务状态(0正常 1暂停) */ | 34 | + /** 任务状态(0暂停 1正常) */ |
35 | private Integer status; | 35 | private Integer status; |
36 | 36 | ||
37 | /** 来源ID:即创建定时任务对应的业务ID */ | 37 | /** 来源ID:即创建定时任务对应的业务ID */ |
@@ -194,7 +194,6 @@ public class SysJobServiceImpl extends AbstractBaseService<SysJobMapper, SysJob> | @@ -194,7 +194,6 @@ public class SysJobServiceImpl extends AbstractBaseService<SysJobMapper, SysJob> | ||
194 | @Transactional(rollbackFor = Exception.class) | 194 | @Transactional(rollbackFor = Exception.class) |
195 | public SysJobDTO saveOrUpdateJob(SysJobDTO jobDTO) throws SchedulerException { | 195 | public SysJobDTO saveOrUpdateJob(SysJobDTO jobDTO) throws SchedulerException { |
196 | if (StringUtils.isEmpty(jobDTO.getId())) { | 196 | if (StringUtils.isEmpty(jobDTO.getId())) { |
197 | - jobDTO.setStatus(StatusEnum.PAUSE.getIndex()); | ||
198 | SysJob job = jobDTO.getEntity(SysJob.class); | 197 | SysJob job = jobDTO.getEntity(SysJob.class); |
199 | baseMapper.insert(job); | 198 | baseMapper.insert(job); |
200 | ScheduleUtils.createScheduleJob(scheduler, job); | 199 | ScheduleUtils.createScheduleJob(scheduler, job); |
@@ -13,28 +13,27 @@ import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants; | @@ -13,28 +13,27 @@ import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants; | ||
13 | import org.thingsboard.server.common.data.yunteng.core.exception.YtDataValidationException; | 13 | import org.thingsboard.server.common.data.yunteng.core.exception.YtDataValidationException; |
14 | import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage; | 14 | import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage; |
15 | import org.thingsboard.server.common.data.yunteng.dto.*; | 15 | import org.thingsboard.server.common.data.yunteng.dto.*; |
16 | +import org.thingsboard.server.common.data.yunteng.dto.request.ExecuteAttributesDTO; | ||
17 | +import org.thingsboard.server.common.data.yunteng.dto.request.QueryConditionDTO; | ||
16 | import org.thingsboard.server.common.data.yunteng.enums.JobGroupEnum; | 18 | import org.thingsboard.server.common.data.yunteng.enums.JobGroupEnum; |
17 | import org.thingsboard.server.common.data.yunteng.enums.StatusEnum; | 19 | import org.thingsboard.server.common.data.yunteng.enums.StatusEnum; |
18 | import org.thingsboard.server.common.data.yunteng.utils.JacksonUtil; | 20 | import org.thingsboard.server.common.data.yunteng.utils.JacksonUtil; |
19 | import org.thingsboard.server.common.data.yunteng.utils.tools.YtPageData; | 21 | import org.thingsboard.server.common.data.yunteng.utils.tools.YtPageData; |
20 | import org.thingsboard.server.dao.yunteng.entities.ReportFormConfig; | 22 | import org.thingsboard.server.dao.yunteng.entities.ReportFormConfig; |
21 | import org.thingsboard.server.dao.yunteng.mapper.OrganizationMapper; | 23 | import org.thingsboard.server.dao.yunteng.mapper.OrganizationMapper; |
22 | -import org.thingsboard.server.dao.yunteng.mapper.ReportFromConfigMapper; | 24 | +import org.thingsboard.server.dao.yunteng.mapper.ReportFormConfigMapper; |
23 | import org.thingsboard.server.dao.yunteng.service.AbstractBaseService; | 25 | import org.thingsboard.server.dao.yunteng.service.AbstractBaseService; |
24 | import org.thingsboard.server.dao.yunteng.service.YtReportFormConfigService; | 26 | import org.thingsboard.server.dao.yunteng.service.YtReportFormConfigService; |
25 | import org.thingsboard.server.dao.yunteng.service.YtSysJobService; | 27 | import org.thingsboard.server.dao.yunteng.service.YtSysJobService; |
26 | 28 | ||
27 | -import java.util.List; | ||
28 | -import java.util.Map; | ||
29 | -import java.util.Objects; | ||
30 | -import java.util.Optional; | 29 | +import java.util.*; |
31 | import java.util.stream.Collectors; | 30 | import java.util.stream.Collectors; |
32 | 31 | ||
33 | @Slf4j | 32 | @Slf4j |
34 | @Service | 33 | @Service |
35 | @RequiredArgsConstructor | 34 | @RequiredArgsConstructor |
36 | public class YtReportFromConfigServiceImpl | 35 | public class YtReportFromConfigServiceImpl |
37 | - extends AbstractBaseService<ReportFromConfigMapper, ReportFormConfig> | 36 | + extends AbstractBaseService<ReportFormConfigMapper, ReportFormConfig> |
38 | implements YtReportFormConfigService { | 37 | implements YtReportFormConfigService { |
39 | private final OrganizationMapper organizationMapper; | 38 | private final OrganizationMapper organizationMapper; |
40 | private final YtSysJobService ytSysJobService; | 39 | private final YtSysJobService ytSysJobService; |
@@ -43,11 +42,6 @@ public class YtReportFromConfigServiceImpl | @@ -43,11 +42,6 @@ public class YtReportFromConfigServiceImpl | ||
43 | public YtPageData<ReportFormConfigDTO> page(Map<String, Object> queryMap) { | 42 | public YtPageData<ReportFormConfigDTO> page(Map<String, Object> queryMap) { |
44 | String tenantId = | 43 | String tenantId = |
45 | Optional.ofNullable(queryMap.get("tenantId")).map(Object::toString).orElse(null); | 44 | Optional.ofNullable(queryMap.get("tenantId")).map(Object::toString).orElse(null); |
46 | - String name = Optional.ofNullable(queryMap.get("name")).map(Object::toString).orElse(null); | ||
47 | - Integer status = | ||
48 | - Optional.ofNullable(queryMap.get("status")) | ||
49 | - .map(value -> Integer.valueOf(value.toString())) | ||
50 | - .orElse(null); | ||
51 | List<String> organizationIds = | 45 | List<String> organizationIds = |
52 | Optional.ofNullable(queryMap.get("organizationId")) | 46 | Optional.ofNullable(queryMap.get("organizationId")) |
53 | .map( | 47 | .map( |
@@ -63,17 +57,10 @@ public class YtReportFromConfigServiceImpl | @@ -63,17 +57,10 @@ public class YtReportFromConfigServiceImpl | ||
63 | return null; | 57 | return null; |
64 | }) | 58 | }) |
65 | .orElse(null); | 59 | .orElse(null); |
66 | - IPage<ReportFormConfig> page = | ||
67 | - baseMapper.selectPage( | ||
68 | - getPage(queryMap, "create_time", false), | ||
69 | - new LambdaQueryWrapper<ReportFormConfig>() | ||
70 | - .eq(StringUtils.isNotEmpty(tenantId), ReportFormConfig::getTenantId, tenantId) | ||
71 | - .eq(null != status, ReportFormConfig::getStatus, status) | ||
72 | - .like(null != name, ReportFormConfig::getName, name) | ||
73 | - .in( | ||
74 | - null != organizationIds && organizationIds.size() > 0, | ||
75 | - ReportFormConfig::getOrganizationId, | ||
76 | - organizationIds)); | 60 | + queryMap.put("organizationIds", organizationIds); |
61 | + IPage<ReportFormConfigDTO> page = | ||
62 | + baseMapper.getReportFormConfigPage( | ||
63 | + getPage(queryMap, FastIotConstants.DefaultOrder.CREATE_TIME, false), queryMap); | ||
77 | return getPageData(page, ReportFormConfigDTO.class); | 64 | return getPageData(page, ReportFormConfigDTO.class); |
78 | } | 65 | } |
79 | 66 | ||
@@ -93,8 +80,7 @@ public class YtReportFromConfigServiceImpl | @@ -93,8 +80,7 @@ public class YtReportFromConfigServiceImpl | ||
93 | .getExecuteAttributes() | 80 | .getExecuteAttributes() |
94 | .forEach( | 81 | .forEach( |
95 | item -> { | 82 | item -> { |
96 | - if (StringUtils.isEmpty(item.getDevice()) | ||
97 | - || StringUtils.isEmpty(item.getAttribute())) { | 83 | + if (StringUtils.isEmpty(item.getDevice()) || item.getAttributes().isEmpty()) { |
98 | throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); | 84 | throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); |
99 | } | 85 | } |
100 | }); | 86 | }); |
@@ -123,7 +109,7 @@ public class YtReportFromConfigServiceImpl | @@ -123,7 +109,7 @@ public class YtReportFromConfigServiceImpl | ||
123 | 109 | ||
124 | @Override | 110 | @Override |
125 | @Transactional | 111 | @Transactional |
126 | - public boolean deleteReportFormConfig(DeleteDTO deleteDTO) { | 112 | + public boolean deleteReportFormConfig(DeleteDTO deleteDTO) throws SchedulerException { |
127 | if (deleteDTO.getIds().isEmpty()) { | 113 | if (deleteDTO.getIds().isEmpty()) { |
128 | throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); | 114 | throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); |
129 | } | 115 | } |
@@ -146,11 +132,13 @@ public class YtReportFromConfigServiceImpl | @@ -146,11 +132,13 @@ public class YtReportFromConfigServiceImpl | ||
146 | new LambdaQueryWrapper<ReportFormConfig>() | 132 | new LambdaQueryWrapper<ReportFormConfig>() |
147 | .eq(ReportFormConfig::getId, id) | 133 | .eq(ReportFormConfig::getId, id) |
148 | .eq(ReportFormConfig::getTenantId, tenantId)); | 134 | .eq(ReportFormConfig::getTenantId, tenantId)); |
149 | - updateCheckSysJob(queryEntity); | 135 | + if (queryEntity != null) { |
136 | + queryEntity.setStatus(status); | ||
137 | + updateCheckSysJob(queryEntity); | ||
138 | + } | ||
150 | return Optional.ofNullable(queryEntity) | 139 | return Optional.ofNullable(queryEntity) |
151 | .map( | 140 | .map( |
152 | entity -> { | 141 | entity -> { |
153 | - entity.setStatus(status); | ||
154 | baseMapper.updateById(entity); | 142 | baseMapper.updateById(entity); |
155 | return entity.getDTO(ReportFormConfigDTO.class); | 143 | return entity.getDTO(ReportFormConfigDTO.class); |
156 | }) | 144 | }) |
@@ -167,14 +155,26 @@ public class YtReportFromConfigServiceImpl | @@ -167,14 +155,26 @@ public class YtReportFromConfigServiceImpl | ||
167 | if (null == formConfig) { | 155 | if (null == formConfig) { |
168 | throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); | 156 | throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); |
169 | } | 157 | } |
170 | - return formConfig.getDTO(ReportFormConfigDTO.class); | 158 | + return getReportFormConfigDTOByEntity(formConfig); |
159 | + } | ||
160 | + | ||
161 | + @Override | ||
162 | + public ReportFormConfigDTO findReportFormConfigById(String id) { | ||
163 | + return Optional.ofNullable(baseMapper.selectById(id)) | ||
164 | + .map(obj -> getReportFormConfigDTOByEntity(obj)) | ||
165 | + .orElseThrow( | ||
166 | + () -> { | ||
167 | + throw new YtDataValidationException(ErrorMessage.INTERNAL_ERROR.getMessage()); | ||
168 | + }); | ||
171 | } | 169 | } |
172 | 170 | ||
173 | private void addCheckSysJob(ReportFormConfig reportFormConfig) throws SchedulerException { | 171 | private void addCheckSysJob(ReportFormConfig reportFormConfig) throws SchedulerException { |
174 | boolean isNowExecute = | 172 | boolean isNowExecute = |
175 | Objects.equals(reportFormConfig.getExecuteWay(), FastIotConstants.MagicNumber.ZERO); | 173 | Objects.equals(reportFormConfig.getExecuteWay(), FastIotConstants.MagicNumber.ZERO); |
176 | if (isNowExecute) { | 174 | if (isNowExecute) { |
177 | - // 立即执行报表生成,并创建一条报表执行记录 | 175 | + if (Objects.equals(reportFormConfig.getStatus(), StatusEnum.ENABLE.getIndex())) { |
176 | + // 立即执行报表生成,并创建一条报表执行记录 | ||
177 | + } | ||
178 | } else { | 178 | } else { |
179 | createSysJob(reportFormConfig); | 179 | createSysJob(reportFormConfig); |
180 | } | 180 | } |
@@ -186,30 +186,29 @@ public class YtReportFromConfigServiceImpl | @@ -186,30 +186,29 @@ public class YtReportFromConfigServiceImpl | ||
186 | String cronExpression = reportFormConfig.getExecuteContent(); | 186 | String cronExpression = reportFormConfig.getExecuteContent(); |
187 | // 查看之前是否创建了定时任务 | 187 | // 查看之前是否创建了定时任务 |
188 | SysJobDTO sysJobDTO = ytSysJobService.findSysJobBySourceId(reportFormConfig.getId()); | 188 | SysJobDTO sysJobDTO = ytSysJobService.findSysJobBySourceId(reportFormConfig.getId()); |
189 | - | ||
190 | - if (null != sysJobDTO | ||
191 | - && Objects.equals(reportFormConfig.getStatus(), StatusEnum.ENABLE.getIndex())) { | 189 | + boolean enableStatus = |
190 | + Objects.equals(reportFormConfig.getStatus(), StatusEnum.ENABLE.getIndex()); | ||
191 | + if (null != sysJobDTO) { | ||
192 | // 立即执行 | 192 | // 立即执行 |
193 | if (isNowExecute) { | 193 | if (isNowExecute) { |
194 | // 删除定时任务 | 194 | // 删除定时任务 |
195 | ytSysJobService.deleteJob(sysJobDTO); | 195 | ytSysJobService.deleteJob(sysJobDTO); |
196 | - // 立即执行报表生成,并创建一条报表执行记录 | ||
197 | - // TODO hxp | 196 | + if (enableStatus) { |
197 | + // 立即执行报表生成,并创建一条报表执行记录 | ||
198 | + // TODO hxp | ||
199 | + } | ||
198 | } else { | 200 | } else { |
199 | // 修改cron表达式 | 201 | // 修改cron表达式 |
200 | sysJobDTO.setCronExpression(cronExpression); | 202 | sysJobDTO.setCronExpression(cronExpression); |
203 | + sysJobDTO.setStatus(reportFormConfig.getStatus()); | ||
201 | ytSysJobService.saveOrUpdateJob(sysJobDTO); | 204 | ytSysJobService.saveOrUpdateJob(sysJobDTO); |
202 | } | 205 | } |
203 | - } else if (null != sysJobDTO | ||
204 | - && Objects.equals(reportFormConfig.getStatus(), StatusEnum.DISABLE.getIndex())) { | ||
205 | - // 修改定时任务状态 | ||
206 | - sysJobDTO.setStatus(StatusEnum.DISABLE.getIndex()); | ||
207 | - ytSysJobService.updateSysJobStatus(sysJobDTO); | ||
208 | - } else if (null == sysJobDTO | ||
209 | - && Objects.equals(reportFormConfig.getStatus(), StatusEnum.ENABLE.getIndex())) { | 206 | + } else { |
210 | if (isNowExecute) { | 207 | if (isNowExecute) { |
211 | - // 立即执行报表生成,并创建一条报表执行记录 | ||
212 | - // TODO hxp | 208 | + if (enableStatus) { |
209 | + // 立即执行报表生成,并创建一条报表执行记录 | ||
210 | + // TODO hxp | ||
211 | + } | ||
213 | } else { | 212 | } else { |
214 | createSysJob(reportFormConfig); | 213 | createSysJob(reportFormConfig); |
215 | } | 214 | } |
@@ -240,7 +239,7 @@ public class YtReportFromConfigServiceImpl | @@ -240,7 +239,7 @@ public class YtReportFromConfigServiceImpl | ||
240 | sysJobDTO.setTenantId(reportFormConfig.getTenantId()); | 239 | sysJobDTO.setTenantId(reportFormConfig.getTenantId()); |
241 | sysJobDTO.setCronExpression(cronExpression); | 240 | sysJobDTO.setCronExpression(cronExpression); |
242 | sysJobDTO.setConcurrent(StatusEnum.ENABLE.getIndex()); | 241 | sysJobDTO.setConcurrent(StatusEnum.ENABLE.getIndex()); |
243 | - sysJobDTO.setInvokeTarget("reportTask.generateReport(\""+reportId+"\")"); | 242 | + sysJobDTO.setInvokeTarget("reportTask.generateReport(\"" + reportId + "\")"); |
244 | ytSysJobService.saveOrUpdateJob(sysJobDTO); | 243 | ytSysJobService.saveOrUpdateJob(sysJobDTO); |
245 | } | 244 | } |
246 | } | 245 | } |
@@ -250,24 +249,36 @@ public class YtReportFromConfigServiceImpl | @@ -250,24 +249,36 @@ public class YtReportFromConfigServiceImpl | ||
250 | * | 249 | * |
251 | * @param id 配置ID | 250 | * @param id 配置ID |
252 | */ | 251 | */ |
253 | - private void checkAndDeleteJob(String id) { | 252 | + private void checkAndDeleteJob(String id) throws SchedulerException { |
254 | ReportFormConfig config = baseMapper.selectById(id); | 253 | ReportFormConfig config = baseMapper.selectById(id); |
255 | - Optional.ofNullable(config) | ||
256 | - .map( | ||
257 | - obj -> { | ||
258 | - SysJobDTO sysJobDTO = ytSysJobService.findSysJobBySourceId(id); | ||
259 | - if (null != sysJobDTO) { | ||
260 | - try { | ||
261 | - ytSysJobService.deleteJob(sysJobDTO); | ||
262 | - } catch (SchedulerException e) { | ||
263 | - log.error(e.getMessage()); | ||
264 | - } | ||
265 | - } | ||
266 | - return sysJobDTO; | ||
267 | - }) | ||
268 | - .orElseThrow( | ||
269 | - () -> { | ||
270 | - throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); | ||
271 | - }); | 254 | + if (null != config) { |
255 | + SysJobDTO sysJobDTO = ytSysJobService.findSysJobBySourceId(id); | ||
256 | + if (null != sysJobDTO) { | ||
257 | + ytSysJobService.deleteJob(sysJobDTO); | ||
258 | + } | ||
259 | + } | ||
260 | + } | ||
261 | + | ||
262 | + private ReportFormConfigDTO getReportFormConfigDTOByEntity(ReportFormConfig obj) { | ||
263 | + ReportFormConfigDTO dto = new ReportFormConfigDTO(); | ||
264 | + obj.copyToDTO(dto, "executeAttributes"); | ||
265 | + JsonNode jsonNode = obj.getExecuteAttributes(); | ||
266 | + List<ExecuteAttributesDTO> list = new ArrayList<>(); | ||
267 | + for (JsonNode node : jsonNode) { | ||
268 | + ExecuteAttributesDTO attributesDTO = | ||
269 | + JacksonUtil.convertValue(node, ExecuteAttributesDTO.class); | ||
270 | + List<String> attributes = new ArrayList<>(); | ||
271 | + JsonNode attribute = node.get("attributes"); | ||
272 | + for (JsonNode key : attribute) { | ||
273 | + attributes.add(JacksonUtil.convertValue(key, String.class)); | ||
274 | + } | ||
275 | + attributesDTO.setAttributes(attributes); | ||
276 | + list.add(attributesDTO); | ||
277 | + } | ||
278 | + QueryConditionDTO queryCondition = | ||
279 | + JacksonUtil.convertValue(obj.getQueryCondition(), QueryConditionDTO.class); | ||
280 | + dto.setExecuteAttributes(list); | ||
281 | + dto.setQueryCondition(queryCondition); | ||
282 | + return dto; | ||
272 | } | 283 | } |
273 | } | 284 | } |
@@ -48,7 +48,7 @@ public class YtReportGenerateRecordServiceImpl | @@ -48,7 +48,7 @@ public class YtReportGenerateRecordServiceImpl | ||
48 | .orElse(null); | 48 | .orElse(null); |
49 | IPage<ReportGenerateRecord> iPage = | 49 | IPage<ReportGenerateRecord> iPage = |
50 | baseMapper.selectPage( | 50 | baseMapper.selectPage( |
51 | - getPage(queryMap, "", false), | 51 | + getPage(queryMap, "execute_time", false), |
52 | new LambdaQueryWrapper<ReportGenerateRecord>() | 52 | new LambdaQueryWrapper<ReportGenerateRecord>() |
53 | .like( | 53 | .like( |
54 | StringUtils.isNotEmpty(reportConfigName), | 54 | StringUtils.isNotEmpty(reportConfigName), |
@@ -71,16 +71,15 @@ public class YtReportGenerateRecordServiceImpl | @@ -71,16 +71,15 @@ public class YtReportGenerateRecordServiceImpl | ||
71 | if (StringUtils.isEmpty(recordDTO.getId())) { | 71 | if (StringUtils.isEmpty(recordDTO.getId())) { |
72 | baseMapper.insert(reportGenerateRecord); | 72 | baseMapper.insert(reportGenerateRecord); |
73 | } else { | 73 | } else { |
74 | - Optional.ofNullable(recordDTO.getId()) | ||
75 | - .map(id -> baseMapper.selectById(id)) | ||
76 | - .filter(obj -> !obj.getTenantId().equals(recordDTO.getTenantId())) | ||
77 | - .map(record -> baseMapper.updateById(record)) | 74 | + ReportGenerateRecord record = baseMapper.selectById(recordDTO.getId()); |
75 | + Optional.ofNullable(record) | ||
76 | + .map(obj -> baseMapper.updateById(reportGenerateRecord)) | ||
78 | .orElseThrow( | 77 | .orElseThrow( |
79 | () -> { | 78 | () -> { |
80 | throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); | 79 | throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); |
81 | }); | 80 | }); |
82 | } | 81 | } |
83 | - return recordDTO; | 82 | + return reportGenerateRecord.getDTO(ReportGenerateRecordDTO.class); |
84 | } | 83 | } |
85 | 84 | ||
86 | @Override | 85 | @Override |
@@ -111,17 +110,20 @@ public class YtReportGenerateRecordServiceImpl | @@ -111,17 +110,20 @@ public class YtReportGenerateRecordServiceImpl | ||
111 | } | 110 | } |
112 | OrganizationDTO organizationDTO = | 111 | OrganizationDTO organizationDTO = |
113 | ytOrganizationService.findOrganizationById( | 112 | ytOrganizationService.findOrganizationById( |
114 | - reportFormConfigDTO.getId(), reportFormConfigDTO.getTenantId()); | 113 | + reportFormConfigDTO.getOrganizationId(), reportFormConfigDTO.getTenantId()); |
115 | // 创建报表生成记录 | 114 | // 创建报表生成记录 |
116 | ReportGenerateRecordDTO dto = new ReportGenerateRecordDTO(); | 115 | ReportGenerateRecordDTO dto = new ReportGenerateRecordDTO(); |
116 | + LocalDateTime time = LocalDateTime.now(); | ||
117 | dto.setJobId(jobId); | 117 | dto.setJobId(jobId); |
118 | dto.setReportConfigName(reportFormConfigDTO.getName()); | 118 | dto.setReportConfigName(reportFormConfigDTO.getName()); |
119 | dto.setOrganizationName(null != organizationDTO ? organizationDTO.getName() : null); | 119 | dto.setOrganizationName(null != organizationDTO ? organizationDTO.getName() : null); |
120 | - dto.setDataCompare(reportFormConfigDTO.getDataCompare()); | ||
121 | - dto.setExecuteTime(LocalDateTime.now()); | 120 | + dto.setDataCompare(reportFormConfigDTO.getDataType()); |
121 | + dto.setExecuteTime(time); | ||
122 | + dto.setCreateTime(time); | ||
123 | + dto.setCreator(reportFormConfigDTO.getCreator()); | ||
124 | + dto.setTenantId(reportFormConfigDTO.getTenantId()); | ||
122 | dto.setExecuteStatus(StatusEnum.RUNNING.getIndex()); | 125 | dto.setExecuteStatus(StatusEnum.RUNNING.getIndex()); |
123 | dto.setExecuteWay(reportFormConfigDTO.getExecuteWay()); | 126 | dto.setExecuteWay(reportFormConfigDTO.getExecuteWay()); |
124 | - saveOrUpdateReportGenerateRecord(dto); | ||
125 | - return dto; | 127 | + return saveOrUpdateReportGenerateRecord(dto); |
126 | } | 128 | } |
127 | } | 129 | } |
dao/src/main/java/org/thingsboard/server/dao/yunteng/mapper/ReportFormConfigMapper.java
renamed from
dao/src/main/java/org/thingsboard/server/dao/yunteng/mapper/ReportFromConfigMapper.java
1 | package org.thingsboard.server.dao.yunteng.mapper; | 1 | package org.thingsboard.server.dao.yunteng.mapper; |
2 | 2 | ||
3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
4 | +import com.baomidou.mybatisplus.core.metadata.IPage; | ||
4 | import org.apache.ibatis.annotations.Mapper; | 5 | import org.apache.ibatis.annotations.Mapper; |
5 | -import org.thingsboard.server.dao.yunteng.entities.FrpInfo; | 6 | +import org.apache.ibatis.annotations.Param; |
7 | +import org.thingsboard.server.common.data.yunteng.dto.ReportFormConfigDTO; | ||
6 | import org.thingsboard.server.dao.yunteng.entities.ReportFormConfig; | 8 | import org.thingsboard.server.dao.yunteng.entities.ReportFormConfig; |
7 | 9 | ||
8 | -@Mapper | ||
9 | -public interface ReportFromConfigMapper extends BaseMapper<ReportFormConfig> { | 10 | +import java.util.Map; |
10 | 11 | ||
12 | +@Mapper | ||
13 | +public interface ReportFormConfigMapper extends BaseMapper<ReportFormConfig> { | ||
14 | + IPage<ReportFormConfigDTO> getReportFormConfigPage( | ||
15 | + IPage<?> page, @Param("queryMap") Map<String, Object> queryMap); | ||
11 | } | 16 | } |
@@ -12,9 +12,11 @@ public interface YtReportFormConfigService { | @@ -12,9 +12,11 @@ public interface YtReportFormConfigService { | ||
12 | 12 | ||
13 | ReportFormConfigDTO saveOrUpdateReportFormConfig(ReportFormConfigDTO report) throws SchedulerException; | 13 | ReportFormConfigDTO saveOrUpdateReportFormConfig(ReportFormConfigDTO report) throws SchedulerException; |
14 | 14 | ||
15 | - boolean deleteReportFormConfig(DeleteDTO deleteDTO); | 15 | + boolean deleteReportFormConfig(DeleteDTO deleteDTO) throws SchedulerException; |
16 | 16 | ||
17 | ReportFormConfigDTO updateStatusById(String tenantId,Integer status,String id) throws SchedulerException; | 17 | ReportFormConfigDTO updateStatusById(String tenantId,Integer status,String id) throws SchedulerException; |
18 | 18 | ||
19 | ReportFormConfigDTO findReportFormConfigById(String id,String tenantId); | 19 | ReportFormConfigDTO findReportFormConfigById(String id,String tenantId); |
20 | + | ||
21 | + ReportFormConfigDTO findReportFormConfigById(String id); | ||
20 | } | 22 | } |
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | ||
3 | + | ||
4 | +<mapper namespace="org.thingsboard.server.dao.yunteng.mapper.ReportFormConfigMapper"> | ||
5 | + <resultMap id="formConfigDtoMap" type="org.thingsboard.server.common.data.yunteng.dto.ReportFormConfigDTO"> | ||
6 | + <result property="id" column="id"/> | ||
7 | + <result property="name" column="name"/> | ||
8 | + <result property="organizationId" column="organization_id"/> | ||
9 | + <result property="executeWay" column="execute_way"/> | ||
10 | + <result property="executeContent" column="execute_content"/> | ||
11 | + <result property="dataType" column="data_type"/> | ||
12 | + <result property="startTs" column="start_ts"/> | ||
13 | + <result property="endTs" column="end_ts"/> | ||
14 | + <result property="status" column="status"/> | ||
15 | + <result property="remark" column="remark"/> | ||
16 | + <result property="tenantId" column="tenant_id"/> | ||
17 | + <result property="creator" column="creator"/> | ||
18 | + <result property="createTime" column="create_time"/> | ||
19 | + <result property="updater" column="updater"/> | ||
20 | + <result property="updateTime" column="update_time"/> | ||
21 | + <association property="organizationDTO" | ||
22 | + javaType="org.thingsboard.server.common.data.yunteng.dto.OrganizationDTO"> | ||
23 | + <result property="name" column="organization_name"/> | ||
24 | + </association> | ||
25 | + </resultMap> | ||
26 | + | ||
27 | + <sql id="columns"> | ||
28 | + config.id,config.name,config.organization_id,config.execute_way,config.execute_content, | ||
29 | + config.data_type,config.start_ts,config.end_ts,config.status,config.remark,config.create_time,config.creator, | ||
30 | + config.updater,config.update_time,config.tenant_id | ||
31 | + </sql> | ||
32 | + <select id="getReportFormConfigPage" resultMap="formConfigDtoMap"> | ||
33 | + SELECT | ||
34 | + <include refid="columns"/>,io.name as organization_name | ||
35 | + FROM iotfs_report_form_config config | ||
36 | + LEFT JOIN iotfs_organization io ON io.id = config.organization_id | ||
37 | + <where> | ||
38 | + config.tenant_id = #{queryMap.tenantId} | ||
39 | + <if test="queryMap.name !=null and queryMap.name !=''"> | ||
40 | + AND config.name LIKE concat('%',#{queryMap.name}::TEXT,'%') | ||
41 | + </if> | ||
42 | + <if test="queryMap.status !=null"> | ||
43 | + AND config.status = #{queryMap.status} | ||
44 | + </if> | ||
45 | + <if test="queryMap.organizationIds !=null"> | ||
46 | + AND config.organization_id IN | ||
47 | + <foreach collection="queryMap.organizationIds" item="organizationId" open="(" separator="," close=")"> | ||
48 | + #{organizationId} | ||
49 | + </foreach> | ||
50 | + </if> | ||
51 | + </where> | ||
52 | + </select> | ||
53 | +</mapper> |