大文件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.rhkb.cn/news/348353.html

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

相关文章

[ROS 系列学习教程] 建模与仿真 - 使用 Arbotix 控制机器人

ROS 系列学习教程(总目录) 本文目录 一、Arbotix 简介二、安装Arbotix三、配置Arbotix控制器四、配置launch启动文件五、数据交互接口六、在rviz中仿真控制机器人6.1 直接发topic控制6.2 使用键盘控制6.3 编写代码控制机器人移动 前面讲了机器人的建模&#xff0c;是静态的&…

Mysql查询分析工具Explain的使用

一、前言 作为一名合格的开发人员&#xff0c;与数据库打交道是必不可少的&#xff0c;尤其是在业务规模和数据体量大规模增长的条件下&#xff0c;应用系统大部分请求读写比例在10:1左右&#xff0c;而且插入操作和一般的更新操作很少出现性能问题&#xff0c;遇到最多的&…

遇到Windows无法启动时不要担心,这里有解决办法

序言 如果有一天你打开电脑,Windows拒绝启动,你该怎么办?其实“Windows无法启动”是一种常见症状,原因多种多样,因此你需要进行一些故障排除。 现代版本的Windows更善于从这种情况中自动恢复,而Windows XP遇到此问题时可能会停止在运行的地方,现代版本的Windows将尝试…

论文解读——《I2EDL: Interactive Instruction Error Detection and Localization》

一、研究背景 视觉与语言导航&#xff08;VLN&#xff09;是一个AI领域的研究任务&#xff0c;旨在开发能够按照自然语言指令在三维空间中导航到指定位置的智能体。这项任务与人类的日常活动——如按照口头指示到达某个地点——十分相似&#xff0c;对于推动人机交互的自然性和…

为什么总选不到合适的安全数据交换系统?解决问题重点在这

安全数据交换系统对于企业而言&#xff0c;重要性不言而喻。企业业务开展离不开数据交换&#xff0c;只有数据流动起来&#xff0c;才能真正发挥价值&#xff0c;但数据流动的过程&#xff0c;涉及多个系统、多种环境、多个人员角色&#xff0c;因此&#xff0c;有较大的风险。…

Gi标签管理

文章目录 前言理解标签创建标签操作标签总结 前言 理解标签 标签&#xff0c;可以理解为对某次commit的一次标识&#xff0c;相当于起起了一个别名。 例如&#xff0c;在项目发布某个版本时候&#xff0c;针对最后一次commit起一个v1.0这样的标签来标识里程碑的意义。 这有什…

【Linux】线程(一)

谈论之前需要先谈论一些线程的背景知识 其中就有进程地址空间&#xff0c;又是这个让我们又爱又恨的东西 目录 背景知识&#xff1a;地址空间&#xff1a; 背景知识&#xff1a; 地址空间&#xff1a; 说在前边&#xff0c;OS通常分为4个核心模块&#xff1a;执行流管理&…

Flutter项目开发模版,开箱即用

前言 当前案例 Flutter SDK版本&#xff1a;3.22.2 每当我们开始一个新项目&#xff0c;都会 引入常用库、封装工具类&#xff0c;配置环境等等&#xff0c;我参考了一些文档&#xff0c;将这些内容整合、简单修改、二次封装&#xff0c;得到了一个开箱即用的Flutter开发模版…

喜讯!云起无垠入选《2024中国AI大模型产业图谱1.0版》

近日&#xff0c;数据猿与上海大数据联盟联合策划并启动了“2024全年度三大策划活动”&#xff0c;经过数月的精心筹备和严格筛选&#xff0c;通过直接申报交流、深入访谈调研、外部咨询评价以及匿名访谈等多维度交叉验证的方式&#xff0c;最终完成了《2024中国AI大模型产业图…

鸿蒙开发文件管理:【@ohos.securityLabel (数据标签)】

数据标签 该模块提供文件数据安全等级的相关功能&#xff1a;向应用程序提供查询、设置文件数据安全等级的JS接口。 说明&#xff1a; 本模块首批接口从API version 9开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 导入模块 import security…

【单片机毕业设计选题】-基于STM32和阿里云的家庭安全监测系统

系统功能: 此设计采用STM32单片机采集环境温湿度,烟雾浓度和一氧化碳浓度显示在OLED上&#xff0c;并将这些信息上报至阿里云平台。 1. 上电连接手机热点后自动连接阿里云&#xff0c;可通过阿里云平台收到系统上报的温湿度&#xff0c;烟雾 浓度&#xff0c;一氧化碳数据以…

大数据时代下哈尔滨等保测评的新挑战与对策

引言 大数据时代&#xff0c;信息爆炸式增长&#xff0c;数据成为了新时代的“石油”。作为黑龙江省的省会城市&#xff0c;哈尔滨在积极推进智慧城市建设的过程中&#xff0c;大数据技术的应用日益广泛&#xff0c;随之而来的是信息安全领域的新挑战&#xff0c;特别是对信息…

WEB基础--TOMCAT服务器

服务器概述 什么是服务器 服务器&#xff1a;就是一个提供为人民服务的机器&#xff0c;这里的服务器主要指计算机服务器&#xff0c;分为两种&#xff1a;服务器软件和硬件服务器&#xff1b; 服务器分类 1、硬件服务器&#xff1a;安装了服务器软件的主机。就相当于高配的…

AI绘画基础教学:我用AI做建筑设计,10分钟完成100个方案

人工智能进入大众视野&#xff0c;就是ChatGPT给所有人打开了一扇通往人工智能世界的大门&#xff0c;面对这样一个强大又不太好驾驭的工具&#xff0c;很多人都经历了从惊讶、到惊喜&#xff0c;再到不知道能干啥用的茫然。 AI能帮人们做什么&#xff1f;建筑行业有哪些专门针…

Linux网络 - json,网络计算服务器与客户端改进

文章目录 前言一、json1.引入库2. 使用步骤2.Calculator.hpp3.Task.hpp4.serverCal.hpp 新客户端 前言 本章内容主要对上一章的网络计算器客户端和服务器进行一些Bug修正与功能改进。 并学习如何使用json库和daemon函数。 一、json 在我们自己的电脑上一些软件的文件夹中&…

顶顶通呼叫中心中间件-限制最大通话时间(mod_cti基于FreeSWITCH)

顶顶通呼叫中心中间件-限制最大通话时间(mod_cti基于FreeSWITCH) 一、最大通话时间 1、配置拨号方案 1、点击拨号方案 ->2、在框中输入通话最大时长->3、点击添加->4、根据图中配置->5、勾选continue。修改拨号方案需要等待一分钟即可生效 action"sched…

《Brave New Words 》2.2 阅读理解的未来,让文字生动起来!

Part II: Giving Voice to the Social Sciences 第二部分&#xff1a;为社会科学发声 The Future of Reading Comprehension, Where Literature Comes Alive! 阅读理解的未来&#xff0c;让文字生动起来&#xff01; Saanvi, a ninth grader in India who attends Khan World S…

Echarts 在折线图平滑位置处添加该处信息

文章目录 需求分析需求 分析 通过自定义折线图的标签(label)来实现。在 ECharts 中,可以通过设置 series 中的 label.normal.formatter 属性来实现这一点。 需要注意的是拐点处symbol不能设置为 none,否则会展示不出 label ,以下是一个示例代码,演示了如何在折线图的相邻…

超详解——Python 元组详解——小白篇

目录 1. 元组简介 创建元组 2. 元组常用操作 访问元组元素 切片操作 合并和重复 成员操作符 内置函数 解包元组 元组方法 3. 默认集合类型 作为字典的键 作为函数参数 作为函数的返回值 存储多种类型的元素 4.元组的优缺点 优点 缺点 5.元组的使用场景 数据…

如何保证数据库和缓存的一致性

背景&#xff1a;为了提高查询效率&#xff0c;一般会用redis作为缓存。客户端查询数据时&#xff0c;如果能直接命中缓存&#xff0c;就不用再去查数据库&#xff0c;从而减轻数据库的压力&#xff0c;而且redis是基于内存的数据库&#xff0c;读取速度比数据库要快很多。 更新…