日常,工作

在这里总结一下上传吧(是以前做过的练习,就汇总到个人博客吧)

java ssm 框架实现文件上传

实现:单文件上传、多文件上传(单选和多选),并且用 ajax 异步刷新,在当前界面显示上传的文件

后端

首先 springmvc 的配置文件要配置上传文件解析器:

class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
p:defaultEncoding="utf-8">
209715200
4096

其次在 pom.xml 中要配置上传文件的依赖

commons-io
commons-io
2.4
commons-fileupload
commons-fileupload
1.3.1
org.apache.commons
commons-lang3
3.3.2

单文件上传

/**
* 单文件上传
* @param file
* @param request
* @return
* @throws IllegalStateException
* @throws IOException
* @throws JSONException
*/
public static String simUpload(MultipartFile file, HttpServletRequest request)
throws IllegalStateException, IOException, JSONException{
if(!file.isEmpty()){
String path = request.getSession().getServletContext().getRealPath("/upload");
//定义文件
File parent = new File(path);
if(!parent.exists()) parent.mkdirs();
HashMap map = new HashMap();
String oldName = file.getOriginalFilename();
long size = file.getSize();
//使用TmFileUtil文件上传工具获取文件的各种信息
//优化文件大小
String sizeString = TmFileUtil.countFileSize(size);
//获取文件后缀名
String ext = TmFileUtil.getExtNoPoint(oldName);
//随机重命名,10位时间字符串
String newFileName = TmFileUtil.generateFileName(oldName, 10, "yyyyMMddHHmmss");
String url = "upload/"+newFileName;
//文件传输,parent文件
file.transferTo(new File(parent, newFileName));
map.put("oldname",oldName);//文件原名称
map.put("ext",ext);
map.put("size",sizeString);
map.put("name",newFileName);//文件新名称
map.put("url",url);
//以json方式输出到页面
return JSONUtil.serialize(map);
}else{
return null;
}
}

多文件上传(整合了单选文件和多选文件的两种)

/**
* 多文件上传
* @param files
* @param request
* @return
* @throws IllegalStateException
* @throws IOException
* @throws JSONException
*/
public static List> mutlUpload(MultipartFile[] files, HttpServletRequest request)
throws IllegalStateException, IOException, JSONException{
if(files.length > 0){
String path = request.getSession().getServletContext().getRealPath("/upload");
//定义文件
File parent = new File(path);
if(!parent.exists()) parent.mkdirs();
//创建这个集合保存所有文件的信息
List> listMap = new ArrayList>();
//循环多次上传多个文件
for (MultipartFile file : files) {
//创建map对象保存每一个文件的信息
HashMap map = new HashMap();
String oldName = file.getOriginalFilename();
long size = file.getSize();
//使用TmFileUtil文件上传工具获取文件的各种信息
//优化文件大小
String sizeString = TmFileUtil.countFileSize(size);
//获取文件后缀名
String ext = TmFileUtil.getExtNoPoint(oldName);
//随机重命名,10位时间字符串
String newFileName = TmFileUtil.generateFileName(oldName, 10, "yyyyMMddHHmmss");
String url = "upload/"+newFileName;
//文件传输,parent文件
file.transferTo(new File(parent, newFileName));
map.put("oldname",oldName);//文件原名称
map.put("ext",ext);
map.put("size",sizeString);
map.put("name",newFileName);//文件新名称
map.put("url",url);
listMap.add(map);
}
//以json方式输出到页面
return listMap;
}else{
return null;
}
}

前端

前端代码:

文件多选,实际上在

name="fileupmulti"
accept="image/jpeg,image/png"
οnchange="mutiFiles(this)"
multiple/>

多加了一个 multiple 属性

onchange 事件代码

// 单文件上传
function uploadFile(obj){
// 创建一个 FormData 对象,用一些键值对来模拟一系列表单控件
// 即把 form 中所有表单元素的 name 与 value 组装成一个 queryString
let form = new FormData();
let fileObj = obj.files[0];
form.append('doc',fileObj);
// ajax 代码...
}
// 多文件上传(多选)
function mutiFiles(obj){
let form = new FormData();
let fileObj = obj.files;
let length = fileObj.length;
// 将 fileObj 转换成数组
// let filese = Array.from(fileObj);
for(let i = 0; i < length; i++){
form.append('doc', fileObj[i]);
}
// ajax 代码...
}
// 多文件上传(单选:一个一个选择文件,最后点击提交按钮触发的方法)
function multipartone(){
let file1 = $('.fileupon11').get(0).files[0];
let file2 = $('.fileupon12').get(0).files[0];
let file3 = $('.fileupon13').get(0).files[0];
//如果都是空,则直接退出
isEmpty(file1) && isEmpty(file2) && isEmpty(file3) return;
let form = new FormData();
//用同一个名字,注入到controller层的参数数组
form.append('doc', file1);
form.append('doc', file2);
form.append('doc', file3);
// ajax 代码...
}

要想在当前界面显示上传的文件,而不跳转,就利用 ajax 异步请求

不过需要注意的是,我这里使用 FormData() 储存文件对象, ajax 要配上这几个参数才可实现文件上传:

$.ajax({
type: "post",
data: form, // FormData()对象
url: basePath+"/upload/mutl",
contentType: false, // 必须false才会自动加上正确的Content-Type
processData: false, // 必须false才会避开 jQuery 对 formdata 的默认处理, XMLHttpRequest会对 formdata 进行正确的处理
success: function(data){
// TODO
}
})

controller 层调用

package com.krry.controller;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.json.JSONException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import com.krry.util.UploadUtil;
/**
* 文件上传类
* KrryUploadController
* @author krry
* @version 1.0.0
*
*/
@Controller
@RequestMapping("/upload")
public class KrryUploadController {
/**
* 单文件上传
* @param file
* @param request
* @return
* @throws IllegalStateException
* @throws IOException
* @throws JSONException
*/
@ResponseBody
@RequestMapping(value = "/file")
public String krryupload(@RequestParam("doc") MultipartFile file, HttpServletRequest request) throws IllegalStateException, IOException, JSONException{
//调用工具类完成上传,返回相关数据到页面
return UploadUtil.simUpload(file, request);
}
/**
* 多文件上传
* @param file
* @param request
* @return
* @throws IllegalStateException
* @throws IOException
* @throws JSONException
*/
// 这里的MultipartFile[] file表示前端页面上传过来的多个文件,file对应页面中多个file类型的input标签的name,但框架只会将一个文件封装进一个MultipartFile对象,
// 并不会将多个文件封装进一个MultipartFile[]数组,直接使用会报[Lorg.springframework.web.multipart.MultipartFile;.()错误,
// 所以需要用@RequestParam校正参数(参数名与MultipartFile对象名一致),当然也可以这么写:@RequestParam("file") MultipartFile[] files。
@ResponseBody
@RequestMapping(value = "/mutl")
public List> krryuploadMutl(@RequestParam("doc") MultipartFile[] file, HttpServletRequest request) throws IllegalStateException, IOException, JSONException{
//调用工具类完成上传,返回相关数据到页面
return UploadUtil.mutlUpload(file, request);
}
}

进度条

要显示上传进度条,我这里采用原生 ajax 方法

function uploadFile(obj) {
// ...
// 一些获取上传对象的相关代码
// 创建一个 ajax 对象
var xhr = new XMLHttpRequest();
// 规定请求的类型、URL 以及是否异步处理请求。true为异步
// 请求是异步的。因为要实时获取到上传的进度,则请求需是异步的,如果是同步的话,会直到请求完成才能获取到响应
xhr.open("post", basePath+"/upload/file", true);
// 上传成功进入的回调函数
xhr.onreadystatechange = function(){
if(xhr.readyState==4 && xhr.status==200){ // 状态 4 和 200 代表和服务器端交互成功
// 获取上传成功的返回数据
var data = xhr.responseText.trim();
jdata = eval("("+data+")");
krry_uploadsuccess(jdata);
}
};
// 监听文件上传的进度
xhr.upload.addEventListener("progress", progressFunction, false);
// 发送http请求:将请求发送到服务器,与后台交互
xhr.send(form);
}
// 上传进度的回调函数
function progressFunction(event) {
let prograssbarDom = document.getElementById("prograssbar");
let fileRea = document.getElementById("fileRea");
if (prograssbarDom && event.lengthComputable) {
let percent = event.loaded / event.total; //文件上传进度百分比
let p = Math.floor(percent*100);
prograssbarDom.style.width = p+"%";
fileRea.innerHTML = p+"%";
}
}

附上优化文件大小的代码:

/**
* 将文件的字节数转换成文件的大小
* com.krry.uitl
* 方法名:format
* @author krry
* @param size
* @return String
* @exception
* @since 1.0.0
*/
public static String format(long size){
float fsize = size;
String fileSizeString;
if (fsize < 1024) {
fileSizeString = String.format("%.2f", fsize) + "B"; //2f表示保留两位小数
} else if (fsize < 1048576) {
fileSizeString = String.format("%.2f", fsize/1024) + "KB";
} else if (fsize < 1073741824) {
fileSizeString = String.format("%.2f", fsize/1024/1024) + "MB";
} else if (fsize < 1024 * 1024 * 1024) {
fileSizeString = String.format("%.2f", fsize/1024/1024/1024) + "GB";
} else {
fileSizeString = "0B";
}
return fileSizeString;
}