720 Stimmen

Wie kann ich mit JSP/Servlet Dateien auf einen Server hochladen?

Wie kann ich mit JSP/Servlet Dateien auf den Server hochladen?

Ich habe das ausprobiert:

<form action="upload" method="post">
    <input type="text" name="description" />
    <input type="file" name="file" />
    <input type="submit" />
</form>

Ich erhalte jedoch nur den Dateinamen, nicht den Inhalt der Datei. Wenn ich hinzufüge enctype="multipart/form-data" zum <form> entonces request.getParameter() gibt zurück. null .

Bei meinen Recherchen bin ich auf Folgendes gestoßen Apache Common FileUpload . Ich habe dies versucht:

FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List items = upload.parseRequest(request); // This line is where it died.

Leider löste das Servlet eine Ausnahme aus, ohne eine klare Meldung und Ursache. Hier ist der Stacktrace:

SEVERE: Servlet.service() for servlet UploadServlet threw exception
javax.servlet.ServletException: Servlet execution threw an exception
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:313)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:852)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
    at java.lang.Thread.run(Thread.java:637)

1259voto

BalusC Punkte 1034465

Einführung

Zum Durchsuchen und Auswählen einer Datei zum Hochladen benötigen Sie eine HTML <input type="file"> Feld des Formulars. Wie in der HTML-Spezifikation müssen Sie die POST Methode und die enctype Attribut des Formulars muss gesetzt werden auf "multipart/form-data" .

<form action="upload" method="post" enctype="multipart/form-data">
    <input type="text" name="description" />
    <input type="file" name="file" />
    <input type="submit" />
</form>

Nach dem Absenden eines solchen Formulars stehen die binären, mehrteiligen Formulardaten im Anfragekörper in ein anderes Format als wenn die enctype nicht eingestellt ist.

Vor Servlet 3.0 (Dezember 2009) unterstützte die Servlet-API nicht nativ multipart/form-data . Es unterstützt nur den Standard-Formular-Enctype von application/x-www-form-urlencoded . El request.getParameter() und Gefährtinnen würden alle zurückkehren null bei der Verwendung von mehrteiligen Formulardaten. Hier ist die bekannte Apache Commons FileUpload kam ins Spiel.

Analysieren Sie es nicht manuell!

Theoretisch können Sie den Request Body selbst analysieren, indem Sie ServletRequest#getInputStream() . Dies ist jedoch eine präzise und langwierige Arbeit, die eine genaue Kenntnis der RFC2388 . Sie sollten nicht versuchen, dies auf eigene Faust zu tun oder einen selbst erstellten, bibliothekslosen Code zu kopieren, den Sie irgendwo im Internet gefunden haben. Viele Online-Quellen, wie z. B. roseindia.net, sind hieran gescheitert. Siehe auch Hochladen einer pdf-Datei . Sie sollten lieber eine echte Bibliothek verwenden, die seit Jahren von Millionen von Nutzern verwendet (und implizit getestet!) wird. Eine solche Bibliothek hat ihre Robustheit bewiesen.

Wenn Sie bereits Servlet 3.0 oder eine neuere Version einsetzen, verwenden Sie die native API

Wenn Sie mindestens Servlet 3.0 verwenden (Tomcat 7, Jetty 9, JBoss AS 6, GlassFish 3 usw., die es bereits seit 2010 gibt), dann können Sie einfach die Standard-API verwenden, die [HttpServletRequest#getPart()](http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getParts()) um die einzelnen mehrteiligen Formulardaten zu sammeln (die meisten Servlet-3.0-Implementierungen じつに verwenden Sie Apache Commons FileUpload unter der Haube für diese!). Auch normale Formularfelder sind verfügbar durch getParameter() auf die übliche Weise.

Kommentieren Sie zunächst Ihr Servlet mit @MultipartConfig um sie erkennen und unterstützen zu lassen multipart/form-data Anfragen und erhalten somit getPart() zur Arbeit:

@WebServlet("/upload")
@MultipartConfig
public class UploadServlet extends HttpServlet {
    // ...
}

Dann implementieren Sie seine doPost() wie folgt:

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String description = request.getParameter("description"); // Retrieves <input type="text" name="description">
    Part filePart = request.getPart("file"); // Retrieves <input type="file" name="file">
    String fileName = Paths.get(filePart.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
    InputStream fileContent = filePart.getInputStream();
    // ... (do your job here)
}

Beachten Sie die Path#getFileName() . Dies ist eine MSIE-Korrektur, um den Dateinamen zu erhalten. Dieser Browser sendet fälschlicherweise den vollständigen Dateipfad zusammen mit dem Namen und nicht nur den Dateinamen.

Falls Sie mehrere Dateien hochladen möchten, entweder über multiple="true" ,

<input type="file" name="files" multiple="true" />

oder auf die altmodische Weise mit mehreren Eingängen,

<input type="file" name="files" />
<input type="file" name="files" />
<input type="file" name="files" />
...

dann können Sie sie wie folgt sammeln (leider gibt es keine solche Methode wie request.getParts("files") ):

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // ...
    List<Part> fileParts = request.getParts().stream().filter(part -> "files".equals(part.getName()) && part.getSize() > 0).collect(Collectors.toList()); // Retrieves <input type="file" name="files" multiple="true">

    for (Part filePart : fileParts) {
        String fileName = Paths.get(filePart.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
        InputStream fileContent = filePart.getInputStream();
        // ... (do your job here)
    }
}

Wenn Sie noch nicht mit Servlet 3.1 arbeiten, lassen Sie sich den Dateinamen manuell übermitteln

なお [Part#getSubmittedFileName()](https://docs.oracle.com/javaee/7/api/javax/servlet/http/Part.html#getSubmittedFileName()) wurde mit Servlet 3.1 eingeführt (Tomcat 8, Jetty 9, WildFly 8, GlassFish 4, usw. gibt es bereits seit 2013). Wenn Sie noch nicht mit Servlet 3.1 arbeiten (wirklich?), benötigen Sie eine zusätzliche Dienstprogrammmethode, um den übermittelten Dateinamen zu erhalten.

private static String getSubmittedFileName(Part part) {
    for (String cd : part.getHeader("content-disposition").split(";")) {
        if (cd.trim().startsWith("filename")) {
            String fileName = cd.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
            return fileName.substring(fileName.lastIndexOf('/') + 1).substring(fileName.lastIndexOf('\\') + 1); // MSIE fix.
        }
    }
    return null;
}

String fileName = getSubmittedFileName(filePart);

Beachten Sie die MSIE-Korrektur, um den Dateinamen zu erhalten. Dieser Browser sendet fälschlicherweise den vollständigen Dateipfad zusammen mit dem Namen und nicht nur den Dateinamen.

Wenn Sie noch nicht mit Servlet 3.0 arbeiten, verwenden Sie Apache Commons FileUpload

Wenn Sie noch nicht mit Servlet 3.0 arbeiten (ist es nicht an der Zeit, ein Upgrade vorzunehmen? es wurde vor über einem Jahrzehnt veröffentlicht! Apache Commons FileUpload zum Parsen der mehrteiligen Formulardatenanforderungen. Es hat eine ausgezeichnete Benutzerhandbuch y FAQ (gehen Sie beide sorgfältig durch). Es gibt auch die O'Reilly (" cos ") MultipartRequest , aber es hat einige (kleinere) Fehler und wird seit Jahren nicht mehr aktiv gepflegt. Ich würde nicht empfehlen, es zu benutzen. Apache Commons FileUpload wird immer noch aktiv gepflegt und ist derzeit sehr ausgereift.

Um Apache Commons FileUpload nutzen zu können, müssen Sie mindestens die folgenden Dateien in Ihrer Webapplikation haben /WEB-INF/lib :

Ihr erster Versuch scheiterte höchstwahrscheinlich, weil Sie das gemeinsame IO vergessen haben.

Hier ist ein Beispiel für den Start, wie die doPost() Ihrer UploadServlet aussehen kann, wenn Sie Apache Commons FileUpload verwenden:

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    try {
        List<FileItem> items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);
        for (FileItem item : items) {
            if (item.isFormField()) {
                // Process regular form field (input type="text|radio|checkbox|etc", select, etc).
                String fieldName = item.getFieldName();
                String fieldValue = item.getString();
                // ... (do your job here)
            } else {
                // Process form file field (input type="file").
                String fieldName = item.getFieldName();
                String fileName = FilenameUtils.getName(item.getName());
                InputStream fileContent = item.getInputStream();
                // ... (do your job here)
            }
        }
    } catch (FileUploadException e) {
        throw new ServletException("Cannot parse multipart request.", e);
    }

    // ...
}

Es ist sehr wichtig, dass Sie nicht anrufen getParameter() , getParameterMap() , getParameterValues() , getInputStream() , getReader() usw. auf die gleiche Anfrage im Voraus. Andernfalls wird der Servlet-Container den Request-Body lesen und parsen und Apache Commons FileUpload erhält einen leeren Request-Body. Siehe auch a.o. ServletFileUpload#parseRequest(request) gibt eine leere Liste zurück .

Beachten Sie die FilenameUtils#getName() . Dies ist eine MSIE-Korrektur, um den Dateinamen zu erhalten. Dieser Browser sendet fälschlicherweise den vollständigen Dateipfad zusammen mit dem Namen und nicht nur den Dateinamen.

Alternativ können Sie das Ganze auch in eine Filter die alles automatisch parst und in die Parametermap der Anfrage zurückstellt, so dass Sie weiterhin mit request.getParameter() auf die übliche Weise und rufen Sie die hochgeladene Datei über request.getAttribute() . Ein Beispiel finden Sie in diesem Blog-Artikel .

Abhilfe für GlassFish3-Bug von getParameter() immer noch zurückkehrend null

Beachten Sie, dass Glassfish-Versionen älter als 3.1.2 über eine Wanze wobei die getParameter() kehrt immer noch zurück null . Wenn Sie einen solchen Container anvisieren und ihn nicht aktualisieren können, müssen Sie den Wert aus getPart() mit Hilfe dieser Utility-Methode:

private static String getValue(Part part) throws IOException {
    BufferedReader reader = new BufferedReader(new InputStreamReader(part.getInputStream(), "UTF-8"));
    StringBuilder value = new StringBuilder();
    char[] buffer = new char[1024];
    for (int length = 0; (length = reader.read(buffer)) > 0;) {
        value.append(buffer, 0, length);
    }
    return value.toString();
}

String description = getValue(request.getPart("description")); // Retrieves <input type="text" name="description">

Speichern der hochgeladenen Datei (nicht mit getRealPath() noch part.write() !)

In den folgenden Antworten finden Sie ausführliche Informationen zum richtigen Speichern der erhaltenen Daten InputStream (die fileContent wie in den obigen Codeschnipseln gezeigt) auf die Festplatte oder in die Datenbank:

Hochgeladene Datei servieren

In den folgenden Antworten erfahren Sie, wie Sie die gespeicherte Datei von der Festplatte oder aus der Datenbank wieder an den Client übergeben:

Ajaxifizierung des Formulars

Lesen Sie in den folgenden Antworten, wie Sie mit Ajax (und jQuery) hochladen können. Bitte beachten Sie, dass der Servlet-Code zum Sammeln der Formulardaten dafür nicht geändert werden muss! Lediglich die Art und Weise, wie Sie antworten, muss geändert werden, aber das ist ziemlich trivial (d.h. anstatt an JSP weiterzuleiten, drucken Sie einfach etwas JSON oder XML oder sogar reinen Text aus, je nachdem, was das für den Ajax-Aufruf zuständige Skript erwartet).


Ich hoffe, das alles hilft :)

26voto

Amila Punkte 5125

Wenn Sie zufällig Spring MVC So geht's (ich lasse es hier, falls es jemand nützlich findet):

Verwenden Sie ein Formular mit enctype Attribut gesetzt auf " multipart/form-data " (gleichbedeutend mit BalusC's Antwort ):

<form action="upload" method="post" enctype="multipart/form-data">
    <input type="file" name="file" />
    <input type="submit" value="Upload"/>
</form>

Ordnen Sie in Ihrem Controller den Anfrageparameter file à MultipartFile Typ wie folgt:

@RequestMapping(value = "/upload", method = RequestMethod.POST)
public void handleUpload(@RequestParam("file") MultipartFile file) throws IOException {
    if (!file.isEmpty()) {
            byte[] bytes = file.getBytes(); // alternatively, file.getInputStream();
            // application logic
    }
}

Sie können den Dateinamen und die Größe mit MultipartFile 's getOriginalFilename() y getSize() .

Ich habe dies mit der Spring-Version getestet 4.1.1.RELEASE .

12voto

joseluisbz Punkte 2580

Ohne Komponenten oder externe Bibliotheken in Tomcat 6 oder Tomcat 7

Aktivieren des Hochladens in der web.xml Datei:

Manuelle Installation von PHP, Tomcat und Httpd Lounge .

<servlet>
    <servlet-name>jsp</servlet-name>
    <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
    <multipart-config>
      <max-file-size>3145728</max-file-size>
      <max-request-size>5242880</max-request-size>
    </multipart-config>
    <init-param>
        <param-name>fork</param-name>
        <param-value>false</param-value>
    </init-param>
    <init-param>
        <param-name>xpoweredBy</param-name>
        <param-value>false</param-value>
    </init-param>
    <load-on-startup>3</load-on-startup>
</servlet>

Wie Sie sehen können :

<multipart-config>
  <max-file-size>3145728</max-file-size>
  <max-request-size>5242880</max-request-size>
</multipart-config>

Hochladen von Dateien mit JSP. Dateien:

In der HTML-Datei

<form method="post" enctype="multipart/form-data" name="Form" >

  <input type="file" name="fFoto" id="fFoto" value="" /></td>
  <input type="file" name="fResumen" id="fResumen" value=""/>

In der JSP-Datei o Servlet

InputStream isFoto = request.getPart("fFoto").getInputStream();
InputStream isResu = request.getPart("fResumen").getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte buf[] = new byte[8192];
int qt = 0;
while ((qt = isResu.read(buf)) != -1) {
  baos.write(buf, 0, qt);
}
String sResumen = baos.toString();

Bearbeiten Sie Ihren Code entsprechend den Servlet-Anforderungen, z. B. max-file-size , max-request-size und andere Optionen, die Sie einstellen können...

11voto

Pranav Punkte 227

Sie benötigen die common-io.1.4.jar Datei, die in Ihre lib Verzeichnis, oder wenn Sie in einem beliebigen Editor wie NetBeans arbeiten, dann müssen Sie zu den Projekteigenschaften gehen und einfach die JAR-Datei hinzufügen und schon sind Sie fertig.

Um die common.io.jar Datei einfach googeln oder zum Apache gehen Tomcat Website, wo Sie die Möglichkeit haben, diese Datei kostenlos herunterzuladen. Aber denken Sie an eines: Laden Sie die binäre ZIP-Datei herunter, wenn Sie ein Windows-Benutzer sind.

9voto

Nagappa L M Punkte 1330

Ich verwende ein gewöhnliches Servlet für jede HTML-Formular, unabhängig davon, ob es Anhänge enthält oder nicht.

Dieses Servlet gibt ein TreeMap wobei die Schlüssel JSP-Namensparameter und die Werte Benutzereingaben sind, und speichert alle Anhänge in einem festen Verzeichnis, das Sie später in ein Verzeichnis Ihrer Wahl umbenennen. Hier Verbindungen ist unsere benutzerdefinierte Schnittstelle mit einem Verbindungsobjekt.

public class ServletCommonfunctions extends HttpServlet implements
        Connections {

    private static final long serialVersionUID = 1L;

    public ServletCommonfunctions() {}

    protected void doPost(HttpServletRequest request,
                          HttpServletResponse response) throws ServletException,
                          IOException {}

    public SortedMap<String, String> savefilesindirectory(
            HttpServletRequest request, HttpServletResponse response)
            throws IOException {

        // Map<String, String> key_values = Collections.synchronizedMap(new
        // TreeMap<String, String>());
        SortedMap<String, String> key_values = new TreeMap<String, String>();
        String dist = null, fact = null;
        PrintWriter out = response.getWriter();
        File file;
        String filePath = "E:\\FSPATH1\\2KL06CS048\\";
        System.out.println("Directory Created   ????????????"
            + new File(filePath).mkdir());
        int maxFileSize = 5000 * 1024;
        int maxMemSize = 5000 * 1024;

        // Verify the content type
        String contentType = request.getContentType();
        if ((contentType.indexOf("multipart/form-data") >= 0)) {
            DiskFileItemFactory factory = new DiskFileItemFactory();
            // Maximum size that will be stored in memory
            factory.setSizeThreshold(maxMemSize);
            // Location to save data that is larger than maxMemSize.
            factory.setRepository(new File(filePath));
            // Create a new file upload handler
            ServletFileUpload upload = new ServletFileUpload(factory);
            // maximum file size to be uploaded.
            upload.setSizeMax(maxFileSize);
            try {
                // Parse the request to get file items.
                @SuppressWarnings("unchecked")
                List<FileItem> fileItems = upload.parseRequest(request);
                // Process the uploaded file items
                Iterator<FileItem> i = fileItems.iterator();
                while (i.hasNext()) {
                    FileItem fi = (FileItem) i.next();
                    if (!fi.isFormField()) {
                        // Get the uploaded file parameters
                        String fileName = fi.getName();
                        // Write the file
                        if (fileName.lastIndexOf("\\") >= 0) {
                            file = new File(filePath
                                + fileName.substring(fileName
                                        .lastIndexOf("\\")));
                        } else {
                            file = new File(filePath
                                + fileName.substring(fileName
                                        .lastIndexOf("\\") + 1));
                        }
                        fi.write(file);
                    } else {
                        key_values.put(fi.getFieldName(), fi.getString());
                    }
                }
            } catch (Exception ex) {
                System.out.println(ex);
            }
        }
        return key_values;
    }
}

2 Stimmen

Wenn Sie einen Code schreiben, um ein Verzeichnis im Servlet zu erstellen, wird das Verzeichnis im Live-Server erstellt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X