第一步:
1.ckeditor中配置文件 config。js
/**
* @license Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.editorConfig = function( config ) {
config.toolbar = 'Full';
config.toolbar_Full = [
{ name: 'mode' },
{ name: 'document', items : ['Source','-','Save','NewPage','DocProps','Preview','Print','-','Templates' ] },
{ name: 'clipboard', items : [ 'Cut','Copy','Paste','PasteText','PasteFromWord','-','Undo','Redo' ] },
{ name: 'editing', items : [ 'Find','Replace','-','SelectAll','-','SpellChecker', 'Scayt' ] },
{ name: 'forms', items : [ 'Form', 'Checkbox', 'Radio','TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField' ] },
'/',
{ name: 'basicstyles', items : ['Bold','Italic','Underline','Strike','Subscript','Superscript','-','RemoveFormat' ] },
{ name: 'paragraph', items : ['JustifyLeft', 'JustifyCenter', 'JustifyRight','JustifyBlock' , 'NumberedList','BulletedList','-','Outdent','Indent','-','Blockquote','CreateDiv', '-','JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock','-','BidiLtr','BidiRtl'] },
{ name: 'links', items : [ 'Link','Unlink','Anchor' ] },
{ name: 'insert', items: ['Image','Flash','Table','HorizontalRule','Smiley','SpecialChar','PageBreak','Iframe' ]},
'/',
{ name: 'styles', items : [ 'Styles','Format','Font','FontSize' ] },
{ name:'colors', items : [ 'TextColor','BGColor' ] },
{ name: 'tools', items : [ 'Maximize','ShowBlocks','-','About' ] } ];
config.toolbar = 'MyToolbar';
//其中'-'表示工具之间分隔的竖线,'/'表示换行 ,其中下面的代码分别代表什么可以去网上查,这里不加以赘述。
config.toolbar_MyToolbar =
[
{ name: 'document', items : [ 'Preview','-','Templates'] },
{ name: 'clipboard', items : [ 'Cut','Copy','Paste','PasteText','PasteFromWord','-','Undo','Redo' ] },
{ name: 'insert', items : [ 'Image','Table','HorizontalRule','Smiley','SpecialChar' ] },
{ name: 'links', items : [ 'Link','Unlink','Anchor' ] },
{ name: 'tools', items : [ 'Maximize' ] },
'/',
{ name: 'styles', items : [ 'Styles','Format' ] },
{ name: 'basicstyles', items : [ 'Bold','Italic','Underline' ] },
{ name: 'paragraph', items : [ 'JustifyLeft', 'JustifyCenter', 'JustifyRight','JustifyBlock' ,'NumberedList','BulletedList','-','Outdent','Indent','-','Blockquote' ] }
];
config.removeDialogTabs = 'image:advanced;link:advanced';
config.pasteFromWordRemoveStyles = true;
config.image_previewText=' '; //预览区域显示内容(预览区域在开始的时候会有一大串英文,在此将这些英文去除)
//获得action的相对路径
var pathName = window.document.location.pathname;
//获取带"/"的项目名
var projectName = pathName.substring(0, pathName.substr(1).indexOf('/') + 1);
//加上改行代码后就会显示上传功能,但是“上传到服务器”按钮不能正常使用,这里配置的action就是处理图片上传的后台逻辑
config.filebrowserUploadUrl=projectName+'/jxhd/uploadImAction.do?'; //固定路径
};
============================================================================================================================================
第二步:
2.设置jsp页面,引用ckeditor
//引入ckeditor的js文件,src中为ckeditor.js的路径
<script type="text/javascript" src='<%=host%>/thirdparty/ckeditor/ckeditor.js'></script>
//使用ckeditor的代码部分
·····
<td>
<common:textarea name="xxlbActionForm"
property="content" validator="text(0,3000)"
empty="true" styleId="contentid" cols="1" rows="8" label="内容" />
<script type="text/javascript">
//使用ckeditor,这里可以设置ckeditor的一些属性,比如高度和宽度,工具栏等等
CKEDITOR.replace("contentid",{toolbar : 'MyToolbar',width:600,height:200});
</script>
</td>
·····
//js获得ckeditor框中内容,
<script type="text/javascript">
function fun_save(){
//获取当前页面部分内容
var ckEditor = CKEDITOR.instances.contentid;
//其中contentval是以html的格式
var contentval = ckEditor.getData();
····
}
</script>
============================================================================================================================================
第三步:
2。Struts1中后台处理图片上传的action代码
/**
* uploadImAction.java
* @date 2015年3月6日
* @author xiaomage
*/
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import org.apache.log4j.Logger;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import sun.misc.BASE64Encoder;
import com.cvicse.exception.DataAccessException;
import com.cvicse.infra.base.BaseAction;
/**
* @author ma_hju
*
*/
public class UploadImAction extends BaseAction {
/**
*
* @param mapping
* ActionMapping 映射对象
* @param form
* ActionForm 表单对象
* @param request
* HttpServletRequest 请求
* @param response
* HttpServletResponse 响应
* @throws DataAccessException
* @throws ObjectNotExistException
*/
/**
* <p>功能描述:[字段功能描述]</p>
*/
private static final long serialVersionUID = 1L;
protected final Logger logger = Logger
.getLogger(UploadImAction.class);
/** ~~~ 上传文件的保存路径 */
private static final String FILE_UPLOAD_DIR = "/upload";
/** ~~~ 上传文件的保存的下一级路径,标示存储类型 */
private static final String FILE_UPLOAD_SUB_IMG_DIR = "/img";
/** ~~~ 为了能让CKEDITOR加载到上传的图片,此处将位置限制在了/file/jxhdxxlb下,这个文件夹可以自定义*/
private static final String FOR_FREEMARKER_LOAD_DIR = "/file/jxhdxxlb";
/** ~~~ 每个上传子目录保存的文件的最大数目 */
private static final int MAX_NUM_PER_UPLOAD_SUB_DIR = 500;
/** ~~~ 上传文件的最大文件大小 */
private static final long MAX_FILE_SIZE = 1024 * 1024 * 2;
/** ~~~ 系统默认建立和使用的以时间字符串作为文件名称的时间格式*/
private static final String DEFAULT_SUB_FOLDER_FORMAT_AUTO = "yyyyMMdd";
/** ~~~ 这里扩充一下格式,防止手动建立的不统一*/
private static final String DEFAULT_SUB_FOLDER_FORMAT_NO_AUTO = "yyyy-MM-dd";
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws DataAccessException {
response.setCharacterEncoding("UTF-8");
PrintWriter out=null;
// 判断提交的请求是否包含文件
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (!isMultipart) {
//return;
}
// 获取目录
File floder = buildFolder(request);
if (null == floder) {
//return;
}
//获得ckeditor的一个重要参数
String callback =request.getParameter("CKEditorFuncNum");
//获得项目名
String xmName = request.getContextPath();
//String path = request.getSession().getServletContext().getRealPath("/");
//StringBuffer URL = request.getRequestURL();
try{
response.setContentType("text/html; charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
out = response.getWriter();
// 上传文件的返回地址
String fileUrl = "";
//----start----从request中获得上传文件的方法,此为核心代码
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload servletFileUpload = new ServletFileUpload(factory);
//中文路径、上传图片名中文乱码问题解决代码
servletFileUpload.setHeaderEncoding("UTF-8");
servletFileUpload.setFileSizeMax(MAX_FILE_SIZE);
@SuppressWarnings("unchecked")
List<FileItem> fileitem = servletFileUpload.parseRequest(request);
if (null == fileitem || 0 == fileitem.size()) {
//return;
}
Iterator<FileItem> fileitemIndex = fileitem.iterator();
if (fileitemIndex.hasNext()) {
FileItem file = fileitemIndex.next();
if (file.isFormField()) {
logger.error("上传文件非法!isFormField=true");
}
//----end----从request中获得上传文件的方法,此为核心代码,file中就是上传的文件信息
//file.getName()获得文件在本地的地址,getFileName()方法获得文件名
String fileClientName = getFileName(file.getName());
//fileFix为该文件的格式
String fileFix = StringUtils.substring(fileClientName,
fileClientName.lastIndexOf(".") + 1);
//判断图片的格式
if (!StringUtils.equalsIgnoreCase(fileFix, "jpg")
&& !StringUtils.equalsIgnoreCase(fileFix, "jpeg")
&& !StringUtils.equalsIgnoreCase(fileFix, "bmp")
&& !StringUtils.equalsIgnoreCase(fileFix, "gif")
&& !StringUtils.equalsIgnoreCase(fileFix, "png")) {
logger.error("上传文件的格式错误=" + fileFix);
//return;
}
if (logger.isInfoEnabled()) {
logger.info("开始上传文件:" + file.getName());
}
// 为了客户端已经设置好了图片名称在服务器继续能够明确识别,这里不改名称
File newfile = new File(floder, fileClientName);
//开始上传文件
file.write(newfile);
if (logger.isInfoEnabled()) {
logger.info("上传文件结束,新名称:" + fileClientName + ".floder:"
+ newfile.getPath());
}
// 组装返回url,以便于ckeditor定位图片
fileUrl = FOR_FREEMARKER_LOAD_DIR + FILE_UPLOAD_DIR + FILE_UPLOAD_SUB_IMG_DIR + File.separator+floder.getName()+ File.separator + newfile.getName();
fileUrl = fileUrl.substring(1);// 去掉/jxhdxxlb的第一个/,否则ckeditor不识别
fileUrl = StringUtils.replace(fileUrl, "\\", "/");
// 返回“图像”选项卡并显示图片,这里是ckeditor返回图像并显示的代码
out.println("<script type=\"text/javascript\">");
out.println("window.parent.CKEDITOR.tools.callFunction(" + callback+ ",'" + xmName+"/"+fileUrl+ "','')"); // 相对路径用于显示图片
out.println("</script>");
}
out.flush();
out.close();
}catch(Exception e){
response.setContentType("text/html;charset=UTF-8");
out.println("<script type=\"text/javascript\">");
out.println("window.parent.CKEDITOR.tools.callFunction("+ callback + ",'','图片上传失败,请重新上传!','')");
out.println("</script>");
}
return null ;
}
/**
* 获取文件名称
* @param str
* @return
*/
public String getFileName(String str){
int index = str.lastIndexOf("\\");
if(-1 != index){
return str.substring(index+1);
} else {
return str;
}
}
/**
* 创建目录
*
* @return
*/
public File buildFolder(HttpServletRequest request) {
// 这里照顾一下CKEDITOR,由于ftl放置位置的原因,这里必须要在freemarker目录下才能被加载到图片,否则虽然可以正常上传和使用,但是
// 在控件中无法正常操作
String realPath = request.getSession().getServletContext()
.getRealPath(FOR_FREEMARKER_LOAD_DIR);
logger.error(realPath);
// 一级目录,如果不存在,创建
File firstFolder = new File(realPath + FILE_UPLOAD_DIR);
if (!firstFolder.exists()) {
if (!firstFolder.mkdir()) {
//return null;
}
}
// 二级目录,如果不存在,创建
String folderdir = realPath + FILE_UPLOAD_DIR + FILE_UPLOAD_SUB_IMG_DIR;
if (logger.isDebugEnabled()) {
logger.debug("folderdir" + folderdir);
}
if (StringUtils.isBlank(folderdir)) {
logger.error("路径错误:" + folderdir);
//return null;
}
File floder = new File(folderdir);
if (!floder.exists()) {
if (!floder.mkdir()) {
logger.error("创建文件夹出错!path=" + folderdir);
//return null;
}
}
// 再往下的文件夹都是以时间字符串来命名的,所以获取最新时间的文件夹即可
String[] files = floder.list();
if (null != files && 0 < files.length) {
// 含有子文件夹,则获取最新的一个
Date oldDate = null;
int index = -1;
for (int i = 0; i < files.length; i++) {
String fileName = files[i];
try {
Date thisDate = DateUtils.parseDate(fileName, new String[] {
DEFAULT_SUB_FOLDER_FORMAT_AUTO, DEFAULT_SUB_FOLDER_FORMAT_NO_AUTO });
if (oldDate == null) {
oldDate = thisDate;
index = i;
} else {
if (thisDate.after(oldDate)) {
// 保存最新的时间和数组中的下标
oldDate = thisDate;
index = i;
}
}
} catch (ParseException e) {
// 这里异常吃掉,不用做什么,如果解析失败,会建立新的文件夹,防止人为的建立文件夹导致的异常。
}
}// for
// 判断当前最新的文件夹下是否已经存在了最大数目的图片
if (null != oldDate && -1 != index) {
File pointfloder = new File(folderdir + File.separator
+ files[index]);
if (!pointfloder.exists()) {
if (!pointfloder.mkdir()) {
logger.error("创建文件夹出错!path=" + folderdir);
//return null;
}
}
// 如果文件夹下的文件超过了最大值,那么也需要新建一个文件夹
String[] pointfloderFiles = pointfloder.list();
if (null != pointfloderFiles
&& MAX_NUM_PER_UPLOAD_SUB_DIR < pointfloderFiles.length) {
return buildNewFile(folderdir);
}
return pointfloder;
}
// 查找当前子文件夹失败,新建一个
return buildNewFile(folderdir);
} else {
// 不含有子文件夹,新建一个,通常系统首次上传会有这个情况
return buildNewFile(folderdir);
}
}
/**
* 创建一个新文件
* @param path
* @return
*/
public File buildNewFile(String path){
// 不含有子文件夹,新建一个,通常系统首次上传会有这个情况
File newFile = buildFileBySysTime(path);
if (null == newFile) {
logger.error("创建文件夹失败!newFile=" + newFile);
}
return newFile;
}
/**
* 根据当前的时间建立文件夹,时间格式yyyyMMdd
*
* @param path
* @return
*/
public File buildFileBySysTime(String path) {
DateFormat df = new SimpleDateFormat(DEFAULT_SUB_FOLDER_FORMAT_AUTO);
String fileName = df.format(new Date());
File file = new File(path + File.separator + fileName);
if (!file.mkdir()) {
return null;
}
return file;
}
}
================================================================================================================================
第四步:
Struts文件中要配置action的跳转
<!-- 图片上传 start-->
<action path="/uploadImAction" scope="request"
type="com.cvicse.szxy.jxhd.xxlb.action.UploadImAction" >
</action>
注意:这里配置时不要配置form,原因是struts1.2中ActionForm和ServletFileUpload.parseRequest(request)不能同时使用。
网上匿名高人是这么解释的:
解释struts用ActionForm的方式处理上传附件的一些问题,struts接收到enctype="multipart/form-data"的post请求后,会看那
个对应的action有没有配置actionform,如果配置了,就会作一些处理,所以你在action里得到的request已经不是一个普通的request
了,而是一个被封装过的request。如果想得到原始的request,就不要struts-config.xml里给action类配置actionform。
ServletFileUpload.parseRequest(request)中的request用的是普通的request,而使用actionForm时request被封装,从而
导致ServletFileUpload.parseRequest(request)取不到值,为空。目前来说,无法解决ActionForm和ServletFileUpload.parseRequest(request)
共存问题,那只能换别的上传方式了!
详情可参考:http://blog.sina.com.cn/s/blog_4873f8e00100qxnn.html
==============================================================================================================================================================
至此ckeditor功能基本上是配置完成了。
下面说一下在配置过程中可能遇到的一些问题和解决方法:
1.上传图片时路径或图片名含中文有乱码问题。
解决方法:添加一下代码
//中文路径、上传图片名中文乱码问题解决代码
servletFileUpload.setHeaderEncoding("UTF-8");
2。图片能上传到服务器但是预览时不能查看图片。
主要原因是:返回图像地址时路径不正确
// 返回“图像”选项卡并显示图片,这里是ckeditor返回图像并显示的代码
out.println("<script type=\"text/javascript\">");
out.println("window.parent.CKEDITOR.tools.callFunction(" + callback+ ",'" + xmName+"/"+fileUrl+ "','')"); // 相对路径用于显示图片
out.println("</script>");
解决方法:根据自己的实际情况修改返回的图片路径。
3.点击“上传到服务器”按钮,显示找不到网页错误,即跳转不到action
可能原因:查看Struts中的action跳转的配置,看是否配置了actionform,struts1.2中ActionForm和ServletFileUpload.parseRequest(request)不能同时使用。
4.该action中保存图片用的是三级目录,我也是引用网上大神的代码,对此大神是这样说的:
“写代码前,看看我们的现状吧,我们可能会让这个图片上传到图片服务器去,但是呢,兜里尚未有足够的银子,而且这个图片暂时量不大,
所以现阶段还是保存在应用的特定位置中,够无奈的吧,没办法,谁让咱么有特定的图片服务器呢,那么就下办法在本应用下作文章吧。
我们采用一个upload/img的目录,来保存图片文件,以后要迁移到图片服务器也方便些。但是问题来了,所有的图片都放到这个文件夹下,
岂不是很庞大,而且一旦超过1000张,文件搜索速度是有点折磨的,那就咱想想办法吧,那就再建立一级目录,每一级下面最多放500张,
如果当前文件夹下超过了500张,就重新建立一个文件夹,放入其中。这样目录就变成了三级的 upload/img/20100824 我们采用时间字符串来命名。”
5.这个action方法也是我参考网上大神的代码,根据自己项目的需求加以修改。我项目使用的是Struts1。
详情可参考:http://blog.youkuaiyun.com/quzishen/article/details/5834207
6.ckeditor工具缓存比较严重,开发的时候修改他的js文件后每次都需要清浏览器缓存才能起作用。
Java 设置添加ckeditor图片上传功能
最新推荐文章于 2021-03-08 21:48:33 发布