springBoot、springSecurity、H-ui通用mvc后台(七)集成ueditor并拓展图片删除、上传到云空间(以七牛云为例)

H-ui里面集成的是百度的ueditor插件,所以我们这里只说明下ueditor的集成与使用。关于富文本编辑器,对应的选择算是比较多的,比如:fckEditor、kindEditor等,可根据具体的要求来做选择。

1、集成ueditor并在页面中使用

1.1、先将H-ui中的ueditor拷贝到自己的项目中

如下图所示:



需要注意的是,我这里并没有直接直接使用admin/lib目录下面的ueditor包,而是直接复制了一份放在了static当中,这样做只是为了将来拓展时,路径看起来更方便一点,因为不止是后台需要用到ueditor。有一些官网包含一些简单的会员互动,就可以用ueditor的简约版(如果在一个项目的话)。

大家会发现在我们的ueditor文件夹上面有一个小小的红叉,原因是eclipse的编辑校验对json文件的注释不认识,这个只需要更改一下eclipse的json校验就可以,Window——>Preferences——>Validation,具体操作时如图:



1.2、页面中使用ueditor

我们先在noticeList页面中写好跳转js和控制台的action,如下列图片:

noticeAdd.html页面的代码,只要自己参考一下H-ui的添加页面就可以了。这里就不上完整的代码了,只说明下ueditor的集成方式。在集成thymeleaf时说明过静态资源的根路径是src/main/resource下面的static,所以在当前项目中,页面引入ueditor的路径是:

<script type="text/javascript" th:src="@{/ueditor/1.4.3/ueditor.config.js}"></script> 
<script type="text/javascript" th:src="@{/ueditor/1.4.3/ueditor.all.js}"> </script> 
<script type="text/javascript" th:src="@{/ueditor/1.4.3/lang/zh-cn/zh-cn.js}"></script>

展示的元素代码如下:

		<div class="row cl">
			<input type="hidden" id="content" name="content" />
			<label class="form-label col-xs-4 col-sm-2"><span class="c-red">*</span>文章内容:</label>
			<div class="formControls col-xs-8 col-sm-9"> 
				<script id="editor" type="text/plain" style="width:100%;height:300px;"></script> 
			</div>
		</div> 

核心代码就是如下:

<script id="editor" type="text/plain" style="width:100%;height:300px;"></script> 

OK到了,这一步,基本的样式展示就可以了,如图:

2、图片、文件上传

对于富文本编辑器的集成难点,我想大概就是在这块,有许多的小伙伴们都知道原理,但就是不知道入口在哪里,加上路径调试的问题,常常让人容易泄气。
目前我们集成的ueditor还不能支持图片上传的功能,原理大家都知道,上传图片是需要调用有效的action的。那么我们先来看看它报什么错!

2.1、ueditor的配置与说明

在1.2小节中,我们看见页面引入了两个非常重要的文件,其中一个是ueditor.config.js,通过名称我们就知道,它是ueditor的配置文件,我们打开看看,你会发现,里面的注释非常的详细(详细的注释是程序员的基本素养)。我们不难找到以下注释:

我们还发现了一个核心的数组配置:window.UEDITOR_CONFIG,我们只要在引入他的页面中打印出来看看它获取到的是什么?在noticeAdd.html中js区写上console.log(window.UEDITOR_CONFIG),刷新下页面,查看控制台,如图:


我们重点看下UEDITOR_HOME_URLserverUrl的值,发现URL的值是“http://localhost:8090/ueditor/1.4.3”,初始化来至于getUEBasePath()函数(就在当前ueditor.config.js文件中,有时间可以自己查看)。代码调试和读到这里,我们会发现,我们只要修改serverUrl成为可以访问的action就可以了。所以,我们现在需要根据当前引用页面的地址拼接一个根路径:“http://localhost:8090/”。那么我们加这么一个函数getRootUrl,如图:

OK,到了这一步,我们剩下的就是仿照jsp示例封装ueditor的action了。在进行下一步之前,这里拓展一下。

在springboot当中,我们可以配置内置的Tomcat,这其中包括可以配置项目的根路径context-path,如图:


当前,我这里配置的是“/”,所以,以上的自定义函数getRootUrl那么写没有问题,但如果我这里配置的context-path: /timblog,那么,我们的getRootUrl函数就要生成“http://localhost:8090/timblog”。这里就不放代码了,用js截取下pathname就可以。当然,在修改了context-path之后,对应的thymeleaf的基础路径配置也要做相关的修改,这里不赘述。

2.2、改造ueditor的jsp成spring的action

结合上面的配置,我们有了根路径后,接下来就是怎么访问ueditor的action。我们先看看ueditor的目录结构

我们发现,ueditor对于.net、php、java都有对应的处理包。这里明显php就更好用了,直接访问就可以,而对于java的jsp,我们实在不太方便处理。怎么办呢?为了一劳永逸,决定把jsp改造成一个通用的action。怎么改?我们先看看jsp写了些什么,又依赖了些什么jar与类。

有jsp和servlet基础的同学不难发现,jsp中调用了ActionEnter,并且以request和rootPath为参数。那么我们的改造就从这些类开始。
我们先建立好自己的目录结构,我们在common目录下建一个ueditor目录,并把jsp目录中的java文件和文件夹拷贝到当前目录下,修改调试好package路径,如图:

要达到这一步,只要多使用一下ide的技巧就可以。然后,我们发现,类ConfigManager还是报错,看看具体的错误,发现是对应的android-json异常没有处理,我们分别在getConfig与getArray这两个方法中try...catch处理一下,如图:


接下来,我们自定义的一个类UEditorController(在common.ueditor目录之下),这个类该怎么写呢?我们先来看看jsp中关于ActionEnter的源码。我们发现类ActionEnter其实是ueditor的action处理类,如下图所示,在request中,一定会传入一个action的参数,根据action的值,判断并获取对应的配置信息(获取文件jsp/config.json中对应的配置信息):
那么我们自定义ueditor的入口就有思路了,只要写一个spring的action,并且复制jsp中的代码。这里直接上代码:

package com.ruiyi.common.ueditor;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
* <p> Title:  </p>
* <p> Description: </p>
* @user yangtao
* @date 2020年8月27日
* @版本 1.00
* @修改记录
* <pre>
* 版本           修改人          修改时间          修改内容描述
* ----------------------------------------
* 1.00 yangtao  2020年8月27日     初始化版本
* ----------------------------------------
* </pre>
*/
@Controller
@RequestMapping("/ueditor")
public class UEditorController {
	
	/**
	 * 将ueditor示例中的jsp访问转换到springMVC中
	 * */
	@RequestMapping("/dispatch")
	public void config(HttpServletRequest request,
			HttpServletResponse response, String action) {	    
	    
		response.setContentType("application/json");
		String rootPath = request.getSession().getServletContext()
				.getRealPath("/");
		try {
			String exec = new ActionEnter(request, rootPath).exec();

			PrintWriter writer = response.getWriter();
			writer.write(exec);
			writer.flush();
			writer.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
}

然后,我们修改一下ueditor.config.js中的serverUrl访问路径:

到了这一步,对应的图片上传按钮就可以点击了(还不能实现功能),对应的controller.jsp就可以删除了。

2.3、ueditor的初始化与获取config.json简单说明

上一小节,我们完成了对ueditor入口jsp的改造,但还不能使用,我们先看看页面错误。

点击进去,发现一脸懵逼,这怎么调试呢?其实,想想都知道,就算我们的图片上传成功了,图片又保存在哪里呢?所以,我们先要明白,ueditor的处理思路是什么,这就需要我们来看看ueditor的源码了。由于不是视频,我这里不方便演示调试(注意,不方便debug,因为js端在等候断点的时候,会直接报错),就直接说明了。
我们稍微看下ActionEnter的源码,并且打印一下,每次请求的action的值,就不难发现,ueditor的动作都在类ActionEnter做区分与分发,初始化的时候,action传入的值是config,根据ActionEnter中的invoke方法,我们不难找到ConfigManager类。那么到这一步就好办了。再读下ConfigManager类就知道,原来ConfigManager类一直在找一个文件:config.json,并根据config.json中的配置封装各项的值。而ConfigManager类中的方法getConfigPath就是用来获取config.json文件路径的,因此我们只要根据项目中config.json所在的位置,修改一下getConfigPath方法的代码:

ConfigManager类中的getConfigPath方法修改如下:

/**
 * update by yangtao
 * 根据实际情况,修改获取config.json文件的获取路径
 * */
private String getConfigPath () {
	// 这是ueditor默认的路径
	// return this.parentPath + File.separator + ConfigManager.configFileName;

	// roorPath为项目的根目录带"/"号,指到WebRoot下
	String resourcePath = StringUtils.replace(this.rootPath, "webapp", "resources");
	String path = resourcePath + "static/ueditor/1.4.3" + File.separator + "jsp" + File.separator
					+ ConfigManager.configFileName;
	return path;
}

再次刷新页面测试一下,不再报错了(还不能真正上传图片,下一小节详细说明)。关于config.json的具体说明,可以直接打开文件查看,注释很详细。 

2.4、图片上传的实现

到目前为止,我们梳理到了ueditor的初始化,那么怎么才能上传图片呢?我们先看看目前的图片上传效果。

由上图可以看见,我们的ueditor集成已经没有报错了,但是却还是不能上传图片,报“未找到上传数据”。

继续打印调试,得知图片上传的action对应的值是:uploadimage,通过查看ActionEnter中的invoke方法,图片、视频、文件等的上传都是共用Uploader类中的上传方法。

剩下的事情就只要改造上传的类了,也就是Base64Uploader和BinaryUploader类中的save方法

解读配置源码,我们修改BinaryUploader中的save方法如下,原来的save方法注释掉就可以。

public static final State save(HttpServletRequest request,
            Map<String, Object> conf) {

        try {
            MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
            MultipartFile multipartFile = multipartRequest.getFile(conf.get("fieldName").toString());

            String savePath = (String) conf.get("savePath");
            String originFileName = multipartFile.getOriginalFilename();
            String suffix = FileType.getSuffixByFilename(originFileName);

            originFileName = originFileName.substring(0,originFileName.length() - suffix.length());
            savePath = savePath + suffix;

            long maxSize = ((Long) conf.get("maxSize")).longValue();

            if (!validType(suffix, (String[]) conf.get("allowFiles"))) {
                return new BaseState(false, AppInfo.NOT_ALLOW_FILE_TYPE);
            }
            /***********/
            //自定义
            savePath = PathFormat.parse(savePath, originFileName);
           
            String [] savePathBySplit_temp = savePath.split("/");
            String temp = "";
            String fileName = savePathBySplit_temp[savePathBySplit_temp.length-1];
            for(int i = 1;i < savePathBySplit_temp.length-1; i++){
                if(i!=savePathBySplit_temp.length-1){
                    temp+=savePathBySplit_temp[i]+"/";
                }else{
                    temp+=savePathBySplit_temp[i];
                }
            }
            
            String rootpath = request.getSession().getServletContext().getRealPath("/");
                        
            String pathTemp = rootpath + temp; 

            File targetFile = new File(pathTemp);
            if(!targetFile.exists()){  
                targetFile.mkdirs();  
            }

            /************/
            //State storageState = StorageManager.saveFileByInputStream(multipartFile.getInputStream(),savePath, maxSize);
            State storageState = StorageManager.saveFileByInputStream(multipartFile.getInputStream(),pathTemp+"/"+fileName, maxSize);

            if (storageState.isSuccess()) {
                storageState.putInfo("url", PathFormat.format(savePath));
                storageState.putInfo("type", suffix);
                storageState.putInfo("original", originFileName + suffix);
            }

            return storageState;

        }catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.getMessage());
        }
        return new BaseState(false, AppInfo.IO_ERROR);
    }

核心是方法中的这句代码(将文件保存到自己项目的有效目录下):

State storageState = StorageManager.saveFileByInputStream(multipartFile.getInputStream(),pathTemp+"/"+fileName, maxSize);

 再次打开Ueditor,图片可以完美上传了。 

我这里使用的是config.json中默认的配置,比较冗长,大家可以修改config.json中的值,自定义自己的文件存放目录。

3、多图上传与在线管理

3.1、多图上传

其实,调试好了单图上传的路径、配置等,多图上传就显得格外的简单了。这里直接上示例。大家试试就可以。

3.2、图片在线管理 

如果大家是一步一步走到这里的话,那么,你的在线管理应该是显示如下图的状态:

这说明,我们图片确实上传成功了,但是在线管理却没有获取到正确的图片路径。该如何处理呢?有了以往的调试经验,只要找到“在线管理”对应的处理程序就可以了,action的值为:listimage。

 找到这里,我们发现原来FileManager默认是找的图片保存的path,也就是图片保存的本地实际地址。我们可以这么操作一下,选中“在线管理”中的一张,然后看下html源码,就是我们图片的本地保存地址了:

因此,思路来了,我们只要将path修改转换成页面浏览器可以访问的url就行。我们这里就不去修改FileManager的源码了,对于已经封装好的类,真是牵一发而动全身。我们在自定义的类UEditorController中,加一段处理listimage的代码就行。这里直接上代码,其中增加的if就是将path转换成url的处理逻辑:

package com.ruiyi.common.ueditor;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
* <p> Title:  </p>
* <p> Description: </p>
* @user yangtao
* @date 2020年8月27日
* @版本 1.00
* @修改记录
* <pre>
* 版本           修改人          修改时间          修改内容描述
* ----------------------------------------
* 1.00 yangtao  2020年8月27日     初始化版本
* ----------------------------------------
* </pre>
*/
@Controller
@RequestMapping("/ueditor")
public class UEditorController {
	
	private static final String LIST_FILE = "listfile";
	private static final String LIST_IMAGE = "listimage";
	
	/**
	 * 将ueditor示例中的jsp访问转换到springMVC中
	 * */
	@RequestMapping("/dispatch")
	public void config(HttpServletRequest request,
			HttpServletResponse response, String action) {	    
	    
//System.out.println("action:" + action);
		
		response.setContentType("application/json");
		String rootPath = request.getSession().getServletContext()
				.getRealPath("/");
		try {
			String exec = new ActionEnter(request, rootPath).exec();
			
			/*
			 * update by yangtao 
			 * 修改“在线管理”图片的访问路径
			 */
			if (action != null
					&& (StringUtils.equals(action, LIST_FILE) || StringUtils.equals(action, LIST_IMAGE))) {
				String path = request.getContextPath();
				String basePath = request.getScheme() + "://"
						+ request.getServerName() + ":"
						+ request.getServerPort() + path + "/";
				
				rootPath = rootPath.replace("\\", "/");
								
				exec = exec.replaceAll(rootPath, basePath);
			}

			PrintWriter writer = response.getWriter();
			writer.write(exec);
			writer.flush();
			writer.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
}

之前上传的图片,就出现了:

4、图片在线删除(拓展)

如果有人问哪些行业容易产生强迫症,个人认为IT行业绝对上榜。调试到以上的步骤,对于ueditor的基本集成已经算是完成了。但有些小伙伴们会想,既然是“在线管理”,那么除了可以增加图片,也应该可以删除图片。最重要的是,这个功能并不是毫无用处,当上传的一些图片没用,或者重复了,这个功能就可以很好发挥了。那么,我们就来实现这个功能,算是一个简单的拓展吧(实现这一步,小伙伴们需要一定的js、jquery、css基础)。

首先,我们来捋一捋删除图片的思路:
1) 修改“在线管理”的图片样式,为每张图片添加一个小红叉;
2) 设计一个js函数事件,点击图片小红叉时触发,并将图片从列表中移除;
3) 请求后台action,根据图片地址,真正删除项目中指定的图片;
有了以上的思路,拓展就很有条理了。

4.1、为每张图片增加一张删除按钮

我们打开ueditor的会话框组件包,找到图片相关的会话框

读一读image.html源码,我们发现在线图片的id是imageList

然后,我们到image.js中寻找对应的处理逻辑。不难发现,通过函数getImageData来加载指定url上的图片。

而单个图片的加载时通过函数pushData

源码读到这里,我们就只要在这个函数里面为每张图片增加一个样式了。具体怎么添加呢?我们先看看图片的样式对应的css选择器是什么样的?在线管理中打开浏览器源码查看:

因此,我们有这么一个思路,在所在的image所在的li中增加一个✖按钮,并且放置在图片的右上角。这里调试样式的过程就不写了,直接上代码,写在image.css的最后:

有了这个样式,我们再在image.js中的pushData函数中添加进去:

大家跟着的代码如果没有敲错,就已经实现以下效果了:

4.2、为删除按钮注册函数事件

到这一步就是js的事情了,我们只要注册一个函数,并且调试相关事件,这里就不多说明,直接上代码:

 4.3、ajax请求后台删除图片

上面的js调试逻辑已经很明显了,我们只要在后面的代码加上对应的ajax请求后台就可以,代码如下:

/*
                     * add by yangtao 
                     * 在线管理图片增加图片删除功能
                     * */
                    item.appendChild($("<span class='delbtn' url='" + list[i].url + "'>✖</span>").click(function (){
                    	var del = $(this);
                    	try {
	                    	window.event.cancelBubble = true; //停止冒泡
	                    	window.event.returnValue = false; //阻止事件的默认行为
	                    	window.event.preventDefault(); //取消事件的默认行为 
	                    	window.event.stopPropagation(); //阻止事件的传播
                    	} finally {//确保逻辑的执行,放置到finally中          
                    		var bool = confirm("确定要删除吗?");
                    		if (!bool) return; 
                    		
                    		$.ajax({
                    	        type: "POST",
                    	        url:editor.getOpt("serverUrl"), //还记得config.js中的配置吗?
                    	        data:{
                    	        	"action" : "deleteImage",
                    	        	"imageUrl" : del.attr("url")
                    	        },
                    	        error: function(request) {
                    	            alert("Connection error");
                    	        },
                    	        success: function(data) {
                    	        	if(data){
                    	        		del.parent().remove();
                    	        	}else{
                    	        		alert("删除失败");
                    	        	}        	
                    	        }
                    			
                    		});
                    	}
                    })[0]);

所以,我们这里的请求还是config.js中的全局配置,参数我们自定义了action的值为deleteImage

剩下的逻辑就是我们自定义的UEditorController的了。这里我也直接上代码,用一个if做相关的处理

package com.ruiyi.common.ueditor;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
* <p> Title:  </p>
* <p> Description: </p>
* @user yangtao
* @date 2020年8月27日
* @版本 1.00
* @修改记录
* <pre>
* 版本           修改人          修改时间          修改内容描述
* ----------------------------------------
* 1.00 yangtao  2020年8月27日     初始化版本
* ----------------------------------------
* </pre>
*/
@Controller
@RequestMapping("/ueditor")
public class UEditorController {
	
	private static final String LIST_FILE = "listfile";
	private static final String LIST_IMAGE = "listimage";
	private static final String DELETE_IMAGE = "deleteImage";
	
	/**
	 * 将ueditor示例中的jsp访问转换到springMVC中
	 * */
	@RequestMapping("/dispatch")
	public void config(HttpServletRequest request,
			HttpServletResponse response, String action) {
		
		response.setContentType("application/json");
		String rootPath = request.getSession().getServletContext()
				.getRealPath("/");
		try {
			/*
			 * 在线管理图片,删除图片功能
			 * */
			if (action != null && StringUtils.equals(action, DELETE_IMAGE)) {
				String imageUrl = request.getParameter("imageUrl");
				
				String path = request.getContextPath();
				String basePath = request.getScheme() + "://"
                        + request.getServerName() + ":"
                        + request.getServerPort() + path + "/";
				
				rootPath = rootPath.replace("\\", "/");
				
				String imagePath = imageUrl.replaceAll(basePath, rootPath);
				
				File file = new File(imagePath);
				boolean delflag = file.delete();

				PrintWriter writer = response.getWriter();
				writer.write(String.valueOf(delflag));
				writer.flush();
				writer.close();
				return;
			}
			
			String exec = new ActionEnter(request, rootPath).exec();
			
			/*
			 * update by yangtao 
			 * 修改“在线管理”图片的访问路径
			 */
			if (action != null
					&& (StringUtils.equals(action, LIST_FILE) || StringUtils.equals(action, LIST_IMAGE))) {
				String path = request.getContextPath();
				String basePath = request.getScheme() + "://"
						+ request.getServerName() + ":"
						+ request.getServerPort() + path + "/";
				
				rootPath = rootPath.replace("\\", "/");
								
				exec = exec.replaceAll(rootPath, basePath);
			}

			PrintWriter writer = response.getWriter();
			writer.write(exec);
			writer.flush();
			writer.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
}

到这一步,调试好删除路径与url的对应关系,删除功能就完成了。需要注意的是,我们这里的删除图片纯粹是针对项目上的资源。实际项目中,上传图片时,会将图片的url保存在数据库中,那么删除的时候就要注意了,需要做对应的判断,保证数据的原子性。

5、ueditor图片、文件上传到云空间 

在互联网迅速发展的今天,网络资源的迅速增长、泛滥,催生了云空间这类的统一管理技术。那么我们的系统资源不再单单的只在自己的服务器上了,如果要共享到别的子系统,云空间格外的方便。各大平台的OBS(对象存储服务)都会提供对应的接口,我们这里以七牛云为例。
小伙伴们根据自己的需要,先在七牛云官网申请到对应的空间,获取到ACCESS_KEY和SECRET_KEY,并指定对应的空间和目录。这里我就直接上相关的资源和代码:
七牛云所需的坐标,版本自行和自己使用的springboot适配

<!-- 七牛云相关jar -->
		<dependency>
            <groupId>com.qiniu</groupId>
            <artifactId>qiniu-java-sdk</artifactId>
            <version>7.2.11</version>
            <scope>compile</scope>
        </dependency>
    
        <dependency>
            <groupId>com.qiniu</groupId>
            <artifactId>happy-dns-java</artifactId>
            <version>0.1.4</version>
            <scope>compile</scope>
        </dependency>

 编写七牛云公共util代码(网上很多资源的):

package com.ruiyi.common.util;

import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import javax.imageio.ImageIO;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import com.google.gson.Gson;
import com.qiniu.common.QiniuException;
import com.qiniu.common.Zone;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import com.ruiyi.common.ConstantConfig;

/**
* <p> Title:  </p>
* <p> Description: </p>
* @user yangtao
* @date 2019年5月7日
* @版本 1.00
* @修改记录
* <pre>
* 版本           修改人          修改时间                    修改内容描述
* ----------------------------------------
* 1.00 yangtao  2019年5月7日     初始化版本
* ----------------------------------------
* </pre>
*/
public class QiniuyunUtil {
	
	private static Logger logger = LoggerFactory.getLogger(QiniuyunUtil.class);

    //设置好账号的ACCESS_KEY和SECRET_KEY
    private static final String ACCESS_KEY = ConstantConfig.QINIU_ACCESS_KEY; //这两个登录七牛 账号里面可以找到
    private static final String SECRET_KEY = ConstantConfig.QINIU_SECRET_KEY;
    //要上传的空间
    private static final String BUCKET_NAME =ConstantConfig.QINIU_BUCKET;
    private static final String DOMAIN = ConstantConfig.QINIUYUN_URL; 

    //密钥配置
    private static Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY);
    private static Configuration cfg = new Configuration(Zone.huanan());
    //创建上传对象

    private static UploadManager uploadManager = new UploadManager(cfg);

    //简单上传,使用默认策略,只需要设置上传的空间名就可以了
    public static String getUpToken(){
        return auth.uploadToken(BUCKET_NAME);
    }

    
    public static String UploadPic(String FilePath,String FileName){
        Configuration cfg = new Configuration(Zone.huanan());
        UploadManager uploadManager = new UploadManager(cfg);
        String accessKey = ACCESS_KEY;      //AccessKey的值
        String secretKey = SECRET_KEY;      //SecretKey的值
        String bucket = BUCKET_NAME;                                          //存储空间名
        Auth auth = Auth.create(accessKey, secretKey);
        String upToken = auth.uploadToken(bucket);
        try {
            Response response = uploadManager.put(FilePath, FileName, upToken);
            //解析上传成功的结果
            DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
            System.out.println(putRet.key);
            System.out.println(putRet.hash);
            return DOMAIN+FileName;
        }catch (QiniuException ex){
        	logger.error(ex.getMessage());
        }
        return null;
    }
    
    
    /**
     * 上传web式MultipartFile类型的文件
     * @param file 上传的MultipartFile文件
     * @param filename 上传到七牛云上的文件名(时间戳 + 2位随机数)
     * */
	public static String updateMultipartFile(MultipartFile file, String filename)  {
         //默认不指定key的情况下,以文件内容的hash值作为文件名
    	 InputStream inputStream = null;    	 
    	 ByteArrayOutputStream swapStream = null;
    	 
    	//解析上传成功的结果
         DefaultPutRet putRet = null;
         try {
        	 inputStream = file.getInputStream();
        	 swapStream = new ByteArrayOutputStream();
             byte[] buff = new byte[1024]; //buff用于存放循环读取的临时数据
             int rc = 0;
             while ((rc = inputStream.read(buff, 0, 128)) > 0) {
                 swapStream.write(buff, 0, rc);
             }
             byte[] uploadBytes  = swapStream.toByteArray();
             Response response = uploadManager.put(uploadBytes,filename,getUpToken());
             
             putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
             
             return DOMAIN + putRet.key;
         } catch (QiniuException ex) {
        	 logger.error(ex.response.toString());
         } catch (UnsupportedEncodingException ex) {
        	 logger.error(ex.getMessage());
         } catch (Exception e) {
        	 logger.error(e.getMessage());
		} finally {
        	 if(swapStream != null) {
        		 try {
					swapStream.close();
				} catch (IOException e) {
					logger.error(e.getMessage());
				}
        	 }
        	 
        	 if(inputStream != null) {
        		 try {
					inputStream.close();
				} catch (IOException e) {
					logger.error(e.getMessage());
				}
        	 }
         }
         
         return null;
     }

	/**
	 * 下载公有图片文件
	 * 
	 * */
	public static BufferedImage downloadImage(String imageUrl) {
		URL url = null;
		HttpURLConnection conn = null;
		DataInputStream dataInputStream = null;
		BufferedInputStream bufferedInputStream = null;
		BufferedImage preImage = null;
		try {
			url = new URL(imageUrl);
			
			conn = (HttpURLConnection)url.openConnection();  
            //设置超时时间为3秒
		    conn.setConnectTimeout(3*1000);
		    //防止屏蔽程序抓取而返回403错误
		    conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
			
			//1.获取url的输入流 dataInputStream
			dataInputStream = new DataInputStream(url.openStream());
            //2.加一层BufferedInputStream
			bufferedInputStream = new BufferedInputStream(dataInputStream);
            //3.构造原始图片流 preImage
			preImage = ImageIO.read(bufferedInputStream);			
		} catch (MalformedURLException e) {
			logger.error(e.getMessage());
		} catch (IOException e) {
			logger.error(e.getMessage());
		} finally {
			if(dataInputStream != null) {
				try {
					dataInputStream.close();
				} catch (IOException e) {
					logger.error(e.getMessage());
				}
			}
			
			if(bufferedInputStream != null) {
				try {
					dataInputStream.close();
				} catch (IOException e) {
					logger.error(e.getMessage());
				}
			}
		}
		
		return preImage;
	}
     
}

 有了这些工具,剩下的事情非常的简单,只要修改一下ueditor中上传文件的方法使用七牛云的就可以了,具体只要修改BinaryUploader类中的save方法了,不过,为了类的通用性,我们增加一个方法qiniuyunSave(复制一份save,然后改造)

public static final State qiniuyunSave(HttpServletRequest request,
			Map<String, Object> conf) {
		
		try {
			MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
			MultipartFile multipartFile = multipartRequest.getFile(conf.get("fieldName").toString());

			String savePath = (String) conf.get("savePath");
			String originFileName = multipartFile.getOriginalFilename();
			String suffix = FileType.getSuffixByFilename(originFileName);

			originFileName = originFileName.substring(0, originFileName.length() - suffix.length());
			savePath = savePath + suffix;

			long maxSize = ((Long) conf.get("maxSize")).longValue();

			if (!validType(suffix, (String[]) conf.get("allowFiles"))) {
				return new BaseState(false, AppInfo.NOT_ALLOW_FILE_TYPE);
			}

			savePath = PathFormat.parse(savePath, originFileName);

		
			InputStream is = multipartFile.getInputStream();

			/**
			 * 上传到七牛云
			 */
			// *******************开始***********************
			String fileName = new StringBuffer().append(new Date().getTime())
					.append(savePath.substring(savePath.indexOf("."))).toString();
			State storageState = null;
			try {
                //上传到七牛云
                QiniuyunUtil.updateMultipartFile(multipartFile, fileName);
				storageState = StorageManager.saveFileByInputStream(is, fileName, maxSize);
				storageState.putInfo("state", "SUCCESS");
				// url:返回前端的访问路径,请根据自己实际情况填写
				storageState.putInfo("url", ConstantConfig.QINIUYUN_URL + fileName);
				storageState.putInfo("title", fileName);
				storageState.putInfo("original", fileName);
			} catch (Exception e) {
				// TODO: handle exception
				System.out.println(e.getMessage());
				storageState.putInfo("state", "文件上传失败!");
				storageState.putInfo("url", "");
				storageState.putInfo("title", "");
				storageState.putInfo("original", "");
				// System.out.println("文件 "+fileName+" 上传失败!");
			}

			// ********************结束**********************
			is.close();
			return storageState;
		} catch (IOException e) {
		}
		return new BaseState(false, AppInfo.IO_ERROR);
	}

然后,在类Uploader中换成七牛云的这个方法就可以了
 测试一下,成功后查看一下,这个网址就是七牛云对应的访问地址了。

 至于删除,这里就不多加赘述了,弄通了第4小节的内容,重构起来非常简单。

6、ueditor的一些其它说明

6.1、form表单怎么获取ueditor内容?

回到curd的逻辑,页面集成的ueditor,怎么将内容获取,并保存到数据库中?要知道,我们的ueditor是一个script标签。这里我们设计一个隐藏域,将值通过js赋进去就行

var ue = UE.getEditor('editor');
//将uEditor中的内容赋值到content中
var content=ue.getContent();
$("#content").val(content);	

6.2、如何让ueditor不可编辑(查看页面)?

var ue=new UE.ui.Editor({readonly:true,});
ue.render('editor');

总结:

内容有点多,这篇博文做一个小小的总结

1、复制全ueditor包到自定的路径;

2、配置好ueditor.config.js中的servletUrl

3、改造ueditor.jsp成springboot的controller

4、调试图片的保存路径(一定要弄清楚)

5、拓展图片删除功能

6、图片上传与云空间的对接

以上就是关于ueditor集成的全部内容,个人觉得算是比较全面了,请仔细阅读与调试。下一节我们来集成一下webuploader,我们下节见。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值