一、图片上传介绍
JavaWeb方向编程过程中,实现图片上传有三种方式:
1、传统的基于SpringMVC的MultipartFile类实现图片上传。
2、基于Ajax的图片上传。
3、基于Base64压缩的图片上传。
二、springMVC图片上传(springboot通用)
此方法的优点是可以将图片和其他的表单元素一起提交到服务器,服务器接受的图片其实已经存储于容器的临时文件中,进行文件拷贝工作比较简单。
缺点是无法及时看到图片上传的预览效果,图片一旦选择错误只能重新提交。
1、页面代码
<form action="/upload" method="post" enctype="multipart/form-data">
选择头像:<input type="file" name="file" accept="image/*" /> <br>
用户名字:<input type="text" name="userName"/> <br>
<input type="submit" value="提交">
</form>
2、config.properties配置文件
创建名为config.properties的配置文件,并且在其中配置图片上传物理路径。注意window和linux的写法不同。
此配置内容在springboot结构中的application.properties文件中配置
file.location.path=d:/upload
3、spring-servlet.xml配置文件
此配置文件在springboot中不需要配置 - “习惯大于配置”
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 设置使用注解的类所在的jar包 -->
<context:component-scan base-package="org.lanqiao.service"/>
<context:component-scan base-package="org.lanqiao.controller"/>
<!--读取属性文件-->
<context:property-placeholder location="classpath:config.properties" ignore-unresolvable="true"/>
<!-- 注册HandlerMapping和HandlerAdapter组件 -->
<mvc:annotation-driven/>
<!-- 对静态资源文件的访问 支持访问WEB-INF目录 -->
<mvc:default-servlet-handler/>
<!-- 对转向页面的路径解析。prefix:前缀,suffix:后缀 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/" p:suffix=".jsp"/>
<!--文件上传-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="104857600"/>
<property name="maxInMemorySize" value="4096"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
</beans>
4、controller代码
若是一次上传多个文件,需要使用注解@RequestParam(“inputName”)指明该文件对应表单的input标签的name属性。如果name都是同名的,可以使用MultipartFile [] 文件数组来接收
@Controller
public class UserController {
@Autowired
UserService userService;
@Value("${file.location.path}")
private String fileLocation;
@RequestMapping("/insert")
public String insert(User user, MultipartFile file){
String uri = FileUpload.upload(file,"/upload",fileLocation);
user.setFacePic(uri);
int ret = userService.insertUser(user);
if(ret > 0 ){
return "redirect:/get";
}else{
return "register";
}
}
}
5、上传工具类代码
public class FlieUpload{
/**
* @param file 上传的文件
* @param path 文件的虚拟路径,例如 /upload
* @param fileLocation 文件的物理路径,例如d:/upload
* @return 文件的虚拟路径+文件名
*
* fileName.lastIndexOf(".")为获取后缀名
* UUID.randomUUID()为获取唯一标识,保证文件的唯一性
*/
public static String upload(MultipartFile file,String path,String fileLocation){
String fileFinishName = null;
try{
//如果目录不存在则创建
File uploadDir = new File(fileLocation);
if(!uploadDir.exists()){
uploadDir.mkdir();
}
//获取源文件名称
String fileName = file.getOrignalFileName();
fileFinishName = UUID.randomUUID() +
fileName.substring(fileName.lastIndoxOf("."),fileName.length());
//上传文件到指定目录下
File uploadFile = new File(uploadDir + uploadDir.separator + fileFinishName);
file.transferTo(uploadFile);
} catch(Exception ex){
ex.printStackTrace();
}
return path + "/" + fileFinishName;
}
}
三、基于Ajax的图片上传
这种方式同第一种方式一样都是使用multipart/form-data方式上传,服务器端同样使用springMVC(springboot)实现所以只有页面代码不一致,其他代码(2、3、4、5)同上。
1、页面先一用jQuery的插件
顺序不能错误
<script src="js/jquery-3.2.1.min.js"></script>
<!-- jquery file upload相关js -->
<script src="js/jquery.ui.widget.js"></script>
<script src="js/jquery.iframe-transport.js"></script>
<script src="js/jquery.fileupload.js"></script>
<script src="js/jquery.fileupload-process.js"></script>
<script src="js/jquery.fileupload-validate.js"></script>
2、HTML代码编写
不需要form标签
<style>
/* input样式 */
#uploadImg{
display: none;
}
/* button样式 */
#chooseFile{
background: #93b6fc;
}
#uploadFile,#rechooseFile {
display: none;
background: #93b6fc;
}
#image{
width:200px;
height:200px;
}
/* 进度条样式 */
.bar {
background-image: -webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);
background-image: -o-linear-gradient(top,#5cb85c 0,#449d44 100%);
background-image: -webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));
background-image: linear-gradient(to bottom,#5cb85c 0,#449d44 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
background-repeat: repeat-x;
height: 20px;
line-height: 20px;
-webkit-box-shadow: inset 0 -1px 0 rgba(0,0,0,.15);
box-shadow: inset 0 -1px 0 rgba(0,0,0,.15);
-webkit-transition: width .6s ease;
-o-transition: width .6s ease;
transition: width .6s ease;
}
#progress {
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
background-repeat: repeat-x;
height: 20px;
width: 0%;
margin-bottom: 20px;
overflow: hidden;
background-color: #f5f5f5;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
margin-top: 20px;
}
</style>
<body>
<div class="jquery-fileupload">
<div class="">
<input id="uploadImg" type="file" name="uploadImg" multiple style="display: none" />
<button id="chooseFile">+选择文件</button>
<button id="uploadFile">~开始上传</button>
<button id="rechooseFile">+重新选择</button>
</div>
<div>
<img id="image" src="">
</div>
<div id="progress">
<div class="bar" style="width: 0%;"></div>
</div>
</div>
</body
3、js代码
$(function() {
$("#chooseFile").on("click", function() {
$("#uploadImg").click();
});
$('#uploadImg').fileupload({
url : '/upload',//请求发送的目标地址
Type : 'POST',//请求方式 ,可以选择POST,PUT或者PATCH,默认POST
//dataType : 'json',//服务器返回的数据类型
autoUpload : false,
acceptFileTypes : /(gif|jpe?g|png)$/i,//验证图片格式
maxNumberOfFiles : 1,//最大上传文件数目
maxFileSize : 1000000, // 文件上限1MB
minFileSize : 100,//文件下限 100b
messages : {//文件错误信息
acceptFileTypes : '文件类型不匹配',
maxFileSize : '文件过大',
minFileSize : '文件过小'
}
})
//图片添加完成后触发的事件
.on("fileuploadadd", function(e, data) {
//validate(data.files[0])这里也可以手动来验证文件格式和大小
//隐藏或显示页面元素
$('#progress .bar').css(
'width', '0%'
);
$('#progress').hide();
$("#chooseFile").hide();
$("#uploadFile").show();
$("#rechooseFile").show();
//获取图片路径并显示
var url = getUrl(data.files[0]);
$("#image").attr("src", url);
//绑定开始上传事件
$('#uploadFile').click(function() {
$("#uploadFile").hide();
jqXHR = data.submit();
//解绑,防止重复执行
$("#uploadFile").off("click");
})
//绑定点击重选事件
$("#rechooseFile").click(function(){
$("#uploadImg").click();
//解绑,防止重复执行
$("#rechooseFile").off("click");
})
})
//当一个单独的文件处理队列结束触发(验证文件格式和大小)
.on("fileuploadprocessalways", function(e, data) {
//获取文件
file = data.files[0];
//获取错误信息
if (file.error) {
console.log(file.error);
$("#uploadFile").hide();
}
})
//显示上传进度条
.on("fileuploadprogressall", function(e, data) {
$('#progress').show();
var progress = parseInt(data.loaded / data.total * 100, 10);
$('#progress').css(
'width','15%'
);
$('#progress .bar').css(
'width',progress + '%'
);
})
//上传请求失败时触发的回调函数
.on("fileuploadfail", function(e, data) {
console.log(data.errorThrown);
})
//上传请求成功时触发的回调函数
.on("fileuploaddone", function(e, data) {
alert(data.result);
})
//上传请求结束后,不管成功,错误或者中止都会被触发
.on("fileuploadalways", function(e, data) {
})
//手动验证
function validate(file) {
//获取文件名称
var fileName = file.name;
//验证图片格式
if (!/.(gif|jpg|jpeg|png|gif|jpg|png)$/.test(fileName)) {
console.log("文件格式不正确");
return true;
}
//验证excell表格式
/* if(!/.(xls|xlsx)$/.test(fileName)){
alert("文件格式不正确");
return true;
} */
//获取文件大小
var fileSize = file.size;
if (fileSize > 1024 * 1024) {
alert("文件不得大于一兆")
return true;
}
return false;
}
//获取图片地址
function getUrl(file) {
var url = null;
if (window.createObjectURL != undefined) {
url = window.createObjectURL(file);
} else if (window.URL != undefined) {
url = window.URL.createObjectURL(file);
} else if (window.webkitURL != undefined) {
url = window.webkitURL.createObjectURL(file);
}
return url;
}
});
四、基于Base64压缩的图片上传
图片的Base64 编码就是可以将一副图片数据编码成一串字符串,使用该字符串代替图像地址。例如:
基于Base64实现图片上传其实就是在浏览器端先将图片转换成字符串,然后将代表图片的字符串传输到服务器进行存储。需要显示的时候可以将字符串写入直接显示。
该图片上传的方式比较简单,且没有其他的例如跨域提交、头文件等问题。但是其编码后的字符串大小远远大于实际的图片大小。所以只适合上传小尺寸的图片,例如用户头像等。
1、页面代码
$("#img").change(function (e) {
var img = e.target.files[0];
var reader = new FileReader();
reader.readAsDataURL(img);
reader.onload = function (e) {
// ajax 上传图片
$.post("uploadPic", {img: e.target.result}, function (ret) {
if (ret.img != '') {
//显示图片
$('#showimg').attr("src", ret.imgUrl);
}
}, 'json');
}
});
2、服务器接收到Base64字符串,就可以得到图片并且将图片直接存入数据库。这里不再描述。
五、配置图片访问路径
1、Springboot中可以使用下面的代码将虚拟路径/image/**下的图片映射成到D://盘下。
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
/**
* 图片绝对地址与虚拟地址映射
* 访问地址示例:http://localhost:8080/image/1.png
*/
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//windows
//registry.addResourceHandler("/image/**").addResourceLocations("file:d://upload/");
//linux和mac
registry.addResourceHandler("/image/**").addResourceLocations("file:/Users/David/upload/");
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
}
}
2、如果使用springMVC的SSM框架,则可以在tomcat的service.xml文件中直接配置虚拟路径,代码如下:
<Context docBase="/Users/David/upload" path="/image" reloadable="true"/>