文件上传的各框架都基于servlet实现,本文章介绍常用的文件上传方式
有些指定临时存储了路径,有些不指定临时存储目录会在tmp中缓存,完了后会删除
1、servlet
html代码
<form action="/file/upload" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"><br>
<input type="submit" valie="上传"/>
</form>
WEB-INF/web.xml
<servlet>
<servlet-name>FileUploadServlet</servlet-name>
<servlet-class>com.example.FileUploadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FileUploadServlet</servlet-name>
<url-pattern>/upload</url-pattern>
</servlet-mapping>
servlet
@WebServlet("/upload")
@MultipartConfig
public class FileUploadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 检查是否是multipart内容类型
if (!ServletFileUpload.isMultipartContent(request)) {
throw new IllegalArgumentException("表单必须包含enctype=multipart/form-data");
}
// 创建ServletFileUpload实例
ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
try {
// 解析请求,获取文件项
List<FileItem> items = upload.parseRequest(request);
for (FileItem item : items) {
if (!item.isFormField()) {
// 处理上传的文件
String fileName = item.getName();
InputStream inputStream = item.getInputStream();
// 这里可以编写代码将文件保存到服务器
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
}
}
2、过滤器
过滤器的目的是拦截上传的文件,上传到指定的临时目录,然后servlet或controller通过request.getAttribute("filePath")拿到上传的文件
这样的好处统一处理上传,验证,存储,便于对原始上传文件留档分析
@Slf4j
public class UploadFilter extends OncePerRequestFilter implements Filter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
if (ServletFileUpload.isMultipartContent(request)) {
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List<FileItem> fileItemList = null;
try {
fileItemList = upload.parseRequest(request);
}catch (FileUploadException e) {
log.error("upload file get fileItemList failed {}", e.getMessage());
}catch (Exception e){
if (e.getMessage().contains("EOF")){
log.warn("上传文件失败,客户端主动或因超时被动断开");
}
}
if (fileItemList != null) {
log.debug("web 文件上传开始时间:{}", DateUtils.formatDate(new Date(), DateUtils.DATE_FORMATE_PATTERN));
int i = 0;
for (FileItem fi : fileItemList) {
if (fi.isFormField()) {
request.setAttribute(fi.getFieldName(), fi.getString());
} else {
if (StringUtils.isEmpty(fi.getName()) || (fi.getName().lastIndexOf(".") <= 0 || fi.getName().lastIndexOf(".") == (fi.getName().length() - 1))) {
request.setAttribute("uploadStatus", "0");
request.setAttribute("uploadMessage", "文件名称为空或格式不正确!");
break;
}
String sourceFileName = fi.getName();
String basePath = FileUtils.getTempFilePath(sourceFileName);
File file = FileUtils.getTempFile(basePath, sourceFileName);
try {
fi.write(file);
request.setAttribute("filePath", basePath + file.getName());
request.setAttribute("uploadStatus", "1");
}catch (IOException | ClassNotFoundException ee){
log.warn("上传文件失败,客户端主动或因超时被动断开");
} catch (Exception e) {
e.printStackTrace();
request.setAttribute("uploadStatus", "0");
request.setAttribute("uploadMessage", "上传文件失败!");
log.error("上传文件失败 fileName={}", sourceFileName,e);
break;
}
request.setAttribute("fileName" + String.valueOf(++i), sourceFileName);
}
}
log.debug("web 文件上传结束时间:{}", DateUtils.formatDate(new Date(), DateUtils.DATE_FORMATE_PATTERN));
}
}
filterChain.doFilter(request, response);
}
}
3、commons-fileupload包
pom引包
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
html代码
<form action="/file/upload" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"><br>
<input type="submit" valie="上传"/>
</form>
配置解析器:上传文件的大小最大是10兆
<!--配置文件解析器-->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxInMemorySize" value="10485760"/>
</bean>
constroller代码
@Controller
@RequestMapping("/file")
public class FileController {
//文件上传
@RequestMapping("/upload")
public String upload(HttpServletRequest request) throws Exception {
//解析 request 对象,获取上传文件项
DiskFileItemFactory factory=new DiskFileItemFactory();
ServletFileUpload upload=new ServletFileUpload(factory);
List<FileItem> items=upload.parseRequest(request);
//遍历
for(FileItem item:items)
{
//判断当前 item 是否是上传文件项,
// 如果是,需要把文件存在路径下,否则需要额外处理
if(item.isFormField())
{
//说明是普通表单项
}
else
{
//需要获取到上传文件的名称
String fileName=item.getName();
//把文件的名称设置为唯一值
String uid=UUID.randomUUID().toString().replace("-","");
fileName=uid+"_"+fileName;
//需要获取到上传文件的名称
String fileName=item.getFieldName();
//完成文件上传
item.write(new File(path,fileName));
//删除临时文件
item.delete();
}
}
return "success";
}
}
4、json
function uploadFile(){
// 获取选择的文件
var file = this.files[0];
// 创建FormData对象来发送文件
// var formData = new FormData();
//formData.append("file",file);
const param ={
funcNo:"91000000"
type:"1",
excel_file: file,
};
doRequest(param,function(data){
console.log("上传文件接口");
console.log(data);
});
}
java代码
获取的文件被转成base64的字符串
public Result execute() throws Exception {
Result result = new Result();
result.setErr_no(0);
Map map = this.getParamMap();
/***接收页面入参***/
String type = MapHelper.getString(map, "type");
String excelFile = MapHelper.getString(map, "excel_file");
try {
List<String> list = readExcelData(excelFile);
result.setResult(list);
}catch ( FrameException fe){
throw fe;
}catch (Exception ex){
result.setErr_no(-99);
result.setErr_info("系统错误");
logger.error("文件上传异常 type={}",type, ex);
}
return result;
}
/**
* @param base64Str 文件路径
* @description: 读取excel数据
* @return: List<String> 手机号列表
* @author: luohh
* @date: 2024/7/25 13:36
*/
protected List<String> readExcelData(String base64Str) throws Exception {
List<String> list = new ArrayList<>();
Workbook workbook = null;
InputStream inputStream = null;
try {
inputStream = new ByteArrayInputStream(Base64Utils.decode(base64Str));
//判断输入的流是否是2007以上版本,如果是则对应文件后缀应该是xlsx
try{
if (POIFSFileSystem.hasPOIFSHeader(inputStream)) {
workbook = new HSSFWorkbook(inputStream);
}else{
// WorkbookFactory可以通过文件流直接生成合适的Workbook(HSSFWorkbook/XSSFWorkbook)
workbook = WorkbookFactory.create(inputStream);
}
}catch (Exception e){
//这里try是为了解决xls和xls在读取的时候可能会的错,兜底使用WorkbookFactory
workbook = WorkbookFactory.create(inputStream);
}
Sheet sheet = workbook.getSheetAt(0);
for (Row row : sheet) {
if (row.getRowNum() == 0) {
//第一行为标题
continue;
}
for (Cell cell : row) {
if (cell.getColumnIndex() == 0) {
//第一列为序号
continue;
}
if (cell.getCellTypeEnum() == CellType.NUMERIC) {
list.add(cell.getNumericCellValue() + "");
continue;
}
list.add(cell.getStringCellValue());
}
}
}catch(InvalidFormatException xe){
logger.error("文件格式错误",xe);
throw new FrameException("文件格式错误!", 2);
} catch(OLE2NotOfficeXmlFileException xe){
logger.error("文件格式错误",xe);
throw new FrameException("文件格式错误!", 2);
} finally {
if (null != inputStream) {
try {
inputStream.close();
} catch (Exception ex) {
logger.error("关闭workbook异常 " , ex);
}
}
if (null != workbook) {
try {
workbook.close();
} catch (Exception ex) {
logger.error("关闭workbook异常 " , ex);
}
}
}
return list;
}