图片上传的方式:
1.上传到数据库中的Blob类型,从数据库中取出来并显示。详细见下面链接
http://blog.sina.com.cn/s/blog_5b0745e80102we31.html
2.上传到服务器的固定目录下,在数据库中仅保存图片的地址。详细见下文
效果展现:
一.前端实现批量上传弹出框
二.后端实现图片的保存于回显
具体实现步骤:
一.前端图片上传框的展现
1.1下载插件Kindeditor,并添加到项目目录中
2.2编写jsp文件,该代码的编写可以参考官方文档的源代码
view-source:http://kindeditor.net/ke4/examples/multi-image-dialog.html
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<html>
<meta charset="utf-8" />
<title>批量上传图片</title>
<link href="js/kindeditor-4.1.10/themes/default/default.css" type="text/css" rel="stylesheet">
<script type="text/javascript" charset="utf-8" src="js/kindeditor-4.1.10/kindeditor-all-min.js"></script>
<script type="text/javascript" charset="utf-8" src="js/kindeditor-4.1.10/lang/zh_CN.js"></script>
<script>
KindEditor.ready(function(K) {
var editor = K.editor({
filePostName:"uploadFile",//上传组件名
uploadJson: '/rest/pic/upload',//上传地址
dir:"image"//类型
});
K('#J_selectImage').click(function() {
editor.loadPlugin('multiimage', function() {
editor.plugin.multiImageDialog({
clickFn : function(urlList) {
var div = K('#J_imageView');
div.html('');
K.each(urlList, function(i, data) {
div.append('<img src="' + data.url + '">');
});
editor.hideDialog();
}
});
});
});
});
</script>
</head>
<body>
<input type="button" id="J_selectImage" value="批量上传" />
<div id="J_imageView"></div>
</body>
</html>
注意:这里涉及到静态资源映射的问题。
具体的解决办法可以参考该文档:http://blog.csdn.net/u012730299/article/details/51872704
我使用的是文档中介绍的第二种方法,在springmvc配置文件中添加如下语句:
<!--对静态资源文件的访问-->
<mvc:resources mapping="/js/**" location="/js/" />
启动项目访问路径正确的情况下就可以看到如下效果:
二.后端实现图片的保存于回显
2.1 在web项目的pom文件中导入依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
2.2 在springmvc配置文件中添加文件上传解析器
<!-- 上传文件解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置最大的文件大小 5M*1024*1024-->
<property name="maxUploadSize" value="5242880"/>
</bean>
2.3 编写上传逻辑
2.3.1确定图片的保存路径
E:\0725\taotao-upload
2.3.2在nginx配置图片的路径
server {
listen 80;
server_name image.taotao.com;
#charset koi8-r;
#access_log logs/host.access.log main;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
location / {
root E:\\0725\\taotao-upload;
}
}
2.3.3把图片的请求域名配置到host中
2.3.4确定该组件需要的返回类型,响应类型
查看官方文档了解返回格式为json,响应类型为文本(text)
(1)可以创建一个对象包含返回的属性,然后序列化为json(import com.fasterxml.jackson.databind.ObjectMapper;),ObjectMapper依赖于jackson,所以要在pom文件中添加对应的依赖。如下:
<!-- JacksonJson处理工具包 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.2</version>
</dependency>
package com.bdit.common;
public class PicUploadResult {
private Integer error;
private String url;
private String width;
private String height;
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 getWidth() {
return width;
}
public void setWidth(String width) {
this.width = width;
}
public String getHeigth() {
return height;
}
public void setHeigth(String heigth) {
this.height = heigth;
}
}
(2)在controller中设置响应类型为文本
produces=MediaType.TEXT_PLAIN_VALUE
2.3.5编写controller文件,直接贴源码
package com.bdit.controller;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import com.bdit.common.PicUploadResult;
import com.bdit.service.PropertyService;
import com.fasterxml.jackson.databind.ObjectMapper;
@RequestMapping("pic")
@Controller
public class PicUploadController {
private static final Logger LOGGER=LoggerFactory.getLogger(PicUploadController.class);
private static final ObjectMapper mapper = new ObjectMapper();
// 允许上传的格式
private static final String[] IMAGE_TYPE=new String[]{".image",".png",".bmp",".jepg",".gif"};
// 校验图片格式
/**
* produces:指定响应的类型
* @param uploadFile接收文件上传的对象
* @param response
* @return
* @throws Exception
*/
@RequestMapping(value="upload",method=RequestMethod.POST,produces=MediaType.TEXT_PLAIN_VALUE)
@ResponseBody
public String upload(@RequestParam("uploadFile") MultipartFile uploadFile , HttpServletResponse response) throws Exception {
// 校验图片格式
boolean isLegal = false;
/**
* 用for循环判断上传的文件,是不是以type作为结尾,并且忽略大小写。type类型来自于IMAGE_TYPE
* 然后做一个标记true表示合法
*/
for (String type : IMAGE_TYPE) {
if (StringUtils.endsWithIgnoreCase(uploadFile.getOriginalFilename(), type)) {
isLegal = true;
break;
}
}
// 封装Result对象
PicUploadResult fileUploadResult = new PicUploadResult();
// 状态
fileUploadResult.setError(isLegal ? 0 : 1);//如果为0表示上传成功,如果为1表示失败
// 获取文件新路径,也就是保存的路径
String filePath = getFilePath(uploadFile.getOriginalFilename());
// 判断是否启用了debug,如果启用就Pic file upload图片文件上传哪里到哪里,就会在日志中显示清楚
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Pic file upload .[{}] to [{}] .", uploadFile.getOriginalFilename(), filePath);
}
// 生成图片的绝对引用地
// E:\0725\taotao-upload\images\2017\11\21\2017112102113742308216.png 这是服务器上的地址,不可访问
// E:\\0725\\taotao-upload为图片上传的地址
// http://imager.taotao.com为访问图片的地址
// 最终的请求地址:http://imager.taotao.com/images/2017/08/08/20170808162211.jpg
String picUrl = StringUtils.replace(StringUtils.substringAfter(filePath, "E:\\0725\\taotao-upload"), "\\", "/");
fileUploadResult.setUrl("http://image.taotao.com" + picUrl);
// 找打一个新生成的文件,
File newFile = new File(filePath);
// 把上传的文件写入到目标文件中去;该语句执行完成后,就把上传的文件写入到目标地址中了
uploadFile.transferTo(newFile);
// 校验图片是否合法
isLegal = false;
try {
// 通过BufferedImage读取图片,该内容数据Java界面编程
BufferedImage image = ImageIO.read(newFile);
if (image != null) {
// 获取图片的宽和高
fileUploadResult.setWidth(image.getWidth() + "");
fileUploadResult.setHeigth(image.getHeight() + "");
// 标记为true表示合法
isLegal = true;
}
} catch (IOException e) {
}
// 再次设置上传的状态
fileUploadResult.setError(isLegal ? 0 : 1);
if (!isLegal) {
// 不合法,将磁盘上的文件删除
newFile.delete();
}
response.setContentType(MediaType.TEXT_HTML_VALUE);
// 将Java对象序列化成json数据
return mapper.writeValueAsString(fileUploadResult);
}
// 6.最终返回的路径如:E:\\0725\\taotao-upload\\images\\2017(yyyy)\\08(MM)\\08(dd)\\20170808162211(yyyyMMddhhmmssSSSS).jpg(IMAGE_TYPE)
// 上面的地址就是图片上传到服务器保存的绝对路径
private String getFilePath(String sourceFileName) {
// 1.定义一个目录,并在该目录下创建一个imagers文件夹
String baseFolder = "E:\\0725\\taotao-upload" + File.separator + "images";
// 2.创建时间对象
Date nowDate = new Date();
// yyyy/MM/dd
// DateTime使用的是时间操作组件,功能很强大,就是用来操作时间的。比JDK提供的时间类要更好用
// 3. 获取目录
String fileFolder = baseFolder + File.separator + new DateTime(nowDate).toString("yyyy") + File.separator + new DateTime(nowDate).toString("MM") + File.separator
+ new DateTime(nowDate).toString("dd");
// 4. 判断目录是否存在
File file = new File(fileFolder);
if (!file.isDirectory()) {
// 如果目录不存在,则创建目录
file.mkdirs();
}
//5.最后 生成新的文件名
String fileName = new DateTime(nowDate).toString("yyyyMMddhhmmssSSSS") + RandomUtils.nextInt(100, 9999) + "." + StringUtils.substringAfterLast(sourceFileName, ".");
return fileFolder + File.separator + fileName;
}
}
2.3.6 启动nginx,启动项目上传图片实现效果如下:
后续:上面的controller代码中关于图片的路径问题可以写成配置文件
1.创建一个外部配置文件upload.properties
REPOSITORY_PATH=E:\\0725\\taotao-upload
IMAGE_BASE_URL=http://image.taotao.com
2.让spring容器加载该配置文件即在spring配置文件中加载
3.编写service文件,获取配置文件内容
package com.bdit.service;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
public class PropertyService {
@Value("${REPOSITORY_PATH}")
public String REPOSITORY_PATH;
@Value("${IMAGE_BASE_URL}")
public String IMAGE_BASE_URL;
}
4.把service文件注入到controller中,controller即可获取内容并替换代码中的字符串
package com.bdit.controller;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import com.bdit.common.PicUploadResult;
import com.bdit.service.PropertyService;
import com.fasterxml.jackson.databind.ObjectMapper;
@RequestMapping("pic")
@Controller
public class PicUploadController {
private static final Logger LOGGER=LoggerFactory.getLogger(PicUploadController.class);
private static final ObjectMapper mapper = new ObjectMapper();
@Autowired
private PropertyService propertyService;
// 允许上传的格式
private static final String[] IMAGE_TYPE=new String[]{".image",".png",".bmp",".jepg",".gif"};
// 校验图片格式
/**
* produces:指定响应的类型
* @param uploadFile接收文件上传的对象
* @param response
* @return
* @throws Exception
*/
@RequestMapping(value="upload",method=RequestMethod.POST,produces=MediaType.TEXT_PLAIN_VALUE)
@ResponseBody
public String upload(@RequestParam("uploadFile") MultipartFile uploadFile , HttpServletResponse response) throws Exception {
// 校验图片格式
boolean isLegal = false;
/**
* 用for循环判断上传的文件,是不是以type作为结尾,并且忽略大小写。type类型来自于IMAGE_TYPE
* 然后做一个标记true表示合法
*/
for (String type : IMAGE_TYPE) {
if (StringUtils.endsWithIgnoreCase(uploadFile.getOriginalFilename(), type)) {
isLegal = true;
break;
}
}
// 封装Result对象
PicUploadResult fileUploadResult = new PicUploadResult();
// 状态
fileUploadResult.setError(isLegal ? 0 : 1);//如果为0表示上传成功,如果为1表示失败
// 获取文件新路径,也就是保存的路径
String filePath = getFilePath(uploadFile.getOriginalFilename());
// 判断是否启用了debug,如果启用就Pic file upload图片文件上传哪里到哪里,就会在日志中显示清楚
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Pic file upload .[{}] to [{}] .", uploadFile.getOriginalFilename(), filePath);
}
// 生成图片的绝对引用地
// E:\0725\taotao-upload\images\2017\11\21\2017112102113742308216.png 这是服务器上的地址,不可访问
// E:\\0725\\taotao-upload为图片上传的地址
// http://imager.taotao.com为访问图片的地址
// 最终的请求地址:http://imager.taotao.com/images/2017/08/08/20170808162211.jpg
String picUrl = StringUtils.replace(StringUtils.substringAfter(filePath, propertyService.REPOSITORY_PATH), "\\", "/");
fileUploadResult.setUrl(propertyService.IMAGE_BASE_URL + picUrl);
// 找打一个新生成的文件,
File newFile = new File(filePath);
// 把上传的文件写入到目标文件中去;该语句执行完成后,就把上传的文件写入到目标地址中了
uploadFile.transferTo(newFile);
// 校验图片是否合法
isLegal = false;
try {
// 通过BufferedImage读取图片,该内容数据Java界面编程
BufferedImage image = ImageIO.read(newFile);
if (image != null) {
// 获取图片的宽和高
fileUploadResult.setWidth(image.getWidth() + "");
fileUploadResult.setHeigth(image.getHeight() + "");
// 标记为true表示合法
isLegal = true;
}
} catch (IOException e) {
}
// 再次设置上传的状态
fileUploadResult.setError(isLegal ? 0 : 1);
if (!isLegal) {
// 不合法,将磁盘上的文件删除
newFile.delete();
}
response.setContentType(MediaType.TEXT_HTML_VALUE);
// 将Java对象序列化成json数据
return mapper.writeValueAsString(fileUploadResult);
}
// 6.最终返回的路径如:E:\\0725\\taotao-upload\\images\\2017(yyyy)\\08(MM)\\08(dd)\\20170808162211(yyyyMMddhhmmssSSSS).jpg(IMAGE_TYPE)
// 上面的地址就是图片上传到服务器保存的绝对路径
private String getFilePath(String sourceFileName) {
// 1.定义一个目录,并在该目录下创建一个imagers文件夹
String baseFolder = propertyService.REPOSITORY_PATH + File.separator + "images";
// 2.创建时间对象
Date nowDate = new Date();
// yyyy/MM/dd
// DateTime使用的是时间操作组件,功能很强大,就是用来操作时间的。比JDK提供的时间类要更好用
// 3. 获取目录
String fileFolder = baseFolder + File.separator + new DateTime(nowDate).toString("yyyy") + File.separator + new DateTime(nowDate).toString("MM") + File.separator
+ new DateTime(nowDate).toString("dd");
// 4. 判断目录是否存在
File file = new File(fileFolder);
if (!file.isDirectory()) {
// 如果目录不存在,则创建目录
file.mkdirs();
}
//5.最后 生成新的文件名
String fileName = new DateTime(nowDate).toString("yyyyMMddhhmmssSSSS") + RandomUtils.nextInt(100, 9999) + "." + StringUtils.substringAfterLast(sourceFileName, ".");
return fileFolder + File.separator + fileName;
}
}