SpringMvc + Jsp+ 富文本 kindeditor 进行 图片ftp上传nginx服务器 实现
2017-08-26 20:15
691 查看
一:html 原生态的附件上传
二:实现逻辑分析;
1.1.1 需求分析
Common.js
1、绑定事件
2、初始化参数
3、上传图片的url:
/pic/upload
4、上图片参数名称:
uploadFile
5、返回结果数据类型json
参考文档:
http://kindeditor.net/docs/upload.html
返回格式(JSON)
//成功时 { "error" : 0, "url" : "http://www.example.com/path/to/file.ext" } //失败时 { "error" : 1, "message" : "错误信息" }
6 Service
7: Controller
8:需要引入的jar包的maven 配置参数:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <artifactId>taotao-common</artifactId> <!-- jar包依赖 --> <dependencies> <!-- 时间操作组件 --> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> </dependency> <!-- Apache工具组件 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-io</artifactId> </dependency> <dependency> <groupId>commons-net</groupId> <artifactId>commons-net</artifactId> </dependency> <!-- Jackson Json处理工具包 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency> <!-- 文件上传组件 --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> </dependency> </dependencies> </project>
三:逻辑实现:
1:前端实现:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <link href="/js/kindeditor-4.1.10/themes/default/default.css" type="text/css" rel="stylesheet"> <script type="text/javascript" charset="utf-8" src="/js/kindeditor-4.1.10/kindeditor-all-min.js"></script> <script type="text/javascript" charset="utf-8" src="/js/kindeditor-4.1.10/lang/zh_CN.js"></script> <div style="padding:10px 10px 10px 10px"> <form id="itemAddForm" class="itemForm" method="post"> <table cellpadding="5"> <tr> <td>商品类目:</td> <td> <a href="javascript:void(0)" class="easyui-linkbutton selectItemCat">选择类目</a> <input type="hidden" name="cid" style="width: 280px;"></input> </td> </tr> <tr> <td>商品标题:</td> <td><input class="easyui-textbox" type="text" name="title" data-options="required:true" style="width: 280px;"></input></td> </tr> <tr> <td>商品卖点:</td> <td><input class="easyui-textbox" name="sellPoint" data-options="multiline:true,validType:'length[0,150]'" style="height:60px;width: 280px;"></input></td> </tr> <tr> <td>商品价格:</td> <td><input class="easyui-numberbox" type="text" name="priceView" data-options="min:1,max:99999999,precision:2,required:true" /> <input type="hidden" name="price"/> </td> </tr> <tr> <td>库存数量:</td> <td><input class="easyui-numberbox" type="text" name="num" data-options="min:1,max:99999999,precision:0,required:true" /></td> </tr> <tr> <td>条形码:</td> <td> <input class="easyui-textbox" type="text" name="barcode" data-options="validType:'length[1,30]'" /> </td> </tr> <tr> <td>商品图片:</td> <td> <a href="javascript:void(0)" class="easyui-linkbutton picFileUpload">上传图片</a> <input type="hidden" name="image"/> </td> </tr> <tr> <td>商品描述:</td> <td> <textarea style="width:800px;height:300px;visibility:hidden;" name="desc"></textarea> </td> </tr> <tr class="params hide"> <td>商品规格:</td> <td> </td> </tr> </table> <input type="hidden" name="itemParams"/> </form> <div style="padding:5px"> <a href="javascript:void(0)" class="easyui-linkbutton" onclick="submitForm()">提交</a> <a href="javascript:void(0)" class="easyui-linkbutton" onclick="clearForm()">重置</a> </div> </div> <script type="text/javascript"> var itemAddEditor ; //页面初始化完毕后执行此方法 $(function(){ //创建富文本编辑器 itemAddEditor = TAOTAO.createEditor("#itemAddForm [name=desc]"); //初始化类目选择和图片上传器 TAOTAO.init({fun:function(node){ //根据商品的分类id取商品 的规格模板,生成规格信息。第四天内容。 //TAOTAO.changeItemParam(node, "itemAddForm"); }}); }); //提交表单 function submitForm(){ //有效性验证 if(!$('#itemAddForm').form('validate')){ $.messager.alert('提示','表单还未填写完成!'); return ; } //取商品价格,单位为“分” $("#itemAddForm [name=price]").val(eval($("#itemAddForm [name=priceView]").val()) * 100); //同步文本框中的商品描述 itemAddEditor.sync(); //取商品的规格 /* var paramJson = []; $("#itemAddForm .params li").each(function(i,e){ var trs = $(e).find("tr"); var group = trs.eq(0).text(); var ps = []; for(var i = 1;i<trs.length;i++){ var tr = trs.eq(i); ps.push({ "k" : $.trim(tr.find("td").eq(0).find("span").text()), "v" : $.trim(tr.find("input").val()) }); } paramJson.push({ "group" : group, "params": ps }); }); //把json对象转换成字符串 paramJson = JSON.stringify(paramJson); $("#itemAddForm [name=itemParams]").val(paramJson); */ //ajax的post方式提交表单 //$("#itemAddForm").serialize()将表单序列号为key-value形式的字符串 $.post("/item/save",$("#itemAddForm").serialize(), function(data){ if(data.status == 200){ $.messager.alert('提示','新增商品成功!'); } }); } function clearForm(){ $('#itemAddForm').form('reset'); itemAddEditor.html(''); } </script>
commom.js
Date.prototype.format = function(format){ var o = { "M+" : this.getMonth()+1, //month "d+" : this.getDate(), //day "h+" : this.getHours(), //hour "m+" : this.getMinutes(), //minute "s+" : this.getSeconds(), //second "q+" : Math.floor((this.getMonth()+3)/3), //quarter "S" : this.getMilliseconds() //millisecond }; if(/(y+)/.test(format)){ format = format.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length)); } for(var k in o) { if(new RegExp("("+ k +")").test(format)){ format = format.replace(RegExp.$1, RegExp.$1.length==1 ? o[k] : ("00"+ o[k]).substr((""+ o[k]).length)); } } return format; }; var TT = TAOTAO = { // 编辑器参数 kingEditorParams : { //指定上传文件参数名称 filePostName : "uploadFile", //指定上传文件请求的url。 uploadJson : '/pic/upload', //上传类型,分别为image、flash、media、file dir : "image" }, // 格式化时间 formatDateTime : function(val,row){ var now = new Date(val); return now.format("yyyy-MM-dd hh:mm:ss"); }, // 格式化连接 formatUrl : function(val,row){ if(val){ return "<a href='"+val+"' target='_blank'>查看</a>"; } return ""; }, // 格式化价格 formatPrice : function(val,row){ return (val/1000).toFixed(2); }, // 格式化商品的状态 formatItemStatus : function formatStatus(val,row){ if (val == 1){ return '正常'; } else if(val == 2){ return '<span style="color:red;">下架</span>'; } else { return '未知'; } }, init : function(data){ // 初始化图片上传组件 this.initPicUpload(data); // 初始化选择类目组件 this.initItemCat(data); }, // 初始化图片上传组件 initPicUpload : function(data){ $(".picFileUpload").each(function(i,e){ var _ele = $(e); _ele.siblings("div.pics").remove(); _ele.after('\ <div class="pics">\ <ul></ul>\ </div>'); // 回显图片 if(data && data.pics){ var imgs = data.pics.split(","); for(var i in imgs){ if($.trim(imgs[i]).length > 0){ _ele.siblings(".pics").find("ul").append("<li><a href='"+imgs[i]+"' target='_blank'><img src='"+imgs[i]+"' width='80' height='50' /></a></li>"); } } } //给“上传图片按钮”绑定click事件 $(e).click(function(){ var form = $(this).parentsUntil("form").parent("form"); //打开图片上传窗口 KindEditor.editor(TT.kingEditorParams).loadPlugin('multiimage',function(){ var editor = this; editor.plugin.multiImageDialog({ clickFn : function(urlList) { var imgArray = []; KindEditor.each(urlList, function(i, data) { imgArray.push(data.url); form.find(".pics ul").append("<li><a href='"+data.url+"' target='_blank'><img src='"+data.url+"' width='80' height='50' /></a></li>"); }); form.find("[name=image]").val(imgArray.join(",")); editor.hideDialog(); } }); }); }); }); }, // 初始化选择类目组件 initItemCat : function(data){ $(".selectItemCat").each(function(i,e){ var _ele = $(e); if(data && data.cid){ _ele.after("<span style='margin-left:10px;'>"+data.cid+"</span>"); }else{ _ele.after("<span style='margin-left:10px;'></span>"); } _ele.unbind('click').click(function(){ $("<div>").css({padding:"5px"}).html("<ul>") .window({ width:'500', height:"450", modal:true, closed:true, iconCls:'icon-save', title:'选择类目', onOpen : function(){ var _win = this; $("ul",_win).tree({ url:'/item/cat/list', animate:true, onClick : function(node){ if($(this).tree("isLeaf",node.target)){ // 填写到cid中 _ele.parent().find("[name=cid]").val(node.id); _ele.next().text(node.text).attr("cid",node.id); $(_win).window('close'); if(data && data.fun){ data.fun.call(this,node); } } } }); }, onClose : function(){ $(this).window("destroy"); } }).window('open'); }); }); }, createEditor : function(select){ return KindEditor.create(select, TT.kingEditorParams); }, /** * 创建一个窗口,关闭窗口后销毁该窗口对象。<br/> * * 默认:<br/> * width : 80% <br/> * height : 80% <br/> * title : (空字符串) <br/> * * 参数:<br/> * width : <br/> * height : <br/> * title : <br/> * url : 必填参数 <br/> * onLoad : function 加载完窗口内容后执行<br/> * * */ createWindow : function(params){ $("<div>").css({padding:"5px"}).window({ width : params.width?params.width:"80%", height : params.height?params.height:"80%", modal:true, title : params.title?params.title:"", href : params.url, onClose : function(){ $(this).window("destroy"); }, onLoad : function(){ if(params.onLoad){ params.onLoad.call(this); } } }).window("open"); }, closeCurrentWindow : function(){ $(".panel-tool-close").click(); }, changeItemParam : function(node,formId){ $.getJSON("/item/param/query/itemcatid/" + node.id,function(data){ if(data.status == 200 && data.data){ $("#"+formId+" .params").show(); var paramData = JSON.parse(data.data.paramData); var html = "<ul>"; for(var i in paramData){ var pd = paramData[i]; html+="<li><table>"; html+="<tr><td colspan=\"2\" class=\"group\">"+pd.group+"</td></tr>"; for(var j in pd.params){ var ps = pd.params[j]; html+="<tr><td class=\"param\"><span>"+ps+"</span>: </td><td><input autocomplete=\"off\" type=\"text\"/></td></tr>"; } html+="</li></table>"; } html+= "</ul>"; $("#"+formId+" .params td").eq(1).html(html); }else{ $("#"+formId+" .params").hide(); $("#"+formId+" .params td").eq(1).empty(); } }); }, getSelectionsIds : function (select){ var list = $(select); var sels = list.datagrid("getSelections"); var ids = []; for(var i in sels){ ids.push(sels[i].id); } ids = ids.join(","); return ids; }, /** * 初始化单图片上传组件 <br/> * 选择器为:.onePicUpload <br/> * 上传完成后会设置input内容以及在input后面追加<img> */ initOnePicUpload : function(){ $(".onePicUpload").click(function(){ var _self = $(this); KindEditor.editor(TT.kingEditorParams).loadPlugin('image', function() { this.plugin.imageDialog({ showRemote : false, clickFn : function(url, title, width, height, border, align) { var input = _self.siblings("input"); input.parent().find("img").remove(); input.val(url); input.after("<a href='"+url+"' target='_blank'><img src='"+url+"' width='80' height='50'/></a>"); this.hideDialog(); } }); }); }); } };
2:后台的逻辑实现
2-1: ftp配置文件
FTP_ADDRESS=192.168.1.5 FTP_PORT=21 FTP_USERNAME=ftpuser FTP_PASSWORD=123456 FTP_BASEPATH=/home/ftpuser/www/images/ IMAGE_BASE_URL=http://192.168.1.5/images/
引入到SpringMVC.xml配置文件中
2-2:SpringMvc.xml的实现配置
<!-- 定义文件上传解析器 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 设定默认编码 --> <property name="defaultEncoding" value="UTF-8"></property> <!-- 设定文件上传的最大值5MB,5*1024*1024 --> <property name="maxUploadSize" value="5242880"></property> </bean>
2-3:controller层实现:
package com.taotao.controller; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import com.taotao.common.utils.JsonUtils; import com.taotao.service.PictureService; /** * * @ClassName: PictureController * @Description:上传图片处理 * @author: 刘军/shall_liu(1136808529@qq.com) * @date: 2017年8月26日 下午4:03:42 * * @Copyright: 2017 */ @Controller public class PictureController { @Autowired private PictureService pictureService; /** * * @Title: pictureUpload * @Description: 接收图片上传服务 * @param: @param uploadFile * @param: @return * @return: Map * @throws */ @RequestMapping("/pic/upload") @ResponseBody public String pictureUpload(MultipartFile uploadFile){ Map result =pictureService.uploadPicture(uploadFile); //为了保证能的兼容性,需要把 Result转换成json格式的字符串 String json= JsonUtils.objectToJson(result); return json; } }
2_-4: service 层实现
package com.taotao.service; import java.util.Map; import org.springframework.web.multipart.MultipartFile; /** * * @ClassName: PictureService * @Description: 图片生成接口 * * @author: 刘军/shall_liu(1136808529@qq.com) * @date: 2017年8月26日 下午2:29:35 * * @Copyright: 2017 */ public interface PictureService { /** * * @Title: uploadPicture * @Description: 生成图片接口 * @param: @param uploadFile * @param: @return * @return: Map * @throws */ Map uploadPicture(MultipartFile uploadFile); }
package com.taotao.service.impl; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.apache.ibatis.annotations.ResultMap; import org.joda.time.DateTime; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import com.mysql.jdbc.ResultSetMetaData; import com.taotao.common.utils.FtpUtil; import com.taotao.common.utils.IDUtils; import com.taotao.service.PictureService; /** * * @ClassName: PictureServiceImpl * @Description:图片上传 服务 * @author: 刘军/shall_liu(1136808529@qq.com) * @date: 2017年8月26日 下午2:33:25 * * @Copyright: 2017 */ @Service public class PictureServiceImpl implements PictureService{ /** * 实现原理: * 利用了springMvc的加载properties的一套实现工具的机制 * 使用注解@value 自动注入properties的参数信息 * * ftp ip 访问地址 */ @Value("${FTP_ADDRESS}") private String FTP_ADDRESS; /** * ftp 服务端口 */ @Value("${FTP_PORT}") private String FTP_PORT; /** * ftp 登录用户名 */ @Value("${FTP_USERNAME}") private String FTP_USERNAME; /** * ftp 登录密码 */ @Value("${FTP_PASSWORD}") private String FTP_PASSWORD; /** * ftp 保存文件的跟文件路径 */ @Value("${FTP_BASEPATH}") private String FTP_BASEPATH; /** * 图片服务器的基础URL */ @Value("${IMAGE_BASE_URL}") private String IMAGE_BASE_URL; /** * * <p>Title: uploadPicture</p> * <p>Description: </p> 图片上传的实现 * @param uploadFile * @return * @see com.taotao.service.PictureService#uploadPicture(org.springframework.web.multipart.MultipartFile) */ @Override public Map uploadPicture(MultipartFile uploadFile) { Map resultMap =new HashMap<>(); try { /* * 生成一个新的文件名 */ //取原文件名 String oldName=uploadFile.getOriginalFilename(); //生成新文件名 String newName = IDUtils.genImageName(); newName=newName+oldName.substring(oldName.indexOf("."), oldName.length()); // 图片上传 String imagePath=new DateTime().toString("/yyyy/MM/dd"); System.out.println(FTP_PORT); boolean result= FtpUtil.uploadFile(FTP_ADDRESS,Integer.parseInt(FTP_PORT.trim()) , FTP_USERNAME, FTP_PASSWORD, FTP_BASEPATH, imagePath, newName, uploadFile.getInputStream()); if(!result){ resultMap.put("error", 1); resultMap.put("message", "文件上传失败"); return resultMap; } resultMap.put("error", 0); resultMap.put("url", IMAGE_BASE_URL+imagePath+"/"+newName); return resultMap ; } catch (IOException e) { resultMap.put("error", 1); resultMap.put("message", "文件上传发生异常"+e.toString()); return resultMap; } } }
2-5: dao 层
无实现
2-6:工具类
package com.taotao.common.utils; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPFile; import org.apache.commons.net.ftp.FTPReply; /** * * @ClassName: FtpUtil * @Description: ftp上传下载工具类 * 来自传智播客 * @author: 刘军/shall_liu(1136808529@qq.com) * @date: 2017年8月26日 下午7:10:41 * * @Copyright: 2017 */ public class FtpUtil { /** * Description: 向FTP服务器上传文件 * @param host FTP服务器hostname * @param port FTP服务器端口 * @param username FTP登录账号 * @param password FTP登录密码 * @param basePath FTP服务器基础目录 * @param filePath FTP服务器文件存放路径。例如分日期存放:/2015/01/01。文件的路径为basePath+filePath * @param filename 上传到FTP服务器上的文件名 * @param input 输入流 * @return 成功返回true,否则返回false */ public static boolean uploadFile(String host, int port, String username, String password, String basePath, String filePath, String filename, InputStream input) { boolean result = false; FTPClient ftp = new FTPClient(); try { int reply; ftp.connect(host, port);// 连接FTP服务器 // 如果采用默认端口,可以使用ftp.connect(host)的方式直接连接FTP服务器 ftp.login(username, password);// 登录 reply = ftp.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { ftp.disconnect(); return result; } //切换到上传目录 if (!ftp.changeWorkingDirectory(basePath+filePath)) { //如果目录不存在创建目录 String[] dirs = filePath.split("/"); String tempPath = basePath; for (String dir : dirs) { if (null == dir || "".equals(dir)) continue; tempPath += "/" + dir; if (!ftp.changeWorkingDirectory(tempPath)) { if (!ftp.makeDirectory(tempPath)) { return result; } else { ftp.changeWorkingDirectory(tempPath); } } } } //设置上传文件的类型为二进制类型 ftp.setFileType(FTP.BINARY_FILE_TYPE); //上传文件 if (!ftp.storeFile(filename, input)) { return result; } input.close(); ftp.logout(); result = true; } catch (IOException e) { e.printStackTrace(); } finally { if (ftp.isConnected()) { try { ftp.disconnect(); } catch (IOException ioe) { } } } return result; } /** * Description: 从FTP服务器下载文件 * @param host FTP服务器hostname * @param port FTP服务器端口 * @param username FTP登录账号 * @param password FTP登录密码 * @param remotePath FTP服务器上的相对路径 * @param fileName 要下载的文件名 * @param localPath 下载后保存到本地的路径 * @return */ public static boolean downloadFile(String host, int port, String username, String password, String remotePath, String fileName, String localPath) { boolean result = false; FTPClient ftp = new FTPClient(); try { int reply; ftp.connect(host, port); // 如果采用默认端口,可以使用ftp.connect(host)的方式直接连接FTP服务器 ftp.login(username, password);// 登录 reply = ftp.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { ftp.disconnect(); return result; } ftp.changeWorkingDirectory(remotePath);// 转移到FTP服务器目录 FTPFile[] fs = ftp.listFiles(); for (FTPFile ff : fs) { if (ff.getName().equals(fileName)) { File localFile = new File(localPath + "/" + ff.getName()); OutputStream is = new FileOutputStream(localFile); ftp.retrieveFile(ff.getName(), is); is.close(); } } ftp.logout(); result = true; } catch (IOException e) { e.printStackTrace(); } finally { if (ftp.isConnected()) { try { ftp.disconnect(); } catch (IOException ioe) { } } } return result; } public static void main(String[] args) { try { FileInputStream in=new FileInputStream(new File("D:\\temp\\image\\gaigeming.jpg")); boolean flag = uploadFile("192.168.25.133", 21, "ftpuser", "ftpuser", "/home/ftpuser/www/images","/2015/01/21", "gaigeming.jpg", in); System.out.println(flag); } catch (FileNotFoundException e) { e.printStackTrace(); } } }
package com.taotao.common.utils; import java.util.Random; /** * * @ClassName: IDUtils * @Description:各种id生成策略 * @author: 刘军/shall_liu(1136808529@qq.com) * @date: 2017年8月26日 下午2:49:33 * * @Copyright: 2017 */ public class IDUtils { /** * 图片名生成 */ public static String genImageName() { //取当前时间的长整形值包含毫秒 long millis = System.currentTimeMillis();//毫秒 //纳秒 1秒=1000毫秒=1000 X 1000 微秒 =1000 X 1000X 1000 纳秒 //long millis = System.nanoTime(); //加上三位随机数 Random random = new Random(); int end3 = random.nextInt(999); //如果不足三位前面补0 String str = millis + String.format("%03d", end3); return str; } /** * 商品id生成 */ public static long genItemId() { //取当前时间的长整形值包含毫秒 long millis = System.currentTimeMillis(); //long millis = System.nanoTime(); //加上两位随机数 Random random = new Random(); int end2 = random.nextInt(99); //如果不足两位前面补0 String str = millis + String.format("%02d", end2); long id = new Long(str); return id; } public static void main(String[] args) { for(int i=0;i< 100;i++) System.out.println(genItemId()); } }
package com.taotao.common.utils; import java.util.List; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; /** * 淘淘商城自定义响应结构 */ public class JsonUtils { // 定义jackson对象 private static final ObjectMapper MAPPER = new ObjectMapper(); /** * 将对象转换成json字符串。 * <p>Title: pojoToJson</p> * <p>Description: </p> * @param data * @return */ public static String objectToJson(Object data) { try { String string = MAPPER.writeValueAsString(data); return string; } catch (JsonProcessingException e) { e.printStackTrace(); } return null; } /** * 将json结果集转化为对象 * * @param jsonData json数据 * @param clazz 对象中的object类型 * @return */ public static <T> T jsonToPojo(String jsonData, Class<T> beanType) { try { T t = MAPPER.readValue(jsonData, beanType); return t; } catch (Exception e) { e.printStackTrace(); } return null; } /** * 将json数据转换成pojo对象list * <p>Title: jsonToList</p> * <p>Description: </p> * @param jsonData * @param beanType * @return */ public static <T>List<T> jsonToList(String jsonData, Class<T> beanType) { JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType); try { List<T> list = MAPPER.readValue(jsonData, javaType); return list; } catch (Exception e) { e.printStackTrace(); } return null; } }
2-7:对于 linux环境下的nginx 服务器和ftp服务器的搭建 请查看以下文章:
《centos7_ linux : Nginx安装手册》、《CentOS7 搭建FTP服务器》、《centos7 nginx图片 服务器可以访问ftp用户上传的图片资源的配置》
四:效果展示:
相关文章推荐
- SpringMVC实现FTP服务器之图片和富文本上传
- SSM框架中-使用KindEditor+Nginx服务器+FTP服务,实现多文件上传
- ftp+nginx搭建图片服务器,上传FTP文件可以传到服务器上,但是文件大小是0字节的 而且点击按钮后程序会卡死
- Nginx+Ftp+Fileinput做图片上传显示服务器(二)
- FTP+nginx图片服务器上传图片异常解决
- 在Java-web中实现图片上传到ftp图片服务器
- Nginx+Ftp+Fileinput做图片上传显示服务器(三)
- centos7 nginx图片 服务器可以访问ftp用户上传的图片资源的配置
- 【Ts 3】Nginx的Http(图片)服务器配置+ftp上传使用说明
- 【Ts 3】Nginx的Http(图片)服务器配置+ftp上传使用说明
- 【T电商 3】Nginx的Http(图片)服务器配置+ftp上传使用说明
- java操作ftp实现文件的上传下载(适用于图片文档服务器)
- springMVC+ Linux + VSFTPD + nginx实现文件上传至图片服务器
- summernote富文本的改写onImageUpload在服务器上传图片,并利用MutationObserver实时监测进行图片在服务器删除
- Nginx+Ftp+Fileinput做图片上传显示服务器(一)
- 使用KindEditor的图片上传功能,实现图片上传到专门的图片服务器。
- [置顶] 使用FTP上传图片到图片服务器
- Java连接FTP服务器并且实现对其文件的上传和下载
- Struts2框架下实现向服务器上传图片
- uploadFile+nginx实现上传图片(Windows/Linux均可用)