100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > Java MultipartFile实现文件上传并为图片加上水印(二)

Java MultipartFile实现文件上传并为图片加上水印(二)

时间:2021-01-05 14:54:01

相关推荐

Java MultipartFile实现文件上传并为图片加上水印(二)

防止走丢~~欢迎大家留言收藏点赞

在上一篇我们已经实现了文件的上传,那么如果对于图片的上传,我们要给图片加上我们需要的水印信息,比如图片的上传人,上传地点等信息,此时我们为上传功能再新增水印功能。

最终上传效果如图所示

一、前端上传至服务端(controller层)

水印信息可以由客户端请求过来,也可以服务端自定义,因为我现在的业务是车辆图片上传,需要为上传的车辆图片增加车牌号、上传人、上传经纬度以及地址信息等,这些信息是由客户端获取以后给到服务端的,水印信息加什么东西大家可以灵活操作。

/*** 文件/图片上传* @param files 文件集合* @param type 1储存相对路径 2储存绝对路径* @return* @Author Smily* @DateTime 2月7日*/@ResponseBody@RequestMapping(value = "uploadTest.html", method = RequestMethod.POST)public Object uploadTest(MultipartFile[] files,@RequestParam(defaultValue = "") String describe,//图片描述@RequestParam(defaultValue = "") String isWaterMarker,//是否增加水印 0不增加 1增加@RequestParam(defaultValue = "") String waterJson,//水印文字@RequestParam(defaultValue = "1") String type) //1返回图片相对路径 2返回图片绝对路径{if (files == null || (files.length == 1 && files[0].getSize() == 0)){return putData("图片为空");}//水印信息List<FileUploadWaterMarkerEntity> fileUploadWaterMarkerEntityList = new ArrayList<>();if ("1".equals(isWaterMarker)){if (StringUtils.isBlank(waterJson)){return putData("水印信息为空");}//水印数组的长度应该和图片数组长度相同fileUploadWaterMarkerEntityList = JSON.parseArray(waterJson, FileUploadWaterMarkerEntity.class);if (fileUploadWaterMarkerEntityList.size() != files.length){return putData("水印信息数量与图片数量不符");}//登录用户信息for (FileUploadWaterMarkerEntity fileUploadWaterMarkerEntity : fileUploadWaterMarkerEntityList){//Common.getLoginName()是获取用户信息的方法,这里我就不贴出来了,大家自行处理fileUploadWaterMarkerEntity.setUserName(Common.getLoginName());}}Map<String, Object> map = fileUploadService.uploadTest(files,describe,type);return map;}

二、水印实体

package com.mon;/*** * 上传图片时需要的水印信息实体** @author Smily* @date 2月7日**/public class FileUploadWaterMarkerEntity {//用户姓名private String userName;//车牌private String carNumber;//时间private String time;//经度private String longitude;//纬度private String latitude;//地址private String address;public String getCarNumber() {return carNumber;}public void setCarNumber(String carNumber) {this.carNumber = carNumber;}public String getTime() {return time;}public void setTime(String time) {this.time = time;}public String getLongitude() {return longitude;}public void setLongitude(String longitude) {this.longitude = longitude;}public String getLatitude() {return latitude;}public void setLatitude(String latitude) {this.latitude = latitude;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}}

三、service层

/*** 文件上传** @Author: Smily* @Date: /2/7 14:00*/Map<String, Object> uploadTest(MultipartFile[] files,String describe, String type, String isWaterMarker, List<FileUploadWaterMarkerEntity> fileUploadWaterMarkerEntityList);

四、实现文件上传

水印信息添加原理是先将原图片上传至图片服务器,再通过图片IO流读取到源图片,使用Graphics2D绘图对源图片进行处理,生成新的目标图片再存储在图片服务器上,这时我们再获取到新的图片地址就OK了

package com.mon.impl;import java.io.File;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Date;import java.util.List;import java.util.Map;import mons.lang3.StringUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Service;import org.springframework.web.multipart.MultipartFile;import com.app.base.basecontroller.BaseController;import com.mon.FileUploadEntity;import com.mon.FileUploadWaterMarkerEntity;import com.mon.FileUploadService;import com.app.util.fileupload.ImageWatermarkUtil;/*** 文件/图片上传* @Author Smily* @DateTime 2月7日*/@Service("fileUploadService")public class FileUploadServiceImpl extends BaseController implements FileUploadService {public static Logger logger = LoggerFactory.getLogger(FileUploadServiceImpl.class);@Value("${httpHead}")private String httpHead;@Overridepublic Map<String, Object> uploadTest(MultipartFile[] files, String describe, String type,String isWaterMarker,List<FileUploadWaterMarkerEntity> fileUploadWaterMarkerEntityList) {SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");List<String> urlList = new ArrayList<>();for (int i = 0; i < files.length; i++) {MultipartFile file = files[i];String saveDBPath = "";if (file != null && file.getSize() > 0) {String fileName = file.getOriginalFilename();//根据文件类型储存在不同的文件夹下String extension = getSuffix(fileName);//文件格式if ((".pjpeg").equals(extension)) {//图片扩展名=转换extension = ".jpeg";}if (StringUtils.isBlank(extension)){logger.error("上传失败,未获取到文件名");return putData(Boolean.FALSE, "上传失败,未获取到文件名!", null);}//文件存储目录String datePath = new SimpleDateFormat("yyyy/MM/dd/").format(new Date());//根据日期创建不同目录String folderPath = "";if (isImage(extension)) {folderPath = "image/" + datePath;}else {folderPath = "file/" + datePath;}String path = "/home/file_storage/" + folderPath;//文件名 普通地址 命名方式:时间-数字-描述String newFileName = sdf.format(new Date()) + "-" + (i + 1) + extension;//文件名 加了水印图片地址String wFileName = "w-" + sdf.format(new Date()) + "-" + describe + "-" + (i + 1) + extension;File targetFile = new File(path, newFileName);if (!targetFile.exists()) targetFile.mkdirs();try {file.transferTo(targetFile);//判断是否需要加水印,如果要加水印则返回加水印的图片,否则正常返回图片地址if ("1".equals(isWaterMarker) && isImage(extension) && fileUploadWaterMarkerEntityList.size() > 0){List<String> list = new ArrayList<>();try {//将水印对象转化成需要的字符串FileUploadWaterMarkerEntity fileUploadWaterMarkerEntity = fileUploadWaterMarkerEntityList.get(i);//账号信息if (StringUtils.isNotBlank(fileUploadWaterMarkerEntity.getUserName())){list.add("账号:"+ fileUploadWaterMarkerEntity.getUserName());}//车牌信息if (StringUtils.isNotBlank(fileUploadWaterMarkerEntity.getCarNumber())){list.add("车牌:"+fileUploadWaterMarkerEntity.getCarNumber());}//时间if (StringUtils.isNotBlank(fileUploadWaterMarkerEntity.getTime())){list.add("时间:"+fileUploadWaterMarkerEntity.getTime());}//经度if (StringUtils.isNotBlank(fileUploadWaterMarkerEntity.getLongitude())){list.add("经度:"+fileUploadWaterMarkerEntity.getLongitude());}//纬度if (StringUtils.isNotBlank(fileUploadWaterMarkerEntity.getLatitude())){list.add("纬度:"+fileUploadWaterMarkerEntity.getLatitude());}//地址if (StringUtils.isNotBlank(fileUploadWaterMarkerEntity.getAddress())){list.add("地址:"+fileUploadWaterMarkerEntity.getAddress());}}catch (Exception e){logger.error("平台上传图片时解析水印信息json串异常");}ImageWatermarkUtil.imageAddWater(list,path + newFileName,path + wFileName,null);newFileName = wFileName;//如果有水印图片,则数据库储存水印图片地址}//储存数据库文件名if ("1".equals(type)){//相对路径saveDBPath = "/fileserver/"+ folderPath + newFileName;}else if ("2".equals(type)){//绝对路径saveDBPath = httpHead + "/fileserver/"+ folderPath + newFileName;}urlList.add(saveDBPath);} catch (Exception e) {logger.error("文件上传失败", e);}}}return putData(Boolean.TRUE, "上传成功!", urlList);}/*** 获取文件后缀* @Author Smily* @DateTime 2月7日* @param filename* @return*/private String getSuffix(String filename) {if (StringUtils.isNotBlank(filename)){String suffix = "";int pos = filename.lastIndexOf('.');if (pos > 0 && pos < filename.length() - 1) {suffix = filename.substring(pos);}return suffix.toLowerCase();}return "";}/*** 判断文件类型* @param suffix* @Author Smily* @DateTime 2月7日* @return*/public static boolean isImage(String suffix) {suffix = suffix.toUpperCase();if (".PNG".equals(suffix)|| ".JPG".equals(suffix)|| ".JEPG".equals(suffix)|| ".JPEG".equals(suffix)|| ".BMP".equals(suffix)|| ".HEIC".equals(suffix)) {return true;}return false;}}

五、水印操作类

这里新增水印有很多细节操作,我这里水印生成在图片的左下角,并且为了保证生成的文字可见,增加了一张透明的底色背景图,Graphics2D有很多操作,比如等比分布,旋转,对称渲染等都能够实现,后面有时间我会专门写一篇关于绘图的文章,这里我们先实现简单水印操作

package com.app.util.fileupload;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import java.awt.*;import java.awt.image.BufferedImage;import java.io.*;import java.util.Objects;import javax.imageio.ImageIO;import javax.servlet.http.HttpServletRequest;/*** 上传的图片增加水印** @Author Smily* @Date /2/7*/public class ImageWatermarkUtil {public static Logger logger = LoggerFactory.getLogger(ImageWatermarkUtil.class);// 水印文字颜色private static Color color = Color.black;/*** 给图片添加水印文字** @param logoText 水印文字* @param srcImgPath 源图片路径* @param targerPath 目标图片路径*/public static void imageAddWater(java.util.List<String> logoText, String srcImgPath, String targerPath,Integer degree) {doImage(logoText, srcImgPath, targerPath, degree);}/*** 给图片添加水印* 在图片的左下角添加,先添加半透明图片,再添加水印文字** @param logoText* @param srcImgPath* @param targerPath* @param degree* @param*/public static void doImage(java.util.List<String> logoText, String srcImgPath, String targerPath, Integer degree) {OutputStream os = null;try {// 源图片Image srcImg = ImageIO.read (new File (srcImgPath));int width = srcImg.getWidth (null);// 原图宽度int height = srcImg.getHeight (null);// 原图高度//通过原图计算出字体大小int FONT_SIZE = width / 3600;Font font = new Font ("宋体", Font.BOLD, FONT_SIZE);BufferedImage buffImg = new BufferedImage (srcImg.getWidth (null), srcImg.getHeight (null),BufferedImage.TYPE_INT_RGB);// 得到画笔Graphics2D g = buffImg.createGraphics();// 对线段的锯齿状边缘处理g.setRenderingHint (RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);//水印图片的坐标点g.drawImage(srcImg, 0, 0, width, height, null);//添加水印图片,增加一张底色图片,这里我把路径放在resources/images/bg_water_mark_white.png下面HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();String url = request.getSession().getServletContext().getRealPath("/") + "resources/images/bg_water_mark_white.png";Image srcWaterImg = ImageIO.read(new File(url));//水印文字的字体高度(多加一行,防止地址信息过长)int markHeight = FONT_SIZE * (logoText.size() + 1);//水印图片透明度g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,0.2f));int imgX = 0,imgY;//水印图片x轴原点,水印图片y轴原点imgY = height - markHeight - FONT_SIZE;//水印图片在底部添加,长度为原图片长度,宽度为字体高度再往上加一点点g.drawImage(srcWaterImg, imgX, imgY, width, markHeight, null);//添加水印文字// 设置水印旋转if (null != degree) {g.rotate (Math.toRadians (degree), (double) buffImg.getWidth () / 2, (double) buffImg.getHeight () / 2);}// 设置水印文字颜色g.setColor (color);// 设置水印文字Fontg.setFont (font);// 设置水印文字透明度g.setComposite(AlphaComposite.getInstance (AlphaComposite.SRC_ATOP, 0.8f));int x,y;//水印文字x轴原点,水印文字y轴原点//添加多行文字水印,水印文字也在图片左下角for (int i = 0;i < logoText.size();i++){if (!logoText.get(i).contains("地址")){x = 15;y = (height - (markHeight - (i * FONT_SIZE)));g.drawString (logoText.get(i), x, y);}else {//如果包含地址信息,文字可能超过图片宽度,这时需要换行操作(注意:地址信息一定要在logoText数组的最后一个)x = 15;y = (height - (markHeight - (i * FONT_SIZE)));int tempCharLen = 0;//单字符长度int tempLineLen = 0;//单行字符总长度StringBuffer sb =new StringBuffer();for(int j = 0; j < logoText.get(i).length(); j++) {char tempChar = logoText.get(i).charAt(j);tempCharLen = getCharLen(tempChar, g);tempLineLen += tempCharLen;if(tempLineLen >= width) {//长度已经满一行,进行文字叠加g.drawString(sb.toString(), x, y);//清空内容,重新赋值追加sb.delete(0, sb.length());int k = i;k++;y = (height - (markHeight - (k * FONT_SIZE)));tempLineLen = 0;}sb.append(tempChar);//追加字符}//最后叠加余下的文字g.drawString(sb.toString(), x, y);}}g.dispose();// 生成图片os = new FileOutputStream (targerPath);ImageIO.write (buffImg, "JPG", os);os.close();} catch (Exception e) {e.printStackTrace ();logger.error("图片添加水印失败");}}/*** 单个字符长度** @Param [c, g]* @Author: Smily* @Date: /9/9 14:20*/public static int getCharLen(char c, Graphics2D g) {return g.getFontMetrics(g.getFont()).charWidth(c);}}

现在己经实现了水印图片的上传,这里我把底色图片也贴出来给大家。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。