Bootstrap

RocketMQ发送接收项目实战+对cos或者oss服务上的pdf文件和图片加水印

使用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>


;