说在前面
工作中会遇到很多需要使用富文本编辑器的地方,比如我现在发布这篇文章离不开这个神器,而且现在网上编辑器太多了。记得之前,由于工作需要自己封装过一个编辑器的公共插件,是用ckeditor改版的,目的是要兼容公司所有项目,使用方便。废话不多说,今天写这篇文章,一是总结自己学习复习,二是关于FTP上传官方资料太少,也便于他人少趟坑,我在这里会说的很细很明白,希望亲们以后不要中枪了!
关于编辑器的简单部署
去官网下载后,我们需要把下载的编辑器文件夹,摘一部分放到项目中,下载之后的目录,如下图(我这里用的是jsp简化版 1.2.2)
我在外面新建了个插件目录umeditor,如下图:
除了jsp文件夹,其余拷到项目静态资源的目录中,然后 我们来分析jsp文件夹都有哪些东东?
这里,我把那两个jar包带入到项目中,这里我改了名字,方便导入,fileupload那个jar包项目之前就有。如下图:
接下来,就是页面调用了,很简单,首先将编辑器所需要的样式和脚本文件引入:
/**以上省略,这里引入到页面头部**/ <link href="${ctx}/static/umeditor/themes/default/css/umeditor.css" type="text/css" rel="stylesheet"> <script type="text/javascript" charset="utf-8" src="${ctx}/static/umeditor/umeditor.config.js"></script> <script type="text/javascript" charset="utf-8" src="${ctx}/static/umeditor/umeditor.min.js"></script> <script type="text/javascript" src="${ctx}/static/umeditor/lang/zh-cn/zh-cn.js"></script> </head>
接下来,需要在页面调用编辑器对象,官方用的是script标签,我这里用textarea来构造
<div class="controls"> <form:textarea id="content" htmlEscape="true" path="articleData.content" rows="4" maxlength="200" class="input-xxlarge"/> <script type="text/javascript"> //实例化编辑器 var um = UM.getEditor('content'); //注意ID的一致 um.setWidth(700); //设置编辑器宽度 </script> </div>
至此基本的工作已做完,上述相信大部分搞开发的同胞们,都没问题吧!效果图如下:
关于编辑器的后台实现
官方下载给的后台处理文件除了必要的jar外有三个文件:
(1) Uploader.java 文件
该文件主封装了一个文件上传对象,包括上传后需要返回的参数、状态、URL,除此还有一个上传的处理函数,当然只是普通的文件存储,不符合我们的需求,但是我们可以知道前端需要的一些返回值。
(2) imageUp.jsp 文件
上传图片默认配置后台处理文件,主要调用Upload上传类,完成上传 并把上传结果 以json字符串发往前台,其中包括重要的state、url等参数
(3) getContent.jsp 文件 (和上传没关系,略过)
以上分析过官方给的简单后台处理逻辑,我们不难知道实际上就是需要我们提供一个上传处理函数并返回包含必要参数的JSON串
那好,接下来我们开始写自己的后台上传处理函数了。
第一步 后台控制器处理函数(重要程度:☆☆☆☆☆)
1 /** 2 * 编辑器上传图片 3 */ 4 @RequiresPermissions("cms:article:view") 5 @RequestMapping(value={"/upload"}) 6 @ResponseBody() 7 public String upload(HttpServletRequest request,HttpServletResponse response){ 8 9 //request.getParameter("path"); 10 String[] allowExtName = {".jpg",".png",".gif",".bmp",".jpeg"};//图片格式限制 11 List<MultipartFile> multipartFiles = getFileSet(request, 1024 * 1024 * 10, allowExtName); //上传的图片大小可以放到配置中读取,这里设置10M 12 Map<String,Object> map = new HashMap<String,Object>(); 13 try { 14 if(multipartFiles.size() > 0){ 15 MultipartFile file = multipartFiles.get(0); 16 InputStream is = file.getInputStream(); 17 String tempFileName = file.getOriginalFilename(); 18 if(is != null&&StringUtils.isNotBlank(tempFileName)){ 19 20 //生成文件名 21 String uuid = IdGen.uuid(); //生成的一个随机字符串,用于图片名 22 String fileName = uuid+tempFileName.substring(tempFileName.indexOf(".")); 23 //生成文件路徑 24 boolean ftpWaterRs=true; 25 FTPUtils ftpUtils = FTPUtils.getInstance(); 26 SimpleDateFormat sf = new SimpleDateFormat("yyyy/MM/"); 27 String ss = sf.format(new Date()); //以当前时间,生成存放目录,格式/yyyy/MM 28 String storePath = ftpUtils.getSaveFilePath() + ss; //读取配置的存储目录 比如 /upload/image/ 29 //图片加水印 getResourceRootRealPath ; 若图片大小小于logo大小则不加水印 30 if(file.getSize()>1200){ //这里给图片增加水印功能 31 String waterName= uuid + "_water"+tempFileName.substring(tempFileName.indexOf(".")); 32 //缓存文件类型转换 33 CommonsMultipartFile cf= (CommonsMultipartFile)file; 34 DiskFileItem fi = (DiskFileItem)cf.getFileItem(); 35 File tempFile = fi.getStoreLocation(); 36 String waterTempPath = SpringContextHolder.getRootRealPath()+"/"+waterName; 37 String logoPath=SpringContextHolder.getRootRealPath()+"/static/images/shuiyin.png"; //水印图片路径 38 ImageUtils.markImageByIcon(logoPath, tempFile, waterTempPath, 45); //添加水印 39 File waterFile = new File(waterTempPath); 40 //上传水印图片 41 ftpWaterRs = ftpUtils.storeFile(storePath,waterName,new FileInputStream(waterFile)); 42 if(ftpWaterRs){ 43 FileUtils.deleteFile(waterTempPath); 44 is.close(); 45 map.clear(); 46 map.put("state","SUCCESS"); //注意:返回的参数state 成功必须是 SUCCESS,否则需要到image.js中改,失败可以自定义 47 //map.put("url",ftpUtils.getSiteName().trim()+storePath.trim() + waterName); 48 map.put("url",storePath.trim() + waterName);
//url 这里有个坑,绝对完整地址图片不会显示
//我现在返回的是不包含域名的路径 如 /upload/images/2016/08/03/a23ssds6s6d56ds656a6a5652636.jpg
//域名部分路径也就是http://static.xx.com/ 需要到前端配置,具体是 在umeditor.config.js 配置参数 imagePath 所谓的图片修正地址喽 49 return JsonMapper.toJsonString(map); 50 } 51 } 52 53 //上传源文件 54 boolean ftpFileRs = ftpUtils.storeFile(storePath, fileName, is); 55 is.close(); 56 if(ftpFileRs){ //这里水印图片上传失败 会采用原图 57 map.clear(); 58 map.put("state","SUCCESS"); 59 map.put("url",storePath.trim() + fileName); 60 return JsonMapper.toJsonString(map); 61 } 62 } 63 } 64 else{ 65 map.clear(); 66 map.put("state","请检查图片格式或尺寸,图片必须小于10M"); 67 return JsonMapper.toJsonString(map); 68 } 69 } catch (Exception e) { 70 e.printStackTrace(); 71 } 72 map.clear(); 73 map.put("state","上传请求异常"); 74 return JsonMapper.toJsonString(map); 75 }
第二步 处理函数用到上传图片验证函数包含大小和格式(重要程度:☆☆☆)
1 /** 2 * @descrption 根据HttpServletRequest对象获取MultipartFile集合 3 * @author zp 4 * @param request 5 * @param maxLength 6 * 文件最大限制 7 * @param allowExtName 8 * 不允许上传的文件扩展名 9 * @return MultipartFile集合 10 */ 11 public static List<MultipartFile> getFileSet(HttpServletRequest request, 12 long maxLength, String[] allowExtName) { 13 MultipartHttpServletRequest multipartRequest = null; 14 try { 15 multipartRequest = (MultipartHttpServletRequest) request; 16 } catch (Exception e) { 17 return new LinkedList<MultipartFile>(); 18 } 19 20 List<MultipartFile> files = new LinkedList<MultipartFile>(); 21 files = multipartRequest.getFiles("upfile"); //upfile 是编辑器默认的上传图片表单name,在文件umeditor.config.js 可自定义配置参数 imageFieldName 22 // 移除不符合条件的 23 for (int i = 0; i < files.size(); i++) { 24 if (!validateFile(files.get(i), maxLength, allowExtName)) { 25 files.remove(files.get(i)); 26 if (files.size() == 0) { 27 return files; 28 } 29 } 30 } 31 return files; 32 } 33 34 /** 35 * @descrption 验证文件格式,这里主要验证后缀名 36 * @author zp 37 * @param file 38 * MultipartFile对象 39 * @param maxLength 40 * 文件最大限制 41 * @param allowExtName 42 * 不允许上传的文件扩展名 43 * @return 文件格式是否合法 44 */ 45 private static boolean validateFile(MultipartFile file, long maxLength, 46 String[] allowExtName) { 47 if (file.getSize() < 0 || file.getSize() > maxLength) 48 return false; 49 String filename = file.getOriginalFilename(); 50 51 // 处理不选择文件点击上传时,也会有MultipartFile对象,在此进行过滤 52 if (filename == "") { 53 return false; 54 } 55 String extName = filename.substring(filename.lastIndexOf(".")) 56 .toLowerCase(); 57 if (allowExtName == null || allowExtName.length == 0 58 || Arrays.binarySearch(allowExtName, extName) != -1) { 59 return true; 60 } else { 61 return false; 62 } 63 }
第三步 FTP上传处理类,绝对福利..好多人想要哦 0.0(重要程度:☆☆☆☆)
1 package com.xx.utils; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.IOException; 6 import java.io.InputStream; 7 8 import org.apache.commons.net.ftp.FTPClient; 9 import org.apache.commons.net.ftp.FTPFile; 10 import org.apache.commons.net.ftp.FTPReply; 11 12 import com.xx.Global; 13 14 /** 15 * FTP服务器工具类 16 */ 17 public class FTPUtils { 18 19 private static FTPUtils ftpUtils; 20 private FTPClient ftpClient; 21 //private FTPFile ftpFile; 22 private String port; // 服务器端口 23 private String username; // 用户登录名 24 private String password; // 用户登录密码 25 private String serverName; // 服务名 26 private int localPasv;//开启本地被动模式 27 private String siteName; // 站点域名 28 private String saveFilePath;//存储路径 29 30 31 private InputStream is; // 文件下载输入流 32 33 /** 34 * 私有构造方法 35 */ 36 private FTPUtils() { 37 initConfig(); 38 if (null == ftpClient) { 39 ftpClient = new FTPClient(); 40 } 41 } 42 43 /** 44 * 获取FTPUtils对象实例 45 * @return 46 * FTPUtils对象实例 47 */ 48 public synchronized static FTPUtils getInstance () { 49 if (null == ftpUtils) { 50 ftpUtils = new FTPUtils(); 51 } 52 return ftpUtils; 53 } 54 55 /** 56 * 初始化FTP服务器连接属性 57 */ 58 // public void initConfig () { 59 // // 构造Properties对象 60 // Properties properties = new Properties(); 61 // 62 // // 定义配置文件输入流 63 // InputStream is = null; 64 // try { 65 // // 获取配置文件输入流 66 // is = FTPUtils.class.getResourceAsStream("/ftp.properties"); 67 // // 加载配置文件 68 // properties.load(is); 69 // // 读取配置文件 70 // port = (String) properties.get("port"); // 设置端口 71 // username = (String) properties.get("username1"); // 设置用户名 72 // password = (String) properties.get("password1"); // 设置密码 73 // serverName = (String) properties.get("serverName"); // 服务名 74 // localPasv = Integer.valueOf(String.valueOf(properties.get("localPasv"))); 75 // } catch (IOException e) { 76 // e.printStackTrace(); 77 // } finally { 78 // // 判断输入流是否为空 79 // if (null != is) { 80 // try { 81 // // 关闭输入流 82 // is.close(); 83 // } catch (IOException e) { 84 // e.printStackTrace(); 85 // } 86 // } 87 // } 88 // } 89 90 public void initConfig () { 91 serverName = Global.getConfig("ftp.serverName"); 92 // SystemConfig.getInstance().getApplication().get("ftp.serverName"); 93 port = Global.getConfig("ftp.port"); 94 // SystemConfig.getInstance().getApplication().get("ftp.port"); 95 username = Global.getConfig("ftp.username1"); 96 // SystemConfig.getInstance().getApplication().get("ftp.username1"); 97 password =Global.getConfig("ftp.password1"); 98 // portSystemConfig.getInstance().getApplication().get("ftp.password1"); 99 localPasv = Integer.valueOf(Global.getConfig("ftp.localPasv")); 100 // Integer.valueOf(SystemConfig.getInstance().getApplication().get("ftp.localPasv")); 101 siteName = Global.getConfig("ftp.readPath"); //读取配置 访问路径 102 saveFilePath = Global.getConfig("ftp.upLoadPath"); //读取配置 上传路径 103 104 } 105 /** 106 * 连接(配置通用连接属性)至服务器 107 * 108 * @param serverName 109 * 服务器名称 110 * @param remotePath 111 * 当前访问目录 112 * @return 113 * <b>true</b>:连接成功 114 * <br/> 115 * <b>false</b>:连接失败 116 */ 117 public boolean connectToTheServer (String remotePath) { 118 // 定义返回值 119 boolean result = false; 120 try { 121 // 连接至服务器,端口默认为21时,可直接通过URL连接 122 ftpClient.connect(serverName, Integer.parseInt(port)); 123 // 登录服务器 124 ftpClient.login(username, password); 125 // 判断返回码是否合法 126 if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) { 127 // 不合法时断开连接 128 ftpClient.disconnect(); 129 // 结束程序 130 return result; 131 } 132 if(localPasv==1) 133 ftpClient.enterLocalPassiveMode(); 134 // 设置文件操作目录 135 result = createDirAndToDir(remotePath); 136 System.out.println("result===="+result); 137 // 设置文件类型,二进制 138 result = ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); 139 // 设置缓冲区大小 140 ftpClient.setBufferSize(3072); 141 // 设置字符编码 142 ftpClient.setControlEncoding("UTF-8"); 143 } catch (IOException e) { 144 e.printStackTrace(); 145 } 146 return result; 147 } 148 149 /** 150 * 上传文件至FTP服务器 151 * 152 * @param serverName 153 * 服务器名称 154 * @param storePath 155 * 上传文件存储路径 156 * @param fileName 157 * 上传文件存储名称 158 * @param is 159 * 上传文件输入流 160 * @return 161 * <b>true</b>:上传成功 162 * <br/> 163 * <b>false</b>:上传失败 164 */ 165 public boolean storeFile (String storePath, String fileName, InputStream is) { 166 boolean result = false; 167 try { 168 // 连接至服务器 169 result = connectToTheServer(storePath); 170 // 判断服务器是否连接成功 171 if (result) { 172 // 上传文件 173 result = ftpClient.storeFile(fileName, is); 174 } 175 // 关闭输入流 176 is.close(); 177 } catch (IOException e) { 178 e.printStackTrace(); 179 } finally { 180 // 判断输入流是否存在 181 if (null != is) { 182 try { 183 // 关闭输入流 184 is.close(); 185 } catch (IOException e) { 186 e.printStackTrace(); 187 } 188 } 189 // 登出服务器并断开连接 190 ftpUtils.logout(); 191 } 192 return result; 193 } 194 195 /** 196 * 下载FTP服务器文件至本地<br/> 197 * 操作完成后需调用logout方法与服务器断开连接 198 * 服务器名称 199 * @param remotePath 200 * 下载文件存储路径 201 * @param fileName 202 * 下载文件存储名称 203 * @return 204 * <b>InputStream</b>:文件输入流 205 */ 206 public InputStream retrieveFile (String remotePath, String fileName) { 207 try { 208 boolean result = false; 209 // 连接至服务器 210 result = connectToTheServer(remotePath); 211 // 判断服务器是否连接成功 212 if (result) { 213 // 获取文件输入流 214 is = ftpClient.retrieveFileStream(fileName); 215 } 216 } catch (IOException e) { 217 e.printStackTrace(); 218 } 219 return is; 220 } 221 222 /** 223 * 删除FTP服务器文件 224 * 225 * @param serverName 226 * 服务器名称 227 * @param remotePath 228 * 当前访问目录 229 * @param fileName 230 * 文件存储名称 231 * @return 232 * <b>true</b>:删除成功 233 * <br/> 234 * <b>false</b>:删除失败 235 */ 236 public boolean deleteFile (String serverName, String remotePath, String fileName) { 237 boolean result = false; 238 // 连接至服务器 239 result = connectToTheServer(remotePath); 240 // 判断服务器是否连接成功 241 if (result) { 242 try { 243 // 删除文件 244 result = ftpClient.deleteFile(fileName); 245 } catch (IOException e) { 246 e.printStackTrace(); 247 } finally { 248 // 登出服务器并断开连接 249 ftpUtils.logout(); 250 } 251 } 252 return result; 253 } 254 255 /** 256 * 创建目录 257 * 258 * @param remotePath 259 * 目录储路径 260 * @return 261 * <b>true</b>:创建成功 262 * <br/> 263 * <b>false</b>:创建失败 264 */ 265 public boolean createDirAndToDir (String remotePath) { 266 boolean result = false; 267 try { 268 // 连接至服务器 269 //result = ftpClient.changeWorkingDirectory(remotePath); 270 String [] dirs = remotePath.split("/"); 271 if(dirs!=null){ 272 String tempDir = ""; 273 for(String dir : dirs){ 274 tempDir += dir +"/"; 275 result = ftpClient.changeWorkingDirectory(tempDir); 276 if(!result){ 277 result = ftpClient.makeDirectory(dir); 278 ftpClient.changeWorkingDirectory(dir); 279 } 280 } 281 } 282 } catch (IOException e) { 283 e.printStackTrace(); 284 return false; 285 } 286 return true; 287 } 288 /** 289 * 检测FTP服务器文件是否存在 290 * 服务器名称 291 * @param remotePath 292 * 检测文件存储路径 293 * @param fileName 294 * 检测文件存储名称 295 * @return 296 * <b>true</b>:文件存在 297 * <br/> 298 * <b>false</b>:文件不存在 299 */ 300 public boolean checkFile (String remotePath, String fileName) { 301 boolean result = false; 302 try { 303 // 连接至服务器 304 result = connectToTheServer(remotePath); 305 // 判断服务器是否连接成功 306 if (result) { 307 // 默认文件不存在 308 result = false; 309 // 获取文件操作目录下所有文件名称 310 String[] remoteNames = ftpClient.listNames(); 311 // 循环比对文件名称,判断是否含有当前要下载的文件名 312 for (String remoteName: remoteNames) { 313 if (fileName.equals(remoteName)) { 314 result = true; 315 } 316 } 317 } 318 } catch (IOException e) { 319 e.printStackTrace(); 320 } finally { 321 // 登出服务器并断开连接 322 ftpUtils.logout(); 323 } 324 return result; 325 } 326 327 /** 328 * 登出服务器并断开连接 329 * 330 * @param ftp 331 * FTPClient对象实例 332 * @return 333 * <b>true</b>:操作成功 334 * <br/> 335 * <b>false</b>:操作失败 336 */ 337 public boolean logout () { 338 boolean result = false; 339 if (null != is) { 340 try { 341 // 关闭输入流 342 is.close(); 343 } catch (IOException e) { 344 e.printStackTrace(); 345 } 346 } 347 if (null != ftpClient) { 348 try { 349 // 登出服务器 350 result = ftpClient.logout(); 351 } catch (IOException e) { 352 e.printStackTrace(); 353 } finally { 354 // 判断连接是否存在 355 if (ftpClient.isConnected()) { 356 try { 357 // 断开连接 358 ftpClient.disconnect(); 359 } catch (IOException e) { 360 e.printStackTrace(); 361 } 362 } 363 } 364 } 365 return result; 366 } 367 368 public String getSiteName() { 369 return siteName; 370 } 371 372 public String getSaveFilePath() { 373 return saveFilePath; 374 } 375 }
第四步 用到的副类,真正做到任君品尝 !!(重要程度:☆☆)
(1)IDGen工具类
1 /** 2 * 随机ID工具类 3 */ 4 package com.xx.utils; 5 6 import java.io.Serializable; 7 import java.security.SecureRandom; 8 import java.text.DecimalFormat; 9 import java.util.Date; 10 import java.util.UUID; 11 12 import org.apache.shiro.session.Session; 13 import org.apache.shiro.session.mgt.eis.SessionIdGenerator; 14 import org.springframework.context.annotation.Lazy; 15 import org.springframework.stereotype.Service; 16 17 /** 18 * 封装各种生成唯一性ID算法的工具类. 19 * @author ThinkGem 20 * @version 2013-01-15 21 */ 22 @Service 23 @Lazy(false) 24 public class IdGen implements SessionIdGenerator { 25 26 private static SecureRandom random = new SecureRandom(); 27 private static int num; 28 29 /** 30 * 封装JDK自带的UUID, 通过Random数字生成, 中间无-分割. 31 */ 32 public static String uuid() { 33 return UUID.randomUUID().toString().replaceAll("-", ""); 34 } 35 /** 36 * 生成投资编号 37 * @return 38 */ 39 public static String investNo(){ 40 String date = DateUtils.formatDateToStr("yyyyMMddHHmmss",new Date()); 41 if(num>999999){ 42 num = 0; 43 } 44 String numStr = new DecimalFormat("000000").format(num++); 45 return date.substring(2)+ numStr; 46 } 47 48 /** 49 * 使用SecureRandom随机生成Long. 50 */ 51 public static long randomLong() { 52 return Math.abs(random.nextLong()); 53 } 54 55 56 57 @Override 58 public Serializable generateId(Session session) { 59 return IdGen.uuid(); 60 } 61 62 public static String getRandomName(int k){ 63 String chars = "abcdefghijklmnopqrstuvwxyz0123456789"; 64 StringBuilder sb = new StringBuilder(); 65 for (int i = 0; i < k; i++) { 66 sb.append(chars.charAt((int)(Math.random() * 36))); 67 } 68 return sb.toString(); 69 } 70 71 72 }
(2)ImageUtil工具类
1 package com.xx.utils; 2 3 import java.awt.AlphaComposite; 4 import java.awt.Color; 5 import java.awt.Font; 6 import java.awt.Graphics2D; 7 import java.awt.Image; 8 import java.awt.RenderingHints; 9 import java.awt.image.BufferedImage; 10 import java.io.File; 11 import java.io.FileOutputStream; 12 import java.io.InputStream; 13 import java.io.OutputStream; 14 15 import javax.imageio.ImageIO; 16 import javax.swing.ImageIcon; 17 18 import org.slf4j.Logger; 19 import org.slf4j.LoggerFactory; 20 21 /** 22 * 图片处理类 23 * @author xx 24 */ 25 public class ImageUtils { 26 private final static Logger logger = LoggerFactory.getLogger(ImageUtils.class); 27 // 水印透明度 28 private static float alpha = 0.5f; 29 // 水印横向位置 30 private static int positionWidth = 150; 31 // 水印纵向位置 32 private static int positionHeight = 300; 33 // 水印文字字体 34 private static Font font = new Font("宋体", Font.BOLD, 30); 35 // 水印文字颜色 36 private static Color color = Color.red; 37 38 /** 39 * 给图片添加图片水印 40 * @param iconPath 水印图片路径 41 * @param file 源文件 42 * @param targerPath 目标图片路径 43 * @param degree 水印图片旋转角度 44 */ 45 public static void markImageByIcon(String iconPath, File file, 46 String targerPath, Integer degree) { 47 OutputStream os = null; 48 try { 49 logger.info("水印图片路径:{}", iconPath); 50 logger.info("源文件:{}", file.getAbsolutePath()); 51 logger.info("目标图片路径:{}", targerPath); 52 Image srcImg = ImageIO.read(file); 53 54 BufferedImage buffImg = new BufferedImage(srcImg.getWidth(null), 55 srcImg.getHeight(null), BufferedImage.TYPE_INT_RGB); 56 57 // 得到画笔对象 58 Graphics2D g = buffImg.createGraphics(); 59 60 // 设置对线段的锯齿状边缘处理 61 g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, 62 RenderingHints.VALUE_INTERPOLATION_BILINEAR); 63 64 g.drawImage(srcImg.getScaledInstance(srcImg.getWidth(null), srcImg 65 .getHeight(null), Image.SCALE_SMOOTH), 0, 0, null); 66 67 if (null != degree) { 68 // 设置水印旋转 69 g.rotate(Math.toRadians(degree), 70 (double) buffImg.getWidth() / 2, (double) buffImg 71 .getHeight() / 2); 72 } 73 74 // 水印图象的路径 水印一般为gif或者png的,这样可设置透明度 75 ImageIcon imgIcon = new ImageIcon(iconPath); 76 77 // 得到Image对象。 78 Image img = imgIcon.getImage(); 79 80 float alpha = 0.5f; // 透明度 81 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 82 alpha)); 83 84 // 表示水印图片的位置 相对于中心店的宽高以及水印图片宽高(img,x,y,width,height,obnull) 85 g.drawImage(img, buffImg.getWidth() / 6,buffImg.getHeight() / 3, buffImg.getWidth() / 2,buffImg.getHeight() / 4, null); 86 87 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); 88 89 g.dispose(); 90 91 os = new FileOutputStream(targerPath); 92 93 // 生成图片 94 ImageIO.write(buffImg, "JPG", os); 95 96 logger.info("图片完成添加水印"); 97 } catch (Exception e) { 98 e.printStackTrace(); 99 logger.error("图片完成添加水印error:{}", e.getMessage()); 100 } finally { 101 try { 102 if (null != os) 103 os.close(); 104 } catch (Exception e) { 105 e.printStackTrace(); 106 } 107 } 108 } 109 110 /** 111 * 给图片添加水印文字 112 * @param logoText 水印文字 113 * @param srcImgPath 原图片路径 114 * @param targerPath 目标图片路径 115 * @param degree 旋转角度 116 */ 117 public static void markImageByText(String logoText, String srcImgPath, 118 String targerPath, Integer degree) { 119 120 InputStream is = null; 121 OutputStream os = null; 122 try { 123 // 1、源图片 124 Image srcImg = ImageIO.read(new File(srcImgPath)); 125 BufferedImage buffImg = new BufferedImage(srcImg.getWidth(null),srcImg.getHeight(null), BufferedImage.TYPE_INT_RGB); 126 127 // 2、得到画笔对象 128 Graphics2D g = buffImg.createGraphics(); 129 // 3、设置对线段的锯齿状边缘处理 130 g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR); 131 g.drawImage(srcImg.getScaledInstance(srcImg.getWidth(null), srcImg.getHeight(null), Image.SCALE_SMOOTH), 0, 0, null); 132 // 4、设置水印旋转 133 if (null != degree) { 134 g.rotate(Math.toRadians(degree),(double) buffImg.getWidth() / 2, (double) buffImg.getHeight() / 2); 135 } 136 // 5、设置水印文字颜色 137 g.setColor(color); 138 // 6、设置水印文字Font 139 g.setFont(font); 140 // 7、设置水印文字透明度 141 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,alpha)); 142 // 8、第一参数->设置的内容,后面两个参数->文字在图片上的坐标位置(x,y) 143 g.drawString(logoText, positionWidth, positionHeight); 144 // 9、释放资源 145 g.dispose(); 146 // 10、生成图片 147 os = new FileOutputStream(targerPath); 148 ImageIO.write(buffImg, "JPG", os); 149 150 logger.info("图片完成添加水印文字"); 151 152 } catch (Exception e) { 153 e.printStackTrace(); 154 } finally { 155 try { 156 if (null != is) 157 is.close(); 158 } catch (Exception e) { 159 e.printStackTrace(); 160 } 161 try { 162 if (null != os) 163 os.close(); 164 } catch (Exception e) { 165 e.printStackTrace(); 166 } 167 } 168 } 169 170 /** 171 * 判断文件是不是图片 172 * @param file 173 * @return 174 * @author guogf 175 */ 176 public static boolean isImage(File file) 177 { 178 boolean flag = false; 179 try 180 { 181 Image is = ImageIO.read(file); 182 if(null != is) 183 { 184 flag = true; 185 } 186 } catch (Exception e) 187 { 188 e.printStackTrace(); 189 } 190 return flag; 191 } 192 193 }
关于编辑器的前台配置
到此后台处理函数已完整实现,现在需要将后台返回的json串回调到前端编辑器来处理,写入上传容器框以及编辑器文章当中。
首先去找到umeditor.config.js 找到如下并修改:
1 //图片上传配置区 2 ,imageUrl:ctx+"/cms/article/upload" //图片上传提交地址 很重要!上传提交地址,这里配置成我刚才写的那个控制器函数 路径很重要 ctx获取的是当前域名 3 ,imagePath:"http://static.xx.com/" //图片修正地址,对应刚才我提到的域名配置的地方 必须配置!! 4 ,imageFieldName:"upfile" //图片数据的key,若此处修改,需要在后台对应文件修改对应参数 对应刚才提到的上传图片的表单name 默认即可
配置好之后,后来调试发现 返回的json 串包含在pre标签里,编辑器脚本解析不了,报错,所以,这里还需要修改编辑器目录 dialogsimageimage.js文件
1 uploadComplete: function(r){ 2 debugger; 3 var me = this; 4 try{ 5 var json = eval('('+$(r).html()+')'); //这里需要把返回的字符串转化成对象 pre对象,然后获取里面json串 6 Base.callback(me.editor, me.dialog, json.url, json.state); 7 }catch (e){ 8 var lang = me.editor.getLang('image'); 9 Base.callback(me.editor, me.dialog, '', (lang && lang.uploadError) || 'Error!'); 10 } 11 },
好了,到这里基本完事了,我们看下最终效果吧!
开始上传效果图:
拖曳或者上传效果图:
编辑器效果图:
文章预览效果图:
说在后面
这篇博文写了挺长时间,手都酸了...之前有部分分享总是被移除首页,所以,在格式排版上花很长时间..