it-swarm.com.de

Wie lade ich Dateien mit JSP / Servlet auf den Server hoch?

Wie kann ich Dateien mit JSP/Servlet auf den Server hochladen? Ich habe es versucht:

<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 Dateiinhalt. Wenn ich enctype="multipart/form-data" zum <form> hinzufüge, gibt request.getParameter()null zurück.

Während der Recherche bin ich auf Apache Common FileUpload gestoßen. Ich habe es versucht:

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

Leider hat das Servlet eine Ausnahme ohne eindeutige Meldung und Ursache ausgelöst. 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)
668
Thang Pham

Einführung

Zum Durchsuchen und Auswählen einer Datei zum Hochladen benötigen Sie ein HTML _<input type="file">_ -Feld im Formular. Wie in der HTML-Spezifikation angegeben, müssen Sie die POST -Methode verwenden und das enctype -Attribut des Formulars auf _"multipart/form-data"_ setzen.

_<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 sind die binären mehrteiligen Formulardaten im Anforderungshauptteil in einem anderen Format verfügbar, als wenn enctype nicht festgelegt ist.

Vor Servlet 3.0 hat die Servlet-API _multipart/form-data_ nativ nicht unterstützt. Es wird nur der Standardformularextyp _application/x-www-form-urlencoded_ unterstützt. Die request.getParameter() und die consorts würden alle null zurückgeben, wenn sie mehrteilige Formulardaten verwenden. Hier kam das bekannte Apache Commons FileUpload ins Spiel.

Parsen Sie es nicht manuell!

Theoretisch können Sie den Anfragetext selbst anhand von ServletRequest#getInputStream() analysieren. Dies ist jedoch eine präzise und langwierige Arbeit, die genaue Kenntnisse von RFC2388 erfordert. Versuchen Sie nicht, dies alleine zu tun, und kopieren Sie keinen selbst erstellten bibliothekslosen Code, der an anderer Stelle im Internet zu finden ist. Viele Online-Quellen, wie zum Beispiel roseindia.net, sind schwer gescheitert. Siehe auch Hochladen der PDF-Datei . Sie sollten lieber eine echte Bibliothek verwenden, die von Millionen von Benutzern seit Jahren verwendet (und implizit getestet!) Wird. Eine solche Bibliothek hat sich als robust erwiesen.

Wenn Sie bereits mit Servlet 3.0 oder neuer arbeiten, verwenden Sie die native API

Wenn Sie mindestens Servlet 3.0 (Tomcat 7, Jetty 9, JBoss AS 6, GlassFish 3 usw.) verwenden, können Sie einfach die mitgelieferte Standard-API verwenden HttpServletRequest#getPart() , um die einzelnen mehrteiligen Formulardatenelemente zu erfassen (Die meisten Servlet 3.0-Implementierungen verwenden dafür Apache Commons FileUpload unter der Decke!). Normale Formularfelder sind auch über getParameter() auf die übliche Weise verfügbar.

Kommentieren Sie Ihr Servlet zuerst mit @MultipartConfig , damit es _multipart/form-data_ -Anfragen erkennt und unterstützt und damit getPart() zum Laufen bringt:

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

Implementieren Sie dann 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 ein MSIE-Fix zum Abrufen des Dateinamens. Dieser Browser sendet fälschlicherweise den vollständigen Dateipfad entlang des Namens anstatt nur des Dateinamens.

Falls Sie einen _<input type="file" name="file" multiple="true" />_ für das Hochladen mehrerer Dateien haben, sammeln Sie diese wie folgt (leider gibt es keine Methode wie request.getParts("file")):

_protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // ...
    List<Part> fileParts = request.getParts().stream().filter(part -> "file".equals(part.getName())).collect(Collectors.toList()); // Retrieves <input type="file" name="file" 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, rufen Sie den übergebenen Dateinamen manuell ab

Beachten Sie, dass Part#getSubmittedFileName() in Servlet 3.1 eingeführt wurde (Tomcat 8, Jetty 9, WildFly 8, GlassFish 4 usw.). Wenn Sie noch nicht mit Servlet 3.1 arbeiten, benötigen Sie eine zusätzliche Dienstprogrammmethode, um den übergebenen Dateinamen abzurufen.

_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 das MSIE-Update, um den Dateinamen zu erhalten. Dieser Browser sendet fälschlicherweise den vollständigen Dateipfad entlang des Namens anstatt nur des Dateinamens.

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 durchzuführen?), Verwenden Sie normalerweise Apache Commons FileUpload , um die mehrteiligen Formulardatenanforderungen zu analysieren. Es hat eine ausgezeichnete ser Guide und FAQ (sorgfältig durch beide gehen). Es gibt auch den O'Reilly (" cos ") MultipartRequest, aber er hat einige (kleinere) Fehler und wird seit Jahren nicht mehr aktiv gewartet. Ich würde es nicht empfehlen. Apache Commons FileUpload ist immer noch aktiv gepflegt und derzeit sehr ausgereift.

Um Apache Commons FileUpload verwenden zu können, müssen mindestens die folgenden Dateien in der Webanwendung _/WEB-INF/lib_ enthalten sein:

Ihr erster Versuch ist höchstwahrscheinlich fehlgeschlagen, weil Sie die Commons-E/A vergessen haben.

Hier ist ein Kickoff-Beispiel, wie die doPost() Ihres UploadServlet bei Verwendung von Apache Commons FileUpload aussehen kann:

_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 getParameter(), getParameterMap(), getParameterValues(), getInputStream(), getReader() usw. nicht vorher auf dieselbe Anfrage anrufen. Andernfalls liest und analysiert der Servlet-Container den Anforderungshauptteil und Apache Commons FileUpload erhält einen leeren Anforderungshauptteil. Siehe auch a.o. ServletFileUpload # parseRequest (request) gibt eine leere Liste zurück .

Beachten Sie die FilenameUtils#getName(). Dies ist ein MSIE-Fix zum Abrufen des Dateinamens. Dieser Browser sendet fälschlicherweise den vollständigen Dateipfad entlang des Namens anstatt nur des Dateinamens.

Alternativ können Sie dies alles auch in ein Filter packen, das alles automatisch analysiert und das Zeug wieder in das Parametermap der Anfrage einfügt, so dass Sie request.getParameter() auf die übliche Weise weiter verwenden und die hochgeladene Datei von request.getAttribute() abrufen können. Ein Beispiel finden Sie in diesem Blog-Artikel .

Problemumgehung für GlassFish3-Fehler von getParameter(), der immer noch null zurückgibt

Beachten Sie, dass Glassfish-Versionen älter als 3.1.2 einen Fehler hatten, wobei die getParameter() immer noch null zurückgibt. Wenn Sie auf einen solchen Container abzielen und diesen nicht aktualisieren können, müssen Sie den Wert mit Hilfe dieser Dienstprogrammmethode aus getPart() extrahieren:

_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">
_

Hochgeladene Datei wird gespeichert (verwenden Sie weder getRealPath() noch part.write()!)

Lesen Sie die folgenden Antworten, um Einzelheiten zum ordnungsgemäßen Speichern der erhaltenen InputStream -Variable (die fileContent -Variable, wie in den obigen Codefragmenten gezeigt) auf der Festplatte oder in der Datenbank zu erfahren:

Hochgeladene Datei wird bereitgestellt

In den folgenden Antworten erfahren Sie, wie Sie die gespeicherte Datei von der Festplatte oder Datenbank ordnungsgemäß an den Client zurückschicken können:

Ajaxifying das Formular

Gehen Sie zu den folgenden Antworten, wie Sie mit Ajax (und jQuery) hochladen. Beachten Sie, dass der Servlet-Code zur Erfassung der Formulardaten hierfür nicht geändert werden muss! Nur die Art und Weise, wie Sie reagieren, kann geändert werden, dies ist jedoch eher trivial (d. H. Anstatt an JSP weiterzuleiten, drucken Sie einfach etwas JSON oder XML oder sogar einfachen Text, je nachdem, was das für den Ajax-Aufruf verantwortliche Skript erwartet).


Hoffe das alles hilft :)

1151
BalusC

Wenn Sie Spring MVC verwenden, gehen Sie folgendermaßen vor: (Ich lasse dies hier, falls jemand es nützlich findet.).

Verwenden Sie ein Formular mit dem Attribut enctype "multipart/form-data" (wie die Antwort von BalusC).

<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 Anforderungsparameter file dem Typ MultipartFile wie folgt zu:

@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 MultipartFiles getOriginalFilename() und getSize() ermitteln.

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

25
Amila

Sie müssen die common-io.1.4.jar -Datei in Ihr lib -Verzeichnis aufnehmen, oder wenn Sie in einem Editor wie NetBeans arbeiten, müssen Sie zu den Projekteigenschaften gehen und einfach die JAR-Datei und Sie hinzufügen getan werden.

Um die common.io.jar -Datei zu erhalten, googeln Sie sie einfach oder gehen Sie auf die Apache Tomcat - Website, wo Sie die Option zum kostenlosen Download dieser Datei erhalten. Beachten Sie jedoch Folgendes: Laden Sie die binäre Zip-Datei herunter, wenn Sie Windows verwenden.

12
Pranav

Ich verwende allgemeines Servlet für jedes HTML-Formular, ob es Anhänge hat oder nicht. Dieses Servlet gibt ein TreeMap zurück, wobei die Schlüssel jsp name sind. Parameter und Werte sind Benutzereingaben und speichern alle Anhänge in einem festen Verzeichnis. Später benennen Sie das Verzeichnis Ihrer Wahl um. Ich denke, das wird dir helfen

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;
    }
}

Für Spring MVC Ich habe stundenlang versucht, dies zu tun, und es ist mir gelungen, eine einfachere Version zu haben, die sowohl für die Formulareingabe als auch für die Bildeingabe geeignet ist.

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

Controller zu handhaben

@Controller
public class FormController {
    @RequestMapping(value="/handleform",method= RequestMethod.POST)
    ModelAndView register(@RequestParam String name, @RequestParam int age, @RequestParam MultipartFile file)
            throws ServletException, IOException {

        System.out.println(name);
        System.out.println(age);
        if(!file.isEmpty()){
            byte[] bytes = file.getBytes();
            String filename = file.getOriginalFilename();
            BufferedOutputStream stream =new BufferedOutputStream(new FileOutputStream(new File("D:/" + filename)));
            stream.write(bytes);
            stream.flush();
            stream.close();
        }
        return new ModelAndView("index");
    }
}

Ich hoffe es hilft :)

8
Shivangi Gupta

Ohne Komponente oder externe Bibliothek in Tomcat 6 oder 7

Aktivieren des Uploads in der Datei web.xml :

http://joseluisbz.wordpress.com/2014/01/17/manually-installing-php-Tomcat-and-httpd-lounge/#Enabling%20File%20Uploads .

<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 oder 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 gemäß den Servlet-Anforderungen, z. B. Maximale Dateigröße , Maximale Anforderungsgröße und andere Optionen, die Sie verwenden können einstellen...

8
chepe lucho

Eine weitere Ursache für dieses Problem liegt vor, wenn Sie Geronimo mit seinem eingebetteten Tomcat verwenden. In diesem Fall tritt das Problem nach vielen Iterationen des Testens von commons-io und commons-fileupload auf, wenn ein übergeordneter Klassenladeprogramm die commons-xxx-Jars verarbeitet. Dies muss verhindert werden. Der Absturz ereignete sich immer um:

fileItems = uploader.parseRequest(request);

Beachten Sie, dass sich der Listentyp von fileItems mit der aktuellen Version von commons-fileupload geändert hat, um spezifisch List<FileItem> zu sein, im Gegensatz zu früheren Versionen, in denen es generisch List war.

Ich habe den Quellcode für commons-fileupload und commons-io in mein Eclipse-Projekt eingefügt, um den tatsächlichen Fehler zu verfolgen, und habe schließlich einen Einblick erhalten. Erstens ist die geworfene Ausnahme vom Typ Throwable, nicht die angegebene FileIOException oder gar Exception (diese wird nicht abgefangen). Zweitens ist die Fehlermeldung dahingehend verschleiert, dass sie angibt, dass die Klasse nicht gefunden wurde, da axis2 commons-io nicht finden konnte. Axis2 wird in meinem Projekt überhaupt nicht verwendet, ist jedoch im Rahmen der Standardinstallation als Ordner im Geronimo-Repository-Unterverzeichnis vorhanden.

Schließlich fand ich einen Ort, der eine funktionierende Lösung darstellte, die mein Problem erfolgreich löste. Sie müssen die JAR-Dateien im Bereitstellungsplan vor dem übergeordneten Loader verbergen. Dies wurde in geronimo-web.xml mit meiner vollständigen Datei unten gezeigt.

Pasted from <http://osdir.com/ml/user-geronimo-Apache/2011-03/msg00026.html> 



<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<web:web-app xmlns:app="http://geronimo.Apache.org/xml/ns/j2ee/application-2.0" xmlns:client="http://geronimo.Apache.org/xml/ns/j2ee/application-client-2.0" xmlns:conn="http://geronimo.Apache.org/xml/ns/j2ee/connector-1.2" xmlns:dep="http://geronimo.Apache.org/xml/ns/deployment-1.2" xmlns:ejb="http://openejb.Apache.org/xml/ns/openejb-jar-2.2" xmlns:log="http://geronimo.Apache.org/xml/ns/loginconfig-2.0" xmlns:name="http://geronimo.Apache.org/xml/ns/naming-1.2" xmlns:pers="http://Java.Sun.com/xml/ns/persistence" xmlns:pkgen="http://openejb.Apache.org/xml/ns/pkgen-2.1" xmlns:sec="http://geronimo.Apache.org/xml/ns/security-2.0" xmlns:web="http://geronimo.Apache.org/xml/ns/j2ee/web-2.0.1">
    <dep:environment>
        <dep:moduleId>
            <dep:groupId>DataStar</dep:groupId>
            <dep:artifactId>DataStar</dep:artifactId>
            <dep:version>1.0</dep:version>
            <dep:type>car</dep:type>
        </dep:moduleId>

<!--Don't load commons-io or fileupload from parent classloaders-->
        <dep:hidden-classes>
            <dep:filter>org.Apache.commons.io</dep:filter>
            <dep:filter>org.Apache.commons.fileupload</dep:filter>
        </dep:hidden-classes>
        <dep:inverse-classloading/>        


    </dep:environment>
    <web:context-root>/DataStar</web:context-root>
</web:web-app>
6

Hier ist ein Beispiel mit Apache commons-fileupload:

// Apache commons-fileupload to handle file upload
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setRepository(new File(DataSources.TORRENTS_DIR()));
ServletFileUpload fileUpload = new ServletFileUpload(factory);

List<FileItem> items = fileUpload.parseRequest(req.raw());
FileItem item = items.stream()
  .filter(e ->
  "the_upload_name".equals(e.getFieldName()))
  .findFirst().get();
String fileName = item.getName();

item.write(new File(dir, fileName));
log.info(fileName);
0
thouliha