JavaWeb, Spring, SpringBoot realizan la carga y descarga de archivos

Carga y descarga de archivos

1. Archivo front-end.html:

Requisitos del formulario de front-end: para cargar archivos, el método del formulario debe establecerse en POST y el enctype debe establecerse en multipart / form-data. Solo en este caso, el navegador enviará el archivo seleccionado por el usuario al servidor como datos binarios;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>上传</title>
</head>
<body>

<form action="/fileUpload" enctype="multipart/form-data" method="post">
       <input type="file" name="file"/>
       <input type="submit" value=”上传文件”>
</form>

<div>
    <a href="/download">点击下载</a>
</div>
</body>
</html>

Nota:

  • multipart / form-data : este método de codificación procesará los datos del formulario en una secuencia binaria. Este método de codificación también encapsulará el contenido del archivo especificado en el dominio del archivo en los parámetros de solicitud sin codificar caracteres.
  • multipart / form-data carga los datos del formulario en forma de elementos de formulario de varias partes.

2. Carga y descarga de archivos JavaWeb

(1) La carga de archivos
debe importar dos paquetes jar:

  • commons-fileupload-1.2.1.jar
  • commons-io-1.4.jar

Métodos comunes:

  • La clase ServletFileUpload se utiliza para analizar los datos cargados.
  • ServletFileUpload.isMultipartContent (solicitud HttpServletRequest): determina si los datos actuales están en un formato de varias partes
  • List<FileItem> parseRequest(HttpServletRequest request): Analiza los datos cargados y devuelve varios elementos de formulario
  • FileItem.isFormField (): determina si el elemento del formulario es un archivo
  • FileItem.getFieldName (): obtiene el valor del atributo de nombre del elemento del formulario
  • FileItem.getString (): obtiene el valor del elemento del formulario
  • FileItem.getName (): obtiene el nombre del archivo cargado
  • FileItem.write (archivo): escribe el archivo en el elemento del formulario en el directorio del disco al que apunta el archivo
//判断上传的数据是否为多段数据
if(ServletFileUpload.isMultipartContent(req)){
    
    

	//创建FileItemFactory工厂实现类
	FileItemFactory fileItemFactory = new DiskFileItemFactory();
	
	//创建用于解析上传数据的工具类ServletFileUpload
	ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
	
    //解析上传数据,得到表单项FileItem
	List<FileItem> list = servletFileUpload.parseRequest(req);
	
	//循环判断每一个表单项,是普通类型还是上传的文件
	for(FileItem fileItem : list){
    
    
		if(fileItem.isFormField()){
    
    
			//普通表单项
			System.out.pritln(fileItem.getFiledName());
			System.out.pritln(fileItem.getString("UTF-8"));
		}else{
    
    
			//上传的文件
			System.out.pritln(fileItem.getFiledName());
			System.out.pritln(fileItem.getName());
			fileItem.write(new File("e:\\"+fileItem.getName()));
		}
	}
}

(2) Descarga de archivos

//需要下载的文件名
String downloadFileName = "1.jpg";

//读取要下载的文件内容
ServletContext servletContext = getServletContext();

//获取要下载的文件类型
String mimeType = servletContext,getMimeType("/file"+downloadFileName)

//告诉客户端返回的数据类型
resp.setContentType(mimeType);

//告诉客户端收到的数据是用于下载使用还是使用响应头
if(req.getHeader("User-Agent").content("Firefox")){
    
    
  resp.setHeader("Content-Disposition","attachment;
  fiename==?UTF-8?B?"+new BASE64Encoder().encode("中国.jpg","UTF-8")));

}else{
    
    
  resp.setHeader("Content-Disposition","attachment;
  fiename="+URLEncoder.encode("中国.jpg","UTF-8"));
}

InputStream resourceAsStream = servletContext.getResourceAsStream("/file"+downloadFileName);

//获取响应输出流
OutputStream outputStream = resp.getOutputStream();

//将下载的文件内容回传给客户端
IOUtils.copy(resourceAsStream,outputStream);

Nota:

  • Encabezado de respuesta Content-Disposition: cómo tratar los datos recibidos
  • adjunto: significa adjunto, utilizado al descargar
  • req.getHeader ("User-Agent"): usa diferentes codificaciones según los diferentes navegadores. Firefox usa BASE64Encoder, y Google usa codificación URLencoder, que se usa principalmente para resolver el problema confuso en chino.

3. Carga y descarga de archivos de Spring:

(1) MultipartResolver

  • SpringMVC puede soportar bien la carga de archivos, pero MultipartResolver no está equipado de forma predeterminada en el contexto SpringMVC, por lo que no puede manejar la carga de archivos de forma predeterminada. Si desea utilizar la función de carga de archivos de Spring, debe configurar MultipartResolver en el contexto.
  • Spring MVC proporciona soporte directo para la carga de archivos, que se implementa con el MultipartResolver plug-and-play.
  • Spring MVC utiliza la tecnología Apache Commons FileUpload para implementar una clase de implementación MultipartResolver: CommonsMultipartResolver. Por lo tanto, la carga de archivos SpringMVC también debe depender del componente de ApacheCommonsFileUpload.
  • En SpringMVC, la necesidad de importar el commons-iopaquete de dependencias del proceso de carga de archivos :
<dependency>
   <groupId>commons-fileupload</groupId>
   <artifactId>commons-fileupload</artifactId>
   <version>1.3.3</version>
</dependency>

commons-ioSituación de uso de paquetes dependientes :

public String fileUpload(@RequestParam("file") CommonsMultipartFile
file) 

(2) Configurar MultipartResolver

<!--文件上传配置-->
<bean id="multipartResolver"
 class="org.springframework.web.multipart.commons.CommonsMultipartResolve
r">
   <!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,
默认为ISO-8859-1 -->
   <property name="defaultEncoding" value="utf-8"/>
   <!-- 上传文件大小上限,单位为字节(10485760=10M)-->
   <property name="maxUploadSize" value="10485760"/>
   <property name="maxInMemorySize" value="40960"/>
</bean>

Nota:

  • La identificación de bena debe ser: multipartResolver, de lo contrario, el archivo de carga informará un error 400.

Métodos comunes de CommonsMultipartFile:

  • Cadena getOriginalFilename(): obtenga el nombre original del archivo cargado, como test.html
  • InputStream getInputStream(): Obtener el flujo de archivos
  • nulo transferTo(File dest):Guarde el archivo cargado en un archivo de catálogo

(3) Carga de archivos en forma de flujo de E / S

@Controller
public class FileController {
    
    
  
   @RequestMapping("/upload")
   public String fileUpload(@RequestParam("file") CommonsMultipartFile
file , HttpServletRequest request) throws IOException {
    
    

       //获取文件名
       String uploadFileName = file.getOriginalFilename();
       
       //如果文件名为空,直接回到首页!
       if ("".equals(uploadFileName)){
    
    
           return "redirect:/index.jsp";
      }
       System.out.println("上传文件名: "+uploadFileName);
       
       //上传路径保存设置
       String path =
request.getServletContext().getRealPath("/upload");

       //如果路径不存在,创建一个
       File realPath = new File(path);
       if (!realPath.exists()){
    
    
           realPath.mkdir();
      }
       System.out.println("上传文件保存地址:"+realPath);
       
       InputStream is = file.getInputStream(); //文件输入流
       OutputStream os = new FileOutputStream(new
File(realPath,uploadFileName)); //文件输出流

       //读取写出
       int len=0;
       byte[] buffer = new byte[1024];
       while ((len=is.read(buffer))!=-1){
    
    
           os.write(buffer,0,len);
           os.flush();
      }
       os.close();
is.close();
       return "redirect:/index.jsp";
  }
}

Nota:

  • @RequestParam ("archivo") encapsula el archivo obtenido por el control nombre = archivo en un objeto CommonsMultipartFile
  • Carga masiva CommonsMultipartFile es una matriz

(4) Cargue archivos usando transferTo

@RequestMapping("/upload2")
public String  fileUpload2(@RequestParam("file") CommonsMultipartFile
file, HttpServletRequest request) throws IOException {
    
    

   //上传路径保存设置
   String path = request.getServletContext().getRealPath("/upload");
   File realPath = new File(path);
   if (!realPath.exists()){
    
    
       realPath.mkdir();
  }
   //上传文件地址
   System.out.println("上传文件保存地址:"+realPath);

   file.transferTo(new File(realPath +"/"+
file.getOriginalFilename()));

   return "redirect:/index.jsp";
}

(5) Descarga de archivos

  • Establecer el encabezado de respuesta

  • Leer archivo - InputStream

  • Escriba el archivo - OutputStream

  • Cerrar la corriente (abrir primero y luego cerrar)

@RequestMapping(value="/download")
public String downloads(HttpServletResponse response ,HttpServletRequest
request) throws Exception{
    
    

   //要下载的图片地址
   String  path = request.getServletContext().getRealPath("/upload");
   String  fileName = "基础语法.jpg";
   
//1、设置response 响应头
   response.reset(); //设置页面不缓存,清空buffer
   response.setCharacterEncoding("UTF-8"); //字符编码
   response.setContentType("multipart/form-data"); //二进制传输数据
   
   //设置响应头
   response.setHeader("Content-Disposition",
           "attachment;fileName="+URLEncoder.encode(fileName, "UTF-8"));
           
   File file = new File(path,fileName);
   //2、读取文件--输入流
   InputStream input=new FileInputStream(file);
   
   //3、写出文件--输出流
   OutputStream out = response.getOutputStream();
   byte[] buff =new byte[1024];
   int index=0;
   
   //4、执行写出操作
   while((index= input.read(buff))!= -1){
    
    
       out.write(buff, 0, index);
       out.flush();
  }
   out.close();
   input.close();
   return null;
}

Interfaz:

<a href="/download">点击下载</a>

4. Carga y descarga de archivos en springboot:

(1) SpringBoot usa el proceso de carga de archivos predeterminado StandardServletMultipartResolvery la configuración automática relacionada está en él MultipartAutoConfiguration. Podemos usar spring.servlet.multipartpara configurar, por supuesto, también podemos usar commons-iopaquetes, pero necesitamos excluir el método predeterminado:

spring:
  autoconfigure:
    exclude: org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration

(2) Carga y descarga de archivos

  • Los archivos de carga de Springboot se pueden usar directamente org.springframework.web.multipart.MultipartFile.
  • Al cargar un archivo, debe definir la dirección y el nombre del archivo cargado, obtener el flujo de bytes del archivo y enviarlo a la ruta de archivo especificada.
  • Al descargar un archivo, obtenga la ruta completa del archivo descargado y se recomienda descargar el archivo usando Buffer.
@RestController
public class TestController {
    
    

    @PostMapping("/fileUpload")
    public String fileUpload(HttpServletRequest req, HttpServletResponse resp,@RequestParam("file") MultipartFile file) {
    
    
        if(file.isEmpty()){
    
    
            return "未选择上传文件";
        }
        String originalFilename = file.getOriginalFilename();
        String path = "G:/glp/"+originalFilename;
        File dest = new File(path);
        if(!dest.getParentFile().exists()){
    
    
            dest.getParentFile().mkdir();
        }
        try{
    
    
            file.transferTo(dest);
            return "上传成功";
        }catch (IOException e){
    
    
            e.printStackTrace();
        }
        return "上传失败";
    }

    @GetMapping("/download")
    public String fileDownLoad(HttpServletRequest req,HttpServletResponse resp){
    
    
        File file = new File("G:/glp/Java研发工程师.pdf");
        if(!file.exists()){
    
    
            return "下载文件不存在";
        }
        try(BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));){
    
    
            byte[] buff = new byte[1024];
            OutputStream outputStream = resp.getOutputStream();
            int len =0;
            while ((len=bis.read(buff))!=-1){
    
    
                outputStream.write(buff,0,len);
                outputStream.flush();
            }
        }catch (IOException e){
    
    
            e.printStackTrace();
            return "下载失败";
        }
        return "下载成功";
    }
}

Nota:
utilizado aquítransferToPara cargar archivos.

五 、 BufferedInputStream

BufferedInputStream es un flujo de entrada con un búfer, usualmente usarlo puede mejorar nuestra eficiencia de lectura, ahora miramos el principio de implementación de BufferedInputStream:

  • Hay un búfer dentro del BufferedInputStream, el tamaño predeterminado es 8M, cada vez que se llama al método de lectura, primero intenta leer datos del búfer, si la lectura falla (el búfer no tiene datos legibles), selecciona desde el físico la fuente de datos (por ejemplo, un archivo) lee nuevos datos (aquí intentaremos leer tantos bytes como sea posible) en el búfer y, finalmente, devolver parte o todo el contenido del búfer al usuario. Debido a la lectura del buffer Data es mucho más rápido que leer directamente desde fuentes de datos físicas (como archivos), por lo que BufferedInputStream es muy eficiente.
  • Para las operaciones sin almacenamiento en búfer, se escribe un byte cada vez que se lee un byte Dado que las operaciones de E / S relacionadas con el disco son mucho más lentas que las operaciones de memoria, la eficiencia de los flujos sin almacenamiento en búfer es muy baja. Con un flujo almacenado en búfer, puede leer muchos bytes a la vez, pero no escriba en el disco, simplemente póngalo en la memoria primero. Cuando el tamaño del búfer sea suficiente, escriba en el disco de una vez. ¡Este método puede reducir el número de operaciones del disco y aumentar mucho la velocidad! Ésta es la diferencia entre el flujo de entrada y el flujo de entrada con búfer.
  • BufferedInputStream y BufferedOutputStream son subclases de FilterInputStream y FilterOutputStream respectivamente, que implementan el patrón de diseño decorativo.

Supongo que te gusta

Origin blog.csdn.net/glpghz/article/details/108893963
Recomendado
Clasificación