Więc po kilku badań zostały wdrożone płótno rysować JavaFX i tu jest uproszczony przykład:
Najpierw zrobiłem aplikację JavaFX, która jest uruchomiona w osobnym wątku (używam Wiosna taskExecutor ale zwykły java wątek może być użyty).
public class ChartGenerator extends Application {
private static Canvas canvas;
private static volatile byte[] result;
public static void initialize(TaskExecutor taskExecutor) {
taskExecutor.execute(new Runnable() {
@Override
public void run() {
launch(ChartGenerator.class);
}
});
}
public static synchronized byte[] generateChart(final Object... params) {
Platform.runLater(new Runnable() {
@Override
public void run() {
ByteArrayOutputStream baos = null;
try {
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
/**
* Do the work with canvas
**/
final SnapshotParameters snapshotParameters = new SnapshotParameters();
snapshotParameters.setFill(Color.TRANSPARENT);
WritableImage image = canvas.snapshot(snapshotParameters, null);
BufferedImage bImage = SwingFXUtils.fromFXImage(image, null);
baos = new ByteArrayOutputStream();
ImageIO.write(bImage, chartType.outputFormat, baos);
result = baos.toByteArray();
} catch (InstantiationException e) {
throw new ChartGenerationException(e);
} catch (IllegalAccessException e) {
throw new ChartGenerationException(e);
} catch (NoSuchMethodException e) {
throw new ChartGenerationException(e);
} catch (InvocationTargetException e) {
throw new ChartGenerationException(e);
} catch (IOException e) {
throw new ChartGenerationException(e);
} finally {
IOUtils.closeQuietly(baos);
}
}
});
while (result == null) {
//wait
}
byte[] ret = result;
result = null;
return ret;
}
@Override
public void start(Stage stage) {
canvas = new Canvas();
}
public static class ChartGenerationException extends RuntimeException {
public ChartGenerationException(String message) {
super(message);
}
public ChartGenerationException(Throwable cause) {
super(cause);
}
}
}
Następnie wywołać sposób inicjowania() gdy aplikacja Wiosna rozpoczętych
@Autowired private TaskExecutor taskExecutor;
@PostConstruct private void initChartGenerator() {
ChartGenerator.initialize(taskExecutor);
}
Roztwór cource mogą być przeniesione do stosowania bez sprężyny.
To jest rozwiązanie z pojedynczym gwintem (w moim przypadku to wystarczające), ale myślę, że można go zaadaptować do użycia wielowątkowego (może użyć RMI do wywołania metody rysowania).
Również to rozwiązanie działa „jak jest” na moje okna stacji roboczej, ale na środowisku serwera linux pewne dodatkowe działania powinny być powoływane:
- Nie można użyć JavaFX na OpenJDK (od sierpnia 2013) - trzeba przełączyć Oracle JDK
- wersja Java musi być nie mniej niż Java 7u6
najbardziej skomplikowane - trzeba użyć wirtualnego ekranu, aby uruchomić na JavaFX środowiskach bezgłowe:
apt-get install Xvfb
// następnie na początku aplikacji serwera:
export DISPLAY = ": 99"
start-stop-daemon --start --background --user pomost --exec „/ usr/bin/sudo”- -u molo/usr/bin/Xvfb: 99 -screen 0 1024x768x24
PSMożna również użyć innych funkcji JavaFX po stronie serwera (np. Eksportować html do obrazu) za pomocą tego rozwiązania.
To jest fajne. Jestem tak podekscytowany, że mogę tego spróbować. Dzięki za wysiłek! – GGrec