偶尔会使用到文件上传功能,索性在这里记录步骤,需要用的时候方便回来copy。
以下的使用环境:JDK8 ,框架:SSM
文件上传 需要导入两个jar包 Commons FileUpload.Jar 和 Commons IO.Jar 。如果使用Maven那么导入以下依赖就行啦
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
1.首先我们在mysql数据库中创建一张存储文件的信息的表格: tz_attachements
CREATE TABLE `tz_attachements` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '附件主键',
`title` varchar(200) DEFAULT NULL COMMENT '标题',
`fileName` varchar(200) DEFAULT NULL COMMENT '文件名称 ',
`contentType` varchar(50) DEFAULT NULL COMMENT '文件类型',
`filePath` varchar(200) DEFAULT NULL COMMENT '文件路径',
`fileDisgest` varchar(200) DEFAULT NULL COMMENT '文件摘要(MD5生成的信息)',
`createdUser` varchar(255) DEFAULT NULL COMMENT '创建人用户名',
`modifiedUser` varchar(255) DEFAULT NULL COMMENT '修改人用户名',
`createdTime` datetime DEFAULT NULL COMMENT '创建时间',
`modifiedTime` datetime DEFAULT NULL COMMENT '最后修改时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
2.创建 tz_attachements 附件表 的实体类 Attachement.class
3.在Spring-mvc的配置文件中配置 文件上传解析器
<!-- 配置文件上传的视图解析器 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 默认编码 -->
<property name="defaultEncoding" value="utf-8" />
<!-- 文件上传的最大字节是 10MB -->
<property name="maxUploadSize" value="#{1024*1024*10}" />
<!-- 内存中的最大值 -->
<property name="maxInMemorySize" value="40960" />
</bean>
4.建立操作 附件表的持久层Dao接口
/**
* 附件的 持久层
* @author dell
*/
public interface AttachmentDao {
/**
* 添加附件 (保存用户上传的文件)
* @return
*/
public Integer addAttachment(Attachment att);
/**
* 查询数据库中 是否有 与之相同的摘要信息(判断重复文件)
* @param digest md5摘要信息
* @return Integer 等于0则没有相同的摘要信息,大于0则有相同的
*/
public Integer findSameDigest(String digest);
}
5.创建Mapper.xml配置文件 (对DAO层的方法实现)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tanzhou.tzms.product.dao.AttachmentDao">
<!-- 添加附件 -->
<insert id="addAttachment" parameterType="com.tanzhou.tzms.product.domain.Attachment">
INSERT INTO
tz_attachements(
<!-- 如果标题不为空,就添加上 -->
<if test="title!=null and title!=''">
title,
</if>
fileName,contentType,filePath,fileDisgest,
createdUser,modifiedUser,createdTime,modifiedTime)
VALUES(
<if test="title!=null and title!=''">
#{title},
</if>
#{fileName},#{contentType},#{filePath},#{fileDisgest},
#{createdUser},#{modifiedUser},now(),now());
</insert>
<!-- 查询附件表中是否有同样的摘要信息 -->
<select id="findSameDigest" parameterType="string" resultType="integer">
select
count(*)
from
tz_attachements
where
fileDisgest = #{fileDisgest}
</select>
</mapper>
6.创建attachment附件表的业务层接口,以及业务层实现类
package com.tanzhou.tzms.product.service.impl;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;
import com.tanzhou.tzms.common.exception.ServiceException;
import com.tanzhou.tzms.product.dao.AttachmentDao;
import com.tanzhou.tzms.product.domain.Attachment;
import com.tanzhou.tzms.product.service.AttachmentService;
/**
* 附件表的 业务层实现接口
* @author dell
*
*/
@Service("attachmentService")
public class AttachmentServiceImpl implements AttachmentService{
@Autowired
private AttachmentDao attDao;
/**
* 新增附件 (保存 用户 上传的文件)
* MultipartFile mFile 上传的文件表现形式
*/
@Override
public void addAttachment(MultipartFile mFile, String title) {
//获取客户端上传的文件名
String filename = mFile.getOriginalFilename();
//根据上传的文件内容,生成MD5 摘要信息
byte[] bytes;
String md5DigestAsHex = null;
try {
bytes = mFile.getBytes();
/* 使用Spring的工具类md5DigestAsHex
* 生成16进制的MD5摘要信息
* 如果文件内容一样,生成的 MD5摘要信息是一样的
*/
md5DigestAsHex = DigestUtils.md5DigestAsHex(bytes);
} catch (IOException e1) {
e1.printStackTrace();
throw new ServiceException("上传失败");
}
//以生成的文件摘要信息,判断是否有上传重复的文件
if(attDao.findSameDigest(md5DigestAsHex)>0) {
throw new ServiceException("该文件以存在,不能重复上传");
}
/*创建一个新文件 拷贝客户端上传的文件*********/
SimpleDateFormat simpleDate = new SimpleDateFormat("YYYY-MM-dd");
String currentDate = simpleDate.format(new Date());
File fileDir = new File("E:"+File.separator+"uoloads"+File.separator+currentDate);
File newfile = null;
try {
//文件名最后一个 . 索引位置
int indexOf = filename.lastIndexOf(".");
String newFileName = ilename.substring(0,indexOf)+"_"+System.currentTimeMillis();
String fileType = filename.substring(indexOf,filename.length());
//根据父路径和文件名 初始化新文件
newfile = new File(fileDir,newFileName+fileType);
//将从客户端上传的文件拷贝到 新文件中
mFile.transferTo(newfile);
//--------------将文件信息存储到数据库中---------------
Attachment attachment = new Attachment();
attachment.setFileName(newFileName);
attachment.setContentType(fileType);
attachment.setFilePath(newfile.getAbsolutePath());
attachment.setFileDisgest(md5DigestAsHex);
attachment.setTitle(title);
attachment.setCreatedUser("ayue");
attachment.setModifiedUser("ayue");
attachment.setCreatedTime(new Date());
attachment.setModifiedTime(new Date());
//将文件信息存储在数据库中
attDao.addAttachment(attachment);
} catch (Exception e) {
e.printStackTrace();
//若文件已经上传了,那么删除掉
if(newfile.exists()) {
newfile.delete();
}
throw new ServiceException("上传失败");
}
}
}
7.控制器
package com.tanzhou.tzms.product.controller;
import java.io.File;
import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
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.tanzhou.tzms.common.exception.ServiceException;
import com.tanzhou.tzms.common.web.JsonResult;
import com.tanzhou.tzms.product.service.AttachmentService;
@Controller
@RequestMapping("/attachment")
public class AttachementController {
@Autowired
private AttachmentService atts;
/**
* 加载附件上传 UI界面
*/
@RequestMapping("/attachementUI")
public String loadAttachementUI() {
return "attachment/attachment";
}
/**
* @param mFile 文件上传的表现形式
* @return
*/
@RequestMapping("/upload")
@ResponseBody
public JsonResult uploadAttachment(@RequestParam("mFile")MultipartFile mFile,@RequestParam("title")String title) {
atts.addAttachment(mFile,title.trim());
return new JsonResult("上传成功");
}
}
8.前端页面
<form id="uploadFormId" class="form-inline" enctype="multipart/form-data">
<div class="form-group">
<label for="exampleInputName2">Name</label>
<input type="text" class="form-control" name="title" id="exampleInputName2" placeholder="标题">
</div>
<div class="form-group">
<input type="file" name="mFile" id="exampleInputFile">
<!-- 用于清空表单的内容 -->
<input type="reset" id="reset" style="display:none">
</div>
<button type="button" class="btn btn-default btn-upload">上传</button>
</form>
9.编写js,使用jquery-form.js 插件异步 ajax 提交表单,避免submit提交重新加载页面
$(document).ready(function(){
$("#uploadFormId").on("click",".btn-upload",doUpload)
});
//上传文件
function doUpload(){
//如果没有选择要上传的文件
if(!$("#uploadFormId #exampleInputFile").val()){
console.log("请选择文件");
return ;
}
//获取上传按钮,对按钮内容进行修改,提示正在上传中
var btn_upload = $("#uploadFormId .btn-upload");
btn_upload.html("上传中..");
// 使用ajax提交 form表单 (避免submit提交,重新加载页面)
$("#uploadFormId").ajaxSubmit({
url:'attachment/upload',
type:"post",
dataType:"json",
success:function(result){
//触发表单的 reset 按钮 清空表单的数据
$("#uploadFormId #reset").click();
//修改上传按钮的 内容
btn_upload.html("上传");
alert(result.message);
},
//ajax 异常时执行
error:function(){
//修改上传按钮的 内容
btn_upload.html("上传");
}
});
}
PS:使用 Jquery-form 插件,需要先加载 jquery 。
演示:
1.打开页面 ,选择要上传的文件
2.点击上传
3.查看上传的文件
4.附件表中的文件信息