tela Così, dopo qualche ricerca ho implementato disegnare con JavaFX e qui è un esempio semplificato:
Per prima cosa ho fatto l'applicazione JavaFX, che è in fase di lancio in un thread separato (io uso Primavera TaskExecutor ma un java pianura filo può essere usato).
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);
}
}
}
Poi chiamo il metodo initialize() all'avvio dell'applicazione Spring:
@Autowired private TaskExecutor taskExecutor;
@PostConstruct private void initChartGenerator() {
ChartGenerator.initialize(taskExecutor);
}
Questa soluzione di cource può essere portato su un'applicazione non molla.
Questa è una soluzione a thread singolo (nel mio caso è sufficiente) ma penso che potrebbe essere adottata per l'utilizzo multithread (magari utilizzare RMI per richiamare il metodo draw).
Anche questa soluzione funziona "così com'è" sulla mia workstation Windows, ma in ambiente server linux alcune azioni supplementari dovrebbero essere invocate:
- Non è possibile utilizzare JavaFX su OpenJDK (a partire da agosto 2013) - deve passare a Oracle JDK
- versione Java deve essere non meno di Java 7u6
La più complessa - è necessario utilizzare display virtuale per fare JavaFX eseguito su ambienti senza testa:
apt-get install Xvfb
// quindi all'avvio del server delle applicazioni:
export DISPLAY = ": 99"
start-stop-daemon --start --background --user pontile --exec "/ usr/bin/sudo" - u molo/usr/bin/Xvfb: 99-screen 0 1024x768x24
PSÈ inoltre possibile utilizzare altre funzionalità JavaFX sul lato server (ad esempio, esportare html in immagine) con questa soluzione.
Questo è bello. Sono così entusiasta di provarlo. Grazie per lo sforzo! – GGrec