首页 > 技术文章 > 图片上传 mongo + get请求带 token 预览 图片 生成gif动图

tuxiaoer 2020-08-19 18:18 原文

<!-- 图片转gif动图 -->
<dependency>
            <groupId>com.madgag</groupId>
            <artifactId>animated-gif-lib</artifactId>
            <version>1.4</version>
        </dependency>

  

<!-- mogodb 的支持-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
            <version>2.2.2.RELEASE</version>
        </dependency>

 

controller层

import cn.hutool.core.convert.Convert;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * <p>
 *  图片上传和预览控制器
 * </p>
 *
 */
@RestController
@RequestMapping("/image/upload")
@Api(value = "图片上传和预览controller", tags = {"图片上传和预览接口"})
public class ImageUploadController {

    @Autowired
    private ImageUploadService imageUploadService;  

    @ApiOperation(value = "图片上传", notes = "图片上传上传", httpMethod = "POST")
    @PostMapping("/image/upload")
    public String imageUpload(@RequestParam("file") MultipartFile file){        
        return this.imageUploadService.imageUpload(file);
    }
    
    @ApiOperation(value = "基层数据查询成果预览", notes = "基层数据查询成果预览", httpMethod = "GET")
    @ApiImplicitParam(name = "imageid", value = "图片存mongo中的id", required = true, dataType = "String")
    @GetMapping("/image/{imageid}/preview.png")
    public byte[] previewPng(@RequestParam("imageid")String imageid){
        return this.imageUploadService.previewPng(imageid);
    }
        
}

 service 层

import com.baomidou.mybatisplus.extension.service.IService;
import com.sgis.one.map.micro.analysis.model.entity.TMicroAchievement;
import com.sgis.one.map.micro.analysis.model.vo.SelectMicroAchievementVo;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

/**
 * <p>
 *  图片上传和预览服务类
 * </p>
 */
public interface ImageUploadService extends IService<entityTable> {
   /**
     * 图片上传
     * @param file   
     * @return 图片存入mongo中的ObjectId
     */
    String imageUpload(MultipartFile file);

    /**
     * 图片预览
     * @param imageid 图片存入mongo中的ObjectId
     * @return 图片的二进制流
     */
    byte[] previewPng(String imageid);
}

 Impl层

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sgis.common.file.util.MongoService;
import com.sgis.common.handler.BusinessException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * <p>
 *  图片上传和预览实现类
 * </p>
 */
@Service
public class ImageUploadServiceImpl extends ServiceImpl<entityMapper, entityTable> implements ImageUploadService {
    @Autowired
    private MongoService mongoService;

    /**
     * 图片上传
     * @param file
     * @param userId
     * @param fsgisOneMapMacroAnalysis
     * @return
     */
    @Override
    public String imageUpload(MultipartFile file, Integer userId, String serviceId) {
        BufferedImage read = null;
        try {
            read = ImageIO.read(file.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (read == null){
            throw new BusinessException(500,"图片格式不正确");
        }
        String fileName = file.getOriginalFilename();         
        return  this.mongoService.uploadFile(file);
    }

    /**
     * 图片预览
     * @param imageid
     * @return
     */
    @Override
    public byte[] previewPng(String imageid) {
        return this.mongoService.downloadImageByte(imageid, null);
    }
}

  mongoService

import cn.hutool.core.util.ObjectUtil;
import com.madgag.gif.fmsware.AnimatedGifEncoder;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSBuckets;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.GridFSFindIterable;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageDecoder;
import org.apache.commons.io.IOUtils;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.awt.image.BufferedImage;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
/**
 *@program:
 *@description: MongoService 
 */
@Service
public class MongoService {

    @Autowired
    private GridFsTemplate gridFsTemplate;

    @Autowired
    private MongoDbFactory mongoDbFactory;



    /**
     * 保存到本地
     * @param fileId 
     * @param path
     * @param fileName
     * @throws Exception
     */
    public  void downloadToLocal(String fileId,String path,String fileName) throws Exception {
        try {
            //查询单个文件
            Query query = Query.query(Criteria.where("_id").is(fileId));
            GridFSFile gfsFile = gridFsTemplate.findOne(query);
            if (gfsFile == null) {
                return;
            }
            GridFSBucket gridFSBucket= GridFSBuckets.create(mongoDbFactory.getDb());
            GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gfsFile.getObjectId());
            //创建GridFsResource对象,获取流
            GridFsResource gridFsResource = new GridFsResource(gfsFile, gridFSDownloadStream);
            FileOutputStream downloadFile = new FileOutputStream(path + File.separator + fileName);
            IOUtils.copy(gridFsResource.getInputStream(),downloadFile);
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 文件上传到mongo服务器上
     * @param multipartFile 文件
     * @param fileName 存入mongo中的名字    
     * @return
     * @throws Exception
     */
    public  ApiResult<FileInfo> uploadFile(MultipartFile multipartFile,String fileName) throws Exception{
	
        //查看mongo中是否已经保存图片
        Query filename = Query.query(Criteria.where("filename").is(fileName));
        GridFSFile one = this.gridFsTemplate.findOne(filename);
		
        if (ObjectUtil.isNotNull(one)){
            Query deleteQuery = Query.query(Criteria.where("_id").is(one.getId()));
            this.gridFsTemplate.delete(deleteQuery);
        }

        // 获得文件输入流        
        InputStream fileIn = multipartFile.getInputStream();        
		
        // 将文件存储到mongodb中,mongodb 将会返回这个文件的具体信息
        ObjectId objectId = gridFsTemplate.store(fileIn,fileName);
		
        return objectId.toString();
    }

    /**
     *  GIF动图预览
     * @param queryid gif动图的唯一标识
     * @param path gif动图保存路径
     * @param time  gif动图间隔时间
     * @param isCompress 图片是否压缩
     * @param ratio 压缩比例
     * @return
     * @throws IOException
     */
    public  byte[] downloadGifByte(String queryid, String path, Integer time, Boolean isCompress, Integer ratio) throws IOException {
	//匹配mongo中filename满足以queryid开头的文件
        String regex = queryid + "([\\s\\S]*?)";
        Query filename = Query.query(Criteria.where("filename").regex(regex));		
        GridFSFindIterable gridFSFiles = gridFsTemplate.find(filename);
		
        InputStream inputStream = null;
        
	//gif动图创建的类
        AnimatedGifEncoder animatedGifEncoder = new AnimatedGifEncoder();
        animatedGifEncoder.setRepeat(0);
		
        //动图保存地址
        String gifPath = path + "/" + queryid + ".gif";
	//压缩图片保存的地址
        String saveFile = path + "/" + queryid + ".png";
		
        animatedGifEncoder.start(gifPath);
		
	//gif动图返回的二进制流
        byte[] fileBytes=null;

        for (GridFSFile gfsFile : gridFSFiles) {
            if (ObjectUtil.isNotNull(gfsFile)) {
                
                GridFSBucket gridFSBucket = GridFSBuckets.create(mongoDbFactory.getDb());
                GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gfsFile.getObjectId());
				
                //创建GridFsResource对象,获取流
                GridFsResource gridFsResource = new GridFsResource(gfsFile, gridFSDownloadStream);
                inputStream = gridFsResource.getInputStream();

                BufferedImage image = null;
				
                if (!isCompress){
                    JPEGImageDecoder decoderFile = JPEGCodec.createJPEGDecoder(inputStream);
                    image = decoderFile.decodeAsBufferedImage();
                } else
                //压缩图片,压缩图不保存到本地
                    {
                    image = ImageHelper.compress(inputStream, new File(saveFile), ratio);
                }

                animatedGifEncoder.setDelay(time);
                animatedGifEncoder.addFrame(image);
            }
        }
		
        animatedGifEncoder.finish();
        FileInputStream fileInputStream = new FileInputStream(gifPath);
		
		转化inputStream 为byte[]
        fileBytes= is2ByeteArray(fileInputStream);
		
        inputStream.close();

        return fileBytes;
    }


    /**
     * 图片预览
     * @param fileId
     * @param defaultStream
     * @return
     */
    public  byte[] downloadImageByte(String fileId) {
        byte[] fileBytes=null;

        try {
		
            // 查询单个文件
            Query query = Query.query(Criteria.where("_id").is(fileId));
            GridFSFile gfsFile = gridFsTemplate.findOne(query);
			
            InputStream inputStream = null;
            if (ObjectUtil.isNotNull(gfsFile)) {
                GridFSBucket gridFSBucket = GridFSBuckets.create(mongoDbFactory.getDb());
                GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gfsFile.getObjectId());
                //创建GridFsResource对象,获取流
                GridFsResource gridFsResource = new GridFsResource(gfsFile, gridFSDownloadStream);
                
                inputStream = gridFsResource.getInputStream();
            }
            fileBytes= is2ByeteArray(inputStream);
            inputStream.close();

        }catch (Exception e){
            e.printStackTrace();
        }

        return fileBytes;

    }

    //转化inputStream 为byte[]
    public  byte[] is2ByeteArray(InputStream is) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buff = new byte[100];
        int rc = 0;
        while((rc=is.read(buff, 0, 100))>0) {
            baos.write(buff, 0, rc);
        }

        return baos.toByteArray();
    }

}

 图片压缩工具类     ImageHelper

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;
import java.io.*;

/**
 * @author: Supermap·F
 * @descripition: 图片压缩
 * @date: created in 11:05 2020/8/19
 * @modify: Copyright (c) Supermap All Rights Reserved.
 */
public class ImageHelper {
    /**
     * 实现图像的等比缩放
     * @param source
     * @param targetW
     * @param targetH
     * @return
     */
    private static BufferedImage resize(BufferedImage source, int targetW,
                                        int targetH) {
        // targetW,targetH分别表示目标长和宽
        int type = source.getType();
        BufferedImage target = null;
        double sx = (double) targetW / source.getWidth();
        double sy = (double) targetH / source.getHeight();
        // 这里想实现在targetW,targetH范围内实现等比缩放。如果不需要等比缩放
        // 则将下面的if else语句注释即可
        if (sx < sy) {
            sx = sy;
            targetW = (int) (sx * source.getWidth());
        } else {
            sy = sx;
            targetH = (int) (sy * source.getHeight());
        }
        if (type == BufferedImage.TYPE_CUSTOM) { // handmade
            ColorModel cm = source.getColorModel();
            WritableRaster raster = cm.createCompatibleWritableRaster(targetW,
                    targetH);
            boolean alphaPremultiplied = cm.isAlphaPremultiplied();
            target = new BufferedImage(cm, raster, alphaPremultiplied, null);
        } else
            target = new BufferedImage(targetW, targetH, type);
        Graphics2D g = target.createGraphics();
        // smoother than exlax:
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BICUBIC);
        g.drawRenderedImage(source, AffineTransform.getScaleInstance(sx, sy));
        g.dispose();
        return target;
    }

    /**
     * 实现图像的等比缩放和缩放后的截取, 处理成功返回true, 否则返回false
     * @param inFilePath 要截取文件的路径
     * @param outFilePath 截取后输出的路径
     * @param width 要截取宽度
     * @param hight 要截取的高度
     * @throws Exception
     */
    public static BufferedImage compress(String inFilePath, String outFilePath,
                                   int width, int hight) {
        BufferedImage ret = null;
        File file = new File(inFilePath);
        File saveFile = new File(outFilePath);
        InputStream in = null;
        try {
            in = new FileInputStream(file);
            ret = compress(in, saveFile, width, hight);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            ret = ret;
        } finally{
            if(null != in){
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return ret;
    }

    /**
     * 实现图像的等比缩放和缩放后的截取, 处理成功返回true, 否则返回false
     * @param in 要截取文件流
     * @param saveFile 截取后输出的路径
     * @param width 要截取宽度
     * @param hight 要截取的高度
     * @throws Exception
     */
    public static BufferedImage compress(InputStream in, File saveFile,
                                   int width, int hight) {
//     boolean ret = false;
        BufferedImage srcImage = null;
        BufferedImage resultImage = null;

        try {
            srcImage = ImageIO.read(in);
        } catch (IOException e) {
            e.printStackTrace();
            return resultImage;
        }

        if (width > 0 || hight > 0) {
            // 原图的大小
            int sw = srcImage.getWidth();
            int sh = srcImage.getHeight();
            // 如果原图像的大小小于要缩放的图像大小,直接将要缩放的图像复制过去
            if (sw > width && sh > hight) {
                srcImage = resize(srcImage, width, hight);
            } else {
                String fileName = saveFile.getName();
                String formatName = fileName.substring(fileName
                        .lastIndexOf('.') + 1);
                try {
                    ImageIO.write(srcImage, formatName, saveFile);
                } catch (IOException e) {
                    e.printStackTrace();
                    return resultImage;
                }
                return resultImage;
            }
        }
        // 缩放后的图像的宽和高
        int w = srcImage.getWidth();
        int h = srcImage.getHeight();
        // 如果缩放后的图像和要求的图像宽度一样,就对缩放的图像的高度进行截取
        if (w == width) {
            // 计算X轴坐标
            int x = 0;
            int y = h / 2 - hight / 2;
            try {
                resultImage = saveSubImage(srcImage, new Rectangle(x, y, width, hight), saveFile);
            } catch (IOException e) {
                e.printStackTrace();
                return resultImage;
            }
        }
        // 否则如果是缩放后的图像的高度和要求的图像高度一样,就对缩放后的图像的宽度进行截取
        else if (h == hight) {
            // 计算X轴坐标
            int x = w / 2 - width / 2;
            int y = 0;
            try {
                resultImage = saveSubImage(srcImage, new Rectangle(x, y, width, hight), saveFile);
            } catch (IOException e) {
                e.printStackTrace();
                return resultImage;
            }
        }

        return resultImage;
    }

    /**
     * 实现图像的等比缩放和缩放后的截取, 处理成功返回true, 否则返回false
     * @param in 图片输入流
     * @param saveFile 压缩后的图片输出流
     * @param proportion 压缩比
     * @throws Exception
     */
    public static BufferedImage compress(InputStream in, File saveFile, int proportion) {
        if(null == in || null == saveFile || proportion < 1){// 检查参数有效性
            //LoggerUtil.error(ImageHelper.class, "--invalid parameter, do nothing!");
            return null;
        }

        BufferedImage srcImage = null;
        BufferedImage resultImage = null;

        try {
            srcImage = ImageIO.read(in);
        } catch (IOException e) {
            e.printStackTrace();
            return resultImage;
        }
        // 原图的大小
        int width = srcImage.getWidth() / proportion;
        int hight = srcImage.getHeight() / proportion;

        srcImage = resize(srcImage, width, hight);

        // 缩放后的图像的宽和高
        int w = srcImage.getWidth();
        int h = srcImage.getHeight();
        // 如果缩放后的图像和要求的图像宽度一样,就对缩放的图像的高度进行截取
        if (w == width) {
            // 计算X轴坐标
            int x = 0;
            int y = h / 2 - hight / 2;
            try {
                resultImage = saveSubImage(srcImage, new Rectangle(x, y, width, hight), saveFile);
            } catch (IOException e) {
                e.printStackTrace();
                return resultImage;
            }
        }
        // 否则如果是缩放后的图像的高度和要求的图像高度一样,就对缩放后的图像的宽度进行截取
        else if (h == hight) {
            // 计算X轴坐标
            int x = w / 2 - width / 2;
            int y = 0;
            try {
                resultImage = saveSubImage(srcImage, new Rectangle(x, y, width, hight), saveFile);
            } catch (IOException e) {
                e.printStackTrace();
                return resultImage;
            }
        }

        return resultImage;
    }

    /**
     * 实现缩放后的截图
     * @param image 缩放后的图像
     * @param subImageBounds 要截取的子图的范围
     * @param subImageFile 要保存的文件
     * @throws IOException
     */
    private static BufferedImage saveSubImage(BufferedImage image, Rectangle subImageBounds, File subImageFile) throws IOException {
        if (subImageBounds.x < 0 || subImageBounds.y < 0
                || subImageBounds.width - subImageBounds.x > image.getWidth()
                || subImageBounds.height - subImageBounds.y > image.getHeight()) {
            //LoggerUtil.error(ImageHelper.class, "Bad subimage bounds");
            return null;
        }
        BufferedImage subImage = image.getSubimage(subImageBounds.x,subImageBounds.y, subImageBounds.width, subImageBounds.height);
        //暂时不用写在服务器本地
//        String fileName = subImageFile.getName();
//        String formatName = fileName.substring(fileName.lastIndexOf('.') + 1);
//        ImageIO.write(subImage, formatName, subImageFile);
        return image;
    }


}

  图片预览测试

百度图片 - 动图 (任何一个有图片或者动图的网站)

 

 

 http://localhost:端口/******/image/{imageid}/preview.png?imageid=图片存入mongo中返回的id&access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJmaXNoZXIiLCJzY29wZSI6WyJzZXJ2ZXIiXSwiZXhwIjoxNTk3Nzc1MDkyLCJ1c2VyTmFtZSI6ImZpc2hlciIsInVzZXJJZCI6NTAsImF1dGhvcml0aWVzIjpbIlJPTEVfQURNSU4iLCJQRVJfU1VQRVJBRE1

 access_token= token信息

 替换图片中的地址,就可以直接预览图片

  

参考链接:

图片转gif动图

https://www.cnblogs.com/myjoan/p/4739102.html

https://blog.csdn.net/qq_35350654/article/details/83446258

图片压缩

https://my.oschina.net/u/242764/blog/2980538

 

推荐阅读