本文主要是介绍淘淘商城---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、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的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!