转载请注明出处:http://blog.csdn.net/l1028386804/article/details/52389722
相信大家做项目时,很多时候都会用到富文本编辑器。今天是2016年8月的最后一天,那么就给大家带来一篇关于JSP UEditor整合SpringMVC的文章吧,UEditor是百度的一款富文本编辑器产品,网址为:http://ueditor.baidu.com/website/ , 但是直接使用Editor时,会将编辑的图片直接上传到服务器的项目所在路径,如果每次部署项目的时候,都是全量部署(删除服务器上原有项目,重新部署),则之前上传的图片都会清空,所以,一般情况下,我们最好是将图片上传到服务器上某个单独的目录下,这样,即使我们全量部署项目,之前上传的图片也就不会丢失了。好,那我们一起来看如何将Editor整合,并将图片保存到单独的目录下。
这里我们用的UEditor的版本是1.4.3.3 下载地址为:http://ueditor.baidu.com/build/build_down.php?n=ueditor&v=1_4_3_3-utf8-jsp
这里,我们新建Maven工程ueditor,将下载的UEditor解压后重命名为ueditor,并将文件夹拷贝到webapp/static目录下,如下图所示:
如图:
4.0.0
com.lyz
lyz
1.0.0-SNAPSHOT
war
4.0.5.RELEASE
4.3.5.Final
org.springframework
spring-core
${spring.version}
org.springframework
spring-context
${spring.version}
org.springframework
spring-context-support
${spring.version}
org.springframework
spring-orm
${spring.version}
org.springframework
spring-web
${spring.version}
org.springframework
spring-webmvc
${spring.version}
org.springframework
spring-tx
${spring.version}
org.hibernate
hibernate-core
${hibernate.version}
commons-logging
commons-logging
1.1.1
commons-codec
commons-codec
1.4
javax.persistence
persistence-api
1.0
javax.servlet
javax.servlet-api
3.0.1
jstl
jstl
1.2
com.alibaba
druid
1.0.5
mysql
mysql-connector-java
5.1.30
com.google.guava
guava
17.0
net.sf.ezmorph
ezmorph
1.0.6
jar
compile
net.sf.json-lib
json-lib
2.2.3
jdk15
com.thoughtworks.xstream
xstream
1.4.4
ch.qos.logback
logback-classic
1.0.13
org.codehaus.jackson
jackson-mapper-asl
1.9.13
org.codehaus.jackson
jackson-core-asl
1.9.13
commons-fileupload
commons-fileupload
1.2.2
org.apache.commons
commons-io
1.3.2
compile
com.esotericsoftware.reflectasm
reflectasm
1.09
xmlpull
xmlpull
1.1.3.1
provided
xpp3
xpp3
1.1.4c
provided
com.thoughtworks.xstream
xstream
1.4.7
provided
org.apache.poi
poi
3.7
c3p0
c3p0
0.9.1.2
cglib
cglib-nodep
2.1_3
commons-pool
commons-pool
1.2
org.aspectj
aspectjweaver
1.6.0
org.quartz-scheduler
quartz
2.2.1
org.quartz-scheduler
quartz-jobs
2.2.1
joda-time
joda-time
2.4
xml-apis
xml-apis
1.4.01
org.apache.httpcomponents
fluent-hc
4.3.5
provided
org.apache.httpcomponents
httpclient
4.3.5
provided
org.apache.httpcomponents
httpclient-cache
4.3.5
provided
org.apache.httpcomponents
httpcore
4.3.2
provided
org.apache.httpcomponents
httpmime
4.3.5
provided
org.json
json
20140107
org.slf4j
slf4j-simple
1.6.1
org.slf4j
slf4j-api
1.6.1
commons-pool
commons-pool
1.5.6
codec
codec
1.0
system
${project.basedir}/lib/commons-codec-1.9.jar
fileupload
fileupload
1.3.1
system
${project.basedir}/lib/commons-fileupload-1.3.1.jar
commons-io
commons-io
2.4
system
${project.basedir}/lib/commons-io-2.4.jar
json
json
1.0
system
${project.basedir}/lib/json.jar
ueditor
ueditor
1.1.2
system
${project.basedir}/lib/ueditor-1.1.2.jar
lyz
org.apache.maven.plugins
maven-compiler-plugin
3.1
1.7
org.apache.maven.plugins
maven-jar-plugin
2.4
org.apache.maven.plugins
maven-eclipse-plugin
true
true
2.0
lyz
org.springframework.web.context.ContextLoaderListener
contextConfigLocation
classpath*:applicationContext*.xml
lyz
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath*:lyz-servlet*.xml
1
lyz
/
hibernateFilter
org.springframework.orm.hibernate4.support.OpenSessionInViewFilter
singleSession
true
hibernateFilter
/*
CorsFilter
com.lyz.utils.cors.filter.CorsFilter
CorsFilter
/*
CharacterEncodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
forceEncoding
true
CharacterEncodingFilter
/*
index.html
index.htm
index.jsp
default.html
default.htm
default.jsp
none
org.hibernate.dialect.MySQL5InnoDBDialect
true
true
这个文件主要用来设置一些配置信息,比如图片访问路径,上传路径等,具体如下所示:
lyz.uploading.url=d:/lyz/static
lyz.visit.url=/upload/
lyz.resource.url=http://127.0.0.1:8099
#\u8F93\u51FA\u5230\u63A7\u5236\u53F0
log4j.appender.stout=org.apache.log4j.ConsoleAppender
log4j.appender.stout.layout=org.apache.log4j.PatternLayout
log4j.appender.stout.layout.ConversionPattern=[%p]%d{yyyy-MM-dd HH:mm:ss} %l: %m%n
#log4j.appender.stout.layout.ConversionPattern=[%p]%d{yyyy-MM-dd HH:mm:ss}: %m%n
#\u8F93\u51FA\u5230\u6587\u4EF6
log4j.appender.fout=org.apache.log4j.FileAppender
log4j.appender.fout.file=d:/Tomcat_Project/logs/wine.log
#log4j.appender.fout.file=/opt/apache-tomcat-7.0.56/logs/wine.log
log4j.appender.fout.layout=org.apache.log4j.PatternLayout
log4j.appender.fout.layout.ConversionPattern=[%p]%d{yyyy-MM-dd HH:mm:ss} %l: %m%n
#log4j.appender.stout.layout.ConversionPattern=[%p]%d{yyyy-MM-dd HH:mm:ss}: %m%n
#\u8F93\u51FA\u7EA7\u522B
log4j.rootLogger=INFO, stout
创建实体类主要的目的是方便运行整个项目框架,具体如下:
package com.lyz.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* 实体类shop
* @author liuyazhuang
*
*/
@Entity
@Table(name="c_shop")
public class Shop implements Serializable {
private static final long serialVersionUID = -6980546472329430674L;
@Id
@Column(name="id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
public Shop() {
super();
}
public Shop(Long id) {
super();
this.id = id;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public String toString() {
return "Shop [id=" + id + "]";
}
}
package com.lyz.utils;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* 加载Properties文件数据的工具类
* @author liuyazhuang
*
*/
public final class LoadPropertiesDataUtils{
private volatile static Properties mProperties;
static{
mProperties = new Properties();
InputStream in = LoadPropertiesDataUtils.class.getResourceAsStream("/applications.properties");
try{
mProperties.load(in);
} catch (IOException e){
e.printStackTrace();
}
}
public static String getValue(String key){
if(mProperties == null) return "";
return mProperties.getProperty(key, "");
}
}
这个类的主要作用是生成指定位数的随机数,具体如下所示:
package com.lyz.utils;
import java.util.Random;
/**
* 随机数工具类
* @author liuyazhuang
*
*/
public final class RandomUtils {
/**
* 获取指定位数的随机数
* @param num
* @return
*/
public static String getRandom(int num){
Random random = new Random();
StringBuilder sb = new StringBuilder();
for(int i = 0;i < num; i++){
sb.append(String.valueOf(random.nextInt(10)));
}
return sb.toString();
}
}
package com.lyz.utils;
/**
* 字符串工具类
* @author liuyazhuang
*
*/
public final class StringUtils {
/**
* 判断字符串是否为空
* @param str
* @return
*/
public static boolean isEmpty(String str){
return (str == null || "".equals(str.trim()));
}
/**
* 获取名称后缀
* @param name
* @return
*/
public static String getExt(String name){
if(name == null || "".equals(name) || !name.contains("."))
return "";
return name.substring(name.lastIndexOf(".")+1);
}
}
package com.lyz.utils.cors.filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.filter.OncePerRequestFilter;
/**
* 解决跨域
* @author liuyazhuang
*
*/
public class CorsFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS");
response.addHeader("Access-Control-Allow-Headers",
"origin, content-type, accept, x-requested-with, sid, mycustom, smuser");
filterChain.doFilter(request, response);
}
}
package com.lyz.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* 首页controller,主要的功能是跳转到首页
* @author liuyazhuang
*
*/
@Controller
@RequestMapping(value="/index")
public class IndexController {
/**
* 跳转到首页
* @param request
* @param response
*/
@RequestMapping(value="/page", method = RequestMethod.GET)
public String page(HttpServletRequest request, HttpServletResponse response){
return "/index";
}
}
package com.lyz.controller;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import com.lyz.utils.LoadPropertiesDataUtils;
import com.lyz.utils.RandomUtils;
import com.lyz.utils.StringUtils;
/**
* 上传图片的controller
* @author liuyazhuang
*
*/
@Controller
@RequestMapping(value="/resource/upload")
public class UploadImageController {
/**
* 上传图片
* @param file
* @param request
* @param response
* @return
*/
@ResponseBody
@RequestMapping(value="/images")
public Map images (MultipartFile upfile, HttpServletRequest request, HttpServletResponse response){
Map params = new HashMap();
try{
String basePath = LoadPropertiesDataUtils.getValue("lyz.uploading.url");
String visitUrl = LoadPropertiesDataUtils.getValue("lyz.visit.url");
if(basePath == null || "".equals(basePath)){
basePath = "d:/lyz/static"; //与properties文件中lyz.uploading.url相同,未读取到文件数据时为basePath赋默认值
}
if(visitUrl == null || "".equals(visitUrl)){
visitUrl = "/upload/"; //与properties文件中lyz.visit.url相同,未读取到文件数据时为visitUrl赋默认值
}
String ext = StringUtils.getExt(upfile.getOriginalFilename());
String fileName = String.valueOf(System.currentTimeMillis()).concat("_").concat(RandomUtils.getRandom(6)).concat(".").concat(ext);
StringBuilder sb = new StringBuilder();
//拼接保存路径
sb.append(basePath).append("/").append(fileName);
visitUrl = visitUrl.concat(fileName);
File f = new File(sb.toString());
if(!f.exists()){
f.getParentFile().mkdirs();
}
OutputStream out = new FileOutputStream(f);
FileCopyUtils.copy(upfile.getInputStream(), out);
params.put("state", "SUCCESS");
params.put("url", visitUrl);
params.put("size", upfile.getSize());
params.put("original", fileName);
params.put("type", upfile.getContentType());
} catch (Exception e){
params.put("state", "ERROR");
}
return params;
}
}
我们在webapp/static目录下创建lib目录,然后将jquery导入到lib目录下,如下图所示:
在webapp/WEB_INF/jsp目录下创建index.jsp,具体如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
UEditor
由上述代码可知,我们再index.jsp中主要定义了一个textarea标签。
我们在webapp/static目录下创建index文件夹,并在index文件夹中创建index.js,主要内容如下:
$(function(){
//富文本编辑器
UE.getEditor('myEditor')
UE.Editor.prototype._bkGetActionUrl = UE.Editor.prototype.getActionUrl;
UE.Editor.prototype.getActionUrl = function(action){
if(action == '/resource/upload/images'){
return basePath+'resource/upload/images';
}else{
return this._bkGetActionUrl.call(this, action);
}
}
});
编辑后的文件如下图所示:
/* 前后端通信相关的配置,注释只允许使用多行方式 */
{
/* 上传图片配置项 */
"imageActionName": "/resource/upload/images", /* 执行上传图片的action名称 */
"imageFieldName": "upfile", /* 提交的图片表单名称 */
"imageMaxSize": 2048000, /* 上传大小限制,单位B */
"imageAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 上传图片格式显示 */
"imageCompressEnable": true, /* 是否压缩图片,默认是true */
"imageCompressBorder": 1600, /* 图片压缩最长边限制 */
"imageInsertAlign": "none", /* 插入的图片浮动方式 */
"imageUrlPrefix": "http://127.0.0.1:8099", /* 图片访问路径前缀 */
"imagePathFormat": "/upload/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
/* {filename} 会替换成原文件名,配置这项需要注意中文乱码问题 */
/* {rand:6} 会替换成随机数,后面的数字是随机数的位数 */
/* {time} 会替换成时间戳 */
/* {yyyy} 会替换成四位年份 */
/* {yy} 会替换成两位年份 */
/* {mm} 会替换成两位月份 */
/* {dd} 会替换成两位日期 */
/* {hh} 会替换成两位小时 */
/* {ii} 会替换成两位分钟 */
/* {ss} 会替换成两位秒 */
/* 非法字符 \ : * ? " < > | */
/* 具请体看线上文档: fex.baidu.com/ueditor/#use-format_upload_filename */
/* 涂鸦图片上传配置项 */
"scrawlActionName": "uploadscrawl", /* 执行上传涂鸦的action名称 */
"scrawlFieldName": "upfile", /* 提交的图片表单名称 */
"scrawlPathFormat": "/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
"scrawlMaxSize": 2048000, /* 上传大小限制,单位B */
"scrawlUrlPrefix": "", /* 图片访问路径前缀 */
"scrawlInsertAlign": "none",
/* 截图工具上传 */
"snapscreenActionName": "uploadimage", /* 执行上传截图的action名称 */
"snapscreenPathFormat": "/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
"snapscreenUrlPrefix": "", /* 图片访问路径前缀 */
"snapscreenInsertAlign": "none", /* 插入的图片浮动方式 */
/* 抓取远程图片配置 */
"catcherLocalDomain": ["127.0.0.1", "localhost", "img.baidu.com"],
"catcherActionName": "catchimage", /* 执行抓取远程图片的action名称 */
"catcherFieldName": "source", /* 提交的图片列表表单名称 */
"catcherPathFormat": "/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
"catcherUrlPrefix": "", /* 图片访问路径前缀 */
"catcherMaxSize": 2048000, /* 上传大小限制,单位B */
"catcherAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 抓取图片格式显示 */
/* 上传视频配置 */
"videoActionName": "uploadvideo", /* 执行上传视频的action名称 */
"videoFieldName": "upfile", /* 提交的视频表单名称 */
"videoPathFormat": "/ueditor/jsp/upload/video/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
"videoUrlPrefix": "", /* 视频访问路径前缀 */
"videoMaxSize": 102400000, /* 上传大小限制,单位B,默认100MB */
"videoAllowFiles": [
".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid"], /* 上传视频格式显示 */
/* 上传文件配置 */
"fileActionName": "uploadfile", /* controller里,执行上传视频的action名称 */
"fileFieldName": "upfile", /* 提交的文件表单名称 */
"filePathFormat": "/ueditor/jsp/upload/file/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
"fileUrlPrefix": "", /* 文件访问路径前缀 */
"fileMaxSize": 51200000, /* 上传大小限制,单位B,默认50MB */
"fileAllowFiles": [
".png", ".jpg", ".jpeg", ".gif", ".bmp",
".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid",
".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso",
".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml"
], /* 上传文件格式显示 */
/* 列出指定目录下的图片 */
"imageManagerActionName": "listimage", /* 执行图片管理的action名称 */
"imageManagerListPath": "/ueditor/jsp/upload/image/", /* 指定要列出图片的目录 */
"imageManagerListSize": 20, /* 每次列出文件数量 */
"imageManagerUrlPrefix": "", /* 图片访问路径前缀 */
"imageManagerInsertAlign": "none", /* 插入的图片浮动方式 */
"imageManagerAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 列出的文件类型 */
/* 列出指定目录下的文件 */
"fileManagerActionName": "listfile", /* 执行文件管理的action名称 */
"fileManagerListPath": "/ueditor/jsp/upload/file/", /* 指定要列出文件的目录 */
"fileManagerUrlPrefix": "", /* 文件访问路径前缀 */
"fileManagerListSize": 20, /* 每次列出文件数量 */
"fileManagerAllowFiles": [
".png", ".jpg", ".jpeg", ".gif", ".bmp",
".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid",
".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso",
".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml"
] /* 列出的文件类型 */
}
此文件中imageActionName名称的配置与index.js中的判断条件中的配置保持一致,如下图:
imageUrlPrefix为图片访问前缀。
由于我们将图片放到了项目外面,独立于tomcat,所以我们要在tomcat的server.xml文件中设置虚拟路径,如下在
此处的docBase与applications.properties文件中的lyz.uploading.url一致,path与applications.properties文件中的lyz.visit.url一致。
如下图所示:
至此,我们完成了整个项目的开发,下面我们来运行这个项目
我们将项目发布到tomcat,在浏览器地址栏输入http://127.0.0.1:8099/ueditor/index/page,原因是我将tomcat端口设置为8099,
此时,查看我的图片保存路径d:/lyz/static
没有任何图片。那现在我们编辑图片吧。如下图,我在UEditor中编辑了一张图片:
我们再打开d:/lyz/static目录:
图片已经上传到我们的指定的配置目录中了。
至此整个工程创建运行结束。
大家可以到链接http://download.csdn.net/detail/l1028386804/9618375下载基于Maven的SpringMVC整合UEditor(可单独配置上传路径 )的完整实例源码