需求背景
做一个OCR识别的功能,需要导出原图和识别出来的结果的图纸,将数据导出.
解决方案
EasyPOI中可以用字节类型,导出图片,可以将图片存放的url 转成字节,然后导出.但是整个导出过程耗时较久。
具体代码
/**
* 草图OCR识别记录-导出.
*
* @param response: HttpServletResponse.
* @param pageQueryBO:筛选条件.
*/
@RequestMapping(value = "/exportExcel", method = RequestMethod.POST)
public ResponseEntity<ByteArrayResource> exportExcel(@RequestBody BuOrcPicOssRecordPageQueryBO pageQueryBO, HttpServletResponse response) throws IOException {
//导出数据
List<BuOrcPicOssRecordExportBO> list = new ArrayList<>();
// 导出的数据不需要分页
pageQueryBO.setNoNeedPaging(true);
ResultBO<PageBO<List<BuOrcPicOssRecordBO>>> pageBOResultBO = buOrcPicOssRecordService.selectOrcPicOssRecordPageList(pageQueryBO);
List<BuOrcPicOssRecordBO> dataList = pageBOResultBO.getData().getDataList();
if(ObjectUtils.isNotEmpty(dataList)){
list = ModelMapperUtil.mapList(dataList,BuOrcPicOssRecordExportBO.class);
}
// 导出原先的图片和识别后的图片
BASE64Decoder base64Decoder = new BASE64Decoder();
// 解码操作
for(BuOrcPicOssRecordExportBO item:list ){
// Base64 转字节流显示图片
if(ObjectUtils.isNotEmpty(item.getRoofPicUrl())){
byte[] bytes = base64Decoder.decodeBuffer(item.getRoofPicUrl().replace("data:image/png;base64,",""));
item.setRoofPicFile(bytes);
}
// url转字节流显示图片
if(ObjectUtils.isNotEmpty(item.getPicOssUrl())){
byte[] netImgByUrl = ImageUtil.getNetImgByUrl(item.getPicOssUrl());
item.setPicOssFile(netImgByUrl);
}
}
//.xlsx格式
//response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
//.xls格式
response.setContentType("application/vnd.ms-excel;charset=utf-8");
response.setCharacterEncoding("utf-8");
//前端存在跨域不成功,设置可访问
response.setHeader("Access-Control-Allow-Origin","*");
//设置不要缓存
response.setHeader("Pragma", "No-cache");
try {
// 自定义参数-数据行数,下面判断使用.
int listCount =0;
// 循环设置行高
if(!list.isEmpty()){
listCount = list.size();
}
// 这里URLEncoder.encode可以防止中文乱码
String fileName = URLEncoder.encode("草图OCR识别记录", String.valueOf(StandardCharsets.UTF_8));
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");
//设置sheet名
ExportParams params = new ExportParams();
params.setSheetName("草图OCR识别记录");
//设置标题
params.setTitle("草图OCR识别记录");
// 这里需要设置不关闭流
Workbook workbook = ExcelExportUtil.exportExcel(params, BuOrcPicOssRecordExportBO.class, list);
// 如果有内容,则循环赋值行高
if(listCount>0){
Sheet sheet0 = workbook.getSheet("草图OCR识别记录");
for (int i=2;i<listCount+2;i++){
sheet0.getRow(i).setHeight((short)4000);
}
}
//输出流
OutputStream outStream = response.getOutputStream();
//浏览器下载
workbook.write(outStream);
ByteArrayResource byteArrayResource = convertOutputStreamToResource(outStream);
return ResponseEntity.ok().body(byteArrayResource);
} catch (IOException e) {
return ResponseEntity.status(500).body(null);
}
}
/**
* 转换方法 必须得用 public访问.
*
* @param outputStream
* @return
* @throws IOException
*/
public static ByteArrayResource convertOutputStreamToResource(OutputStream outputStream) throws IOException {
// 使用ByteArrayOutputStream来捕获OutputStream的输出
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
// 将原始OutputStream的内容复制到ByteArrayOutputStream中
// 注意:这里假设你有一个方法可以将数据写入outputStream,这里用writeData作为示例
// writeData(outputStream); // 这应该是一个你自定义的方法,用于将数据写入outputStream
// 由于我们不能直接操作原始的outputStream(因为它是只写的,并且数据已经写入),
// 我们假设上面的writeData方法实际上是将数据写入了一个我们可以控制的OutputStream,
// 或者我们在这里模拟写入一些数据到byteArrayOutputStream中。
// 在实际情况中,你需要将你的数据写入byteArrayOutputStream。
// 为了示例,我们直接往byteArrayOutputStream中写一些数据:
String exampleData = "This is some example data that will be in the Excel file.";
byteArrayOutputStream.write(exampleData.getBytes());
// 获取字节数组
byte[] data = byteArrayOutputStream.toByteArray();
// 创建ByteArrayResource
ByteArrayResource resource = new ByteArrayResource(data);
// 返回Resource
return resource;
}
导出的参数类
@ExcelTarget(value = "草图OCR识别记录")
@Data
public class BuOrcPicOssRecordExportBO {
/**
* ltc代理商名称
*/
@Excel(name = "代理商名称", width = 20)
@ContentFontStyle(fontHeightInPoints = 20) // 设置字体大小为20来增加行高
private String ltcAgentName;
/**
* 创建人名称
*/
@Excel(name = "创建人", width = 20)
private String creatorName;
/**
* 创建时间
*/
@Excel(name = "创建时间", width = 20, exportFormat = "yyyy-MM-dd HH:mm:ss")
private Date gmtCreate;
/**
* 图片在oss的路径
*/
private String picOssUrl;
/**
* Excel里面显示图片
*/
@Excel(name = "上传图片", type = 2, width = 60, imageType = 2 )
private byte[] picOssFile;
/**
* 识别成的屋面图形图片Base64
*/
private String roofPicUrl;
/**
* Excel里面显示图片
*/
@Excel(name = "识别后屋面图片", type = 2, width = 60, imageType = 2 )
private byte[] roofPicFile;
/**
* 评价的等级名称
*/
@Excel(name = "评价", width = 20)
private String evaluateLevelName;
/**
* 评价的途径名称
*/
@Excel(name = "评价途径", width = 20)
private String evaluateWayName;
/**
* 评价进度状态 0:未读未评价 1:已读未评价 10:已经评价完成
*
* @see com.chintanneng.ai.enums.EvaluateStateEnum
*/
private Integer evaluateState;
/**
* 图纸/电站id
*/
private Long powerStationId;
/**
* 虚拟电站编码
*/
private String powerStationCode;
/**
* 电站编码-实际电站编码
*/
@Excel(name = "电站编码", width = 20)
private String powerStationRealCode;
/**
* 点评人姓名
*/
@Excel(name = "点评人", width = 20)
private String evaluateUserFullName;
/**
* 点评时间
*/
@Excel(name = "点评时间", width = 20, exportFormat = "yyyy-MM-dd HH:mm:ss")
private Date evaluateTime;
}
ImageUtil 里面的方法
/**
* 获取网络图片转成字节流
* @param strUrl 完整图片地址
* @return 图片资源数组
*/
public static byte[] getNetImgByUrl(String strUrl) {
try {
URL url = new URL(strUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(2 * 1000);
// 通过输入流获取图片数据
InputStream inStream = conn.getInputStream();
// 得到图片的二进制数据
byte[] btImg = readInputStream(inStream);
return btImg;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}