Как я могу отобразить JFreeChart в веб-браузере с Stripes Framework
Это ситуация: моя страница "metrics.jsp" представляет пару переменных, которые необходимы для создания диаграммы. ProjectActionBean.java вызывает несколько других классов Java, которые создают JFreeChart. Я могу отобразить диаграмму во всплывающем окне, но я хочу, чтобы она отображалась в исходном окне браузера.
JFreeChart placeChart = ChartFactory.createBarChart(
"ChartName",
"", //x-axis label
"", //y-axis label
dataset,
PlotOrientation.VERTICAL,
false, //legend
true, //tooltype
false); //generate urls
ChartFrame frame = new ChartFrame(name, placeChart);
frame.pack();
frame.setVisible(true);
3 ответа
Я написал такое заявление, поэтому могу вас заверить, что это выполнимо:)
Во-первых, вам нужно избавиться от всего, что является GUI. У вас просто нет графического интерфейса на сервере. Это означает, что ваш ChartFrame frame
сбрасывается. Моя основная процедура создания диаграммы выглядит следующим образом:
private void createChart(XYPlot plot, String fileName, String caption) throws IOException {
JFreeChart chart = new JFreeChart(caption, plot);
chart.addSubtitle(this.subtitle);
if (plot.getRangeAxis() instanceof LogarithmicAxis) {
chart.addSubtitle(1, new TextTitle("(logarithmische Skala)"));
}
File file = new File(fileName);
file.delete();
ChartUtilities.saveChartAsPNG(file, chart, CHART_WIDTH, CHART_HEIGHT);
}
Это создает файл, который вы можете использовать в качестве <img>
с вашей веб-страницы. В качестве альтернативы (но немного более продвинутого) вы можете использовать ChartUtilities для создания потока, который вы можете использовать в ответ на запрос URL-адреса изображения.
Еще одно волшебство, которое требуется, - сообщить Java, что вы запускаете графический код без графического интерфейса. Вам необходимо установить переменную среды
-Djava.awt.headless=true
Для сервера веб-приложений, такого как Tomcat, это входит в сценарий запуска Tomcat.
Обновить
хорошо, да, не 'ChartUtilities.saveChartAsPNG();' просто сохранить график в файловой системе? Я хочу, чтобы пользователь мог вводить переменные, а затем диаграмма отображалась прямо в браузере.
Пока у вас есть только один пользователь, запись изображений в файловую систему будет работать нормально для сценария, который вы описываете. На самом деле, так работала моя первая версия: у меня было 4 <img>
теги на моей странице ответа HTML из формы, где пользователь указал параметры; и те указали на имена 4 файлов с моими изображениями. Пока вы заканчиваете писать эти файлы, прежде чем возвращать ответ пользователю, это работает нормально.
Проблемы появляются, когда у вас есть несколько пользователей. Они могут в конечном итоге просматривать графики, указанные другим пользователем. Существуют возможные обходные пути с кодированием идентификатора пользователя или сеанса в именах файлов диаграммы, но это становится ужасно быстро. Существует лучший способ, основанный на динамической генерации каждого изображения по требованию, отдельно.
Я не знаю, как много вы знаете о HTML/HTTP, поэтому я надеюсь, что не буду утомлять вас этим:
Для любого данного HTTP-запроса вы можете вернуть только один поток данных. Как правило, это HTML-страница, то есть поток текста. Если вы хотите изображения на вашей HTML-странице, вы вставляете <img>
ссылки с различными URL-адресами на вашу HTML-страницу, и вы все еще просто возвращаете страницу, полную текста. Затем браузер отправляет запросы и запрашивает изображения, запуская запросы для тех URL, которые указаны в <img>
теги. Это довольно легко, когда ваши изображения - это просто файлы в файловой системе. Если вам нужны динамически генерируемые изображения, такие как диаграммы, вам нужно придумать URL-адрес для каждого типа изображения, которое вы хотите сгенерировать, и сопоставить каждый из этих URL-адресов с сервлетом, который знает, как генерировать такое изображение.
В моем приложении было 4 разных графика на одной странице, поэтому в моей HTML-странице было 4 <img>
теги с 4 различными URL-адресами, которые все сопоставлены с одним и тем же сервлетом, генерирующим диаграммы, но в URL-адресе были некоторые параметры, которые указывали сервлету, какой тип диаграммы нужен. После получения запроса сервлет выполняет магию JFreeChart, а затем использует ChartUtilities.writeChartAsPNG()
выгрузить сгенерированное изображение в выходной поток сервлета.
Вам нужно написать сервлет, который записывает изображение (поток байтов) в выходной поток для клиента. Нет необходимости создавать файлы. В принципе что-то вроде этого должно работать:
public class ChartServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
JFreeChart chart = .. // create your chart
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ChartUtilities.writeChartAsPNG(bos, chart, width, height);
response.setContentType("image/png");
OutputStream out = new BufferedOutputStream(response.getOutputStream());
out.write(bos.toByteArray());
out.flush();
out.close();
}
}
Затем сопоставьте его с некоторым URL-адресом в вашем файле web.xml и используйте тег "img" в HTML/JSP. Очевидно, что вы можете передать ему параметры и т. Д.
Если вы хотите остаться в рамках Stripes, вы можете использовать пользовательское расширение StreamingResolution, таким образом:
Создайте новую нормальную реализацию ActionBean, которая будет представлять URL-адрес вашей диаграммы (будет включен в ваш тег img):
@DefaultHandler
public Resolution view() {
JFreeChart chart = ...
return new ChartStreamingResolution(chart);
}
Затем пользовательский StreamingResolution выглядит следующим образом:
public class ChartStreamingResolution extends StreamingResolution {
private JFreeChart chart;
public ChartStreamingResolution(JFreeChart chart) {
super("image/png");
this.chart = chart;
}
@Override
public void stream(HttpServletResponse response) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ChartUtilities.writeChartAsPNG(bos, chart, 400, 200);
OutputStream out = new BufferedOutputStream(response.getOutputStream());
out.write(bos.toByteArray());
out.flush();
out.close();
} catch (Exception e) {
//something sensible
}
}
}