首先我们需要明确上传图片的注意点是什么?
1、表单组件标签只能用<input type="file">
2、上传图片必须采用post请求
get:参数通过请求头提交到后台,参数放到url后面来提交的只能向后台提交文本数据或者字符串数据,二进制如以字节为单位存储的只能用post,url长度有限制,长度超过限制无法提交;效率高,不需要对数据进行封装,还存在get缓存的问题(可以通过加时间戳来解决这个问题),减轻了后台处理请求的压力。
post:参数通过请求体提交到后台;能提交文本数据,又能提交二进制数据。理论上对参数长度没有限制,相对安全。效率相对较低,不管处理什么数据,什么路径都会从服务器重新来一遍。
3、表单的编码格式只能用:multipart/form-data
根据HTTP协议的规定,浏览器每次向后台提交参数,都会对参数进行统一编码:默认采用的编码格式是urlencoded,这种编码格式只能对文本数据进行编码,浏览器每次向后台提交参数,都会首先把所有的参数转换成字符串,然后对这些数据统一进行urlencoded编码,不管前台发的是啥,浏览器统一会变成字符串,我们拿到的永远也是字符串。
文件上传的表单编码格式只能是:multipart/form-data 多样性的表单数据,阻止默认行为,提交的是什么数据,拿到的是什么数据。没有进行任何的编码。
怎么设置表单的编码格式呢?
前台数据,设置ajax的行为
processDate: false //设置ajax向后台提交参数之前,是否把参数统一转换为字符串:true
contentType:false,//设置ajax向后台提交参数之前,是否把参数的编码统一按urlencoded编码。
统一form表单发送的请求,请求是同步的。浏览器发送的是同步请求。
同步请求只能处理字符串数据。无法解析json对象,无法解析Object
接收文件数据,springmvc专门给我们提供了一个类用来接收客户端上传的文件,MultipartFile类,当文件传过来后,会自动的将请求体的文件封装到这个类的对象中。
springmvc怎么去拿文件到请求体中?
springmvc调用了一个内部的类去请求体拿文件,封装这个对象。
那一个类一开始没有放在spring(mvc)容器中,要调用这个方法必须创建这个对象,把类的对象创建好,如果没有创建好这个类,他也没法调用方法从请求体中拿到数据封装对象,他会自动去找文件。
这个类是文件上传解析器,将拿到的文件赋值给MultipartFile
使用第三方工具一般有三步骤
第一步:引入插件的配置文件
第二步:创建容器,放入插件
第三步:加载容器,调用工具函数
七牛云官方文档
七牛云是一个云存储服务提供商,可以用于储存和管理大量数据。FilePult.js是一种JavaScript库,可用于将文件上传到云存储服务。七牛云提供了与FilePut.js兼容的API,以便在使用FilePut.js上传文件时,可以将文件上传到七牛云。当使用FilePut.js上传文件时,可以使用七牛云提供的API密钥和密钥等信息进行身份验证,并通过API将文件上传到七牛云。因此,七牛云和FilePut.js之间是一种可以协同工作的关系。
导入maven
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>[7.7.0, 7.10.99]</version>
</dependency>
对象存储空间-地区
前端:
引入配置文件
<link rel="stylesheet" href="${ctx}/css/fileinput.min.css"></link>
<script type="text/javascript" src="${ctx}/js/fileinput.js"></script>
<!-- 对中文的支持 -->
<script type="text/javascript" src="${ctx}/js/fileinput_locale_zh.js"></script>
添加容器
<tr>
<td>上传商品图片:</td>
<td>
<input type="hidden" name="originalImg" id="originalImg"/>
<form enctype="multipart/form-data">
<input id="file-product" class="file" name="file" type="file" multiple
data-min-file-count="1">
</form>
</td>
</tr>
调用工具函数
//================商品-图片上传==================
/**
* 初始设置
* language指定语言
* uploadUrl指定文件上传的后台地址
* allowedPreviewTypes允许上传文件的类型
*/
$('#file-product').fileinput({
language: 'zh',
uploadUrl: '${ctx}/fileUpload/save',
allowedPreviewTypes: ['image', 'html', 'text', 'video', 'audio', 'flash']
});
/**
* 上传文件失败后 调用方法(回调函数)
*/
$('#file-product').on('fileuploaderror', function (event, data, previewId, index) {
var form = data.form,
files = data.files,
extra = data.extra,
response = data.response,
reader = data.reader;
console.log(data);
console.log('File upload error');
});
/**
* 文件错误 比如文件类型错误 调用方法(回调函数)
*/
$('#file-product').on('fileerror', function (event, data) {
console.log(data.id);
console.log(data.index);
console.log(data.file);
console.log(data.reader);
console.log(data.files);
});
/**
* 文件上传成功后 调用方法(回调函数)
*/
$('#file-product').on('fileuploaded', function (event, data, previewId, index) {
var form = data.form,
files = data.files,
extra = data.extra,
response = data.response,
reader = data.reader;
// 服务器文件地址
// alert(data.response.fileUrl);
// 将服务器文件地址设置至隐藏域
$("#originalImg").val(data.response.fileUrl);
console.log('File uploaded triggered');
});
//================商品-图片上传==================
后端:
pojo
*/
public class FileResult implements Serializable {
// success字符串bootstrap file input必须包含该属性
private String success;
// error字符串bootstrap file input必须包含该属性
private String error;
// 描述信息
private String message;
// 文件路径
private String fileUrl;
public String getSuccess() {
return success;
}
public void setSuccess(String success) {
this.success = success;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getFileUrl() {
return fileUrl;
}
public void setFileUrl(String fileUrl) {
this.fileUrl = fileUrl;
}
}
Controller
@Controller
@RequestMapping("/fileUpload")
public class UploadController {
@Autowired
private UploadService uploadService;
/**
* 将上传的文件赋值给MultipartFile,然后重命名文件,使得每一个文件的名称都不重复,然后调用service方法上传这个文件到后台。
* 返回这个文件的信息,在前端得到响应信息判断文件上传是否成功,渲染页面。
* @param file
* @return
* @throws IOException
*/
@RequestMapping("/save")
@ResponseBody
public FileResult upload(MultipartFile file) throws IOException {
String filename = file.getOriginalFilename();
String date = DateTimeFormatter.ofPattern("yyyy/MM/dd/").format(LocalDateTime.now());
filename = date+System.currentTimeMillis()+filename.substring(filename.lastIndexOf("."));
return uploadService.upload(file.getInputStream(),filename);
}
}
ServiceImpl
@Service("UploadService")
public class UploadServiceImpl implements UploadService {
@Override
public FileResult upload(InputStream inputStream, String fileName) {
FileResult fileResult = new FileResult();
//构造一个带指定 Region 对象的配置类
Configuration cfg = new Configuration(Region.region2());
//...其他参数参考类注释
UploadManager uploadManager = new UploadManager(cfg);
//...生成上传凭证,然后准备上传,密钥
String accessKey = "3scC_cEM9rkaDmh-Nj7djoprxZMUCwqp47GpspS2";
String secretKey = "GkC1lqSJXoZVwJxtiN-j81CES9uAsqkKMFhwZC5k";
String bucket = "shop-wll";
//默认不指定key的情况下,以文件内容的hash值作为文件名
String key = fileName;
System.out.println("文件上传....");
try {
Auth auth = Auth.create(accessKey, secretKey);
String upToken = auth.uploadToken(bucket);
try {
Response response = uploadManager.put(inputStream,key,upToken,null, null);
//解析上传成功的结果
if (response.statusCode==200){
fileResult.setSuccess("success");
fileResult.setMessage("上传成功");
fileResult.setFileUrl("http://ru4mmztz7.hn-bkt.clouddn.com/"+fileName);
return fileResult;
}else {
fileResult.setError("error");
fileResult.setMessage("上传失败");
return fileResult;
}
} catch (QiniuException ex) {
Response r = ex.response;
System.err.println(r.toString());
fileResult.setError("error");
fileResult.setMessage("上传失败");
try {
System.err.println(r.bodyString());
} catch (QiniuException ex2) {
//ignore
}
}
} catch (Exception ex) {
//ignore
}
return fileResult;
}
}