[第三天传智播客淘淘商城之图片上传, 搭建nginx图片服务器/ftp服务器]
图片上传
传统项目中的图片管理
传统项目中,可以在web项目中添加一个文件夹,来存放上传的图片。例如在工程的根目录WebRoot下创建一个images文件夹。把图片存放在此文件夹中就可以直接使用在工程中引用。
优点:引用方便,便于管理
缺点:
1、如果是分布式环境图片引用会出现问题。
2、图片的下载会给服务器增加额外的压力


分布式环境的图片管理

分布式环境一般都有一个专门的图片服务器存放图片。
我们使用虚拟机搭建一个专门的服务器来存放图片。在此服务器上安装一个nginx来提供http服务,安装一个ftp服务器来提供图片上传服务。
搭建图片服务器
第一步:安装vsftpd提供ftp服务
详见:http://www.cnblogs.com/josephcnblog/articles/6930572.html
第二步:安装nginx提供http服务
详见:http://www.cnblogs.com/josephcnblog/articles/6930593.html
测试图片服务器
ftp服务测试
a)使用ftp客户端

b)使用java程序
ftp可以需要依赖commons-net-3.3.jar包。
public static void main(String[] args) throws Exception {
FTPClient ftpClient = new FTPClient();
ftpClient.connect("192.168.25.200");
ftpClient.login("ftpuser", "ftpuser");
FileInputStream inputStream = new FileInputStream(new File("D:\\Documents\\Pictures\\pics\\21.jpg"));
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
ftpClient.storeFile("123.jpg", inputStream);
inputStream.close();
ftpClient.logout();
}
1. http服务测试
a) 浏览器测试
SpringMVC中实现图片上传
上传思路:
第一步:
导入common-fileupload的依赖
<!-- 文件上传组件 --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> </dependency>
第二步:
在SpringMVC配置文件中添加文件上传解析器
<!-- 定义文件上传解析器 --> <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>
Service实现
1. 获取资源配置文件的内容
第一步:
创建资源配置文件

FILI_UPLOAD_PATH=D:/temp/imagestest/webapps/images IMAGE_BASE_URL=http://localhost:9000/images
第二步:
在Spring(taotao-manage-servlet.xml)容器中加载资源文件

第二步:
在Service中获取资源配置:
@Value("${FILI_UPLOAD_PATH}")
private String FILI_UPLOAD_PATH;
@Value("${IMAGE_BASE_URL}")
private String IMAGE_BASE_URL;
图片名生成策略
时间+随机数
/**
* 图片名生成
*/
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;
}
使用UUID:
UUID.randomUUID();
1. Service实现
@Service
public class PictureServiceImpl implements PictureService {
@Value("${IMAGE_BASE_URL}")
private String IMAGE_BASE_URL;
@Value("${FILI_UPLOAD_PATH}")
private String FILI_UPLOAD_PATH;
@Value("${FTP_SERVER_IP}")
private String FTP_SERVER_IP;
@Value("${FTP_SERVER_PORT}")
private Integer FTP_SERVER_PORT;
@Value("${FTP_SERVER_USERNAME}")
private String FTP_SERVER_USERNAME;
@Value("${FTP_SERVER_PASSWORD}")
private String FTP_SERVER_PASSWORD;
@Override
public PictureResult uploadFile(MultipartFile uploadFile) throws Exception {
// 上传文件功能实现
String path = savePicture(uploadFile);
// 回显
PictureResult result = new PictureResult(0, IMAGE_BASE_URL + path);
return result;
}
private String savePicture(MultipartFile uploadFile) {
String result = null;
try {
// 上传文件功能实现
// 判断文件是否为空
if (uploadFile.isEmpty())
return null;
// 上传文件以日期为单位分开存放,可以提高图片的查询速度
String filePath = "/" + new SimpleDateFormat("yyyy").format(new Date()) + "/"
+ new SimpleDateFormat("MM").format(new Date()) + "/"
+ new SimpleDateFormat("dd").format(new Date());
// 取原始文件名
String originalFilename = uploadFile.getOriginalFilename();
// 新文件名
String newFileName = IDUtils.genImageName() + originalFilename.substring(originalFilename.lastIndexOf("."));
// 转存文件,上传到ftp服务器
FtpUtil.uploadFile(FTP_SERVER_IP, FTP_SERVER_PORT, FTP_SERVER_USERNAME, FTP_SERVER_PASSWORD,
FILI_UPLOAD_PATH, filePath, newFileName, uploadFile.getInputStream());
result = filePath + "/" + newFileName;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
Controller实现
@Controller
@RequestMapping("/pic")
public class PictureController {
@Autowired
private PictureService pictureService;
@RequestMapping("/upload")
@ResponseBody
public PictureResult uploda(MultipartFile uploadFile) throws Exception {
//调用service上传图片
PictureResult pictureResult = pictureService.uploadFile(uploadFile);
//返回上传结果
return pictureResult;
}
}
前端JS实现图片上传
Js实现逻辑



=====================================
工具类:
IDUtils.java
package com.taotao.utils;
import java.util.Random;
/**
* 各种id生成策略
* <p>Title: IDUtils</p>
* <p>Description: </p>
* <p>Company: www.itcast.com</p>
* @author 入云龙
* @date 2015年7月22日下午2:32:10
* @version 1.0
*/
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());
}
}
FtpUtil.java
package com.taotao.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;
/**
* ftp上传下载工具类
* <p>Title: FtpUtil</p>
* <p>Description: </p>
* <p>Company: www.itcast.com</p>
* @author 入云龙
* @date 2015年7月29日下午8:11:51
* @version 1.0
*/
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();
}
}
}
JsonUtils.java【这个工具的作用是:返回json格式数据时,chrome浏览器可以兼容,但是火狐浏览器不兼容,为了所有浏览器都兼容,需要返回字符串】
package com.taotao.utils;
import java.util.List;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.taotao.result.TaotaoResult;
/**
* 淘淘商城自定义响应结构
*/
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;
}
}
PictureResult.java
package com.taotao.result;
/**
* 上传图片返回值
* <p>Title: PictureResult</p>
* <p>Description: </p>
* <p>Company: www.itcast.com</p>
* @author 入云龙
* @date 2015年7月22日下午2:09:02
* @version 1.0
*/
public class PictureResult {
/**
* 上传图片返回值,成功:0 失败:1
*/
private Integer error;
/**
* 回显图片使用的url
*/
private String url;
/**
* 错误时的错误消息
*/
private String message;
public PictureResult(Integer state, String url) {
this.url = url;
this.error = state;
}
public PictureResult(Integer state, String url, String errorMessage) {
this.url = url;
this.error = state;
this.message = errorMessage;
}
public Integer getError() {
return error;
}
public void setError(Integer error) {
this.error = error;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

浙公网安备 33010602011771号