Spring Boot开发图片上传并添加水印接口

简介: 现在越来越注重版本的问题,所以很多的文章都需要进行署名,类似于这样:

1 前言


现在越来越注重版本的问题,所以很多的文章都需要进行署名,类似于这样:


3ab28fd2d0be43aaa03c0ca40754e127~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


而且很多的图片网站也为了版权的考虑而采用一些技术,反正别人的随意传播或者用于商业途径,水印技术就是为了图片版权的重要技术之一了,类似这张图片右下角的水印:


8932ce82e9ff43aba8a4bf3145b4cb0a~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


最近公司也刚好由于业务需求,需要对使用的到图片添加水印操作,这篇文章就来说说如何使用springboot来实现图片上传并添加水印。


2 正文


这里不再对过程进行一一的赘述,直接上代码,详细的功能和用法都会写在注释里,并且代码的源码也会同步至github。

完整的项目工程如下,本文相关的为绿色文件(先添加的):


91871a79f4214f259c604819b3003cec~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


先来贴出这里使用的pom文件:


<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.5</version>
        </dependency>
        <!-- springboot 整合 log4j -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <exclusions>
        <exclusion>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-log4j</artifactId>
      <version>1.3.8.RELEASE</version>
    </dependency>
    </dependencies>
复制代码


接着我这里写了几个使用到的工具类:


首先是web相关接口的返回状态的枚举:


package com.springboot.springbootdemo.util;
/**
 * Description: web相关接口返回状态枚举
 */
public enum  ReturnCodeAndMsgEnum {
    Success(0, "ok"),
    No_Data(-1, "no data"),
    SYSTEM_ERROR(10004, "system error");
    private String msg;
    private int code;
    private ReturnCodeAndMsgEnum(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    public static ReturnCodeAndMsgEnum getByCode(int code) {
        ReturnCodeAndMsgEnum[] var1 = values();
        int var2 = var1.length;
        for(int var3 = 0; var3 < var2; ++var3) {
            ReturnCodeAndMsgEnum aiTypeEnum = var1[var3];
            if (aiTypeEnum.code == code) {
                return aiTypeEnum;
            }
        }
        return Success;
    }
    public String getMsg() {
        return this.msg;
    }
    public int getCode() {
        return this.code;
    }
}
复制代码


接着封装web的返回结果:


package com.springboot.springbootdemo.util;
import java.io.Serializable;
/**
 * Description: 统一web返回结果
 */
public class ReturnValue<T> implements Serializable {
    private static final long serialVersionUID = -1959544190118740608L;
    private int ret;
    private String msg;
    private T data;
    public ReturnValue() {
        this.ret = 0;
        this.msg = "";
        this.data = null;
    }
    public ReturnValue(int retCode, String msg, T data) {
        this.ret = 0;
        this.msg = "";
        this.data = null;
        this.ret = retCode;
        this.data = data;
        this.msg = msg;
    }
    public ReturnValue(int retCode, String msg) {
        this.ret = 0;
        this.msg = "";
        this.data = null;
        this.ret = retCode;
        this.msg = msg;
    }
    public ReturnValue(ReturnCodeAndMsgEnum codeAndMsg) {
        this(codeAndMsg.getCode(), codeAndMsg.getMsg(), null);
    }
    public ReturnValue(ReturnCodeAndMsgEnum codeAndMsg, T data) {
        this(codeAndMsg.getCode(), codeAndMsg.getMsg(), data);
    }
    public int getRet() {
        return this.ret;
    }
    public void setRet(int ret) {
        this.ret = ret;
    }
    public String getMsg() {
        return this.msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public T getData() {
        return this.data;
    }
    public void setData(T data) {
        this.data = data;
    }
    @Override
    public String toString() {
        return "ReturnValue{" +
                "ret=" + ret +
                ", msg='" + msg + '\'' +
                ", data=" + data +
                '}';
    }
}
复制代码


最后就是添加水印的工具类:


package com.springboot.springbootdemo.util;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.io.OutputStream;
import javax.imageio.ImageIO;
/**
 *   图片水印工具类
 */
public class WaterMarkUtil {
    // 水印文字字体
    private static Font font = new Font("宋体", Font.BOLD, 20);
    // 水印文字颜色
    private static Color color = Color.red;
    // 水印透明度
    private static float alpha = 0.3f;
    // 水印横向位置
    private static int positionWidth = 50;
    // 水印纵向位置
    private static int positionHeight = 100;
    /**
     * 添加水印的方法
     */
    public static void ImagemarkWater(String text, InputStream inputStream, OutputStream outputStream,
                                     Integer degree, String typeName) {
        try {
            // 1、源图片
            Image srcImg = ImageIO.read(inputStream);
            int imgWidth = srcImg.getWidth(null);
            int imgHeight = srcImg.getHeight(null);
            BufferedImage buffImg = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);
            // 2、得到画笔对象
            Graphics2D g = buffImg.createGraphics();
            // 3、设置对线段的锯齿状边缘处理
            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g.drawImage(srcImg.getScaledInstance(imgWidth, imgHeight, 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(color);
            // 6、设置水印文字Font
            g.setFont(font);
            // 7、设置水印文字透明度
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
            // 8、第一参数->设置的内容,后面两个参数->文字在图片上的坐标位置(x,y)
            g.drawString(text, positionWidth, positionHeight);
            // 9、释放资源
            g.dispose();
            // 10、生成图片
            ImageIO.write(buffImg, typeName.toUpperCase(), outputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
复制代码


接下来就是service层代码:


package com.springboot.springbootdemo.service;
import com.springboot.springbootdemo.util.ReturnValue;
import org.springframework.web.multipart.MultipartFile;
public interface ImageFileService {
    public ReturnValue uploadImageFileTest(MultipartFile imageFile);
}
复制代码


package com.springboot.springbootdemo.service;
import com.springboot.springbootdemo.util.ReturnCodeAndMsgEnum;
import com.springboot.springbootdemo.util.ReturnValue;
import com.springboot.springbootdemo.util.WaterMarkUtil;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.util.UUID;
@Service
public class ImageFileServiceImp implements ImageFileService {
    private static final Logger logger = LoggerFactory.getLogger(ImageFileServiceImp.class);
    @Override
    public ReturnValue uploadImageFileTest(MultipartFile imgFile) {
        //文件保存路径
        String targetFilePath = "C:\\Users\\Jiang\\Desktop\\测试";
        //重命名保存新文件的文件名
        String fileName = UUID.randomUUID().toString().replace("-", "");
        File targetFile = new File(targetFilePath + File.separator + fileName);
        try{
            String originalFilename = imgFile.getOriginalFilename();
            String typeName = originalFilename.substring(originalFilename.indexOf(".")+1 ,originalFilename.length());
            InputStream inputStream = imgFile.getInputStream();
            OutputStream outputStream = new FileOutputStream(targetFile) ;
            //调用添加水印的方法
            WaterMarkUtil.ImagemarkWater("1024笔记", inputStream, outputStream, 0, typeName);
            outputStream.close();
            inputStream.close();
            logger.info("------图片上传、添加水印成功------");
        }catch(IOException e){
        }
        return new ReturnValue<>(ReturnCodeAndMsgEnum.Success, null);
    }
}
复制代码


Controller层代码:


package com.springboot.springbootdemo.controller;
import com.springboot.springbootdemo.service.ImageFileService;
import com.springboot.springbootdemo.util.ReturnValue;
import com.springboot.springbootdemo.util.WaterMarkUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping(value = "/image")
public class ImageFileController {
    private static final Logger logger = LoggerFactory.getLogger(ImageFileController.class);
    @Autowired
    private ImageFileService imageFileService;
    /**
     * 文件上传测试接口
     * @return
     */
    @RequestMapping("/upload")
        public ReturnValue uploadFileTest(@RequestParam("uploadFile") MultipartFile imgFile) {
            return imageFileService.uploadImageFileTest(imgFile);
    }
}
复制代码


接下来启动项目,使用postman进行功能测试:


首先我们使用的两张原图是:


efa76d765b6e4e6e9d518a624d2d5e99~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg    

ae0bb456145a4aec9d8c620475e51de9~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


1c089b4b43b046598355617c05c9fbbf~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


3b271a6152f94cbdae2485b96b629ff3~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


77b5d7b3dda7423a95314124226bcad6~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


添加水印后的图片的效果如下:


22ab6c6f85b44eb8b22d3d8bcba8fe4a~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


dcc5ed98a13f4b92ab96380894ba2737~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


3 总结


上面就是如果使用springboot开发一个上传图片和添加水印的接口,其实该功能的实现和springboot并没有太大的关系,主要的核心代码就那么一块,有任何问题欢迎交流讨论。


另外所有实战文章的源码都会同步至github,有需要的欢迎下载使用。

目录
相关文章
|
20天前
|
XML Java 数据格式
SpringBoot入门(8) - 开发中还有哪些常用注解
SpringBoot入门(8) - 开发中还有哪些常用注解
39 0
|
2月前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
48 4
|
18天前
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
31 2
|
1月前
|
Java 开发者 Spring
精通SpringBoot:16个扩展接口精讲
【10月更文挑战第16天】 SpringBoot以其简化的配置和强大的扩展性,成为了Java开发者的首选框架之一。SpringBoot提供了一系列的扩展接口,使得开发者能够灵活地定制和扩展应用的行为。掌握这些扩展接口,能够帮助我们写出更加优雅和高效的代码。本文将详细介绍16个SpringBoot的扩展接口,并探讨它们在实际开发中的应用。
44 1
|
2月前
|
存储 安全 Java
|
2月前
|
存储 算法 安全
SpringBoot 接口加密解密实现
【10月更文挑战第18天】
|
2月前
|
XML Java 数据格式
提升效率!Spring Boot 开发中的常见失误轻松规避
本文深入探讨了在 Spring Boot 开发中常见的失误,包括不当使用注解、不良异常处理、低效日志记录等,提供了有效的规避策略,帮助开发者提升代码质量和系统性能,构建更健壮、高效的应用程序。
|
23天前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
31 0
|
2月前
|
NoSQL Java Redis
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
这篇文章介绍了如何使用Spring Boot整合Apache Shiro框架进行后端开发,包括认证和授权流程,并使用Redis存储Token以及MD5加密用户密码。
32 0
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
|
1月前
|
JavaScript 前端开发 Java
SpringBoot_web开发-webjars&静态资源映射规则
https://www.91chuli.com/ 举例:jquery前端框架
19 0