写在前面
- 我们常会从客户端上传文件。
- 可是这些文件怎么保存到数据库呢?
- 又怎么从数据库读取出来呢?
- 以上传图片为例(这里用 Java 实现的)
一、先来看一张图

- 从这张图应该可以看出,图片存入流入数据库的大致流程
- 可是还有很多问题要解决! 那我们就一起来解决这些问题吧!
二、待解决的问题
- 前端方面怎么控制参数?
- 怎么将发给服务器的图片数据写入到服务器的磁盘中?
- 数据写入磁盘中的什么地方?
- 怎么将相对路径写入数据库中?
三、依次解决以上问题
(1) 前端中form表单必要的两个属性
- method=“post”
- enctype=“multipart/form-data”


- 可以明显的看出,参数的格式不一样
- 图一是非文件参数请求。
- 图二是文件参数请求(加上了
enctype="multipart/form-data"
)。
- 我们都知道,
GET
请求会将参数拼接在浏览器地址栏后面,且不说长度有限制,拼接这么大一串,也很啊难看嘛。
- 所以用
POST
请求,参数会放在请求体里!
- 图二的参数的格式,用分割线中夹住的,就是一个参数。且格式是固定的。
- 由此我们又引出一个问题,
- 等会在servlet中怎么将参数映射成一个实体对象?
(2)将图片数据写入服务器磁盘中
- 我们解决了前端中的问题,现在来看看后台怎么处理吧!我们这儿也借助一个第三方库,来拿到参数写入磁盘。
①导入jar包
<!--文件上传-->
<dependency>
<groupld>commons-fileupload</groupld>
<artifactld>commons-fileupload</artifactld>
<version>1.4</version>
</dependency>
②拿到参数的关键代码
ServletFileUpload upload = new ServletFileUpload(new DiskFileltemFactory());
List<Fileltem> items = upload.parseRequest(request);
for (Fileltem item : items) {
String fieldName = item.getFieldName();
if (item.isFormField()) {// 非文件参数
System.out.printIn(fieldName + ":" + item.getString("UTF-8"));
} else {// 文件参数
System.out.printIn(fieldName + ":" + item.getName());
}
}

- 可以看出,一个Fileltem的对象,就是一个参数。
- item.isFormField()判断是否是文件参数(处理方法不一样)
- item.getFieldName()∶字段名(属性名)
- item.getString(“UTF-8”)∶属性的值
- item.getName()∶文件名!
- 好的,知道这些,一会就可以用来映射成实体对象了。
④怎么写到磁盘中(先用IO流的知识了解一下本质)

- 从这张图可以看出,我们需要用到输入流和输出流。
- 以服务器为参照物。文件数据是先用输入流,流到服务器上,
- 再以服务器磁盘为参照物,文件数据是从服务器用输出流,流出到服务器的磁盘上。
for (Fileltem item :items) {
String fieldName = item.getFieldName();
if (item.isFormField()){// 非文件参数
}else{// 文件参数
String filePath ="D:/琴女1.jpg";
FileOutputStream fos = new FileOutputStream(new File(filePath));
InputStream is = item.getInputStream();
byte[] buffer = new byte[4096];
int len;
while ((len = is.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
is.close();
fos.close();
}
}

- 可以看到,我们的确写到了服务器的磁盘上!
- fiilePath∶ 是文件路径,我这里随便写一个
- 当然不可能这样写死了,待会再看路径怎么写!
- 下面看看使用第三方库的简便写法!
ServletFileUpload upload = new ServletFileUpload(new DiskFileltemFactory());
List<Fileltem> items = upload.parseRequest(request);
for (Fileltem item : items) {
String fieldName = item.getFieldName();
if (item.isFormField()) {// 非文件参数
} else {// 文件参数
String filePath = "D:/琴女2.jpg";
FileUtils.copylnputStreamToFile(item.getInputStream(), new File(filePath));
}
}
(3)写入磁盘的具体位置(我这里直接写入了项目部署路径中)

- 从上图可以看出,每一个部署的项目,都会在磁盘中有一个根目录
- 属于这个项目的图片,可以跟着它走
- 我们看看怎么将图片写入部署路径中
for (Fileltem item : items) {
String fieldName = item.getFieldName();
if (item.isFormField()) {// 非文件参数
} else {// 文件参数
String dir = request.getServletContext().getRealPath("upload/image");
String fileName = UUID.randomUUID() + "." + FilenameUtils.getExtension(item.getName());
String filePath = dir + "/" + fileName;
System.out.printIn(dir);
System.out.printIn(fileName);
System.out.printIn(filePath);
FileUtils.copylnputStreamToFile(item.getInputStream(), new File(filePath);
}
}

- 文件路径 = 项目所在目录 + 文件名。
- UUD.randomUUD0是获取随机不重复的名字!
- FilenameUtils.getExtension(item.getName( ))是获取文件扩展名
(4)存入数据库中的字符串
- 格式类似于:upload/image/xxxx.jpg
- 将这一串转成
bean
对象的一个字段
- 将其映射转换成一个实体对象,保存到数据库中
public void save(HttpServletRequest request, HttpServletResponse response) throws Exception {
ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
List<FileItem> items = upload.parseRequest(request);
// 非文件参数
Map<String, Object> params = new HashMap<>();
// 文件参数
Map<String, FileItem> fileParams = new HashMap<>();
// 写入数据库的image字段
String image = null;
for (FileItem item : items) {
String fieldName = item.getFieldName();
if (item.isFormField()) {// 非文件参数
params.put(fieldName, item.getString("UTF-8"));
} else {// 文件参数
fileParams.put(fieldName,item);
}
}
Award bean = new Award();
// 将非文件参数映射成bean对象
BeanUtils.populate(bean, params);
// 获取属性名叫imageFile的参数内容
FileItem item = fileParams.get("imageFile");
// 如果有这个内容,那么执行这些写入的操作。没有就算咯!
if (item != null) {
InputStream is = item.getInputStream();
// 别人不传图片,判断一下是不是空串
if (is.available() > 0) {
String fileName = UUID.randomUUID() + "." + FilenameUtils.getExtension(item.getName());
//前面有context,所以只需要传下面的给数据库存储就可以了
image = "upload/image/" + fileName;
// 写入磁盘的路径
String filePath = request.getServletContext().getRealPath(image);
// 写入磁盘
FileUtils.copyInputStreamToFile(item.getInputStream(), new File(filePath));
bean.setImage(image);
}
}
if (service.save(bean)) {
response.sendRedirect(request.getContextPath() + "/award2/admin");
}else {
request.setAttribute("error", "获奖成就保存失败");
request.getRequestDispatcher("WEB-INF/page/error.jsp").forward(request, response);
}
}
写在后面
- 以上代码仅是文件上传这部分的关键代码。
- 前端页面和数据库还得有相关的一些变动
- 比较简单,还没有用到框架啥的。