REST WebService - Datei bekommen und auslesen auf Desktop Applikation?

Hallo zusammen,

ich habe ein REST Webservice, der mir ein File zurückgibt:

Stateless
@Path("/print")
public class PictureWebservice {
   
    @GET
    @Path("/startPrint")
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
    public Response getFile() {
       
        String path = "/mypath.JPG";
      File file = new File(path);
      return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
          .header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"" ) //optional
          .build();
    }
}

Nun möchte ich das File wiederum auf meinem anderen PC einlesen.
Wenn ich die die URL des Webservice in meinen Browser eingebe, dann funktioniert das auch.
Also http://:8080/rest/print/startPrint

Dann kommt das Pop Up und ich kann das Bild herunterladen.
Wenn ich nun aber:
File file = new File(“http://:8080/rest/print/startPrint”) eingebe, dann stimmt etwas nicht.

Was ich nun machen möchte bzw. mein Workflow sieht so aus:

  1. Ich rufe mit einer Desktop Application den Webservice auf
  2. Dieser wiederum gibt mir das File (Bild) zurück
  3. Nun möchte ich dieses Bild anschließend mit der Desktop Application drucken

Nun ist das Problem aber: wie bekomme ich das Bild zurück?
=> Ich möchte das Bild nur drucken, also nicht speichern auf dem PC (auf dem die Desktop Application läuft). Wie kann ich das machen?

Das funktioniert so nicht. Du musst die Datei schon runterladen.

Ein URL-Objekt erstellen. Dort openstream aufrufen. Diesen dann speichern oder wenn möglich direkt verarbeiten.

Um mal die Antwort meines Vorredners zu korrigieren:

Es ist schon möglich ohne das File “runterzuladen” (wobei der Term hier mehrdeutig ist). Aber fangen wir mal mit den Basics an.

Java kennt nur eine Art von File. Und dies bedeutet dass Java einen FileDescriptor vom OS braucht der durch einen Dateisystemtreiber bereitgestellt wird. Dazu zählen dann auch Netshares unter Windows oder Remote-Mounts unter Linux. Da das HTTP aber einen solchen “physischen” FileDescriptor nicht bereitstellt funktioniert sowas wie new File("http://") eben nicht.

Kommen wir nun zum Begriff “runterladen”:
Grundsätzlich bedeutet “runterladen”, oder im Englischen halt “download”, dass Daten von einer externen Quelle zumindest in den RAM zu kopieren und ggf. auf Platte zu speichern. Der Schritt des Speicherns ist jedoch optional und für dein Vorhaben nicht nötig. Das ist übrigens auch der Grund warum das “Streamen” bisher eine rechtliche Grauzone darstellt da es für die Funktionsweise technisch nötig ist die Daten zumindest temporär im RAM zwischenzuladen. Und auch das bewusste dauerhafte Speichern wäre rechtlich eigentlich noch legal (Befürworter vergleichen es gerne mit Dingen wie VHS- oder DVD-Recorder). Lediglich das Weiterverbreiten ist in Deutschland verboten und stellt die eigentliche Straftat dar. Darum sind Tauschbörsen wie Emule oder BitTorrent der Haken: man verteilt die bereits geladenen Daten nämlich direkt weiter. Aber genug off-top.

Zum Drucken:
Soweit mir bekannt braucht man kein File um aus Java zu drucken. Man kann den Inhalt auch selbst direkt zeichnen und den Rest dem Druckertreiber überlassen. Was hat das nun mit “Zwischenparken im RAM” zu tun?
Recht einfach: man fragt die Daten vom Server an, packt die Daten in den RAM und nutzt diese direkt um dann auf das Dokument zu zeichnen. Das wiederum landet auch wieder im RAM und wird von dort vom Druckertreiber in den Speicher vom Drucker kopiert. Nachdem der Transfer komplett ist und der Drucker seine Arbeit aufnimmt können die temporären Daten aus dem RAM fliegen.

Code:
Ich kann dir jetzt keinen fertigen Code posten (widerspricht auch meinem Verständnis dieses Forums), aber dir mal die nötigen Grundschritte kurz skizzieren:

1.) Anfrage an den Server stellen
Du hast eine URL. Gut, mehr brauchst du nicht, und die beiden Pakete java.io und java.net: URL.openConnection()
2.) Daten in den RAM packen
Entsprechend den InputStream der URLConnection einlesen und z.B. in ein ByteArrayOutputStream schreiben.
3.) Rohdaten verarbeiten
Abhängig davon in welchem Format die Daten vorliegen einfach mit ImageIO in ein “Standard-Image” lesen. So hast du Zugriff auf Größe und mit x und y auf die einzelnen Pixel die dann in einem weiteren Schritt auf das Druckdokument kopier/gezeichnet werden können.
4.) Dokument drucken
Hier hab ich jetzt nicht so den plan, aber AFAIK von den Codes die ich kenne öffnet sich dann ein ganz normaler Druckdialog über den dann halt gedruckt werden kann.

*scnr : all das hätte dir Google auch verraten, und auch die Keywords nach denen du hättest suchen müssen … alles nur eine Frage der Eigeninitiative

Danke für die Antworten.
Ich habe das Bild nun geholt und in ein InputStream eingelesen.
Dieses kann ich ja dann wiederum in ein File konvertieren - ist das so korrekt?

Heißt also: Ich speichere das Bild lokal auf der Festplatte ab (z.B. C:/temp) drucke das Bild und lösche danach wieder das Bild?
Oder kann ich aus dem InputStream is = new BufferedInputStream(url.openStream()); -> das Bild direkt drucken? Muss ich zwingend ein File erzeugen?

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import javax.swing.JOptionPane;

public class DownloadAndPrint {

    public static void main(String[] args) throws IOException {
    
        URL url = new URL(args[0]);
        ReadableByteChannel channel = Channels.newChannel(url.openStream());
        File tempFile = File.createTempFile("test-", ".jpg");

        tempFile.deleteOnExit();

        FileOutputStream fos = new FileOutputStream(tempFile);
        fos.getChannel().transferFrom(channel, 0, Long.MAX_VALUE);

        System.out.println("File: " + tempFile.getAbsolutePath());

        Desktop.getDesktop().print(tempFile);

        JOptionPane.showMessageDialog(null, "Quit Application");
    }

}```

Wenn man jetzt nicht selbst zeichnen möchte, sondern nur eine Datei herunterladen und mit den auf dem System zur Verfügung stehenden Mitteln drucken möchte, dann kann man das so machen.

Das deleteOnExit() sorgt dafür, dass die Datei beim Beenden der JVM automatisch gelöscht wird.

Deshalb finde ich es ratsam, die Anwendung solange am laufen zu halten, bis das abgeschlossen ist. Deshalb gibt es einen kleinen Dialog der die Anwendung am laufen hält.

Das Drucken mit print() steht nicht auf jedem Betriebssystem zur Verfügung.

Die Dateiendung muß entsprechend zur jeweiligen Datei angepasst werden, damit Betriebssysteme, insbesondere die vom Marktführer, das richtige Programm zum Drucken finden.

@TO
Lies mein Post bitte noch mal, dann wirst du eine Antwort auf deine Frage erhalten.

vielen Dank für die Antwort.
Ich habe das nun versucht - klappt auch soweit alles super.
Aber die Datei wird nicht vom System gelöscht?
Sie wird abgelegt unter: C:\Users\username\AppData\Local\Temp

Auch nach einem Neustart sind die Dateien immer noch da?

Streams zu schließen bietet sich immer an: fos.close();
auch schon vor dem Drucken, damit dort alles möglichst korrekt läuft, eben immer sobald fertig geschrieben

bei einem kleinen Test bei mir ohne Download, ohne print + Dialog am Ende, nur ordentlich bytes speichern, machte das den Unterschied

Danke.
Jetzt noch eine Frage:
Wie kann ich nun noch überprüfen, ob der Druckvorgang noch läuft, abgeschlossen oder abgebrochen ist?

falls es dir noch nicht aufgefallen sein sollte und falls ich richtig liege, dann ist zumindest meine Interpretation des
JOptionPane.showMessageDialog(null, "Quit Application"); im geposteten Code
dass das Programm solange aktiv bleibt bis ein Mensch es im sicheren Wissen abbricht, etwa weil er das bedruckte Papier bereits in den Händen hält :wink:
oder der Drucker kokelt…

mit Java einen Drucker genauer zu kontrollieren, auch das abzufragen was du möchtest, ist wohl ein größeres Thema für sich,
klingt nicht nach dem simplen Desktop.getDesktop().print(tempFile);

ich kenne es nicht, vielleicht findest du dazu im Internet etwas mit naheliegenden Suchbegriffen, allgemein zum Thema Drucker in Java,
vielleicht eigenes Thema dazu geeigneter, entfernt sich vom WebService + Download,
aber vielleicht hat auch wer hier schnell eine Antwort, alles möglich

hm also so wirklich funktioniert das noch nicht mit dem automatischen Löschen:

Hier mal der Code:

			URL url = new URL(BASE_URL);
			ReadableByteChannel channel = Channels.newChannel(url.openStream());
			File tempFile = File.createTempFile("test-", ".jpg");

		

			FileOutputStream fos = new FileOutputStream(tempFile);
			fos.getChannel().transferFrom(channel, 0, Long.MAX_VALUE);

			System.out.println("File: " + tempFile.getAbsolutePath());
			fos.close();
			tempFile.deleteOnExit();

			Desktop.getDesktop().print(tempFile);

			JOptionPane.showMessageDialog(null, "Quit Application");

		} catch (Exception ex) {
			ex.printStackTrace();
		}

Code ist ja nicht alles, falls das print wirklich stattfindet, da irgendein Programm auf die Datei zugreift,
wie ist denn dein Verhalten in dem Programm, läßt du den Drucker rattern, wartest noch 5 sec. zur Sicherheit und beendest erst dann den Dialog?
und dann wird nicht gelöscht?

nun, genaues fällt mir persönlich zu sowas nicht ein, kein echtes Programmierproblem,
sondern reine Blackbox, geht oder eben nicht :wink:
noch irgendwas im Betriebssystem an Prozessen zu beenden, die auf die Datei zugreifen?

du könntest noch selber am Ende mal ein delete auf das File versuchen und den boolean-Rückgabewert ausgeben,
wenn du manuell nicht löschen kannst dann ist die Frage sicher genauso warum das nicht…,
aber wäre zumindest eine gewisse Erklärung warum nicht automatisch gelöscht wird…,

mit auskommentierten print zum Test geht Löschen auf allen Wegen gewiss?

vielleicht beim nächsten Durchgang alte Dateien finden und zu löschen versuchen…

Ich find es interessant wie es immer mehr vom “ich wills nicht auf dem PC speichern” abdrifftet.