Struts2+FlashFileUpload文件上传并生成缩略图和添加水印
以前用过SWFUpload,功能确实很强大。javaeye上有人发布了这样一篇文章step-by-step多文件WEB批量上传(swfupload)的完美解决方案有兴趣的朋友可以看一下。Leeo觉得SWFUpload稍微不足的就是界面的定制,总感觉自己定制出来的界面有点难登大雅之堂。下面Leeo为大家介绍一下,如何使用FlashFileUpload这个Flash组件来实现多文件上传,并且通过java程序自动生成缩略图和添加水印,FlashFileUpload定制出来的界面还是挺漂亮的(PS:这个界面是Leeo从UUShare上弄下来的,^_^),先来Show一张效果图:
从上面的图片从可以看出中间有个水印(PS:本博客的Logo),这并不是用Photoshop之类的软件弄上去的,而是通过下面将要讲到的java程序自动添加的,效果很不错,(*^__^*) 嘻嘻……好,正式开始吧…
第一步:当然是获取flashfileupload.swf这个Flash组件啦,大家可以从这里下载,或者其他什么途径得到都行
第二步:编写上传页面的代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String uploadType = (String)request.getParameter("uploadType"); Long filmid = Long.parseLong((String)request.getParameter("filmid")); //out.print(uploadType); //out.print(filmid); %> <object id="fileUpload" codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab#version=10,0,22,87" height="310" width="500" align="middle" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"> <param name="_cx" value="13229" /> <param name="_cy" value="8202" /> <% if("Video".equals(uploadType)){ %> <param name="flashvars" value="fileTypeDescription=允许视频格式&fileTypes=*.asx;*.asf;*.mpg;*.wmv;*.3gp;*.mp4;*.mov;*.avi;*.flv;*.wmv9;*.rm;*.rmvb&completeFunction=UploadComplete()&fileSizeLimit=3000000&totalUploadSize=10240000&accounttype=0&uploadPage=flashupload!Upload.action;jsessionid=${session.id}?uploadType=<%=uploadType %>-<%=filmid %>" /> <% }else{ %> <param name="flashvars" value="fileTypeDescription=JPG格式图片&fileTypes=*.jpg;*.jpeg&completeFunction=UploadComplete()&fileSizeLimit=3000000&totalUploadSize=10240000&accounttype=0&uploadPage=flashupload!Upload.action;jsessionid=${session.id}?uploadType=<%=uploadType %>-<%=filmid %>" /> <% } %> <param name="movie" value="flashfileupload.swf?ver=20090520" /> <param name="src" value="flashfileupload.swf?ver=20090520" /> <param name="wmode" value="transparent" /> <param name="play" value="0" /> <param name="loop" value="-1" /> <param name="quality" value="high" /> <param name="salign" value="lt" /> <param name="menu" value="-1" /> <param name="base" value="" /> <param name="allowscriptaccess" value="sameDomain" /> <param name="scale" value="noscale" /> <param name="devicefont" value="0" /> <param name="embedmovie" value="0" /> <param name="bgcolor" value="" /> <param name="swremote" value="" /> <param name="moviedata" value="" /> <param name="seamlesstabbing" value="1" /> <param name="profile" value="0" /> <param name="profileaddress" value="" /> <param name="profileport" value="0" /> <param name="allownetworking" value="all" /> <param name="allowfullscreen" value="true" /> <% if("Video".equals(uploadType)){ %> <embed src="flashfileupload.swf?ver=20090520" flashvars="fileTypeDescription=允许视频格式&fileTypes=*.asx;*.asf;*.mpg;*.wmv;*.3gp;*.mp4;*.mov;*.avi;*.flv;*.wmv9;*.rm;*.rmvb&completeFunction=UploadComplete()&fileSizeLimit=3000000&totalUploadSize=10240000&accounttype=0&uploadPage=flashupload!Upload.action;jsessionid=${session.id}?uploadType=<%=uploadType %>-<%=filmid %>" quality="high" wmode="transparent" width="500" height="310" name="fileUpload" align="middle" allowscriptaccess="samedomain" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"> </embed> <% }else{ %> <embed src="flashfileupload.swf?ver=20090520" flashvars="fileTypeDescription=JPG格式图片&fileTypes=*.jpg;*.jpeg&completeFunction=UploadComplete()&fileSizeLimit=3000000&totalUploadSize=10240000&accounttype=0&uploadPage=flashupload!Upload.action;jsessionid=${session.id}?uploadType=<%=uploadType %>-<%=filmid %>" quality="high" wmode="transparent" width="500" height="310" name="fileUpload" align="middle" allowscriptaccess="samedomain" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"> </embed> <% } %> </object>
说明:其中主要的是flashvars这个参数的设置(PS:Leeo本人对这里的设置也仅仅是略知一二)
fileTypeDescription:允许上传文件的类型描述
fileTypes:允许上传的文件类型
completeFunction:上传完成后调用的js函数
fileSizeLimit:文件大小限制
totalUploadSize:一次性上传文件总大小限制
accounttype:这个没搞清楚怎么用,如果哪位知道的请告知一声,谢谢…
uploadPage:上传文件的请求路径,跟在它后面的是一些用户附加的数据。其中网上有网友说可以;jsessionid=的形式传递session,Leeo没有做测试。?uploadType=是程序中需要的一些附加数据,这里本来需要两个变量的,之所以把它写到一个变量里,然后用“-”隔开两个变量值,就像代码中的<%=uploadType %>-<%=filmid %>,是因为我们知道通常通过url传参是用“&”号隔开的,但这里却不能这么做,因为整个flashvars就是用“&”来隔开不同参数的,如果附加的数据也用“&”隔开就会被截断,得不到我们想要的数据,所以这里用一种比较马虎的解决方法,利用“-”号把不同变量值连接起来,然后在服务器端的java代码中用split("-")再把它们分割开来
第三步:配置struts.xml文件,如下:
<package name="ajaxfileupload" namespace="/" extends="ajaxfileupload-default"> <action name="flashupload" class="leeo.action.FlashfileuploadAction"> <result name="success" type="httpheader"> <param name="status">200</param> </result> </action> </package>
特别说明:这里还用到了ajax-file-upload-plugin-0.4.0.jar(PS:Struts2中用ajxa方式上传文件需要的jar包)
第四步:编写action类代码,如下:
/** 文件对象 */ private transient File[] Filedata; /** 文件名 */ /** 文件对象 */ private transient File[] Filedata; /** 文件名 */ private transient String[] FiledataFileName; /** 文件内容类型 */ private transient String[] FiledataContentType; /** * 区分是上传海报、剧照、片花 * **/ private transient String uploadType; public String Upload() throws Exception { System.out.println("FiledataFileName length:" + FiledataFileName.length); System.out.println("uploadType:" + uploadType); String[] type_filmid = uploadType.split("-"); System.out.println("filmid:" + type_filmid[1]); Film f = filmService.findFilmById(new Long(type_filmid[1])); //原文件存放路径 String OriginalImageDirectory = ServletActionContext.getServletContext().getRealPath("/UploadFile/" + type_filmid[0] + "/OriginalImage") + System.getProperty("file.separator", "\\"); for(int i = 0; i < Filedata.length; i ++){ System.out.println("Filedata["+i+"]:" + Filedata[i]); System.out.println("FiledataFileName["+i+"]:" + FiledataFileName[i]); System.out.println("FiledataContentType["+i+"]:" + FiledataContentType[i]); //在指定目录创建文件 String newname = FileUpload.getFileName(FiledataFileName[i]); File bigFile = new File(OriginalImageDirectory, newname); //把要上传的文件copy过去 FileUpload.copy(Filedata[i], bigFile); if(!"Video".equals(type_filmid[0])){ //缩略图存放路径 String ThumbnailsDirectory = ServletActionContext.getServletContext().getRealPath("/UploadFile/" + type_filmid[0] + "/Thumbnails") + System.getProperty("file.separator", "\\"); //生成缩略图 FileUpload.scaleImage(OriginalImageDirectory + newname, ThumbnailsDirectory + newname, 180, 200); //设置数据库海报字段路径 String waterImgFile = ServletActionContext.getServletContext().getRealPath("/UploadFile") + System.getProperty("file.separator", "\\"); // 给大图添加文字水印 //FileUpload.watermark(bigFile); // 给大图添加图片水印,可以是gif或png格式 FileUpload.imageWaterMark(bigFile, waterImgFile); File smallFile = new File(ThumbnailsDirectory, newname); // 给大图添加文字水印 //FileUpload.watermark(smallFile); // 给大图添加图片水印,可以是gif或png格式 FileUpload.imageWaterMark(smallFile, waterImgFile); } /* * 操作数据库部分 * */ if("Poster".equals(type_filmid[0])){ f.setFPoster(newname); filmService.modFilm(f); }else if("Still".equals(type_filmid[0])){ FilmStill fs = new FilmStill(); fs.setFsPath(newname); fs.setFilm(f); filmService.addFilmStill(fs); }else if("Video".equals(type_filmid[0])){ FilmVideo fv = new FilmVideo(); fv.setFvPath(newname); fv.setFilm(f); filmService.addFilmVideo(fv); } } return SUCCESS; } public File[] getFiledata() { return Filedata; } public void setFiledata(File[] filedata) { this.Filedata = filedata; } public String[] getFiledataFileName() { return FiledataFileName; } public void setFiledataFileName(String[] filedataFileName) { this.FiledataFileName = filedataFileName; } public String[] getFiledataContentType() { return FiledataContentType; } public void setFiledataContentType(String[] filedataContentType) { this.FiledataContentType = filedataContentType; } public String getUploadType() { return uploadType; } public void setUploadType(String uploadType) { this.uploadType = uploadType; }
其中,操作数据库部分的代码跟这个例子无关,可以省去。
第五步:要用到的其他类的代码(PS:这部分代码来自互联网)
1:FileUpload.java用于生成缩略图、添加水印、生成无重复的文件名
import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Image; import java.awt.image.BufferedImage; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.text.SimpleDateFormat; import java.util.Date; import javax.imageio.ImageIO; import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGImageEncoder; public class FileUpload { private static final int BUFFER_SIZE = 16 * 1024; private static final String WATER_TEXT = "文字水印"; private static final String WATER_IMG_NAME = "logo.png"; /*生成无重复文件名*/ public static String getFileName(String name){ SimpleDateFormat df =new SimpleDateFormat("yyyyMMddHHmmss"); Date date = new Date(); String filename=null; if(!"".equals(name) && name != null){ filename=df.format(date) + RandomNum.random2() + name.substring(name.lastIndexOf("."), name.length()); } System.out.println("filename is:"+filename); return filename; } /*上传文件*/ public static void copy(File src, File dst) { try { InputStream in = null; OutputStream out = null; try { in = new BufferedInputStream(new FileInputStream(src), BUFFER_SIZE); out = new BufferedOutputStream(new FileOutputStream(dst), BUFFER_SIZE); byte[] buffer = new byte[BUFFER_SIZE]; while (in.read(buffer) > 0) { out.write(buffer); } } finally { if (null != in) { in.close(); } if (null != out) { out.close(); } } } catch (Exception e) { e.printStackTrace(); } } /*生成缩略图*/ public static String scaleImage(String fromFileStr, String saveToFileStr, int formatWideth, int formatHeight) throws Exception { ScaleImage is = new ScaleImage(); try { is.saveImageAsJpg(fromFileStr, saveToFileStr, formatWideth, formatHeight); }catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); return "error"; } return "ok"; } /** * 添加文字水印 * * @return * @throws Exception * @throws Exception */ public static void watermark(File img) throws Exception { System.out.println("[watermark file name]--" + img.getPath()); try { if (!img.exists()) { throw new IllegalArgumentException("file not found!"); } System.out.println("[watermark][img]--" + img); // 创建一个FileInputStream对象从源图片获取数据流 FileInputStream sFile = new FileInputStream(img); // 创建一个Image对象并以源图片数据流填充 Image src = ImageIO.read(sFile); // 得到源图宽 int width = src.getWidth(null); // 得到源图长 int height = src.getHeight(null); // 创建一个BufferedImage来作为图像操作容器 BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); // 创建一个绘图环境来进行绘制图象 Graphics2D g = image.createGraphics(); // 将原图像数据流载入这个BufferedImage System.out.println("width:" + width + " height:" + height); g.drawImage(src, 0, 0, width, height, null); // 设定文本字体 g.setFont(new Font("宋体", Font.BOLD, 28)); String rand = WATER_TEXT; // 设定文本颜色 g.setColor(Color.blue); // 设置透明度 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.5f)); // 向BufferedImage写入文本字符,水印在图片上的坐标 g.drawString(rand, width - (width - 20), height - (height - 60)); // 使更改生效 g.dispose(); // 创建输出文件流 FileOutputStream outi = new FileOutputStream(img); // 创建JPEG编码对象 JPEGImageEncoder encodera = JPEGCodec.createJPEGEncoder(outi); // 对这个BufferedImage (image)进行JPEG编码 encodera.encode(image); // 关闭输出文件流 outi.close(); sFile.close(); } catch (IOException e) { e.printStackTrace(); throw new Exception(e); } } /** * 添加图片水印 * */ public static void imageWaterMark(File imgFile, String waterFilePath) throws Exception { try { // 目标文件 Image src = ImageIO.read(imgFile); int wideth = src.getWidth(null); int height = src.getHeight(null); BufferedImage image = new BufferedImage(wideth, height, BufferedImage.TYPE_INT_RGB); Graphics2D g = image.createGraphics(); g.drawImage(src, 0, 0, wideth, height, null); // 水印文件 路径 String waterImgPath = waterFilePath + WATER_IMG_NAME; System.out.println("waterImgPath--" + waterImgPath); File waterFile = new File(waterImgPath); Image waterImg = ImageIO.read(waterFile); int w_wideth = waterImg.getWidth(null); int w_height = waterImg.getHeight(null); g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.5f)); g.drawImage(waterImg, (wideth - w_wideth) / 2, (height - w_height) / 2, w_wideth, w_height, null); // 水印文件结束 g.dispose(); FileOutputStream out = new FileOutputStream(imgFile); JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); encoder.encode(image); out.close(); } catch (Exception e) { e.printStackTrace(); } } }
2:RandomNum.java用于生成无重复随机数
import java.util.Random; public class RandomNum { public static int[] random1() { Random r = new Random(); int temp1, temp2; int send[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; int len = send.length; int returnValue[] = new int[22]; for (int i = 0; i < 22; i++) { temp1 = Math.abs(r.nextInt()) % len; returnValue[i] = send[temp1]; temp2 = send[temp1]; send[temp1] = send[len - 1]; send[len - 1] = temp2; len--; } return returnValue; } public static int[] random2() { int send[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; int temp1, temp2, temp3; Random r = new Random(); for (int i = 0; i < send.length; i++){// 随机交换send.length次 temp1 = Math.abs(r.nextInt()) % (send.length - 1); // 随机产生一个位置 temp2 = Math.abs(r.nextInt()) % (send.length - 1); // 随机产生另一个位置 if (temp1 != temp2) { temp3 = send[temp1]; send[temp1] = send[temp2]; send[temp2] = temp3; } } return send; } }
到此,本应用实例的代码就完成了,赶紧体验一下吧。。。
