淘淘商城---8.9
Posted 汪本成
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了淘淘商城---8.9相关的知识,希望对你有一定的参考价值。
昨天忘记给大家说了个事,昨天添加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、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();
);
);
);
);
,
详细的记得要查看我上面发给你的链接资料哟。
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);
//如果不足三位前面补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());
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;
@Override
public 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
@Autowired
private PictureService pictureService;
@RequestMapping("/pic/upload")
@ResponseBody
public 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
@Autowired
private PictureService pictureService;
@RequestMapping("/pic/upload")
@ResponseBody
public String pictureUpload(MultipartFile uploadFile)
Map<?, ?> result = pictureService.uploadFile(uploadFile);
//为了保证兼容性,需要把Result转换成json格式的字符串
String json = JsonUtils.objectToJson(result);
return json;
然后启动进行测试:
ok,完美解决图片上传问题,明天继续开发
以上是关于淘淘商城---8.9的主要内容,如果未能解决你的问题,请参考以下文章