使用mq的原因:因为项目中文件上传比较多,需要使用mq分担当前系统线程压力,所以单独使用一个服务来处理文件上传,加快文件上传速度的同时也缓解了当前服务的处理压力
核心服务1【一个项目】
发送mq:
GeneralFileEvent【需要发送给mq处理的参数,自己业务里需要的,封装了一个类,看你们自己需要】
@Data
public class GeneralFileEvent {//发送mq的参数
private ContentsAnnexReq file;//附件文件
private String companyName; //公司名
private Long orgUserId;//关联文件id
/**
* 发布对象类型
* 1.按照部门批量发布
* 2.按照公司发布
* 3.按照人员发布
*/
private Integer levelType;
}
RocketTopicConstant【mq目的的名字】
public class RocketTopicConstant {
public static final String GENERAL_ADD_PAUSE = "hhr_general_over_dev";
public static final String GENERAL_UPDATE_PAUSE = "hhr_general_update_over_dev";
}
业务核心代码
//发送mq处理文件上传代参数
GeneralFileEvent fileEvent = new GeneralFileEvent();
fileEvent.setFile(file);
fileEvent.setCompanyName(company.getName());
fileEvent.setOrgUserId(orgUser.getId());
fileEvent.setLevelType(req.getLevelType());
Message<GeneralFileEvent> destroyMessage = MessageBuilder.withPayload(fileEvent).build();
rocketMQTemplate.syncSend(RocketTopicConstant.GENERAL_UPDATE_PAUSE, destroyMessage);
配置文件:配置mq
rocketmq:
name-server: mq的ip地址:端口号
producer:
group: pass-test-group
# 发送失败重试次数
retry-times-when-send-failed: 2
message:
#消息发送mq主题文件上传
overTopic: hhr_general_over_dev
generalUpdateTopic: hhr_general_update_over_dev
#消息发送ma消息组
overGroup: hhr_general_over_dev_group
generalUpdateGroup: hhr_general_update_over_dev_group
一个处理服务【一个项目】
接收mq
GeranlAddListener【配置监听器:用于处理你自己要处理的数据接收mq传来的参数做处理】
import com.example.filehandling.listener.constants.GeneralConstants;
import com.example.filehandling.listener.constants.IdConstant;
import com.example.filehandling.listener.constants.RocketConsumerConstant;
import com.example.filehandling.listener.constants.RocketTopicConstant;
import com.example.filehandling.listener.domain.PartnerGeneralContentsFileAnnex;
import com.example.filehandling.listener.domain.PartnerGeneralContentsFileAnnexAble;
import com.example.filehandling.listener.event.ContentsAnnexReq;
import com.example.filehandling.listener.event.GeneralFileEvent;
import com.example.filehandling.listener.id.service.IdGeneratorService;
import com.example.filehandling.listener.mapper.PartnerGeneralContentsFileAnnexAbleMapper;
import com.example.filehandling.listener.mapper.PartnerGeneralContentsFileAnnexMapper;
import com.example.filehandling.tool.SpringBeanUtil;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.*;
import com.szzz.commons.oss.OSS;
import com.szzz.commons.oss.cos.CosClient;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.dom4j.DocumentException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.util.Date;
/**
* //接收mq
*/
@RocketMQMessageListener(topic = RocketTopicConstant.GENERAL_PAUSE, consumerGroup = RocketConsumerConstant.GENERAL_PAUSE)
@Component
@Slf4j
public class GeranlAddListener implements RocketMQListener<GeneralFileEvent> {//接收mq
@Resource
private PartnerGeneralContentsFileAnnexMapper annexMapper;
@Resource
private PartnerGeneralContentsFileAnnexAbleMapper ableMapper;
@Resource
private IdGeneratorService idGeneratorService;
@Autowired
@Qualifier("cosClient")
OSS cosClient;
@Value("${oss.settings.COS.domain}")
private String domain;
@Override
@SneakyThrows
@Transactional(rollbackFor = Exception.class)
public void onMessage(GeneralFileEvent fileEvent) {//接收参数
log.info(String.format("文件上传",fileEvent.getFile()+"================="+fileEvent.getCompanyName()+"==========OrgUserId="+fileEvent.getOrgUserId()));
Long orgUserId = fileEvent.getOrgUserId();
String companyName = fileEvent.getCompanyName();
ContentsAnnexReq file = fileEvent.getFile();
Integer levelType = fileEvent.getLevelType();
if(levelType==3){//人员
//1.全部存储不加水印表file_annex表
PartnerGeneralContentsFileAnnex annex=new PartnerGeneralContentsFileAnnex();
annex.setOrgUserFileId(orgUserId);//org_user表id
annex.setAnnexUrl(file.getAnnexUrl());
annex.setAnnexName(file.getAnnexName());
annex.setDownloadStatus(file.getDownloadStatus());
annex.setPreviewStatus(file.getPreviewStatus());
annex.setDownloadEnableStatus(file.getDownloadEnableStatus());
annex.setFileType(file.getType());
annex.setCreateTime(new Date());
annex.setUpdateTime(new Date());
annex.setId(idGeneratorService.generatorId(IdConstant.annexId));
annexMapper.insert(annex);
//2.获取文件类型,添加水印表【根据附件类型,确定要不要加水印【pdf和图片】】
if(annex.getDownloadStatus()==true){//需要加水印的
//pdf
if(annex.getFileType().equals("pdf")||annex.getFileType().equals("PDF")){//这些文件类型可以加水印
//3.添加annex_able表
PartnerGeneralContentsFileAnnexAble annexAble=new PartnerGeneralContentsFileAnnexAble();
//4.上传带水印的文件(用于下载的时候带水印)
String Url= setPdfMark(annex.getAnnexUrl(),companyName);
log.info("===========【添加】人员加pdf水印,公司名称=============="+companyName);
annexAble.setAnnexId(annex.getId());
annexAble.setAnnexUrl(Url);
annexAble.setCreateTime(new Date());
annexAble.setUpdateTime(new Date());
annexAble.setId(idGeneratorService.generatorId(IdConstant.annexAbleId));
ableMapper.insert(annexAble);
}
//图片
if(annex.getFileType().equals("jpg")||annex.getFileType().equals("png")||annex.getFileType().equals("jpeg")){
//3.添加annex_able表
PartnerGeneralContentsFileAnnexAble annexAble=new PartnerGeneralContentsFileAnnexAble();
//4.上传带水印的图片(用于下载的时候带水印)
String Url= markImageByText(companyName, annex.getAnnexUrl(), null, null);
log.info("===========【添加】人员加图片水印,公司名称=============="+companyName);
annexAble.setAnnexId(annex.getId());
annexAble.setAnnexUrl(Url);
annexAble.setCreateTime(new Date());
annexAble.setUpdateTime(new Date());
annexAble.setId(idGeneratorService.generatorId(IdConstant.annexAbleId));
ableMapper.insert(annexAble);
}
}
}
@SneakyThrows
public String setPdfMark(String cosOriginalUrl,String waterMarkName) throws DocumentException, IOException {
cosClient=SpringBeanUtil.getBean(CosClient.class);
// 如果你想直接输出到某个路径,将os参数改为descFile(具体输出路径)
//BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(descFile)));
URL urlFile = new URL(cosOriginalUrl);
String file1 = urlFile.getFile();
//带水印的
File file = File.createTempFile("watermark_url", ".pdf");
//不带水印
File file2 = File.createTempFile("original", ".pdf");
FileUtils.copyInputStreamToFile(urlFile.openStream(), file2);
OutputStream os = new FileOutputStream(file);
//String waterMarkName = "数字众智";
PdfReader reader = new PdfReader(file2.getPath());
PdfStamper stamper = new PdfStamper(reader, os);
int total = reader.getNumberOfPages() + 1;
PdfContentByte content;
BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
PdfGState gs = new PdfGState();
for (int i = 1; i < total; i++) {
content = stamper.getOverContent(i); // 在内容上方加水印
// content = stamper.getUnderContent(i); //在内容下方加水印
gs.setFillOpacity(0.3f); // 透明度
content.setGState(gs);
content.beginText();
content.setColorFill(BaseColor.RED);//BLACK
content.setFontAndSize(base, 50);
content.setTextMatrix(70, 200);
content.showTextAligned(Element.ALIGN_CENTER, waterMarkName, 300, 150, 55);//150控制水印的y轴位置上下
content.endText();
}
stamper.close();
MultipartFile multipartFile = getMultipartFile(file);
//上传带水印文件
String put = cosClient.simpleUpload(file.getName(), multipartFile);
//获取上传带水印的文件地址
String cosFileUrl=domain+"/"+file.getName();
file.delete();
file2.delete();
return cosFileUrl;
}
/**
* 给图片添加水印文字、可设置水印文字的旋转角度
*
* @param logoText
* @param srcImgPath
* @param targerPath
* @param degree
*/
@SneakyThrows
public String markImageByText(String logoText, String srcImgPath, String targerPath, Integer degree) {
cosClient= SpringBeanUtil.getBean(CosClient.class);
// 如果你想直接输出到某个路径,将os参数改为descFile(具体输出路径)
//BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(descFile)));
URL urlFile = new URL(srcImgPath);
String file1 = urlFile.getFile();
//带水印的
File file = File.createTempFile("watermark_url", ".png");
//不带水印
File file2 = File.createTempFile("original", ".png");
FileUtils.copyInputStreamToFile(urlFile.openStream(), file2);
InputStream is = null;
OutputStream os = null;
// 1、源图片
Image srcImg = ImageIO.read(file2);
BufferedImage buffImg = new BufferedImage(srcImg.getWidth(null), srcImg.getHeight(null), BufferedImage.TYPE_INT_RGB);
// 2、得到画笔对象
Graphics2D g = buffImg.createGraphics();
// 3、设置对线段的锯齿状边缘处理
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(
srcImg.getScaledInstance(srcImg.getWidth(null),
srcImg.getHeight(null), Image.SCALE_SMOOTH), 0, 0, null);
// 4、设置水印旋转
if (null != degree) {
g.rotate(Math.toRadians(degree),
(double) buffImg.getWidth() / 2,
(double) buffImg.getHeight() / 2);
}
// 5、设置水印文字颜色
g.setColor(GeneralConstants.color);
// 6、设置水印文字Font
g.setFont(GeneralConstants.font);
// 7、设置水印文字透明度
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.5f));
// 8、第一参数->设置的内容,后面两个参数->文字在图片上的坐标位置(x,y)
g.drawString(logoText, GeneralConstants.positionWidth, GeneralConstants.positionHeight);
// 9、释放资源
g.dispose();
// 10、生成图片
os = new FileOutputStream(file);
ImageIO.write(buffImg, "PNG", os);//JPG
MultipartFile multipartFile = getMultipartFile(file);
//上传带水印文件
String put = cosClient.simpleUpload(file.getName(), multipartFile);
//获取上传带水印的文件地址
String cosFileUrl=domain+"/"+file.getName();
file.delete();
file2.delete();
System.out.println(cosFileUrl+"=============路径地址=========================");
return cosFileUrl;
}
public static MultipartFile getMultipartFile(File file) {
FileItem item = new DiskFileItemFactory().createItem("file"
, MediaType.MULTIPART_FORM_DATA_VALUE
, true
, file.getName());
try (InputStream input = new FileInputStream(file);
OutputStream os = item.getOutputStream()) {
// 流转移
IOUtils.copy(input, os);
} catch (Exception e) {
throw new IllegalArgumentException("Invalid file: " + e, e);
}
return new CommonsMultipartFile(item);
}
}
GeneralFileEvent
import lombok.Data;
@Data
public class GeneralFileEvent {//发送mq的参数
private ContentsAnnexReq file;//附件文件
private String companyName; //公司名
private Long orgUserId;//关联文件id
/**
* 发布对象类型
* 1.按照部门批量发布
* 2.按照公司发布
* 3.按照人员发布
*/
private Integer levelType;
}
ContentsAnnexReq
@Data
public class ContentsAnnexReq {
@Schema(description = "附件名称")
private String annexName;
@Schema(description = "附件地址")
private String annexUrl;
@Schema(description = "文件类型")
private String type;
@Schema(description = "文件大小")
private String size;
@Schema(description = "预览水印:0无水印false,1加水印true")
private Boolean previewStatus;
@Schema(description = "下载水印:0无水印false,1加水印true")
private Boolean downloadStatus;
@Schema(description = "可下载:不可下载false,1可以下载true")
private Boolean downloadEnableStatus;
}
RocketTopicConstant
public class RocketTopicConstant {
public static final String GENERAL_PAUSE = "hhr_general_over_dev";
public static final String GENERAL_UPDATE_PAUSE = "hhr_general_update_over_dev";
}
配置配置文件
rocketmq:
name-server: mq的ip地址:端口号
producer:
group: pass-test-group
# 发送失败重试次数
retry-times-when-send-failed: 2
message:
#消息发送mq主题文件上传
overTopic: hhr_general_over_dev
generalUpdateTopic: hhr_general_update_over_dev
#消息发送ma消息组
overGroup: hhr_general_over_dev_group
generalUpdateGroup: hhr_general_update_over_dev_group
依赖【两个项目里都需要加mq依赖】
<!-- pdf添加水印 -->
<!-- https://mvnrepository.com/artifact/com.itextpdf/itextpdf -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.itextpdf/itext-asian -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<!--图片加水印-->
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.8</version>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>