Java学习 day54_fileupload

2023-11-03 21:20
文章标签 java 学习 fileupload day54

本文主要是介绍Java学习 day54_fileupload,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文件上传

微信头像

更换头像 本地选择一个头像--------头像更换(就是将本地的图片上传到服务器上面去)

微信的头像:如果是好友更换头像,你可以及时的发现

如果是群里面非好友更换了头像,那么没法及时发现的(群里面的非好友头像,如果你没有点击他的信息查看,那么显示的一直是更入群时那个头像)

微信在处理群内成员信息时,对于好友----及时去更新的;对于非好友-信息不是及时更新的

国庆—头像加国旗

无法更换头像的情况,即便更换成功,依然只是自己可以看到,别人看不到,文件的来源应该是不一样的

在这里插入图片描述

概述

文件上传,其实就是将客户端本地的资源文件上传到服务器上面去,一般情况下,还需要将该文件保存在服务器的硬盘上面。

其实就是将文件的数据写入到HTTP请求报文中(请求体)(将文件数据写入到请求报文中,需要我们自己完成吗?会由浏览器来完成),HTTP请求报文传输到服务器之后,被服务器解析封装到Request对象中,只需要利用request获取请求体的方法就可以拿到上传的文件的数据。

对于开发者来说,你需要做的事情有如下

1.首先需要去在html页面里面写入指定的标签,那么该标签可以用来上传文件,浏览器会帮助你将文件的内容写入到HTTP请求报文的请求体中

2.调用servletRequest.getInputStream()这个方法拿到请求体的部分,然后对其进行处理解析即可。

一切还是围绕着HTTP报文


准备工作

1.准备一个form表单,method根据语义应该设置为post方法

2.准备一个input type=file

点击提交按钮:

POST http://localhost/app/upload HTTP/1.1
Host: localhost
Connection: keep-alive
Content-Length: 11
Cache-Control: max-age=0
sec-ch-ua: "Chromium";v="92", " Not A;Brand";v="99", "Microsoft Edge";v="92"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
Origin: http://localhost
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 Edg/92.0.902.73
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost/app/upload.html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: JSESSIONID=54527195C7ED8AB0C3E99F41C4EEA001image=1.jpg

有没有问题?

Content-Length: 11,该请求头表示啥意思?表示的是请求体的长度。此时通过长度可以发现,文件上传此时传递的不是文件的内容,而是文件的名称。


3.form表单设置属性 enctype=multipart/form-data

在这里插入图片描述


后续如何操作?

其实就是利用request提供的API来进行解析处理

进入到EE阶段之后,我们会遇到一个ServletInputStream和ServletOutputStream,这两个虽然大家很陌生,但是你可以完成把它当做FileInputStream和FileOutputStream来看待,写的过程应当是一模一样的。只是写的目的地不同或者读的来源地不同罢了。

在这里插入图片描述

package com.cskaoyan.upload;import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;@WebServlet("/upload")
public class UploadServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//此时文件的数据在哪呢?//需求,将文件写入到服务器本地硬盘上面。希望传到应用根目录下面 1.jpg//文件的来源是在request的数组内,已经提供好了//你需要做的事情就是将数组里面的内容写入到指定的硬盘路径即可//或者说应用根目录下image/1.jpgServletInputStream inputStream = request.getInputStream();ServletContext servletContext = getServletContext();String realPath = servletContext.getRealPath("image/1.jpg");File file = new File(realPath);if(!file.getParentFile().exists()){//如果file的父级目录不存在,则创建所有的父级目录file.getParentFile().mkdirs();}FileOutputStream fileOutputStream = new FileOutputStream(file);int length = 0;byte[] bytes = new byte[1024];while ((length = inputStream.read(bytes)) != -1){fileOutputStream.write(bytes, 0, length);}inputStream.close();fileOutputStream.close();}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}//从本地硬盘上面某个位置D:/app读取文件,然后将其复制到硬盘另外一个位置D:/app2private void copyFile(){File sourcefile = new File("D:/app/12.jpg");File destFile = new File("D:/app2/12.jpg");try {FileInputStream fileInputStream = new FileInputStream(sourcefile);FileOutputStream outputStream = new FileOutputStream(destFile);} catch (FileNotFoundException e) {e.printStackTrace();}}
}

随后发现,保存在硬盘上面的二进制文件损坏,无法打开,为什么呢?

此时可以从另外一个角度去尝试分析一下,使用文本文件来上传。上传一个txt文本。

在这里插入图片描述

如果这些字符进入到二进制文件中,肯定会导致文件的损坏。

这些字符数据怎么来的呢?

通过抓取请求报文发现,请求报文发出时,就已经包含了这些字符。不是服务器代码写的有问题,导致了该问题。

尝试同时上传表单数据和文件。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><form action="/app/upload" enctype="multipart/form-data" method="post"><input type="file" name="image"><input type="text" name="username"><br><input type="submit"></form>
</body>
</html>

之后,我们尝试获取表单数据username

发现之前可以获取请求参数的方法无法获取到请求参数了,返回null。

与此同时,抓包请求报文

POST http://localhost/app/upload HTTP/1.1
Host: localhost
Connection: keep-alive
Content-Length: 285
Cache-Control: max-age=0
sec-ch-ua: "Chromium";v="92", " Not A;Brand";v="99", "Microsoft Edge";v="92"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
Origin: http://localhost
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary3hX2dTZFTR9Bc514
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 Edg/92.0.902.73
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost/app/upload.html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: JSESSIONID=54527195C7ED8AB0C3E99F41C4EEA001------WebKitFormBoundary3hX2dTZFTR9Bc514
Content-Disposition: form-data; name="image"; filename="1.txt"
Content-Type: text/plainhello
------WebKitFormBoundary3hX2dTZFTR9Bc514
Content-Disposition: form-data; name="username"admin
------WebKitFormBoundary3hX2dTZFTR9Bc514--

发现提交过来的请求参数不再是key=value型了。


问题

1.仅会上传文件名,不会上传文件内容

​ 如何去解决呢? form表单设置属性 **enctype=“multipart/form-data”。**该属性值表示的含义是设置了这个以后,那么form表单不仅可以像之前一样上传普通表单数据,也就是文本数据,还可以上传二进制数据。

2.写了代码解析,随后发现文件损坏,无法打开?

上传逻辑之后,文件里面会多出来一部分字符,导致了二进制文件的损坏。

3.之前可以获取请求参数的API也获取不到了,为什么呢?

因为请求参数不再是key=value型数据了。

总结:

最开始只会上传文件名,不会上传文件内容,采取的措施(enctype=“multipart/form-data”)

添加完之后

可以上传文件内容了,但是此时

二进制文件会直接损坏

文本文件会多出来很多字符

获取请求参数的API也获取不到请求参数了

一切的问题其实都是来自于enctype=“multipart/form-data”,如果不添加,没法进行文件上传的;

如果添加了之后,文件可以上传了。(思考一个问题,如果此时可以提交文件数据了,那么请求体里面提交的数据格式还可以是key=value型吗?不可以。)

此时之前的数据格式不能再使用了,只能采用新的数据格式

Content-Disposition: form-data; name="image"; filename="1.txt"
Content-Type: text/plainhello
------WebKitFormBoundary3hX2dTZFTR9Bc514
Content-Disposition: form-data; name="username"admin
------WebKitFormBoundary3hX2dTZFTR9Bc514--

这些字符其实是用来进行分割每个input部分的。

通过去分析这些分隔符,发现其实是有规律可循的,利用这些分隔符,就可以将原先的数据进行拆分。

但是实际的实现过程还是比较复杂的,并且市面已经存在了比较成熟的解决方案,所以直接使用组件来完成该功能即可。


使用组件来进行文件上传(了解,会用即可)

对于组件部分的要求,根据官网的步骤,完成文件上传功能即可。这里面会涉及很多API,不要过分纠结于这些API的具体实现原理。

package com.cskaoyan.upload;import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.List;@WebServlet("/upload2")
public class UploadServlet2 extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");//如果没有上传的文件,那么是不可以使用commons-fileupload组件的//在使用之前,一定要确认当前请求是否包含上传的文件(判断是否是multipart/form-data)boolean multipart = ServletFileUpload.isMultipartContent(request);if(!multipart){response.getWriter().println("当前的请求没有包含上传文件");return;}//工厂可以用来生产对应的物件,利用factory可以实例化接下来文件上传的处理器DiskFileItemFactory factory = new DiskFileItemFactory();//factory首先先设置一个缓存仓库,当文件很大时,采用边缓存边处理的方式File repository = (File) getServletContext().getAttribute("javax.servlet.context.tempdir");factory.setRepository(repository);//利用factory生产出来一个文件处理器ServletFileUpload upload = new ServletFileUpload(factory);//利用处理器处理我们的请求:将页面提交过来的input封装成一个FileItem对象//页面里面每出现一个input框,那么这里面就对应一个FileItemtry {List<FileItem> items = upload.parseRequest(request);for (FileItem item : items) {//后续的处理中,表单数据和上传的文件要区别对待if(item.isFormField()){//判断当前item是否是表单数据processFormField(item);}else {processUploadFile(item);}}} catch (FileUploadException e) {e.printStackTrace();}}/*** 处理上传的文件逻辑* @param item*/private void processUploadFile(FileItem item) {//想了解一下文件的文件名String fieldName = item.getFieldName();String fileName = item.getName();String contentType = item.getContentType();boolean isInMemory = item.isInMemory();long sizeInBytes = item.getSize();System.out.println(fieldName + "-" + fileName + "-" + contentType + "-" + isInMemory + "-" + sizeInBytes);//将文件保存到硬盘上面//想把它保存在应用根目录下ServletContext servletContext = getServletContext();String realPath = servletContext.getRealPath("image/" + fileName);File file = new File(realPath);try {item.write(file);} catch (Exception e) {e.printStackTrace();}}/*** 处理常规form表单的逻辑* 常规form表单数据,其实只需要获取键值对就可以了* @param item*/private void processFormField(FileItem item) {String key = item.getFieldName();String value = item.getString();System.out.println(key + ":" + value);}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}}

在这里插入图片描述


设置中文乱码解决方案

在文件上传时,还会不会有中文乱码问题?

1.表单数据里面提交中文,还会不会乱码

会。之前的方法不再适用。

String value = null;
try {value = item.getString("utf-8");
} catch (UnsupportedEncodingException e) {e.printStackTrace();
}

2.如果文件名含有中文,会不会乱码?

request.setCharacterEncoding("utf-8");

该代码可以解决文件名乱码问题


其他常用设置

比如设置提交的文件大小限制。

作业提交的时候,页面显示提交的作业大小有限制5M

微信针对视频有严格的大小限制的 朋友圈分享限制时长(对于来源于微视平台的视频不做限制的);群聊限制最大的大小

ServletFileUpload upload = new ServletFileUpload(factory);
//  1024 bytes
upload.setFileSizeMax(1024);

封装数据到对象

思考一个问题,如果这里我上传图片,那么接下来我应该把什么封装到对象中。

存什么路径?硬盘路径?网络路径?

存什么路径其实取决于你接下来这个图片需要干什么?对于用户来说,注册的时候提交了一个头像,接下来肯定是希望web访问过程中能够看到该头像。

这里必须使用jar包,导入jar包时先在module下创建lib,然后add as library,打开project structure,然后artifacts,下面会有一个fix

package com.cskaoyan.upload;import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;@WebServlet("/upload3")
public class UploadServlet3 extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {request.setCharacterEncoding("utf-8");response.setContentType("text/html;charset=utf-8");//如果没有上传的文件,那么是不可以使用commons-fileupload组件的//在使用之前,一定要确认当前请求是否包含上传的文件(判断是否是multipart/form-data)boolean multipart = ServletFileUpload.isMultipartContent(request);if(!multipart){response.getWriter().println("当前的请求没有包含上传文件");return;}//工厂可以用来生产对应的物件,利用factory可以实例化接下来文件上传的处理器DiskFileItemFactory factory = new DiskFileItemFactory();//factory首先先设置一个缓存仓库,当文件很大时,采用边缓存边处理的方式File repository = (File) getServletContext().getAttribute("javax.servlet.context.tempdir");factory.setRepository(repository);User user = new User();//利用factory生产出来一个文件处理器ServletFileUpload upload = new ServletFileUpload(factory);//  1024 bytes
//        upload.setFileSizeMax(1024);//利用处理器处理我们的请求:将页面提交过来的input封装成一个FileItem对象//页面里面每出现一个input框,那么这里面就对应一个FileItemtry {List<FileItem> items = upload.parseRequest(request);for (FileItem item : items) {//后续的处理中,表单数据和上传的文件要区别对待if(item.isFormField()){//判断当前item是否是表单数据processFormField(item, user);}else {processUploadFile(item, user);}}} catch (FileUploadException e) {e.printStackTrace();}System.out.println(user);}/*** 处理上传的文件逻辑* @param item* @param user*/private void processUploadFile(FileItem item, User user) {//想了解一下文件的文件名String fieldName = item.getFieldName();String fileName = item.getName();String contentType = item.getContentType();boolean isInMemory = item.isInMemory();long sizeInBytes = item.getSize();System.out.println(fieldName + "-" + fileName + "-" + contentType + "-" + isInMemory + "-" + sizeInBytes);//将文件保存到硬盘上面//想把它保存在应用根目录下ServletContext servletContext = getServletContext();String relativePath = "image/" + fileName;String realPath = servletContext.getRealPath(relativePath);File file = new File(realPath);try {item.write(file);user.setImage(relativePath);} catch (Exception e) {e.printStackTrace();}}/*** 处理常规form表单的逻辑* 常规form表单数据,其实只需要获取键值对就可以了* @param item* @param user*/private void processFormField(FileItem item, User user) {String key = item.getFieldName();String value = null;try {value = item.getString("utf-8");//判断是username-if(key.equals("username")){user.setUsername(value);}else if(key.equals("password")){user.setPassword(value);}} catch (UnsupportedEncodingException e) {e.printStackTrace();}System.out.println(key + ":" + value);}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}}

封装数据到对象2

BeanUtils出发点是对的。需要一个map。提供一个map。

提供一个空的map对象, 在接下来调用processFormField、processUploadFile方法时,将这个对象作为参数传递进去,对map进行填充数据,数据会保留下来,最后执行BeanUtils的方法,通过反射来完成赋值。

package com.cskaoyan.upload;import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;@WebServlet("/upload4")
public class UploadServlet4 extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {request.setCharacterEncoding("utf-8");response.setContentType("text/html;charset=utf-8");//如果没有上传的文件,那么是不可以使用commons-fileupload组件的//在使用之前,一定要确认当前请求是否包含上传的文件(判断是否是multipart/form-data)boolean multipart = ServletFileUpload.isMultipartContent(request);if(!multipart){response.getWriter().println("当前的请求没有包含上传文件");return;}//工厂可以用来生产对应的物件,利用factory可以实例化接下来文件上传的处理器DiskFileItemFactory factory = new DiskFileItemFactory();//factory首先先设置一个缓存仓库,当文件很大时,采用边缓存边处理的方式File repository = (File) getServletContext().getAttribute("javax.servlet.context.tempdir");factory.setRepository(repository);Map<String, Object> params = new HashMap<>();//利用factory生产出来一个文件处理器ServletFileUpload upload = new ServletFileUpload(factory);//  1024 bytes
//        upload.setFileSizeMax(1024);//利用处理器处理我们的请求:将页面提交过来的input封装成一个FileItem对象//页面里面每出现一个input框,那么这里面就对应一个FileItemtry {List<FileItem> items = upload.parseRequest(request);for (FileItem item : items) {//后续的处理中,表单数据和上传的文件要区别对待if(item.isFormField()){//判断当前item是否是表单数据processFormField(item, params);}else {processUploadFile(item, params);}}} catch (FileUploadException e) {e.printStackTrace();}User user = new User();try {BeanUtils.populate(user, params);} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}System.out.println(user);}/*** 处理上传的文件逻辑* @param item* @param map*/private void processUploadFile(FileItem item, Map<String, Object> map) {//想了解一下文件的文件名String fieldName = item.getFieldName();String fileName = item.getName();String contentType = item.getContentType();boolean isInMemory = item.isInMemory();long sizeInBytes = item.getSize();System.out.println(fieldName + "-" + fileName + "-" + contentType + "-" + isInMemory + "-" + sizeInBytes);//将文件保存到硬盘上面//想把它保存在应用根目录下ServletContext servletContext = getServletContext();String relativePath = "image/" + fileName;String realPath = servletContext.getRealPath(relativePath);File file = new File(realPath);try {item.write(file);map.put(fieldName, relativePath);} catch (Exception e) {e.printStackTrace();}}/*** 处理常规form表单的逻辑* 常规form表单数据,其实只需要获取键值对就可以了* @param item* @param map*/private void processFormField(FileItem item, Map<String, Object> map) {String key = item.getFieldName();String value = null;try {value = item.getString("utf-8");//判断是username-map.put(key, value);} catch (UnsupportedEncodingException e) {e.printStackTrace();}System.out.println(key + ":" + value);}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}}

封装数据到对象3

在方式2的基础上,只需要在稍微改动一点点,就可以形成一个工具类,接下来不管任何场景下进行文件上传,那么都可以复用它。比如用户注册、商品发布时

想象如果由用户注册变成了商品发布,基本上关于文件上传的代码逻辑不需要做任何改变,那么完全可以复用。可以写成工具类。

package com.cskaoyan.upload;import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class FileUploadUtils {public static Map<String, Object> parseRequest(HttpServletRequest request){//工厂可以用来生产对应的物件,利用factory可以实例化接下来文件上传的处理器DiskFileItemFactory factory = new DiskFileItemFactory();//factory首先先设置一个缓存仓库,当文件很大时,采用边缓存边处理的方式File repository = (File) request.getServletContext().getAttribute("javax.servlet.context.tempdir");factory.setRepository(repository);Map<String, Object> params = new HashMap<>();//利用factory生产出来一个文件处理器ServletFileUpload upload = new ServletFileUpload(factory);//  1024 bytes
//        upload.setFileSizeMax(1024);//利用处理器处理我们的请求:将页面提交过来的input封装成一个FileItem对象//页面里面每出现一个input框,那么这里面就对应一个FileItemtry {List<FileItem> items = upload.parseRequest(request);for (FileItem item : items) {//后续的处理中,表单数据和上传的文件要区别对待if(item.isFormField()){//判断当前item是否是表单数据processFormField(item, params);}else {processUploadFile(item, params, request);}}} catch (FileUploadException e) {e.printStackTrace();}return params;}/*** 处理上传的文件逻辑* @param item* @param map* @param request*/private static void processUploadFile(FileItem item, Map<String, Object> map, HttpServletRequest request) {//想了解一下文件的文件名String fieldName = item.getFieldName();String fileName = item.getName();String contentType = item.getContentType();boolean isInMemory = item.isInMemory();long sizeInBytes = item.getSize();System.out.println(fieldName + "-" + fileName + "-" + contentType + "-" + isInMemory + "-" + sizeInBytes);//将文件保存到硬盘上面//想把它保存在应用根目录下ServletContext servletContext = request.getServletContext();String relativePath = "image/" + fileName;String realPath = servletContext.getRealPath(relativePath);File file = new File(realPath);try {item.write(file);map.put(fieldName, relativePath);} catch (Exception e) {e.printStackTrace();}}/*** 处理常规form表单的逻辑* 常规form表单数据,其实只需要获取键值对就可以了* @param item* @param map*/private static void processFormField(FileItem item, Map<String, Object> map) {String key = item.getFieldName();String value = null;try {value = item.getString("utf-8");//判断是username-map.put(key, value);} catch (UnsupportedEncodingException e) {e.printStackTrace();}System.out.println(key + ":" + value);}
}
package com.cskaoyan.upload;import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;@WebServlet("/upload5")
public class UploadServlet5 extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {request.setCharacterEncoding("utf-8");response.setContentType("text/html;charset=utf-8");//如果没有上传的文件,那么是不可以使用commons-fileupload组件的//在使用之前,一定要确认当前请求是否包含上传的文件(判断是否是multipart/form-data)boolean multipart = ServletFileUpload.isMultipartContent(request);if(!multipart){response.getWriter().println("当前的请求没有包含上传文件");return;}Map<String, Object> params = FileUploadUtils.parseRequest(request);User user = new User();try {BeanUtils.populate(user, params);} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}System.out.println(user);}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}}

今后如果进行商品发布等其他场景,直接使用文件上传的代码即可

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>商品的发布页面</title>
</head>
<body><form action="/app/product" enctype="multipart/form-data" method="post"><input type="file" name="image"><input type="text" name="productName"><br><input type="text" name="description"><br><input type="submit"></form>
</body>
</html>
package com.cskaoyan.upload;import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.fileupload.servlet.ServletFileUpload;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;@WebServlet("/product")
public class ProductServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {request.setCharacterEncoding("utf-8");response.setContentType("text/html;charset=utf-8");//如果没有上传的文件,那么是不可以使用commons-fileupload组件的//在使用之前,一定要确认当前请求是否包含上传的文件(判断是否是multipart/form-data)boolean multipart = ServletFileUpload.isMultipartContent(request);if(!multipart){response.getWriter().println("当前的请求没有包含上传文件");return;}Map<String, Object> params = FileUploadUtils.parseRequest(request);Product product = new Product();try {BeanUtils.populate(product, params);} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}
}

文件重名问题

对于一个系统来说,它有很多用户,用户在上传图片的时候,都有可能会选择一个叫做1.jpeg的文件

应该将其改名

改名:wxid + timestamp 形成一个独一无二的名字

或者说完全随机

String fileName = item.getName();
//对文件名进行处理
String uuid = UUID.randomUUID().toString();
//文件后缀名
fileName = uuid + "-" + fileName;

目录内文件数过多的问题

假设电脑性能不是特别好,如果一个目录内文件数过多,那么打开该目录,发现加载速度很慢,磁盘在剧烈的转动。

磁盘在努力的进行IO操作。

网络访问过程也是一样,如果文件数很多,那么加载某个文件也是同样的过程, 也会非常慢,这个时候可以怎么做呢?

设置多个目录。按照什么原则设置呢?

比如

可以按照年、月、日设置目录。

有一个问题,不是特别的均匀。如果碰到节假日,大型的节日,某一天的文件可能要超过平时一周的文件。

如何设置的均匀一些呢?

散列。

文件名—hashcode-----------> 0x 1 2 3 6 7 8 A F/ 文件

private static void processUploadFile(FileItem item, Map<String, Object> map, HttpServletRequest request) {//想了解一下文件的文件名String fieldName = item.getFieldName();String fileName = item.getName();//对文件名进行处理String uuid = UUID.randomUUID().toString();//文件后缀名fileName = uuid + "-" + fileName;int hashCode = fileName.hashCode();String hexString = Integer.toHexString(hashCode);char[] chars = hexString.toCharArray();String basePath = "image";for (char aChar : chars) {basePath = basePath + "/" + aChar;}String contentType = item.getContentType();boolean isInMemory = item.isInMemory();long sizeInBytes = item.getSize();System.out.println(fieldName + "-" + fileName + "-" + contentType + "-" + isInMemory + "-" + sizeInBytes);//将文件保存到硬盘上面//想把它保存在应用根目录下ServletContext servletContext = request.getServletContext();String relativePath = basePath + "/" + fileName;String realPath = servletContext.getRealPath(relativePath);File file = new File(realPath);if(!file.getParentFile().exists()){file.getParentFile().mkdirs();}try {item.write(file);map.put(fieldName, relativePath);} catch (Exception e) {e.printStackTrace();}
}

这篇关于Java学习 day54_fileupload的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/340966

相关文章

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Java判断多个时间段是否重合的方法小结

《Java判断多个时间段是否重合的方法小结》这篇文章主要为大家详细介绍了Java中判断多个时间段是否重合的方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录判断多个时间段是否有间隔判断时间段集合是否与某时间段重合判断多个时间段是否有间隔实体类内容public class D

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

Spring AI集成DeepSeek的详细步骤

《SpringAI集成DeepSeek的详细步骤》DeepSeek作为一款卓越的国产AI模型,越来越多的公司考虑在自己的应用中集成,对于Java应用来说,我们可以借助SpringAI集成DeepSe... 目录DeepSeek 介绍Spring AI 是什么?1、环境准备2、构建项目2.1、pom依赖2.2