昨天忘记给大家说了个事,昨天添加FTP服务器依赖那部分我在搭建项目开始时就已经在taotao-common的pom文件下写好了,大家可以回去看看里面添加Apache组件那部分里面就有。

1、Nginx+FTP出现403错误

还有就是访问nginx下的ftp图片会有我遇到的这个问题,如图:

我不知道大家有没有遇到,假如遇到也不知道大家是怎么去解决的,我把我的解决可以具体点写出来。

1.1、错误分析:

我看了下网上的关于这方面的相关资料,大概总结的两个可能的原因:

1、缺少index.html或者index.php文件(索引文件)

2、权限问题

这是我nginx修改后的配置文件

因此我现在直接排除掉第一种情况。

怎么说呢。果然大部分原因还是会出现在第二种情况下,这就要我们需要去熟悉linux了,可怜的小伙伴们不知道学习的咋样。先解决问题在讨论学习方面吧。

1.2、错误解决

一般这种情况我的是因为是在root用户下编译的安装及启动nginx的,会出现权限问题,没跟ftp服务器所属用户一致导致。于是我就改变了nginx所属的用户和用户组。

root@cdh4>chmod 777 /home/ftpuser/www
root@cdh4>chown -R ftpuser:ftpuser /usr/local/nginx
root@cdh4>/usr/local/nginx/sbin/nginx -s reload

之后在打开浏览器就可以访问的到我昨天用测试代码上传的图片了,地址: http://blog.csdn.net/sinat_31726559/article/details/52153330

如果还是不行就重启一下机器,在关闭好iptables或者firewall就可以了

2、访问Nginx图片失真

上面虽然我们能够访问到图片了,但是图片却存在失真的情况,这又是怎么一回事呢?

2.1、错误分析

先看看昨天我写的测试代码

从上面可以看出我上传到ftp服务器是以字节流传输的,到服务器后是文本格式,而图片是二进制格式,所以上传上去或出现编码不能恢复到原来的图片模样。

2.2、错误解决

知道错误原因就好解决了,只要修改上传文件的格式就行了,添加以下一句代码就ok了

//修改上传文件格式
client.setFileType(FTP.BINARY_FILE_TYPE);

将之前上传的图片先从服务器删除,在用java代码上传一回

上传ok,接着我们再刷新一下浏览器看看效果。

呵呵,搞定!

3、项目所用到的FTP工具类

这里因为是项目中所用到的工具类。考虑到代码的复用性,我就在taotao-common下新建的一个utils的工具类的包,如下:

工具类代码如下:

代码一

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: TODO(ftp服务器的工具类)  * @author 汪本成  * @date 2016年8月9日 上午10:43:38  **/
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();  }  }
}

这个工具类的测试代码就让你们写写了,不会可以给我留言,及时给你答复

4、图片上传的实现

4.1、需求分析

Common.js

1、绑定事件,上传图片的组件

2、初始化参数

2、上传图片的url:

/pic/upload

3、上图片参数名称:

uploadFile

4、返回结果数据类型json

参考文档:http://kindeditor.net/docs/upload.html

返回格式(JSON)

//成功时
{"error" : 0,"url" : "http://www.example.com/path/to/file.ext"
}
//失败时
{"error" : 1,"message" : "错误信息"
}

5、整个组建关键代码

代码二

var TT = TAOTAO = {// 编辑器参数kingEditorParams : {//指定上传文件参数名称filePostName  : "uploadFile",//指定上传文件请求的url。uploadJson : '/pic/upload',//上传类型,分别为image、flash、media、filedir : "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();}});});});});},

详细的记得要查看我上面发给你的链接资料哟。

4.2、Service

功能:接收controller层传递过来的图片对象,把图片上传到ftp服务器。给图片生成一个新的名字,防止文件名重复。返回文件的url路径。需要保证图片上传插件的数据方式。

这里有两种实现方式:

1、创建一个pojo对象来实现

2、创建一个Map实现

这里我用Map实现。

Map中的内容:

key                         Value                
Error 1、0
URL 图片的url(成功时)                          
Message 错误信息(失败时)

首先去service里面定义一个接口,为PictureService

代码三

package com.taotao.service;import java.util.Map;import org.springframework.web.multipart.MultipartFile;/*** * @ClassName: PictureService  * @Description: TODO(图片上传接口)  * @author 汪本成  * @date 2016年8月9日 下午12:01:27  **/
public interface PictureService {Map<?, ?> uploadFile(MultipartFile uploadFile);}

对接口进行实现,但是实现时候我们得先整理好我们的思路。

1、对生成的文件名要保证能够不进行重复,开始我想到的是UUID,但是感觉太长了。就用一个生成id的工具类解决,代码如下:

代码四

package com.taotao.common.utils;import java.util.Random;/*** * @ClassName: IDUtils  * @Description: TODO(各种id生成策略)  * @author 汪本成  * @date 2016年8月9日 下午12:40:19  **/
public class IDUtils {/*** 图片名生成*/public static String genImageName() {//取当前时间的长整形值包含毫秒long millis = System.currentTimeMillis();//long millis = System.nanoTime();//加上三位随机数Random random = new Random();int end3 = random.nextInt(999);//如果不足三位前面补0String 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);//如果不足两位前面补0String 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());}
}

2、进行图片上传时,我们首先考虑到不能绑定死一个机器,在代码中就决定或者说写死这个机器信息,应该在配置文件里进行配置,在读取配置文件信息会比较好,于是新建一个properties文件来记录信息。这里我们绝对不能将这个配置文件写到jar包工程下,所以在taotao-manager-web工程下的resource文件夹下新建一个resource.properties文件来保存配置信息,如下:

代码五

#FTP相关配置
#FTP ip地址
FTP_IP=192.168.43.163
FTP_PORT=21
FTP_USERNAME=ftpuser
FTP_PASSWORD=115010
FTP_BASE_PATH=/home/ftpuser/www/images
#图片服务器的相关配置
#图片服务器的基础url
IMAGE_BASE_URL=http://192.168.43.163/images

然后接下来考虑怎么读取这个配置文件,到这步我们可以回忆一下之前我们是怎么读取数据库的配置文件db.properties的。spring给我们提供了完整的解决方案,不会的伙伴spring可得好好学了哟。考虑细节,这里我就多说一点吧。

spring读取信息这部分是在之前写的xml文件里,这里我截个图给大家看下大家就明白了。

然后就是spring读取文件信息了,这里就要用到@Value("${文件的key字段}")这个知识点了,当你在写java代码声明这个字段的时候spring会给你自动注入进去的。好,直接来给大家写好代码,毕竟得要干货嘛。

代码六

package com.taotao.service.impl;import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;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.taotao.common.utils.FtpUtil;
import com.taotao.common.utils.IDUtils;
import com.taotao.service.PictureService;/*** * @ClassName: PictureServiceImpl  * @Description: TODO(图片上传服务)  * @author 汪本成  * @date 2016年8月9日 下午12:02:33  **/
@Service
public class PictureServiceImpl implements PictureService {//注入resource.properties的Key字段@Value("${FTP_IP}")private String FTP_IP;@Value("${FTP_PORT}")private Integer FTP_PORT;@Value("${FTP_USERNAME}")private String FTP_USERNAME;@Value("${FTP_PASSWORD}")private String FTP_PASSWORD;@Value("${FTP_BASE_PATH}")private String FTP_BASE_PATH;@Value("${IMAGE_BASE_URL}")private String IMAGE_BASE_URL;@Overridepublic Map<?, ?> uploadFile(MultipartFile uploadFile) {Map resultMap = new HashMap<>();try {//生成一个新的文件名//取原始文件名String oldName = uploadFile.getOriginalFilename();//生成新文件名//UUID.randomUUID();String newName = IDUtils.genImageName();newName = newName + oldName.substring(oldName.lastIndexOf("."));//图片上传String imagePath = new DateTime().toString("/yyyy/MM/dd");boolean result = FtpUtil.uploadFile(FTP_IP, FTP_PORT, FTP_USERNAME, FTP_PASSWORD, FTP_BASE_PATH,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", "文件上传异常");return resultMap;}}}

4.3、Controller

功能:接收页面传递过来的图片。调用service上传到图片服务器。返回结果。

参数:MultiPartFileuploadFile

返回值:返回json数据,应该返回一个pojo,PictureResult对象。

代码七

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.service.PictureService;@Controller
public class PictureController {@Autowiredprivate PictureService pictureService;@RequestMapping("/pic/upload")@ResponseBodypublic Map<?, ?> pictureUpload(MultipartFile uploadFile) {Map<?, ?> result = pictureService.uploadFile(uploadFile);return result;}
}

然后更新一下taotao-common这个工程。启动taotao-manager,点击上传图片。

4.4、图片上传异常

控制台输出一下异常信息:

错误分析:缺少配置文件

错误解决:1、需要引入file-up;oad和common-io包;

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>

之后重启taotao-manager,打开qq浏览器,测试下,发现好使,如图:

但是很遗憾,在火狐浏览器上却失败了

这是为什么呢,我觉得这就是插件本身的兼容性问题。但是问题出来了我们必须得解决呀,怎么解决呢?

这里就要换个思路,统一换成利用json数据来返回就ok。这里我就写个json的工具类放到taotao-common下。

代码九

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;/*** * @ClassName: JsonUtils  * @Description: TODO(淘淘商城自定义响应结构)  * @author 汪本成  * @date 2016年8月10日 上午1:32:37  **/
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;}}

然后再修改一下我们写的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: TODO(图片上传的controller)  * @author 汪本成  * @date 2016年8月10日 上午1:33:32  **/
@Controller
public class PictureController {@Autowiredprivate PictureService pictureService;@RequestMapping("/pic/upload")@ResponseBodypublic String pictureUpload(MultipartFile uploadFile) {Map<?, ?> result = pictureService.uploadFile(uploadFile);//为了保证兼容性,需要把Result转换成json格式的字符串String json = JsonUtils.objectToJson(result);return json;}
}

然后启动进行测试:

ok,完美解决图片上传问题,明天继续开发

淘淘商城---8.9相关推荐

  1. 淘淘商城FTP服务器、Redis和solr集群配置

    这是我通过网上查找到的image_server修改而成的,已适用于2015年版本的淘淘商城视频 注意要修改该虚拟机的虚拟网卡网段为192.168.1.133,下面是一些命令:(标红的地方为必须的操作! ...

  2. 删除桌面上淘宝商城,高清电影,精彩小游戏图标

    症状:最近很多朋友反应,桌面上多了高清电影.精彩小游戏.淘宝商城这三个图标,右击这几个图标,只有打开主页或创建快捷方式的选项,无法删除. 经过测试,解决方法如下: 首先在桌面上右击,依次点击排列图标, ...

  3. 淘淘商城学习笔记 之 上传图片到远程服务器,图片的回显出现的bug

    最近在学习淘淘商城中用到的技术,感觉受益良多,遇到一个比较奇怪的bug调了好久,遂心乐之分享于诸君 bug情况是这样的:在商城的后台上传图片之后图片回显不出来,右键查看链接,发现链接被加了localh ...

  4. 淘淘商城项目过程记录

    一.为什么要做这个项目 想想距上次写一个完整的项目已经过了很长时间,因为一直在学习其他的知识,对SSM 知识已经有了生疏,于是就想通过这个商城项目把所有的知识都串一遍,不仅能够回复以前的知识,也可以学 ...

  5. ssm(Spring、Springmvc、Mybatis)实战之淘淘商城-第七天(非原创)

    文章大纲 一.课程介绍 二.Redis基础实战 三.Redis之高可用.集群.云平台搭建实战 四.淘淘商城Jedis整合spring 五.项目源码与资料下载 六.参考文章 一.课程介绍 一共14天课程 ...

  6. 淘淘商城项目分析报告

    目录 第1章 概述 1 1.1 课程设计的核心任务 1 1.2 课程设计工作进程 1 第2章 需求分析 2 2.1 用户需求 2 2.1.1 业务需求 2 2.1.2 商业需求 2 2.1.3 特殊需 ...

  7. 淘淘商城项目mysql服务器_SpringMVC+Spring+Mybatis+Mysql+Maven+Svn[ 淘淘商城项目环境搭建 ]...

    背景:淘淘商城项目的环境搭建 说明:采用SpringMVC+Spring+Mybatis+Mysql+Maven+Svn结构搭建,在开发之中可以参考其结构和搭建步骤去搭建实际的工程项目 工程结构简图: ...

  8. 毕设ssm商城系统_ssm商城系统(爱淘淘购物)项目源码

    ssm商城系统(爱淘淘购物)项目演示 本系统采用SSM架构来搭建. 服务器:tomcat7 java虚拟机:jdk1.7 数据库:mysql 前端:Vue + Bootstrap 管理员用户:root ...

  9. ssm(Spring、Springmvc、Mybatis)实战之淘淘商城-第四天(非原创)

    文章大纲 一.课程介绍 二.今日内容介绍 三.参考资料下载 四.参考文章 一.课程介绍 一共14天课程 (1)第一天:电商行业的背景.淘淘商城的介绍.搭建项目工程.Svn的使用. (2)第二天:框架的 ...

  10. (转)淘淘商城系列——商品搜索功能测试

    http://blog.csdn.net/yerenyuan_pku/article/details/72941506 到这里,我相信大家也是不容易,我自己也算是很不容易写到这里,希望自己能一直写下去 ...

最新文章

  1. 织梦直接写php标签,非常实用的织梦dede所有标签调用方法大全 .
  2. (八十二)利用苹果服务器获取导航信息和绘制路径
  3. python能表示多大整数_Python无法表示99999999999999999999这样大的整数。
  4. python IP地址无效化
  5. mysql存储过程大于小于_mysql5.0存储过程操作符知识_函数方法[Mysql学习]
  6. js闭包原理与例子[转]
  7. [Buzz.Today]2012.04.29
  8. selenium+python学习总结-mac
  9. leetcode python3 简单题100. Same Tree
  10. linux 命令大全_【Linux】命令目录大全
  11. I00019 生成全8数
  12. 两岸大学生体验福州油纸伞制作技艺
  13. 大白话5分钟带你走进人工智能-第二十四节决策树系列之分裂流程和Gini系数评估(3)...
  14. Debit credit problem
  15. Mysql索引会失效的几种情况
  16. 读出我潮流 亚马逊Kindle新品焕彩上市
  17. 使用 GitHub Pages 和 Hexo 以及 Aurora 主题搭建静态个人博客
  18. 微信小程序Post方法提交数据
  19. 三星S9微信和服务器怎么连接,三星s9 微信在后台为什么收不到消息 | 手游网游页游攻略大全...
  20. 视频号如何发表视频呢?

热门文章

  1. Sprite Renderer
  2. 【hdu2298】【三分】Toxophily
  3. vue项目保存代码后浏览器页面自动更新
  4. 2022年博士招生 | 华南理工大学-鹏城实验室 联培博士 专项计划
  5. gitlab从安装到使用到常见问题处理
  6. php职教云答案,职教云答案查询软件下载,职教云提前看答案,职教云php作业答案...
  7. 利用身份证号码算年龄 并排序
  8. 互联网快讯:华为云正式推出区块链服务;猿辅导布局素质教育;轻松筹回应裁员
  9. Android自定义键盘
  10. 元宇宙「虚拟世界」,构建身临其境的社交世界