大文件word生成的处理与解决策略

前言

对于简单word文档的生成导出,java已经有着很多技术来进行处理,在有着相对固定的格式样板下,采用word模板导出相对会是比较好的选择。但是当数据量且包含大量图片后,采用模板导出就显得无力了,模板的缺点是无法应对动态复杂的数据文档生成,这时候采用动态生成word是唯一的选择。

问题背景:需要生成一个包含大量图片表格的word文档,该文档内容在百兆与1G中间

在这里插入图片描述
可以看到该模板是一个相当复杂的文件,既需要对不同类型的图片设置不同的格式还需要动态生成每个类型表格的位置,并将图片插入的word文件当中去

代码处理

controller:

package com.wlh.zetc.restore.controller;import com.wlh.zetc.common.core.util.R;
import com.wlh.zetc.restore.manage.LedgerSequenceManage;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** 台账生成** @author wanghailin* @date 2024-05-23 14:19:56*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/restoreLedger" )
@Tag(description = "restoreLedger" , name = "台账生成" )
//@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
public class LedgerSequenceController {private final LedgerSequenceManage ledgerSequenceManage;/*** 通过乡镇id来生成台账* @param regionId* @return R*/@Operation(summary = "通过乡镇id来生成台账" , description = "通过乡镇id来生成台账" )@GetMapping("/{regionId}" )
//	@PreAuthorize("@pms.hasPermission('zetc_ledger_generate')" )public R getById(@PathVariable("regionId" ) Long regionId) {//log.info("Request thread=>start");System.out.println("Request thread=>start");ledgerSequenceManage.generateAndUpload(regionId);//Log.info("Request thread=>end");System.out.println("Request thread=>end");return R.ok("台账生成中,请稍后到台账中心下载最新文档");}
}

Manage:

package com.wlh.zetc.restore.manage;import cn.hutool.core.date.DateUtil;
import com.wlh.zetc.common.data.tenant.TenantContextHolder;
import com.wlh.zetc.common.security.util.SecurityUtils;
import com.wlh.zetc.restore.bo.SubRegionBO;
import com.wlh.zetc.restore.entity.Activity;
import com.wlh.zetc.restore.entity.RestoreFileEntity;
import com.wlh.zetc.restore.entity.RestoreRegionEntity;
import com.wlh.zetc.restore.enums.LedgerTypeEnum;
import com.wlh.zetc.restore.service.*;
import com.wlh.zetc.restore.service.impl.QiniuServiceImpl;
import com.wlh.zetc.restore.utils.FormatProcessToWordUtils;
import com.wlh.zetc.restore.utils.StrategicChoicesUtils;
import com.wlh.zetc.restore.utils.TextUtils;
import lombok.AllArgsConstructor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;/*** 至农台账导出顺序梳理管理** @author wanghailin* @date 2024-05-8 15:49:33*/
@Service
@AllArgsConstructor
public class LedgerSequenceManage {private final RestoreFileService fileService;private final RestoreInStoreService inStoreService;private final RestoreMatterService matterService;private final RestoreOutStoreService outStoreService;private final RestorePatrolTaskService patrolTaskService;private final RestoreUsePlanService usePlanService;private final List<List<Activity>> activities;private final RestoreRegionService regionService;private final StrategicChoicesUtils strategicChoicesUtils;private final FormatProcessToWordUtils formatProcessToWordUtils;private final QiniuServiceImpl qiniuService;//通过乡镇id,来给所在乡镇下的村数据排序public List<List<Activity>> sequence(Long regionId,String streetTown){//清空数据收集池中的数据strategicChoicesUtils.reset();//1.根据乡镇id拿到该乡镇的名称//2.拿到该乡镇下所有的村id(分为2种情况)//2.1 村id集合String groupSubRegionId = regionService.getGroupSubRegionId(regionId);//2.2 村id单独List<SubRegionBO> subRegionList = regionService.getSubRegionId(regionId);//乡镇为单位//发货单(照片)List<Activity> materialDeliveryData = fileService.getMaterialDeliveryData(groupSubRegionId);//物资到货(照片)List<Activity> inStoreData = inStoreService.getInStoreData(groupSubRegionId);//控地巡视(照片)List<Activity> patrolLandData = patrolTaskService.getPatrolLandData(groupSubRegionId);//旱地种植结构调整照片List<Activity> apsdData = fileService.getAPSDData(groupSubRegionId);//产品照片List<Activity> productData = fileService.getProductData(groupSubRegionId);//会议照片List<Activity> meetData = fileService.getMeetData(groupSubRegionId);//喷施路径照片List<Activity> sprayPathData = usePlanService.getSprayPathData(groupSubRegionId);//数据汇集strategicChoicesUtils.collect(materialDeliveryData).collect(inStoreData).collect(patrolLandData).collect(apsdData).collect(productData).collect(meetData).collect(sprayPathData);//村为单位//出库、施工、回收subRegionList.forEach(subRegion -> {//用于村分隔处理List<Activity> villageSeparation = new ArrayList<>();Activity village = new Activity();village.setRegionName(subRegion.getRegionName());village.setSeparateFlag(true);villageSeparation.add(village);strategicChoicesUtils.collect(villageSeparation);List<String> matterNameList = matterService.getMatterName(Long.valueOf(subRegion.getRegionId()));if (!matterNameList.isEmpty()) {matterNameList.forEach(matterName -> {//出库(照片)List<Activity> outStoreData = outStoreService.getOutStoreData(subRegion.getRegionId(), matterName);//施工过程(照片)List<Activity> usePlanData = usePlanService.getUsePlanData(subRegion.getRegionId(), matterName);//包装袋回收(照片)(需签名)List<Activity> packBackData = usePlanService.getPackBackData(subRegion.getRegionId(), matterName);strategicChoicesUtils.collect(outStoreData).collect(usePlanData).collect(packBackData);});}//水分管理(照片)List<Activity> patrolWaterData = patrolTaskService.getPatrolWaterData(subRegion.getRegionId());strategicChoicesUtils.collect(patrolWaterData);});//自定义规制处理器return strategicChoicesUtils.handle(strategicChoicesUtils.getCollectedListActivities(),streetTown);}//异步调用该方法生成并上传文档@Asyncpublic void generateAndUpload(Long regionId){try {
//			Log.info("Ledger generation thread => start");System.out.println("Ledger generation thread => start");RestoreRegionEntity region = regionService.getById(regionId);String streetTown = region.getRegionName();List<List<Activity>> sequence = sequence(regionId,streetTown);InputStream inputStream = formatProcessToWordUtils.exportActivitiesToWord(sequence);// 上传到服务器String filename = streetTown + DateUtil.today() +"-"+ System.currentTimeMillis()/1000+".docx";String project = "ledger"+ TenantContextHolder.getTenantId()+"/";String key = project+ TextUtils.generateFileName(filename);// 上传完后的伪地址String pseudoAddress = qiniuService.uploadImage2qiniu(inputStream, key);strategicChoicesUtils.reset();// 获取到的地址保存在数据库表中,以供后续下载(放在文件表中使用不同类型区分)RestoreFileEntity wordFile = new RestoreFileEntity();wordFile.setRegionId(regionId);wordFile.setFileUrl(pseudoAddress);wordFile.setFileType(LedgerTypeEnum.LEDGER.getType());wordFile.setFileUse(LedgerTypeEnum.LEDGER.getUse());wordFile.setFileSuffix(LedgerTypeEnum.LEDGER.getSuffix());
//			wordFile.setCreateBy(SecurityUtils.getUser().getUsername());wordFile.setCreateBy("test");fileService.save(wordFile);
//			Log.info("Ledger generation thread => end");System.out.println("Ledger generation thread => end");} catch (Exception e) {e.printStackTrace();}}}

Util:

package com.wlh.zetc.restore.utils;import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.wlh.zetc.restore.entity.Activity;
import com.wlh.zetc.restore.enums.GenerateTypeEnum;
import com.wlh.zetc.restore.service.impl.QiniuServiceImpl;
import lombok.AllArgsConstructor;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHeight;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblWidth;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTrPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblWidth;
import org.springframework.stereotype.Service;import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.math.BigInteger;
import java.util.List;
/*** 至农台账生成工具类** @author wanghailin* @date 2024-05-18 10:49:33*/
@Service
@AllArgsConstructor
public class FormatProcessToWordUtils {private final QiniuServiceImpl qiniuService;public InputStream exportActivitiesToWord(List<List<Activity>> activities) throws Exception {InputStream inputStream = null;try (XWPFDocument document = new XWPFDocument()) {for (int activityListIndex = 0; activityListIndex < activities.size(); activityListIndex++) {for (int activityIndex = 0; activityIndex < activities.get(activityListIndex).size(); activityIndex++) {Activity activity = activities.get(activityListIndex).get(activityIndex);if(activity.getSeparateFlag() != null && activity.getSeparateFlag()){if(StringUtils.isNotEmpty(activity.getRegionName())){for (char ch : activity.getRegionName().toCharArray()) {XWPFParagraph paragraph = document.createParagraph();paragraph.setAlignment(ParagraphAlignment.CENTER); // 设置段落居中XWPFRun run = paragraph.createRun();run.setText(String.valueOf(ch)); // 设置文本为当前字符run.setBold(true); // 设置加粗run.setFontFamily("宋体"); // 设置字体为宋体run.setFontSize(72); // 设置字体大小为72号// 换行,每个字一行if (ch != activity.getRegionName().charAt(activity.getRegionName().length() - 1)) {run.addBreak();}}}// 在内容后添加分页符XWPFParagraph breakParagraph = document.createParagraph();XWPFRun breakRun = breakParagraph.createRun();breakRun.addBreak(BreakType.PAGE);}// 标题仅在第一个Activity中添加if (activityIndex == 0) {XWPFParagraph titleParagraph = document.createParagraph();titleParagraph.setAlignment(ParagraphAlignment.CENTER);XWPFRun titleRun = titleParagraph.createRun();titleRun.setText(activity.getTitle());titleRun.setBold(true);titleRun.setFontFamily("宋体");titleRun.setFontSize(22); // 二号字体大约是22pt}if (activity != null && activity.getType() != null){if(!activity.getType().equals(GenerateTypeEnum.PATROL.getCode())|| !activity.getType().equals(GenerateTypeEnum.DELIVERY.getCode())){// 次标题XWPFParagraph subTitleParagraph = document.createParagraph();subTitleParagraph.setAlignment(ParagraphAlignment.CENTER);XWPFRun subTitleRun = subTitleParagraph.createRun();subTitleRun.setText(getCircleNumber(activityIndex + 1)); // 使用圆圈数字编号subTitleRun.setBold(true);subTitleRun.setFontFamily("宋体");subTitleRun.setFontSize(22);}}//发货单 1*n 表格if (activity != null && activity.getType() != null) {if (activity.getType().equals(GenerateTypeEnum.DELIVERY.getCode())) {// 表格List<String> urls = activity.getUrls(); // 图片URL列表int rows = 0;if (urls != null && urls.size() > 0) {rows = urls.size(); // n行,每个URL一个单元格}XWPFTable table = document.createTable(rows, 1); // 创建n*1的表格// 设置表格宽度CTTblWidth width = table.getCTTbl().addNewTblPr().addNewTblW();width.setType(STTblWidth.DXA);width.setW(BigInteger.valueOf(8500)); // 将宽度设置为原来的两倍,大约30.06厘米try (CloseableHttpClient httpClient = HttpClients.createDefault()) {if (urls != null && urls.size() > 0) {// 填充表格数据并设置单元格宽度for (int i = 0; i < urls.size(); i++) {XWPFTableRow row = table.getRow(i); // 获取当前行XWPFTableCell cell = row.getCell(0); // 获取行中的唯一单元格cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);XWPFParagraph cellParagraph = cell.getParagraphs().get(0);cellParagraph.setAlignment(ParagraphAlignment.CENTER);XWPFRun run = cellParagraph.createRun();run.setBold(true); // 设置文本加粗// 设置单元格高度CTTrPr trpr = row.getCtRow().isSetTrPr() ? row.getCtRow().getTrPr() : row.getCtRow().addNewTrPr();CTHeight ht = trpr.sizeOfTrHeightArray() > 0 ? trpr.getTrHeightArray(0) : trpr.addNewTrHeight();if (StringUtils.isNotEmpty(activity.getTitle()) && i <= 2) {ht.setVal(BigInteger.valueOf(6350)); // 设置行高为11.2厘米对应的DXA单位} else {ht.setVal(BigInteger.valueOf(6550)); // 设置行高为12厘米对应的DXA单位}download(run, httpClient, urls.get(i), activity.getType()); // 假设download方法用于处理图片下载和显示}}} catch (IOException e) {e.printStackTrace();}} else {// 表格List<String> urls = activity.getUrls(); // 图片URL列表int rows = 0;if (urls != null && urls.size() > 0) {rows = (int) Math.ceil(urls.size() / 2.0);}XWPFTable table = document.createTable(rows, 2);// 设置表格宽度CTTblWidth width = table.getCTTbl().addNewTblPr().addNewTblW();width.setType(STTblWidth.DXA);width.setW(BigInteger.valueOf(8500)); // 大约15.03厘米try (CloseableHttpClient httpClient = HttpClients.createDefault()) {if (urls != null && urls.size() > 0) {// 填充表格数据并设置单元格高度for (int i = 0; i < urls.size(); i++) {int rowIndex = i / 2;int colIndex = i % 2;XWPFTableRow row = table.getRow(rowIndex);// 确保行有足够的单元格while (row.getTableCells().size() <= colIndex) {row.createCell();}XWPFTableCell cell = row.getCell(colIndex);cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);XWPFParagraph cellParagraph = cell.getParagraphs().get(0);cellParagraph.setAlignment(ParagraphAlignment.CENTER);XWPFRun run = cellParagraph.createRun();run.setBold(true); // 设置文本加粗// 设置单元格高度CTTrPr trpr = row.getCtRow().isSetTrPr() ? row.getCtRow().getTrPr() : row.getCtRow().addNewTrPr();CTHeight ht = trpr.sizeOfTrHeightArray() > 0 ? trpr.getTrHeightArray(0) : trpr.addNewTrHeight();if (StringUtils.isNotEmpty(activity.getTitle()) && i <= 4) {ht.setVal(BigInteger.valueOf(6350)); // 设置行高为11.2厘米对应的DXA单位} else {ht.setVal(BigInteger.valueOf(6550)); // 设置行高为12厘米对应的DXA单位}download(run, httpClient, urls.get(i), activity.getType());}}} catch (IOException e) {e.printStackTrace();}}}// 在每个Activity处理完毕后添加分页符XWPFParagraph breakParagraph = document.createParagraph();XWPFRun breakRun = breakParagraph.createRun();breakRun.addBreak(BreakType.PAGE);}}// 保存Word文件到InputStreamByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();try {document.write(byteArrayOutputStream);} finally {byteArrayOutputStream.close();}// 创建InputStreaminputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());}return inputStream;}/*** 根据序列号生成对应的带圈数字。* @param number 序列号(1到10)* @return 带圈数字的字符串表示,如果序列号超出范围,则返回null。*/public String getCircleNumber(int number) {if (number < 1 || number > 10) {return null; // 序列号超出范围}return String.valueOf((char) ('\u2460' + number - 1));}/*** 根据url下载图片*/public void download(XWPFRun run, CloseableHttpClient httpClient, String url,Integer type) throws UnsupportedEncodingException {// 下载并插入图片// 拼接出可以访问下载得七牛云图片地址String downloadUrl = qiniuService.getPrivateDownloadUrl(url);HttpGet httpGet = new HttpGet(downloadUrl);try (CloseableHttpResponse response = httpClient.execute(httpGet)) {if (response.getStatusLine().getStatusCode() == 200) {// 将图片内容缓存到内存中ByteArrayOutputStream baos = new ByteArrayOutputStream();response.getEntity().writeTo(baos);byte[] imageBytes = baos.toByteArray();// 从缓存的数据创建一个新的ByteArrayInputStream用于读取图片尺寸InputStream sizeStream = new ByteArrayInputStream(imageBytes);BufferedImage image = ImageIO.read(sizeStream);double originalWidth = image.getWidth();double originalHeight = image.getHeight();double aspectRatio = originalHeight / originalWidth;Integer width = 200;// 根据宽度和宽高比计算高度if (type.equals(GenerateTypeEnum.DELIVERY.getCode())){width = width * 2;}double widthEmus = Units.toEMU(width); // 设定的宽度,单位为EMUdouble heightEmus = widthEmus * aspectRatio; // 根据宽高比计算的高度,单位为EMUif(heightEmus > 5000000.0){heightEmus = heightEmus * 0.75;}// 从缓存的数据创建一个新的ByteArrayInputStream用于插入图片InputStream insertStream = new ByteArrayInputStream(imageBytes);// 插入图片run.addPicture(insertStream, XWPFDocument.PICTURE_TYPE_JPEG, url, (int) widthEmus, (int) heightEmus);}} catch (ClientProtocolException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (InvalidFormatException e) {e.printStackTrace();}}
}

Util:

package com.wlh.zetc.restore.utils;import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.wlh.zetc.restore.entity.Activity;
import com.wlh.zetc.restore.enums.PatrolPatrolTypeEnum;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;/*** 至农台账生成决策数据处理*/
@Service
public class StrategicChoicesUtils {private static final List<List<Activity>> activities = new ArrayList<>();// 收集需要生成的activitypublic StrategicChoicesUtils collect(List<Activity> activityList) {if (activityList != null && !activityList.isEmpty()) {activities.add(new ArrayList<>(activityList));}return this; // 返回当前对象以支持链式调用}public List<List<Activity>> handle(List<List<Activity>> activitiesList,String streetTown) {for (List<Activity> activities : activitiesList) {for (Activity activity : activities) {if (activity.getType() != null) {String title = getTitleBasedOnType(activity,streetTown);activity.setTitle(title);}}}return activitiesList; // 返回处理后的List<List<Activity>>}private String getTitleBasedOnType(Activity activity,String streetTown) {String title = "";String regionName = StringUtils.isNotEmpty(activity.getRegionName()) ? activity.getRegionName() : "";String matterName = StringUtils.isNotEmpty(activity.getMatterName()) ? activity.getMatterName() : "";String date = StringUtils.isNotEmpty(activity.getDate()) ? activity.getDate() + "-" : "";switch (activity.getType()) {case 1: // DELIVERY(1,"发货单"),title = streetTown + regionName + "物资发货单";break;case 2: // ARRIVAL(2,"到货"),title = streetTown + regionName + matterName + "到货";break;case 3: // PATROL(3,"巡视"),String patrolTypeDesc = getPatrolTypeDesc(activity.getPatrolType());title = streetTown + date + patrolTypeDesc + "巡视";break;case 4: // APSD(4,"旱地种植结构调整"),title = "旱地种植结构调整情况";break;case 5: // PRODUCT(5,"产品"),title = matterName + "产品";break;case 6: // MEET(6,"会议"),title = "会议照片";break;case 7: // ROUTE(7,"喷施路径"),title = streetTown + matterName + "喷施路径";break;case 8: // OUTBOUND(8,"出库"),title = streetTown + regionName + matterName + "出库";break;case 9: // SPRINKLE(9,"施工过程"),title = streetTown + regionName + matterName + "施工过程";break;case 10: // RECOVERY(10,"包装袋回收"),title = streetTown + regionName + "包装袋回收";break;case 11: // water(11,"水分管理"),title = streetTown + regionName + "水分管理";break;case 0: // OTHER(0,"其它")title = "其它";break;}return title;}private String getPatrolTypeDesc(Integer patrolType) {if (patrolType == null) return "";switch (patrolType) {case 1: return PatrolPatrolTypeEnum.WATER.getDesc();case 2: return PatrolPatrolTypeEnum.CONTROL.getDesc();case 3: return PatrolPatrolTypeEnum.FLIGHT.getDesc();case 4: return PatrolPatrolTypeEnum.SPRINKLING.getDesc();case 5: return PatrolPatrolTypeEnum.OTHER.getDesc();default: return "";}}// 获取累积后的Activity列表public List<Activity> getCollectedActivities() {return activities.stream().flatMap(List::stream) // 将List<List<Activity>>转换为Stream<Activity>.collect(Collectors.toList()); // 将Stream<Activity>收集到List中}// 获取累积后的List<Activity>public List<List<Activity>> getCollectedListActivities() {return activities;}// 重置activities列表,以便重新开始收集public StrategicChoicesUtils reset() {activities.clear();return this;}
}

七牛云文件上传

maven:

		<!--	七牛云sdk	--><dependency><groupId>com.qiniu</groupId><artifactId>qiniu-java-sdk</artifactId><version>7.7.0</version></dependency><!--	图片信息获取	--><dependency><groupId>com.drewnoakes</groupId><artifactId>metadata-extractor</artifactId><version>2.18.0</version></dependency>

yml:

oss:qiniu:domain: qiniu.znkj0215.com # 访问域名(正式访问域名地址) 暂未配置https
#    domain: qiniu.iswhl.com # 访问域名(测试访问域名地址) 已配置httpsaccessKey: APlM_0fW1A_PRS5bQ92rdGf9oSW-5q9mZK3Tv6yk # 公钥secretKey: Ri2eN9h4htBjZa8J8n_7QBfsAAvM_Arz5_CLqWth # 私钥bucketName: zhinonggengdi  #存储空间名称

service:

package com.wlh.zetc.restore.service;import java.io.InputStream;
import java.io.UnsupportedEncodingException;/*** 七牛文件存储** @author wanghailin* @date 2024-03-12 10:21:35*/
public interface QiniuService {String uploadImage2qiniu(InputStream in, String key);boolean deleteImageFromQiniu(String key);String getPrivateDownloadUrl(String fileName) throws UnsupportedEncodingException;}

impl:

package com.wlh.zetc.restore.service.impl;import com.google.gson.Gson;
import com.qiniu.common.QiniuException;
import com.qiniu.common.Zone;
import com.qiniu.http.Response;
import com.qiniu.storage.*;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import com.wlh.zetc.restore.properties.QiniuProperties;
import com.wlh.zetc.restore.service.QiniuService;
import com.wlh.zetc.restore.utils.TextUtils;
import io.netty.channel.unix.Unix;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;/*** 七牛文件存储** @author wanghailin* @date 2024-03-12 10:21:35*/
@Service
public class QiniuServiceImpl implements QiniuService
{private final String domain;private final String bucketName;private final String ak;private final String sk;// 七牛文件上传管理器private final Configuration cfg;private final Auth auth;@Autowiredpublic QiniuServiceImpl(QiniuProperties oss){this.ak = oss.getAccessKey();this.sk = oss.getSecretKey();this.domain = oss.getDomain(); // CDN域名this.bucketName = oss.getBucketName();// //构造一个带指定 Region 对象的配置类cfg = new Configuration(Zone.zone0());auth = Auth.create(ak,sk);}/*** 上传图片到七牛云* @return 图片url* */@Overridepublic String uploadImage2qiniu(InputStream in, String key){try {UploadManager uploadManager = new UploadManager(cfg);// 根据命名空间生成的上传tokenString upToken = auth.uploadToken(bucketName);Response response = uploadManager.put(in,key,upToken,null, null);//解析上传成功的结果DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);//System.out.println(putRet.key);//System.out.println(putRet.hash);//return String.format("http://%s/%s",this.domain,putRet.key);return putRet.key;} catch (QiniuException ex) {Response r = ex.response;System.err.println(r.toString());try {System.err.println(r.bodyString());} catch (QiniuException ex2) {//ignore}}return null;}/*** 删除图片* */@Overridepublic boolean deleteImageFromQiniu(String imageUrl){BucketManager bucketManager = new BucketManager(auth, cfg);try {String key= TextUtils.getKey(imageUrl);Response response = bucketManager.delete(bucketName,key);return response.isOK();} catch (QiniuException ex) {//如果遇到异常,说明删除失败System.err.println(ex.code());System.err.println(ex.response.toString());}return false;}/*** 获取文件下载路径** @param fileName* @return* @throws UnsupportedEncodingException*/public String getPrivateDownloadUrl(String fileName) throws UnsupportedEncodingException {//文件https访问配置DownloadUrl url = new DownloadUrl(domain, true, fileName);//DownloadUrl url = new DownloadUrl(domain, false, fileName);long expireInSeconds = 3600;//1小时,可以自定义链接过期时间long deadline = System.currentTimeMillis()/1000 + expireInSeconds;Auth auth = Auth.create(ak, sk);String urlString = null;try {urlString = url.buildURL(auth, deadline);} catch (QiniuException e) {throw new RuntimeException(e);}return urlString;}
}

导出效果

在这里插入图片描述
空白部分是因为数据缺失

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/26525.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

visdom使用时所遇的问题及解决方法

最近在用visdom进行可视化的过程中&#xff0c;虽然可有效的避免主机拒绝访问&#xff08;该问题的解决方法&#xff0c;请参考深度学习可视化工具visdom使用-CSDN博客&#xff09;即在终端输入python -m visom.server 1.训练过程中visdom出现ValueError: too many file descr…

简约不简单,建筑装饰演绎现代美学

走在城市的大街小巷&#xff0c;你是否曾被那些独特而精美的建筑装饰所吸引&#xff1f;每一栋建筑都像是艺术家的杰作&#xff0c;通过精美的装饰诉说着它的故事。 我们的建筑装饰&#xff0c;不仅注重外在的美观&#xff0c;更追求内在的品质。从古典的雕花到现代的简约线条&…

Mac 下载并激活IDEA

1.https://3.jetbra.in 打开这个网站,点击第一个网速比较快的连接 2.在新页面顶部有一个蓝色的下载链接文字< jetbra.zip(20220801) >点击下载 3.步骤2打开的页面不要关闭后面还有用 4.在idea官网下载idea对应的版本 https://www.jetbrains.com/idea/download/other.htm…

Chromium源码阅读:Mojo实战:从浏览器JS API 到blink实现

​ 通过在前面几篇文章&#xff0c;我们粗略梳理了Mojo这套跨进程通信的设计思路和IDL细节。 实际上&#xff0c;Mojo不止是跨进程通信框架&#xff0c;而是跨语言的模块通信自动化系统。 在浏览器暴露的JS API&#xff0c;也是需要通过Mojo这个系统进行桥接&#xff0c;最终…

乡村振兴的科技创新引领:加强农业科技研发,推广先进适用技术,提高农业生产效率,助力美丽乡村建设

目录 一、引言 二、农业科技研发的重要性 &#xff08;一&#xff09;提升农业生产效率 &#xff08;二&#xff09;促进农业产业升级 &#xff08;三&#xff09;保障粮食安全 三、加强农业科技研发的策略 &#xff08;一&#xff09;加大投入力度 &#xff08;二&…

云渲染动画:C4D如何正确渲染导出动画?

​C4D是一款功能强大的3D建模、动画和渲染软件&#xff0c;在制作动画时&#xff0c;正确的渲染和导出流程至关重要&#xff0c;以确保动画质量和流畅性。 帧率概念 动画就是一幅幅图片连贯起来&#xff0c;30帧/秒&#xff0c;就是一秒出现30张图片一般国外都是30&#xff0c…

数据预处理——调整方差、标准化、归一化(Matlab、python)

对数据的预处理&#xff1a; (a)、调整数据的方差&#xff1b; (b)、标准化&#xff1a;将数据标准化为具有零均值和单位方差&#xff1b;&#xff08;均值方差归一化(Standardization)&#xff09; (c)、最值归一化&#xff0c;也称为离差标准化&#xff0c;是对原始数据的…

UKP3D用户定制图框的思路

为用户定制图框&#xff0c;记录以下图框制作方法&#xff0c;便于用户自已修改。 1.轴测图与平面图的图框&#xff1a; 1.1.图框在安装目录下&#xff0c;例如&#xff1a;E:\Program Files (x86)\UKSoft\UKP3d9.2\config\TemplateAndBlock\CADTemplate\ 1.2.配置文件在安装…

LVS/NAT负载均衡实操

添加规则,并做持久操作 1 添加规则 [rootlvs ~]# ipvsadm -A -t 10.36.178.183:80 -s wrr [rootlvs ~]# ipvsadm -a -t 10.36.178.183:80 -r 192.168.65.201:80 -m -w 3 [rootlvs ~]# ipvsadm -a -t 10.36.178.183:80 -r 192.168.65.202:80 -m -w 1[rootlvs ~]# ipvsadm -Ln …

vmmare虚拟机没有被分配ip地址问题

打开任务管理器–>服务–>找到与VM和server相关的服务 发现NAT和DHCP服务被关闭了 尝试启动&#xff0c;报错 尝试一 虚拟网络编辑器点击还原默认设置 尝试二 可以了

Android Jetpack Compose入门教程(二)

一、列表和动画 列表和动画在应用内随处可见。在本课中&#xff0c;您将学习如何利用 Compose 轻松创建列表并添加有趣的动画效果。 1、创建消息列表 只包含一条消息的聊天略显孤单&#xff0c;因此我们将更改对话&#xff0c;使其包含多条消息。您需要创建一个可显示多条消…

Cascade和Cascode在电路中含义的区别

两个电路cascade 是指第一个的输出接到第二个的输入. 在cascode 结构中, 第一个电路是common source amplifier, 第二个电路是common gate amplifier. (以FET 为例)

Chromium源码阅读:深入理解Mojo框架的设计思想,并掌握其基本用法(2)

我们继续分析Chromium的Mojo模块。 Dispatcher Dispatcher 是 Mojo IPC 系统中的一个关键概念。它是一个虚基类类&#xff08;或接口&#xff09;&#xff0c;用于实现与特定 MojoHandle 相关联的 Mojo 核心 API 调用。在 Mojo 系统中&#xff0c;应用程序通过这些 API 与各种…

LabVIEW 32位与64位版本比较分析:性能与兼容性详解

LabVIEW的32位和64位版本在功能、性能、兼容性和应用场景等方面存在差异。本文从系统要求、内存管理、性能、兼容性、驱动支持和开发维护等多个角度进行详细分析&#xff0c;帮助用户选择合适的版本。 一、系统要求 操作系统支持&#xff1a; 32位LabVIEW&#xff1a;可以在32位…

XL3001E1 SOP-8 3A 40V 220KHz 降压LED恒流驱动器芯片

XL3001E1是一款LED驱动芯片&#xff0c;主要用于需要稳定电流驱动的LED照明产品中。其应用领域广泛&#xff0c;包括但不限于以下几个方面&#xff1a; 1. 室内照明&#xff1a;XL3001E1可用于各种室内LED灯具&#xff0c;如球泡灯、筒灯、射灯和平板灯&#xff0c;提供恒定的电…

【C++进阶】RBTree封装map与set

1.红黑树的迭代器 1.1 begin() begin()就是红黑树的开头&#xff0c;那么对于红黑树来说按照中序序列是该树的最左节点。 Iterator Begin(){Node* leftMin _root;while (leftMin->_left){leftMin leftMin->_left;}return Iterator(leftMin);} 1.2 end() begin()就是…

好书推荐:生成式AI入门与AWS实战

这本书给LLM的爱好者者提供了完整的学习路线&#xff0c;让读者从使用大语言模型开始到剖析常用的技术概念&#xff0c;能够填补了机器学习爱好者从传统的文字处理到大语言模型的空白知识&#xff0c;包括显存计算优化&#xff0c;微调&#xff0c;RAG&#xff0c; 多模态&…

springboot vue 的在线考试系统

springboot & vue 的在线考试系统 在线考试系统&#xff0c;功能如下&#xff1a; 管理员&#xff1a;题库管理&#xff0c;支持选择题和判断题&#xff0c;考试管理&#xff0c;成绩查询&#xff0c;学生管理&#xff0c;教师管理. 教师&#xff1a;题库管理&#xff0c;…

深入解析TF-IDF算法:文本分析的基石与力量

在信息爆炸的时代文本数据无处不在&#xff0c;从新闻报道到社交媒体帖子&#xff0c;从学术论文到产品评论&#xff0c;大量的文本信息需要被有效地分析和利用。在这样的背景下TF-IDF&#xff08;Term Frequency-Inverse Document Frequency&#xff09;算法作为一种简单而有效…

抖店被扣保证金,做起来太难导致心态崩了,怎么办?

我是王路飞。 技术、黑科技这些东西&#xff0c;决定不了你做店的结果。 能够决定最终结果的&#xff0c;一定是心态&#xff0c;是乐观还是悲观&#xff1f;是自负还是自卑&#xff1f;是焦躁还是踏实&#xff1f;这很关键。 店铺被扣保证金了&#xff0c;感觉没希望了&…