Fileuploader - ładowanie plików na serwer po HTTP Email

Darmowy program Fileuploader napisany w JavaFX, dzięki któremu można ładować pliki na serwer bez potrzeby przeładowywania strony. Współpracuje praktycznie z każdą technologią webową (jsp, php itp). Posiada pasek postępu oraz wysyła komunikaty o stanach transferu poprzez funkcje JavaScript. Umożliwia ładowanie plików o dużych rozmiarach (dzieli plik na części). Rygory bezpieczeństwa utrzymuje się po stronie serwera - zwiększa to poziom bezpieczeństwa (program bez odpowiednich skryptów na serwerze jest bezużyteczny).

Program jest bardzo łatwy w użyciu i konfiguracji.

 

Ładowanie pliku na serwer

 

Licencja:

Aplikację można wykorzystywać i rozpowszechniać bez ograniczeń!
Aplikacja zawiera obcy kod algorytmu Base64 dostępny na stronie http://iharder.net/base64.

Pobierz program:

Download 20091201
zmiany:
dołożona obsługa parametru specialData - przekazywanie treści z aplikacji (poprzez plik JNLP) do wyzwalaczy oraz serwera.

Starsze wersje:
Download 20091128

 

Zapraszam do zaglądania na tą stronę. W przyszłości umieszczę na niej skrypt w PHP oraz demo aplikacji.

 

Sposób użycia.

1. Instalacja aplikacji wewnątrz kodu HTML.

Aby Uploader był widoczny na stronie należy wewnątrz kodu HTML umieścić poniższy skrypt:

<script src="http://dl.javafx.com/1.2/dtfx.js"></script>
<script>
    javafx(
        {
              archive: "Uploader.jar",
              draggable: true,
              width: 255,
              height: 65,
              code: "com.j_ch.app.uploader.Main",
              name: "Uploader"
        }
    );
</script>

Argument archive wskazuje na aplikację (Uploader.jar). Może być to dowolna ścieżka HTTP. Należy także pamiętać o umieszczeniu aplikacji czyli pliku Uploader.jar w odpowiednim katalogu.

 

Wyzwalacze - funkcje JavaScript  wywoływane w kluczowych momentach transferu pliku na serwer - umieszcza się wewnątrz tego samego kodu HTML i powinny mieć postać jak poniżej:

/**
 * Transfer zakończony sukcesem
 * @param jfxuFileName Nazwa pliku
 * @param jfxuFileSize Rozmiar pliku w bajtach
 * @param jfxuUniqKey Unikatowy kod otrzymany z serwera
 * @param specialData Dane przekazane do uploadera
 */
function jfxuSuccess(jfxuFileName, jfxuFileSize, jfxuUniqKey, specialData) { }


/**
 * Transfer został przerwany
 * @param jfxuFileName Nazwa pliku
 * @param jfxuFileSize Rozmiar pliku w bajtach
 * @param jfxuUniqKey Unikatowy kod otrzymany z serwera
 * @param specialData Dane przekazane do uploadera
 */
function jfxuStop(jfxuFileName, jfxuFileSize, jfxuUniqKey, specialData) { }


/**
 * Rozpoczęcie transferu
 * @param jfxuFileName Nazwa pliku
 * @param jfxuFileSize Rozmiar pliku w bajtach
 * @param jfxuUniqKey Unikatowy kod otrzymany z serwera
 * @param specialData Dane przekazane do uploadera
*/
function jfxuStart(jfxuFileName, jfxuFileSize, jfxuUniqKey, specialData) { }


/**
 * Wybrano plik do przesłania
 * @param jfxuFileName Nazwa pliku
 * @param jfxuFileSize Rozmiar pliku w bajtach
 * @param jfxuUniqKey Unikatowy kod otrzymany z serwera
 * @param specialData Dane przekazane do uploadera
 */
function jfxuSelect(jfxuFileName, jfxuFileSize, jfxuUniqKey, specialData) { }

 Opis funkcj JS:

  • jfxuSuccess - gdy transfer zakończy się sukcesem,
  • jfxuStop - gdy transmisja zostanie przerwana przez użytkownika (poprzez kliknięcie na STOP podczas transmisji pliku),
  • jfxuStart - aplikacja rozpoczyna transmisję pliku,
  • jfxuSelect - wybrano plik do przesłania (serwer zaakceptował plik).
Nie ma potrzeby definiowania wszystkich funkcji JavaScript. Można całkowicie pominąć ten etap jeżeli nie podamy nazw funkcji w pliku konfiguracyjnym. Aplikacja wywoła tylko funkcje zdefiniowane. Nazwy funkcji mogą być inne niż te pokazane wyżej, należy tylko pamiętać żeby określić ich prawidłowe nazwy w pliku konfiguracyjnym.

2. Konfiguracja aplikacji.

Tutaj przyda się trochę wiedzy o JavaFX. Ja umieściłem konfigurację w pliku Uploader_browser.jnlp ale można umieścić ją w skrypcie wywołującym aplet. Plik Uploader_browser.jnlp jest wymagany do uruchomienia aplikacji. Dla ułatwienia należy go umieścić w tym samym miejscu co plik z aplikacją czyli Uploader.jar.

<?xml version="1.0" encoding="UTF-8"?>
<jnlp spec="1.0+" codebase="http://localhost:8082/servlet/org.netbeans.modules.javafx.project.JnlpDownloadServlet/D%3A/moje_projekty/JavaFX/Uploader/dist/" href="/Uploader_browser.jnlp">
    <information>
        <title>Uploader</title>
        <vendor>Jacek Chojnacki - Adres poczty elektronicznej jest chroniony przed robotami spamującymi. W przeglądarce musi być włączona obsługa JavaScript, żeby go zobaczyć. </vendor>
        <homepage href="/index.php/myprojects/fileuploader.html"/>
        <description>Uploader</description>
        <offline-allowed/>
        <shortcut>
            <desktop/>
        </shortcut>
    </information>
    <security>
        <all-permissions/>
    </security>
    <resources>
        <j2se version="1.5+"/>
        <extension name="JavaFX Runtime" href="http://dl.javafx.com/1.2/javafx-rt.jnlp"/>
        <jar href="/Uploader.jar" main="true"/>
    </resources>
    <applet-desc name="Uploader" main-class="com.sun.javafx.runtime.adapter.Applet" width="255" height="65">
        <param name="MainJavaFXScript" value="com.j_ch.app.uploader.Main"/>
        <param name="baseUrl" value="http://localhost:8080/WebBase/uploader.htm"/>
        <param name="buferSize" value="512"/>
        <param name="jsFuncSuccess" value="jfxuSuccess"/>
        <param name="jsFuncStop" value="jfxuStop"/>
        <param name="jsFuncStart" value="jfxuStart"/>
        <param name="jsFuncSelect" value="jfxuSelect"/>
        <param name="specialData" value="Test danych w parametrze: specialData"/>
    </applet-desc>
    <update check="background">
</jnlp>

Tutaj należy zwrócić uwagę na poszczególne tagi i argumenty:

  • tag jnlp argument codebase - należy zmodyfikować według własnych potrzeb czyli wskazać adres do katalogu, w którym znajduje się plik Uploader_browser.jnlp,
  • tag resources / jar - href musi wskazywać na aplikację (Uploader.jar) - jeżeli aplikacja nie znajduje się w tym samym miejscu co plik Uploader_browser.jnlp należy podać ścieżkę do pliku Uploader.jar,
  • tag applet-desc / param parametr baseUrl - value musi zawierać ścieżkę do skryptu, który ma obsłużyć transfer danych po stronie serwera (skrypt php, jsp lub inny),
  • tag applet-desc / param parametr buferSize - value musi zawierać wielkość pojedynczej paczki przesyłanej na serwer w bajtach jako HTTP / POST,
  • tag applet-desc / param parametry jsFuncSuccess, jsFuncStop, jsFuncStart, jsFuncSelect (NIE SĄ WYMAGANE) - poszczególne value powinny zawierać dowolne nazwy funkcji JavaScript (patrz na pt 1 wyzwalacze),
  • tag applet-desc / param parametr specialData (NIE JEST WYMAGANY) - value może zawierać dowolną wartość przekazywaną do serwera oraz wyzwalaczy.

3. Skrypt po stronie serwera.

Można wykorzystać dowolny serwer HTTP taki jak: Apache, Tomcat, GlassFish, JBoss i inne. Poniższy przykład przedstawia kod JSP, który wykorzystuję na serwerze Tomcat 6.0.

<%@page contentType="text/html" pageEncoding="UTF-8" import="java.io.*"%><%
int LIMIT_FILE_SIZE_B = 2*1024*1024; // 1M - maksymalny rozmiar pliku
// -- przesyłane dane --
String jfxuOperation =    request.getParameter("jfxuOperation"),
        jfxuSpecialData =    request.getParameter("jfxuSpecialData"), // wartość z uploadera do wyzwalaczy oraz serwera - definiowana w pliku JNLP
        jfxuFileName =   request.getParameter("jfxuFileName"),
        jfxuFileSize =   request.getParameter("jfxuFileSize"),
        jfxuUniqKey =   request.getParameter("jfxuUniqKey"),
        jfxuStatus =    request.getParameter("jfxuStatus"),
        jfxuOffset =    request.getParameter("jfxuOffset"),
        jfxuData =       request.getParameter("jfxuData"),
        d_time =        request.getParameter("d_time");
// -- czy komunikacja z uploaderem --
if(jfxuOperation==null) {
    out.print("false");
    return;
}
// -- poszczególne operacje --
if(jfxuOperation.equals("checkFile")) {
    long fileSize = Long.valueOf(jfxuFileSize);
    if(fileSize>LIMIT_FILE_SIZE_B||!jfxuFileName.endsWith("pdf")) {
        out.print("false;Za duży rozmiar lub niedozwolone rozszerzenie pliku!");
        return;
    }
    out.print("true;"+(new java.util.Date().getTime()));
    return;
}
// -- transmisja danych --
if(jfxuOperation.equals("dataFile")&&jfxuData!=null) {
    byte [] bytes = com.j_ch.utils.Base64.decode(jfxuData,com.j_ch.utils.Base64.URL_SAFE);
    File file = new File("D:\\\\"+jfxuFileName);
    // -- status paczki --
    if(jfxuStatus.equals("begin")) { // pierwsza paczka
        if(file.isFile()) file.delete();
    } else if(jfxuStatus.equals("progress")) { // kolejna paczka
    } else if(jfxuStatus.equals("end")) { } // ostatnia paczka
    // -- zapis pliku na serwerze --
    OutputStream os = new FileOutputStream(file,true);
    try {
        os.write(bytes);
    } catch(Exception e) {
        out.print("false;jfxuOffset:"+jfxuOffset+" ["+e+"]");
        os.close();
        return;
    }
    os.close();
    out.print("true");
    return;
}
// -- transmisja przerwana --
if(jfxuOperation.equals("stop")) {
    File file = new File("D:\\\\"+jfxuFileName);
    // -- sprzątanie --
    if(file.isFile()) file.delete();
}
%>

 Parametry przekazywane z uploader:

  • jfxuOperation - operacje (checkFile - sprawdź plik, dataFile - zapisuj dane, stop - operacja przerwana),
  • jfxuFileName - nazwa pliku,
  • jfxuFileSize - rozmiar pliku w bajtach,
  • jfxuUniqKey - unikatowy kod wygenerowany i przekazany do Uploadera podczas sprawdzania pliku (jfxuOperation / checkFile),
  • jfxuStatus - status występujący podczas transmisji pliku (jfxuOperation / dataFile) i może mieć postać: begin - pierwsza paczka, progress - kolejna paczka oraz end - ostatnia paczka;
  • jfxuOffset - numer kolejny paczki występuje podczas transmisji pliku (jfxuOperation / dataFile),
  • jfxuData - paczka (fragment pliku) zakodowany algorytmem Base64 z opcją URL_SAFE przeznaczona do zapisu,
  • d_time - czas wysłania z Uploadera.
Logikę przechwytywania pliku można wywnioskować z powyższego kodu. Warto mieć na uwadze, żeby wygenerować odpowiedni unikatowy kod podczas sprawdzania pliku i przesłać go do Uploadera. Poszczególne paczki rozkodowywać Base64 i dopisywać do pliku. Autoryzacja może być zaszyta w sesji, w ciasteczkach lub w unikatowym kluczu. Odpowiedzi do Uploadera rozdzielać średnikiem: czy operacja zakończyła się sukcesem (true / false); wiadomość zwrotna (opis błędu lub w przypadku pozytywnego sprawdzenia pliku unikatowy klucz).
Jeżeli ktoś ma problem ze zrozumieniem kodu lub opisu, a chciałby napisać skrypt np w PHP to zapraszam do zadawania pytań. Adres e-mail w zakładce KONTAKT.

 

Schemat komunikacji Klient - Serwer

 

Zmieniony: Wtorek, 01 Grudzień 2009 14:12