1. Descripción general de carga de archivo
Para realizar la función de carga de archivos en el desarrollo web, se requieren dos pasos:
1. Agregar elementos de entrada de carga a la página web
<Form Action = "#" Method = "Post" Enctype = "multipart/form-data"> <input type = "file" name = "filename1"/> <br> <input type = "file" name = "FileName2"/> <br> <input type = "SIPT" Value = "upcar"/> <Form> <!-1. El método de formulario debe ser post 2. El atributo de múltipte de múltipe debe multiplicar. Después de configurar este valor, cuando el navegador carga el archivo, adjuntará los datos del archivo al cuerpo del mensaje de solicitud HTTP y usará el protocolo MIME para describir el archivo cargado para facilitar el receptor para analizar y procesar los datos cargados. 3. El atributo de nombre de la entrada debe establecerse, de lo contrario el navegador no enviará los datos de archivo cargados. ->
2. Lea los datos de carga de archivos en servlet y guárdelo en el disco duro del servidor
El objeto de solicitud proporciona un método getInputStream, a través del cual se pueden leer los datos enviados por el cliente. Sin embargo, dado que los usuarios pueden cargar varios archivos al mismo tiempo, es una tarea muy problemática programar y leer directamente los datos cargados en el lado del servlet y analizar los datos del archivo correspondientes por separado.
Por ejemplo, el siguiente es algunos de los contenidos del protocolo HTTP de la solicitud enviada por el navegador interceptado al cargar el archivo:
Aceptar el idioma: zh-hans-cn, zh-hans; q = 0.5content-type: multipart/form-data; Límite = --------------------------- 7DFA01D1908A4UA-CPU: AMD64ACT-ACODING: GZIP, DeFlateUser-Agent: Mozilla/5.0 (Windows NT 6.2; Win64; x64; Trident/7.0; RV: 11.0) Como GeckOcontent-Longitud: 653host: local: 8080Connection: 8080Connection: Keep-AlivePragma: No-Cachecookie: JSessionID = 11CEFF8E271AB62CE676B5A87B746B5F ----------------------------- 7DFA01D1908A4Content-Disposition: Form-Data; nombre = "Nombre de usuario" Zhangsan ----------------------------- 7DFA01D1908A4Content-Disposition: Form-Data; name = "UserPass" 1234 ----------------------------- 7DFA01D1908A4Content-Disposition: Form-Data; nombre = "FileName1"; FileName = "C: /users/asus/desktop/upload.txt" Content-type: Text/Plainthis es el primer contenido del archivo! ------------------------- 7DFA01D1908A4Content-Disposition: Form-Data; nombre = "FileName1"; FileName = "c: /users/asus/desktop/upload2.txt" Content-type: Text/Plainthis es el segundo contenido del archivo! Hola ----------------------------- 7DFA01D1908A4------
También se puede ver en los datos anteriores que es difícil escribir un programa robusto y estable si divide y lee manualmente los datos. Por lo tanto, para facilitar a los usuarios procesar datos de carga, Apache Open Source Organization proporciona un componente de código abierto (Commons-FileUppload) utilizado para procesar las cargas de archivos de formulario. Este componente tiene un excelente rendimiento y su API es extremadamente simple de usar, lo que permite a los desarrolladores implementar fácilmente funciones de carga de archivos web. Por lo tanto, en el desarrollo web, la función de carga de archivos generalmente se implementa utilizando el componente Commons-FileUppload.
Deben importarse dos paquetes JAR: Commons-FileUpload, Commons-IO
respuesta.setContentType ("text/html; charset = utf-8"); // establecer la solicitud de codificación de respuesta. PrintWriter escritor = respuesta.getWriter (); // Get de respuesta Respuesta Stream ServletInputStream InputStream = request.getInputStream (); // Obtener transmisión de entrada de solicitud/** 1. Cree un objeto diskFileItemFactory, establezca el tamaño de buffer y el directorio de archivos temporales* Hay dos constructores en esta clase, uno es un constructor sin parámetros, y el otro es un constructor de dos parámetros* SIZETHROLD, este parámetro establece el tamaño del búfer de memoria, el valor predeterminado es 10k. Cuando el archivo de carga es más grande que el tamaño del búfer, el componente FileUpload cargará el archivo utilizando la caché del archivo temporal* @param java.io.file repositorio, este parámetro especifica el directorio de archivo temporal, el valor predeterminado es system.getProperty ("java.io.tmpdir"); * * Si se usa un constructor sin parámetros, setSizethReshold (int SizethReshold), setRepository (java.io.file repositorio) * El método se establece manualmente */ diskfileitemFactory factory = new DiskFileItemFactory (); int sizethreshold = 1024*1024; Factory.setsizethreshold (sizethresshold); Repository de archivos = nuevo archivo (request.getSession (). GetServletContext (). GetRealPath ("temp")); // system.out.println (request.getSession (). GetServletContext (). GetRealpath ("temp"); // system.println (request.getRealpath ("Temp");;; factory.setRepository (repository); / * * 2. Use el objeto DiskFileItemFactory para crear un objeto ServletFileUpload y establezca el tamaño del archivo cargado * * El objeto ServletFileUpload es responsable de procesar el archivo de archivo cargado y encapsular cada elemento de entrada en el formulario en un FilEitem * Common Methods de este objeto son: * Boolean ISMultipartContent (solicitud); Determine si el formulario cargado es el tipo de multipart/formulario* Lista de lista Parserequest (solicitud); Analice el objeto de solicitud, envuelva cada elemento de entrada en el formulario en un objeto FileItem y devuelva una recopilación de listas que guarde todos los FileItems* void setFileSizeMax (Long filesizeMax); Establezca el valor máximo de un solo archivo cargado* void setSizeMax (long sizeMax); Establezca el valor máximo de la cantidad total de Wenjiang* void setheaderencoding (); Establezca el formato de codificación para resolver el problema del código confuso que carga los nombres de los archivos*/ servletfileUpload upload = new ServletFileUpload (fábrica); upload.setheaderEncoding ("UTF-8"); // Establezca el formato de codificación para resolver el problema del código de agencia de carga de los nombres de archivo/** 3. Llame al método ServletFileUpload.Parserequest para analizar el objeto de solicitud y obtener un objeto de lista que guarde todo el contenido cargado*/Listem <1Sitem> parserequest = null; intente {parserequest = upload.parserequest (request); } catch (FileUploadException e) {E.PrintStackTrace (); } / * * 4. Iterar sobre la lista. Cada iterado de un objeto FileItem, llame a su método ISFormfield para determinar si se trata de una carga de archivo* Verdadero significa que es un campo de formulario normal, luego llame a los métodos getFieldName y getTring para obtener el nombre de campo y el valor de campo* False es el archivo de archivo de carga y luego el método de la carga de la carga de la carga de la carga de la carga de la carga. de este objeto son: * boolean isformfield (); Determina si FileItem es un objeto de carga de archivo o un objeto de formulario normal * Verdadero significa que es un campo de formulario normal, * luego llame a getFieldName y se getstring métodos para obtener el nombre de campo y el valor de campo * falso como el archivo de carga, * luego llame a getName () para obtener el nombre del archivo del archivo de carga. Nota: Algunos navegadores llevan rutas de clientes y necesitan restar el método GetInputStream () para obtener el flujo de entrada de datos, para leer los datos de carga * delete (); Significa que después de cerrar la transmisión de entrada de FileItem, se eliminan los archivos temporales. */for (fileItem fileItem: parserequest) {if (fileitem.isformfield ()) {// representa el campo normal if ("username" .equals (fileitem.getFieldName ())) {string username = fileItem.getSting (); Writer.Write ("Tu nombre de usuario:"+nombre de usuario+"<br>"); } if ("userpass" .equals (fileItem.getFieldName ()))) {String UserPass = fileItem.getString (); Writer.write ("Su contraseña:"+UserPass+"<br>"); }} else {// significa un archivo cargado // Los archivos cargados por diferentes navegadores pueden tener un nombre de ruta, y debe cortar String ClientName = fileItem.getName (); Cadena filename = ""; if (clientName.Contains ("//")) {// if "/" significa un nombre con una ruta, el último nombre de archivo se interceptó filename = clientName.substring (clientName.lastIndexof ("//")). Subtring (1); } else {FileName = ClientName; } Uuid randomUuid = uuid.randomuuid (); // Generar un identificador único de 128 bits de larga global FileName = RandomUuid.ToString ()+FileName; / * * Diseñe un algoritmo de generación de directorio. Si el número total de archivos cargados por el usuario es órdenes de millones de órdenes de magnitud o más, colocarlos en el mismo directorio hace que el índice de archivos sea muy lento. * Por lo tanto, es muy necesario diseñar una estructura de directorio para almacenar archivos de manera dispersa, y razonablemente * Convertir el algoritmo hash de UUID a un rango más pequeño, * Convierta el CODEDEHCODE de la UUID en UUID en una cadena Octal de 8 bits, * comenzando a partir del primer bit de esta cadena, cada carácter representa un directorio de primer nivel, por lo que se construye un directorio de ocho niveles, con un subdirerio de 16 subdirectors en cada uno de los niveles de nivel, cada uno de los niveles de nivel. Estructura de directorio muy eficiente tanto para el servidor como para el sistema operativo*/ int hashuuid = randomUuid.hashcode (); Cadena hexuuid = integer.tohexString (Hashuuid); //System.out.println(hexuuid); // Obtenga la ruta absoluta a qué carpeta almacenar el archivo cargado en String filePath = request.getSession (). GetServletContext (). GetRealPath ("cargar"); for (char c: hexuuid.tocharArray ()) {filepath = filepath+"/"+c; } // Si el directorio no existe, genere un archivo de directorio de octavo nivel FilePathFile = nuevo archivo (FilePath); if (! FilePathFile.Exists ()) {FilePathFile.MkDirs (); } // Lea el archivo de la transmisión de entrada de solicitud y escriba en el servidor InputStream InputStream2 = FileItem.getInputStream (); // Crear un archivo en el archivo del lado del servidor = nuevo archivo (FilePath+"/"+FileName); BufferedOutputStream Bos = new BufferedOutputStream (nuevo FileOutputStream (archivo)); byte [] buffer = new Byte [10*1024]; int len = 0; while ((len = inputStream2.read (buffer, 0, 10*1024))! =-1) {bos.write (buffer, 0, len); } Writer.Write ("Subiste el archivo"+ClientName+"Exitemente <br>"); // cerrar el recurso bos.close (); inputStream2.Close (); }} // Tenga en cuenta que el archivo cargado de Eclipse se guarda en el directorio de ejecución del proyecto, no en el directorio del proyecto en el espacio de trabajo.2. Problemas que necesitan atención especial a la carga de archivos: (todos estos problemas están provistos con soluciones simples en el código anterior)
1. Dónde almacenar archivos
Para garantizar la seguridad del servidor, el archivo cargado debe guardar en el directorio web-INF de la aplicación, o en un directorio no administrado por el servidor web. Si el usuario carga un archivo con código ejecutable, como un archivo JSP, y lo accede de acuerdo con la ruta de acceso de empalme, puede hacer cualquier cosa en el lado del servidor.
2. Para evitar que varios usuarios carguen archivos con el mismo nombre de archivo, lo que resulta en la sobrescritura del archivo, el cargador de archivos debe asegurarse de que el archivo cargado tenga un nombre de archivo único .
Cambiar el nombre de usar UUID + Nombre de archivo de carga de usuario
Sobre uuid:
UUID (identificador universalmente único) El identificador único globalmente se refiere al número generado en una máquina, lo que asegura que sea exclusivo de todas las máquinas al mismo tiempo y espacio. De acuerdo con los estándares establecidos por Open Software Foundation (OSF), la dirección de la tarjeta Ethernet, el tiempo de nanosegundos, el código de identificación de chip y muchos números posibles se utilizan. Consiste en la combinación de las siguientes partes: la fecha y hora actuales (la primera parte del UUID está relacionada con el tiempo. UUID es que la cadena de resultados generada será relativamente larga.
Es un número largo de 128 bits, generalmente expresado en hexadecimal. La idea central del algoritmo es generar un GUID en combinación con la tarjeta de red de la máquina, la hora local y un número instantáneo. Teóricamente, si una máquina genera 100,000 GUID por segundo, se puede garantizar (en el sentido de probabilidad) que 3240 años no se repetirán.
A partir de JDK1.5, la generación de UUID se ha convertido en algo simple, pensando que JDK ha implementado UUID:
java.util.uuid, solo llámalo directamente.
Uuid uuid = uuid.randomuuid ();
Cadena s = uuid.randomuuid (). ToString (); // La ID de clave principal utilizada para generar la base de datos es muy buena. .
UUID se compone de un número de dieciséis dígitos, que se expresa en forma de
550E8400-E29B-11D4-A716-446655440000
3. Para evitar demasiados archivos en un solo directorio y afectar la velocidad de lectura y escritura de archivos, el programa que maneja los archivos de carga debe elegir el algoritmo de generación de estructura de directorio apropiado en función del volumen total de carga posible y almacenar los archivos cargados de manera dispersa. Por ejemplo, use el método hashcode para construir un directorio multinivel.
4. Si diferentes usuarios cargan el mismo archivo, no es necesario almacenar muchas copias del mismo archivo en el lado del servidor. Este es un desperdicio de recursos. Se debe diseñar un algoritmo para resolver el problema de los archivos duplicados.
5. El principio de tecnología JSP implementa automáticamente el hilo múltiple. Por lo tanto, los desarrolladores no necesitan considerar las operaciones de múltiples subprocesos de los archivos de carga
3. Descarga de archivos
<% ArrayList <String> FileNames = New ArrayList <String> (); filenames.add ("file/aa.txt"); filenames.add ("file/bb.jpg"); for (String FileName: FileNames) { %> <Form Action = "downloadservlet" método = "get"> <input type = "hidden" name = "filename" value = "< %= filename %>" /> <input type = "someten" value = "descargar: < %= fileNe Cadena filename = request.getParameter ("FileName"); String urlname = urlencoder.encode (nombre de archivo, "utf-8"); // prevenir la respuesta china confusión. FileInputStream fis = new FileInputStream (nuevo archivo (request.getSession (). GetServletContext (). GetRealPath (FileName))); BufferedInputStream BIS = new BufferedInputStream (FIS); ServLetOutputStream SOS = Response.getOutputStream (); byte [] buffer = new Byte [1024]; int len = 0; while ((len = bis.read (buffer, 0, 1024))! =-1) {sos.write (buffer, 0, len); } bis.close (); fis.close ();4. Utilice el componente SmartUpload en SSH para simplificar la carga y descarga de archivos
Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.