SpringMVC整合KindEditor,实现图片上传、预览、删除

之前我写过一篇关于《DWZ(JUI)整合Kindeditor应用于dialog弹出框》,只是讨论了前端的应用,并没有详细介绍后台代码实现。本文除了介绍后台的代码实现,还顺便介绍一些KindEditor的前端应用技巧。

以前的是SSH框架实现KindEditor插件的上传、图片空间管理功能。现在的项目底层框架换成了springmvc,代码虽然变化不大,但是需要注意一些细节的实现。
具体后台实现:

@Controller
@RequestMapping("/kindeditor")
public class KindEditorController extends  BaseController {
    private Logger logger = LoggerFactory.getLogger(KindEditorController.class);

    /**
    *文件上传功能
    */
    @ResponseBody
    @RequestMapping(value ="/fileUpload")
    public Map<String, Object> fileUpload(HttpServletRequest request,
                                          HttpServletResponse response) throws ServletException, IOException,
            FileUploadException {
        //这里的路径可以是绝对路径,也可以获取项目下的目录,这里使用的是绝对路径;  
        //String savePath = request.getServletContext().getRealPath("/")+"yourPath/" ;
        String savePath = "yourSavePath"+"/" ;
        //这里的路径需要符合下面另一个RequestMapping方法
        String saveUrl = request.getContextPath() + "/kindeditor/";
        // 定义允许上传的文件扩展名
        HashMap<String, String> extMap = new HashMap<String, String>();
        extMap.put("image", "gif,jpg,jpeg,png,bmp");
        extMap.put("flash", "swf,flv");
        extMap.put("media", "swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb");
        extMap.put("file", "doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2");

        // 最大文件大小
        long maxSize = 1000000;

        response.setContentType("text/html; charset=UTF-8");
        response.setCharacterEncoding("UTF-8");
        if (!ServletFileUpload.isMultipartContent(request)) {
            return getError("请选择文件。");
        }
        String dirName = request.getParameter("dir");
        if (dirName == null) {
            dirName = "image";
        }
        if (!extMap.containsKey(dirName)) {
            return getError("目录名不正确。");
        }
        // 创建文件夹
        savePath += dirName + "/";
        saveUrl += dirName + "/";
        File saveDirFile = new File(savePath);
        if (!saveDirFile.exists()) {
            saveDirFile.mkdirs();
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String ymd = sdf.format(new Date());
        savePath += ymd + "/";
        saveUrl += ymd + "/";
        File dirFile = new File(savePath);
        if (!dirFile.exists()) {
            dirFile.mkdirs();
        }
        //这里需要后台springmvc-servlet.xml配置multipartResolver
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        multipartRequest.setCharacterEncoding("UTF-8");
        MultipartFile qqfile =multipartRequest.getFiles("imgFile").get(0);
        String oldName=qqfile.getOriginalFilename();
        String ext=qqfile.getOriginalFilename().substring(oldName.lastIndexOf(".") + 1);
        if (!Arrays.<String>asList(extMap.get(dirName).split(",")).contains(ext)) {

            return getError("<font size='3'>非常抱歉,目前上传附件格式类型只允许为:<br/>" + extMap.get(dirName)
                    + ",你选择的文件【" + oldName + "】不符合要求,无法上传!</font>");
        }
        String fileSizeNumber = fileMaxSize.substring(0, fileMaxSize.indexOf("M"));
        if (qqfile.getSize() > Long.valueOf(fileSizeNumber) * 1000 * 1000) {
            return getError("<font size='3'>您选择的文件【" + oldName+ "】大小超过" + fileMaxSize + "限制,无法上传!</font>");
        }

        String fileName = null;
        ScmUploadFile uploadFile =null;
        String size=this.calculateFileSize(qqfile.getSize());
        try {
            String createTime= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
            fileName = this.upload(qqfile, savePath);
            uploadFile = new ScmUploadFile();
            uploadFile.setName(oldName);
            uploadFile.setPath(savePath+fileName);
            uploadFile.setSize(size);
            uploadFile.setCreateTime(createTime);
            uploadFile.setExt(ext);
            service.save(uploadFile);
            Map<String, Object> succMap = new HashMap<String, Object>();
            succMap.put("error", 0);
            succMap.put("url", saveUrl + fileName);
            return succMap;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage());
            return getError("<font size='3'>您选择的文件【" + oldName+ "】上传失败!原因是:" + e.getMessage() + "</font>");
        }
    }

    private Map<String, Object> getError(String message) {
        Map<String, Object> msg = new HashMap<String, Object>();
        msg.put("error", 1);
        msg.put("message", message);
        return msg;
    }
    /**
    *图片/文件空间管理功能
    */
    @ResponseBody
    @RequestMapping(value ="/fileManage")
    public Object fileManager(HttpServletRequest request,
                            HttpServletResponse response) throws ServletException, IOException {

        // 根目录路径,可以指定绝对路径,比如 /var/www/
        String rootPath = "yourSavePath"+"/";
        // 根目录URL,可以指定绝对路径,比如 http://www.yoursite.com/
        String rootUrl = request.getContextPath() + "/kindeditor/";
        // 图片扩展名
        String[] fileTypes = new String[] { "gif", "jpg", "jpeg", "png", "bmp" };

        String dirName = request.getParameter("dir");
        if (dirName != null) {
            if(!Arrays.<String>asList(new String[]{"image", "flash", "media", "file"}).contains(dirName)){
                return "Invalid Directory name.";
            }
            rootPath += dirName + "/";
            rootUrl += dirName + "/";
            File saveDirFile = new File(rootPath);
            if (!saveDirFile.exists()) {
                saveDirFile.mkdirs();
            }
        }
        //根据path参数,设置各路径和URL
        String path = request.getParameter("path") != null ? request.getParameter("path") : "";
        String currentPath = rootPath + path;
        String currentUrl = rootUrl + path;
        String currentDirPath = path;
        String moveupDirPath = "";
        if (!"".equals(path)) {
            String str = currentDirPath.substring(0, currentDirPath.length() - 1);
            moveupDirPath = str.lastIndexOf("/") >= 0 ? str.substring(0, str.lastIndexOf("/") + 1) : "";
        }

        //排序形式,name or size or type
        String order = request.getParameter("order") != null ? request.getParameter("order").toLowerCase() : "name";

        //不允许使用..移动到上一级目录
        if (path.indexOf("..") >= 0) {
            return "Access is not allowed.";
        }
        //最后一个字符不是/
        if (!"".equals(path) && !path.endsWith("/")) {
            return "Parameter is not valid.";
        }
        //目录不存在或不是目录
        File currentPathFile = new File(currentPath);
        if(!currentPathFile.isDirectory()){
            return "Directory does not exist.";
        }

        //遍历目录取的文件信息
        List<Map<String, Object>> fileList = new ArrayList<Map<String, Object>>();
        if(currentPathFile.listFiles() != null) {
            for (File file : currentPathFile.listFiles()) {
                Hashtable<String, Object> hash = new Hashtable<String, Object>();
                String fileName = file.getName();
                if(file.isDirectory()) {
                    hash.put("is_dir", true);
                    hash.put("has_file", (file.listFiles() != null));
                    hash.put("filesize", 0L);
                    hash.put("is_photo", false);
                    hash.put("filetype", "");
                } else if(file.isFile()){
                    String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
                    hash.put("is_dir", false);
                    hash.put("has_file", false);
                    hash.put("filesize", file.length());
                    hash.put("is_photo", Arrays.<String>asList(fileTypes).contains(fileExt));
                    hash.put("filetype", fileExt);
                }
                hash.put("filename", fileName);
                hash.put("datetime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(file.lastModified()));
                fileList.add(hash);
            }
        }

        if ("size".equals(order)) {
            Collections.sort(fileList, new SizeComparator());
        } else if ("type".equals(order)) {
            Collections.sort(fileList, new TypeComparator());
        } else {
            Collections.sort(fileList, new NameComparator());
        }
        Map<String, Object> result = new HashMap<String, Object>();
        result.put("moveup_dir_path", moveupDirPath);
        result.put("current_dir_path", currentDirPath);
        result.put("current_url", currentUrl);
        result.put("total_count", fileList.size());
        result.put("file_list", fileList);

        return result;
    }

    class NameComparator implements Comparator {
        public int compare(Object a, Object b) {
            Hashtable hashA = (Hashtable) a;
            Hashtable hashB = (Hashtable) b;
            if (((Boolean) hashA.get("is_dir"))
                    && !((Boolean) hashB.get("is_dir"))) {
                return -1;
            } else if (!((Boolean) hashA.get("is_dir"))
                    && ((Boolean) hashB.get("is_dir"))) {
                return 1;
            } else {
                return ((String) hashA.get("filename"))
                        .compareTo((String) hashB.get("filename"));
            }
        }
    }

    class SizeComparator implements Comparator {
        public int compare(Object a, Object b) {
            Hashtable hashA = (Hashtable) a;
            Hashtable hashB = (Hashtable) b;
            if (((Boolean) hashA.get("is_dir"))
                    && !((Boolean) hashB.get("is_dir"))) {
                return -1;
            } else if (!((Boolean) hashA.get("is_dir"))
                    && ((Boolean) hashB.get("is_dir"))) {
                return 1;
            } else {
                if (((Long) hashA.get("filesize")) > ((Long) hashB
                        .get("filesize"))) {
                    return 1;
                } else if (((Long) hashA.get("filesize")) < ((Long) hashB
                        .get("filesize"))) {
                    return -1;
                } else {
                    return 0;
                }
            }
        }
    }

    class TypeComparator implements Comparator {
        public int compare(Object a, Object b) {
            Hashtable hashA = (Hashtable) a;
            Hashtable hashB = (Hashtable) b;
            if (((Boolean) hashA.get("is_dir"))
                    && !((Boolean) hashB.get("is_dir"))) {
                return -1;
            } else if (!((Boolean) hashA.get("is_dir"))
                    && ((Boolean) hashB.get("is_dir"))) {
                return 1;
            } else {
                return ((String) hashA.get("filetype"))
                        .compareTo((String) hashB.get("filetype"));
            }
        }
    }
     /**
     * 处理文件上传
     *
     * @param file
     * @param absPath 存放文件的目录的绝对路径
     * @return
     */
    public String upload(MultipartFile file, String absPath) {
        long fileTimeStamp = new Date().getTime() + new Random().nextInt(100000);
        String fileName = fileTimeStamp+"-"+file.getOriginalFilename();
        try {
            File targetFile = new File(absPath, fileName);
            FileUtils.writeByteArrayToFile(targetFile, file.getBytes());

        } catch (IOException e) {
            e.printStackTrace();
        }
        return fileName;
    }
     public String calculateFileSize(long size){
        //字节数少于1024,直接以B为单位
        if (size < 1024) {
            return String.valueOf(size) + "B";
        } else {
            size = size / 1024;
        }
        //字节数除于1024之后,少于1024,则可直接以KB作为单位
        if (size < 1024) {
            return String.valueOf(size) + "KB";
        } else {
            size = size / 1024;
        }
        if (size < 1024) {
            //以MB为单位的话,保留最后1位小数
            size = size * 100;
            return String.valueOf((size / 100)) + "."
                    + String.valueOf((size % 100)) + "MB";
        } else {
            //以GB为单位
            size = size * 100 / 1024;
            return String.valueOf((size / 100)) + "."
                    + String.valueOf((size % 100)) + "GB";
        }

    }
    /**
     * 删除文件
     * @param fileAbsSavePath   要删除的图片的绝对保存路径
     */
    public static void deleteFile(String fileAbsSavePath) {
        File file=new File(fileAbsSavePath);
        if(file.exists()) file.delete();
    }
    /**
     * 根据文件名获取ContentType
     * @param suffix    文件名后缀
     * @return      ContentType
     */
    public static String getContentType(String suffix) {

        if(!StringUtils.isEmpty(suffix)){
            //uploadProps是properties对象获取配置文件里的文件名后缀对应的ContentType,
            //contentType.proerties文件在本文末尾
            Object contentType = uploadProps.get(suffix);
            if(contentType != null)
                return contentType.toString();
        }
        return "text/html";
    }
    @RequestMapping(value ="/{fileType}/{uploadDate}/{fileName}.{suffix}")
    public void attached(HttpServletRequest request, HttpServletResponse response,
                         @PathVariable String fileType,
                         @PathVariable String uploadDate,
                         @PathVariable String suffix,
                         @PathVariable String fileName) {


        //根据suffix设置响应ContentType
        response.setContentType(this.getContentType(suffix));

        InputStream is = null;
        OutputStream os = null;
        try {
            File file = new File("yourSavePath"+"/" + fileType + "/" + uploadDate + "/" + fileName + "." + suffix);
            is = new FileInputStream(file);
            byte[] buffer = new byte[is.available()];
            is.read(buffer);

            os = new BufferedOutputStream(response.getOutputStream());
            os.write(buffer);
            os.flush();
        } catch (Exception e) {
            //判断suffix
            //图片请求可以在此显示一个默认图片
            //file显示文件已损坏等错误提示...
            logger.error("读取文件失败", e);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    logger.error("读取文件失败", e);
                }

                if (os != null) {
                    try {
                        os.close();
                    } catch (IOException e) {
                        logger.error("读取文件失败", e);
                    }
                }
            }
        }

    }
    /**
    *图片空间删除功能
    */
    @ResponseBody
    @RequestMapping("deleteImg")
    public Map deleteImg(String url) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("res", 0);
        if(!StringUtils.isEmpty(url)) {

            String absPath = "yourSavePath" + url.replace("/kindeditor","");
            UploadFileUtil.deleteFile(absPath);
            service.deleteByPath(absPath);
            map.put("res", 1);
        }
        return map;
    }
}

前端实现:
为了结合后台图片删除功能需要,修改kindeditor\plugins\filemanager\filemanager.js的200-209行代码

$(".xl_span").click(function(){//这里的.xl_span对应着刚才插入的删除按钮上的class
                var $this=K(this);
                if(!confirm('确定删除吗 ?请慎重操作,删除之后之前引用的地方会找不到图片')) {//提示,如果点击取消则直接退出
                    return false;
                }
                $.post('/kindeditor/deleteImg',{url:$this.attr("data-url")},function(data){//jquery的post,action为指定的配合后端用,url是获取刚才存在删除按钮上的图片路径,你完全可以用别的来写,因为用不好kindeditor的js库才用的jquery
                    data.res==1?$this.parent().remove():alert("删除出现错误");//如果返回1则直接删除 图片,名字的Div达到即时删除,否则提示
                    if(K(".ke-plugin-filemanager-body").children().length<1){K(".ke-plugin-filemanager-body").html("没有图片了")}//检查是否没有图片了
                });
            });

前端页面使用配置

  var DK = {}
    DK.kindeditor={basePath:'include/kindeditor/',upload:'/kindeditor/fileUpload',filemanager:'/kindeditor/fileManage',myForm:'yourform',cssPath:'include/kindeditor/plugins/code/prettify.css'};

前端部分参照《DWZ(JUI)整合Kindeditor应用于dialog弹出框》,这里需要修改一个地方,把步骤1里的20行代码的editor定义为全局变量 ,即在js文件里第一行附近定义var editor,然后文章里的步骤1第20行去掉var,因为最外面已经定义了。这样就可以在其他使用Kindeditor的地方使用js赋值到富文本里,即editor.html(“你赋值的”);还可以实现设置富文本只读,即editor.readonly(true);

contentType.proerties配置文件

#contentType.proerties
ez=application/andrew-inset
hqx=application/mac-binhex40
cpt=application/mac-compactpro
doc=application/msword
bin=application/octet-stream
dms=application/octet-stream
lha=application/octet-stream
lzh=application/octet-stream
exe=application/octet-stream
class=application/octet-stream
so=application/octet-stream
dll=application/octet-stream
oda=application/oda
pdf=application/pdf
ai=application/postscript
eps=application/postscript
ps=application/postscript
smi=application/smil
smil=application/smil
mif=application/vnd.mif
xls=application/vnd.ms-excel
ppt=application/vnd.ms-powerpoint
wbxml=application/vnd.wap.wbxml
wmlc=application/vnd.wap.wmlc
wmlsc=application/vnd.wap.wmlscriptc
bcpio=application/x-bcpio
vcd=application/x-cdlink
pgn=application/x-chess-pgn
cpio=application/x-cpio
csh=application/x-csh
dcr=application/x-director
dir=application/x-director
dxr=application/x-director
dvi=application/x-dvi
spl=application/x-futuresplash
gtar=application/x-gtar
hdf=application/x-hdf
js=application/x-javascript
skp=application/x-koan
skd=application/x-koan
skt=application/x-koan
skm=application/x-koan
latex=application/x-latex
nc=application/x-netcdf
cdf=application/x-netcdf
sh=application/x-sh
shar=application/x-shar
swf=application/x-shockwave-flash
sit=application/x-stuffit
sv4cpio=application/x-sv4cpio
sv4crc=application/x-sv4crc
tar=application/x-tar
tcl=application/x-tcl
tex=application/x-tex
texinfo=application/x-texinfo
texi=application/x-texinfo
t=application/x-troff
tr=application/x-troff
roff=application/x-troff
man=application/x-troff-man
me=application/x-troff-me
ms=application/x-troff-ms
ustar=application/x-ustar
src=application/x-wais-source
xhtml=application/xhtml+xml
xht=application/xhtml+xml
zip=application/zip
au=audio/basic
snd=audio/basic
mid=audio/midi
midi=audio/midi
kar=audio/midi
mpga=audio/mpeg
mp2=audio/mpeg
mp3=audio/mpeg
aif=audio/x-aiff
aiff=audio/x-aiff
aifc=audio/x-aiff
m3u=audio/x-mpegurl
ram=audio/x-pn-realaudio
rm=audio/x-pn-realaudio
rpm=audio/x-pn-realaudio-plugin
ra=audio/x-realaudio
wav=audio/x-wav
pdb=chemical/x-pdb
xyz=chemical/x-xyz
bmp=image/bmp
gif=image/gif
ief=image/ief
jpeg=image/jpeg
jpg=image/jpeg
jpe=image/jpeg
png=image/png
tiff=image/tiff
tif=image/tiff
djvu=image/vnd.djvu
djv=image/vnd.djvu
wbmp=image/vnd.wap.wbmp
ras=image/x-cmu-raster
pnm=image/x-portable-anymap
pbm=image/x-portable-bitmap
pgm=image/x-portable-graymap
ppm=image/x-portable-pixmap
rgb=image/x-rgb
xbm=image/x-xbitmap
xpm=image/x-xpixmap
xwd=image/x-xwindowdump
igs=model/iges
iges=model/iges
msh=model/mesh
mesh=model/mesh
silo=model/mesh
wrl=model/vrml
vrml=model/vrml
css=text/css
html=text/html
htm=text/html
asc=text/plain
txt=text/plain
rtx=text/richtext
rtf=text/rtf
sgml=text/sgml
sgm=text/sgml
tsv=text/tab-separated-values
wml=text/vnd.wap.wml
wmls=text/vnd.wap.wmlscript
etx=text/x-setext
xsl=text/xml
xml=text/xml
mpeg=video/mpeg
mpg=video/mpeg
mpe=video/mpeg
qt=video/quicktime
mov=video/quicktime
mxu=video/vnd.mpegurl
avi=video/x-msvideo
movie=video/x-sgi-movie
ice=x-conference/x-cooltalk
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DataVault善战

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值