淘淘商城---8.9

来源:互联网 发布:linux查看根目录命令 编辑:程序博客网 时间:2024/05/01 21:44

昨天忘记给大家说了个事,昨天添加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/wwwroot@cdh4>chown -R ftpuser:ftpuser /usr/local/nginxroot@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                 Error1、0URL图片的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.163FTP_PORT=21FTP_USERNAME=ftpuserFTP_PASSWORD=115010FTP_BASE_PATH=/home/ftpuser/www/images#图片服务器的相关配置#图片服务器的基础urlIMAGE_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    * */@Servicepublic 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;@Controllerpublic 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    * */@Controllerpublic 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,完美解决图片上传问题,明天继续开发大笑








0 0