Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7123ef0

Browse files
committed
Java: MultiDataSource 导出 CVAuto 测试报告接口新增在 Excel 上粘贴原图和渲染图
1 parent ae2a3fd commit 7123ef0

File tree

6 files changed

+247
-34
lines changed

6 files changed

+247
-34
lines changed

APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/ExcelUtil.java

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ public static String generateCVAutoReport(List<DetailItem> list, String dir, Str
240240
// 动态计算详情区域的表头行索引
241241
int detailHeaderRowIndex = 1 + 6 + 10; // 标题区(1) + 统计区(标题+6行数据) + 空白行(1) = 17
242242

243-
List<List<Object>> data = prepareData(detailItems, detailHeaderRowIndex + 2);
243+
List<List<Object>> data = prepareData(detailItems, detailHeaderRowIndex + 2, dir);
244244

245245
try {
246246
EasyExcel.write(fileName)
@@ -286,7 +286,7 @@ public static String generateCVAutoReport(List<DetailItem> list, String dir, Str
286286
* @param detailDataStartRow 详情数据在Excel中的起始行号 (1-based)
287287
* @return 包含所有报告数据的列表
288288
*/
289-
private static List<List<Object>> prepareData(List<DetailItem> detailItems, int detailDataStartRow) {
289+
private static List<List<Object>> prepareData(List<DetailItem> detailItems, int detailDataStartRow, String dir) {
290290
List<List<Object>> list = new ArrayList<>();
291291

292292
// --- 第 1 部分:主标题 ---
@@ -322,8 +322,11 @@ private static List<List<Object>> prepareData(List<DetailItem> detailItems, int
322322

323323
List<Object> detailRow = new ArrayList<>();
324324
// A-C: 基础信息
325-
detailRow.add(item.getImageName());
326-
detailRow.add(item.getRenderName());
325+
File imgFile = new File(item.getImageName()); // dir + item.getImageName());
326+
File renderFile = new File(item.getRenderName()); // dir + item.getRenderName());
327+
328+
detailRow.add(imgFile.exists() ? imgFile : imgFile.getAbsolutePath());
329+
detailRow.add(renderFile.exists() ? renderFile : renderFile.getAbsolutePath());
327330
// D-F: 手动输入数据
328331
detailRow.add(item.getTargetCount());
329332
detailRow.add(item.getCorrectCount());
@@ -378,11 +381,11 @@ private static WriteCellData<String> createFormulaCell(String formula) {
378381

379382
private static List<DetailItem> getMockDetailData() {
380383
List<DetailItem> list = new ArrayList<>();
381-
list.add(new DetailItem("image_001.jpg", "image_001_res.jpg", 5, 4, 1, "{ \"predictions\": [...] }", "✅", ""));
382-
list.add(new DetailItem("image_002.jpg", "image_002_res.jpg", 3, 3, 0, "{ \"predictions\": [...] }", "✅", ""));
383-
list.add(new DetailItem("image_003.jpg", "image_003_res.jpg", 8, 6, 3, "{ \"predictions\": [...] }", "❌", ""));
384-
list.add(new DetailItem("image_004.jpg", "image_004_res.jpg", 1, 0, 1, "{ \"predictions\": [...] }" ,"❌", ""));
385-
list.add(new DetailItem("image_005.jpg", "image_005_res.jpg", 10, 10, 0, "{ \"predictions\": [...] }", "✅", ""));
384+
list.add(new DetailItem("image_001.jpg", "image_001_render.jpg", 5, 4, 1, "{ \"predictions\": [...] }", "✅", ""));
385+
list.add(new DetailItem("image_002.jpg", "image_002_render.jpg", 3, 3, 0, "{ \"predictions\": [...] }", "✅", ""));
386+
list.add(new DetailItem("image_003.jpg", "image_003_render.jpg", 8, 6, 3, "{ \"predictions\": [...] }", "❌", ""));
387+
list.add(new DetailItem("image_004.jpg", "image_004_render.jpg", 1, 0, 1, "{ \"predictions\": [...] }" ,"❌", ""));
388+
list.add(new DetailItem("image_005.jpg", "image_005_render.jpg", 10, 10, 0, "{ \"predictions\": [...] }", "✅", ""));
386389
return list;
387390
}
388391

APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/boot/DemoController.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.beans.factory.annotation.Autowired;
2828
import org.springframework.http.*;
2929
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
30+
import org.springframework.http.converter.StringHttpMessageConverter;
3031
import org.springframework.stereotype.Service;
3132
import org.springframework.web.bind.annotation.*;
3233
import org.springframework.web.client.RestClientResponseException;
@@ -1862,7 +1863,20 @@ else if (recordType > 0) {
18621863
static {
18631864
try { // 支持 PATCH 方法,需要 Maven 依赖 org.apache.httpcomponents.client5:httpclient5
18641865
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
1866+
requestFactory.setConnectTimeout(30000);
1867+
//requestFactory.setReadTimeout(120000);
1868+
requestFactory.setConnectionRequestTimeout(30000);
1869+
1870+
//requestFactory.setBufferRequestBody(true); // spring-framework 6.1 以下启用请求体缓冲
1871+
18651872
CLIENT.setRequestFactory(requestFactory);
1873+
1874+
// 添加大请求支持的消息转换器
1875+
CLIENT.getMessageConverters().forEach(converter -> {
1876+
if (converter instanceof StringHttpMessageConverter) {
1877+
((StringHttpMessageConverter) converter).setWriteAcceptCharset(false);
1878+
}
1879+
});
18661880
}
18671881
catch (Throwable e) {
18681882
e.printStackTrace();

APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/boot/FileController.java

Lines changed: 144 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,15 @@
1010
import apijson.ExcelUtil;
1111
import apijson.RequestMethod;
1212
import apijson.StringUtil;
13+
import apijson.fastjson2.JSON;
14+
import apijson.JSONResponse;
1315
import com.alibaba.fastjson2.JSONArray;
16+
import jakarta.servlet.http.HttpSession;
1417
import org.apache.commons.io.FileUtils;
18+
import org.springframework.beans.factory.annotation.Autowired;
1519
import org.springframework.core.io.InputStreamResource;
1620
import org.springframework.http.HttpHeaders;
21+
import org.springframework.http.HttpMethod;
1722
import org.springframework.http.MediaType;
1823
import org.springframework.http.ResponseEntity;
1924
import org.springframework.stereotype.Controller;
@@ -28,6 +33,8 @@
2833

2934
import apijson.demo.DemoParser;
3035

36+
import javax.imageio.ImageIO;
37+
3138
import static com.google.common.io.Files.getFileExtension;
3239

3340
/**文件相关的控制器,包括上传、下载、浏览等
@@ -77,6 +84,7 @@ public class FileController {
7784
public static final List<String> VIDEO_SUFFIXES = Arrays.asList("mp4");
7885
public static final List<String> IMG_SUFFIXES = Arrays.asList("jpg", "jpeg", "png");
7986
private static List<String> fileNames = null;
87+
8088
@GetMapping("/files")
8189
@ResponseBody
8290
public JSONObject files() {
@@ -126,8 +134,7 @@ public JSONObject upload(@RequestParam("file") MultipartFile file) {
126134
res.put("path", "/download/" + name);
127135
res.put("size", file.getBytes().length);
128136
return new DemoParser().extendSuccessResult(res);
129-
}
130-
catch (Exception e) {
137+
} catch (Exception e) {
131138
e.printStackTrace();
132139
return new DemoParser().newErrorResult(e);
133140
}
@@ -191,10 +198,15 @@ private MediaType determineContentType(String fileName) {
191198
}
192199
}
193200

194-
@GetMapping("/download/cv/report/{reportId}")
201+
@Autowired
202+
DemoController demoController;
203+
204+
@GetMapping("/download/cv/report/{id}")
195205
@ResponseBody
196-
public ResponseEntity<Object> downloadCVReport(@PathVariable(name = "reportId") String reportId) throws FileNotFoundException, IOException {
197-
String name = "CVAuto_report_" + reportId + ".xlsx";
206+
public ResponseEntity<Object> downloadCVReport(@PathVariable(name = "id") String idStr, HttpSession session) throws FileNotFoundException, IOException {
207+
long reportId = Long.parseLong(idStr);
208+
boolean isLast = reportId <= 0;
209+
String name = "CVAuto_report_" + (isLast ? "last" : reportId) + ".xlsx";
198210
String path = fileUploadRootDir + name;
199211
File file = new File(path);
200212
long size = file.exists() ? file.length() : 0;
@@ -207,15 +219,22 @@ public ResponseEntity<Object> downloadCVReport(@PathVariable(name = "reportId")
207219

208220
{ // TestRecord <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
209221
JSONObject testRecord = new JSONObject();
210-
testRecord.put("reportId", reportId);
211-
testRecord.put("@column", "documentId");
222+
if (isLast) {
223+
testRecord.put("@order", "reportId-");
224+
} else {
225+
testRecord.put("reportId", reportId);
226+
}
227+
testRecord.put("@column", "reportId,documentId,randomId,sameIds");
228+
212229
request.put("TestRecord", testRecord);
213230
} // TestRecord >>>>>>>>>>>>>>>>>>>>>>>>>>>>>
214231

215232
{ // [] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
216233
JSONObject item = new JSONObject();
217234
item.put("count", 3);
235+
//item.put("count", 0);
218236
item.put("join", "&/TestRecord");
237+
//item.put("join", "@/TestRecord");
219238

220239
{ // Random <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
221240
JSONObject random = new JSONObject();
@@ -225,27 +244,83 @@ public ResponseEntity<Object> downloadCVReport(@PathVariable(name = "reportId")
225244
random.put("@combine", "file[>,img[>");
226245
random.put("file[>", 0);
227246
random.put("img[>", 0);
247+
228248
item.put("Random", random);
229249
} // Random >>>>>>>>>>>>>>>>>>>>>>>>>>>>>
230250

231251
{ // TestRecord <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
232252
JSONObject testRecord = new JSONObject();
233-
testRecord.put("randomId@", "/Random/id");
234253
testRecord.put("@column", "id,total,correct,wrong,compare,response");
235-
testRecord.put("reportId", reportId);
254+
testRecord.put("randomId@", "/Random/id");
255+
testRecord.put("documentId@", "TestRecord/documentId");
256+
257+
//testRecord.put("idx{}@", "TestRecord/sameIds");
258+
if (isLast) {
259+
testRecord.put("reportId@", "TestRecord/reportId");
260+
//testRecord.put("@combine", "idx | reportId@");
261+
} else {
262+
testRecord.put("reportId", reportId);
263+
//testRecord.put("@combine", "idx | reportId");
264+
}
265+
//testRecord.put("@key", "idx:(id)");
266+
//testRecord.put("@combine", "idx | reportId");
267+
236268
testRecord.put("total>=", 0);
237269
testRecord.put("correct>=", 0);
238270
testRecord.put("wrong>=", 0);
239271
testRecord.put("@order", "date-");
272+
240273
item.put("TestRecord", testRecord);
241274
} // TestRecord >>>>>>>>>>>>>>>>>>>>>>>>>>>>>
242275

243276
request.put("[]", item);
244277
} // [] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
245278

279+
{ // TestRecord[] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
280+
JSONObject item = new JSONObject();
281+
282+
{ // TestRecord <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
283+
JSONObject testRecord = new JSONObject();
284+
testRecord.put("@column", "id,randomId,total,correct,wrong,compare,response");
285+
testRecord.put("id{}@", "TestRecord/sameIds");
286+
testRecord.put("documentId@", "TestRecord/documentId");
287+
if (isLast) {
288+
testRecord.put("reportId@", "TestRecord/reportId");
289+
} else {
290+
testRecord.put("reportId", reportId);
291+
}
292+
testRecord.put("total>=", 0);
293+
testRecord.put("correct>=", 0);
294+
testRecord.put("wrong>=", 0);
295+
testRecord.put("@order", "date-");
296+
297+
item.put("TestRecord", testRecord);
298+
} // TestRecord >>>>>>>>>>>>>>>>>>>>>>>>>>>>>
299+
300+
request.put("TestRecord[]", item);
301+
302+
} // TestRecord[] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>
303+
246304
DemoParser parser = new DemoParser(RequestMethod.GET, false);
247305
JSONObject response = parser.parseResponse(request);
306+
if (! JSONResponse.isSuccess(response)) {
307+
throw new IOException(JSONResponse.getMsg(response));
308+
}
309+
310+
// JSONObject lastTr = response.getJSONObject("TestRecord");
311+
// long documentId = lastTr == null ? 0 : lastTr.getLongValue("documentId");
312+
// long randomId = lastTr == null ? 0 : lastTr.getLongValue("randomId");
313+
if (isLast) {
314+
JSONObject lastTr = response.getJSONObject("TestRecord");
315+
reportId = lastTr == null ? 0 : lastTr.getLongValue("reportId");
316+
if (reportId > 0) {
317+
name = "CVAuto_report_" + reportId + ".xlsx";
318+
path = fileUploadRootDir + name;
319+
}
320+
}
321+
248322
JSONArray array = response.getJSONArray("[]");
323+
JSONArray trArr = response.getJSONArray("TestRecord[]");
249324

250325
List<ExcelUtil.DetailItem> list = new ArrayList<>();
251326
if (array != null) {
@@ -258,19 +333,75 @@ public ResponseEntity<Object> downloadCVReport(@PathVariable(name = "reportId")
258333
}
259334
if (testRecord == null) {
260335
testRecord = new JSONObject();
336+
if (trArr != null) {
337+
int found = -1;
338+
for (int j = 0; j < trArr.size(); j++) {
339+
JSONObject tr = trArr.getJSONObject(j);
340+
long randomId = tr == null ? 0 : tr.getLongValue("randomId");
341+
if (randomId <= 0 || ! Objects.equals(randomId, random.getLongValue("id"))) {
342+
continue;
343+
}
344+
345+
testRecord = tr;
346+
found = j;
347+
break;
348+
}
349+
350+
if (found >= 0) {
351+
trArr.remove(found);
352+
}
353+
}
261354
}
262355

263356
String fn = random.getString("file");
264357
int ind = fn.lastIndexOf(".");
265358
String nfn = fn.substring(0, ind) + "_render" + fn.substring(ind);
359+
360+
String resStr = testRecord.getString("response");
361+
362+
String img = random.getString("img");
363+
JSONObject resObj = StringUtil.isEmpty(img) ? null : JSON.parseObject(resStr);
364+
365+
int l = resStr == null ? 0 : resStr.length();
366+
if (l > 32767) { // EasyExcel 单元格最长字符数限制
367+
resStr = resStr.substring(0, 20000) + " ... " + resStr.substring(l - 12760);
368+
}
369+
370+
boolean hasResult = resObj != null && ! resObj.isEmpty();
371+
if (hasResult) {
372+
try {
373+
JSONObject renderReq = new JSONObject();
374+
renderReq.put("img", img);
375+
renderReq.put("data", resObj);
376+
String body = renderReq.toJSONString();
377+
HttpHeaders headers = new HttpHeaders();
378+
String renderStr = demoController.sendRequest(session, HttpMethod.POST, "http://localhost:3003/cv/render", body, headers);
379+
renderStr = StringUtil.trim(renderStr);
380+
if (renderStr.length() > 100) {
381+
File renderFile = new File(fileUploadRootDir + nfn);
382+
try (FileOutputStream fos = new FileOutputStream(renderFile)) {
383+
int commaInd = renderStr.startsWith("data:image/") ? -1 : renderStr.indexOf("base64,");
384+
String base64 = commaInd < 0 ? renderStr : renderStr.substring(commaInd + "base64,".length());
385+
byte[] bytes = Base64.getDecoder().decode(base64);
386+
fos.write(bytes);
387+
fos.flush();
388+
} catch (Throwable e) {
389+
e.printStackTrace();
390+
}
391+
}
392+
} catch (Throwable e) {
393+
e.printStackTrace();
394+
}
395+
}
396+
266397
list.add(new ExcelUtil.DetailItem(
267-
fn,
268-
nfn, // TODO 调用 JSONResponse.js 来渲染
398+
fileUploadRootDir + fn,
399+
fileUploadRootDir + nfn, // TODO 调用 JSONResponse.js 来渲染
269400
testRecord.getIntValue("total"),
270401
testRecord.getIntValue("correct"),
271402
testRecord.getIntValue("wrong"),
272-
testRecord.getString("response"),
273-
"✅",
403+
resStr,
404+
hasResult ? "✅" : "❌",
274405
testRecord.getString("compare")
275406
));
276407
}

APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/application.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ spring:
33
multipart:
44
max-file-size: 10MB
55
max-request-size: 10MB
6+
enabled: true
7+
file-size-threshold: 2KB
68
# If using flyway-core dependency, either comment this out or use @FlywayDatasource in DemoDataSourceConfig
79
# flyway:
810
# url: ${spring.datasource.hikari.jdbc-url}

APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/cv/apijson/JSONResponse.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2582,8 +2582,8 @@ var JSONResponse = {
25822582
return item.degree || item.rotate || item.angle || item.perspective || item.d || item.r || item.p || item.a
25832583
},
25842584

2585-
drawDetections: function(canvas, detection, options, img, ctx) {
2586-
if (!detection || typeof detection !== 'object') {
2585+
drawDetections: function(canvas, detection, options, img, ctx, isClear) {
2586+
if (Object.keys(JSONResponse.isObject(detection) ? detection : {}) <= 0) {
25872587
console.error('drawDetections: invalid detection input');
25882588
return;
25892589
}
@@ -2595,7 +2595,9 @@ var JSONResponse = {
25952595
const isRoot = ctx == null;
25962596
if (isRoot) {
25972597
ctx = canvas.getContext('2d');
2598-
ctx.clearRect(0, 0, width, height);
2598+
if (isClear != false) {
2599+
ctx.clearRect(0, 0, width, height);
2600+
}
25992601
}
26002602
ctx.lineWidth = Math.max(1, Math.min(8, height * 0.005));
26012603
ctx.font = `bold ${fontSize}px sans-serif`;

0 commit comments

Comments
 (0)