English 中文(简体)
How can I display a JFreeChart in web browser with Stripes Framework
原标题:

This is the situation: My metrics.jsp page submits a couple variables that are needed to create the chart. The ProjectActionBean.java calls down to a few other java classes that create the JFreeChart. I can display the chart in a pop-up but I want it to be displayed in the original browser window.

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);
问题回答

I ve written an application like this, so I can assure you it s feasible :)

First, you need to get rid of anything that s GUI. You simply don t have a GUI on the server. This means your ChartFrame frame gets dumped. My main routine for creating a chart looks like this:

  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);
   }

This creates a file you can serve up as an <img> from your Web page. Alternatively (but a bit more advanced), you can use ChartUtilities to create a stream that you can serve up in response to a request for the image URL.

Another bit of magic that s required is to tell Java that you re running graphics code without a GUI. You need to set the environment variable

-Djava.awt.headless=true

For a Web app server like Tomcat, this goes into the Tomcat startup script.


Update

okay yeah doesn t the ChartUtilities.saveChartAsPNG(); just save the chart onto the file system? I want the user to be able to input the variables and then a chart be displayed directly back to them in the browser.

As long as you have just one user, writing the images to the file system will work fine for the scenario you describe. In fact, that s how my first version worked: I had 4 <img> tags in my HTML response page from the form where the user specified the parameters; and those pointed at the names of the 4 files with my images. So long as you finish writing those files before returning the answer to the user, this works fine.

Problems appear when you have multiple users. They can end up viewing the charts specified by the other user. There are possible workarounds with encoding the user s ID or session into the chart file names, but that gets ugly real fast. There is a better way, based on on-demand dynamic generation of each image, singly.

I don t know how much you know about HTML/HTTP, so I hope I m not going to bore you with this:

For any given HTTP request, you can only return a single stream of data. Typically, that s a HTML page, i.e. a stream of text. If you want images in your HTML page, you insert <img> links with different URLs into your HTML page, and you re still just returning a page full of text. The browser then goes ahead and requests the images by firing off requests for those URLs mentioned in the <img> tags. This is pretty easy when your images are just files in the file system. If you want dynamically generated images such as charts, then you have to think up a URL for each kind of image you want to generate, and map each of those URLs to a servlet that knows how to generate such an image.

My app had 4 different charts on one page, so my HTML page had 4 <img> tags with 4 different URLs that all mapped to the same chart-generating servlet, but there were some parameters in the URL that told the servlet what kind of chart was wanted. Upon receiving the request, the servlet would do the JFreeChart magic and then it would use ChartUtilities.writeChartAsPNG() to dump the generated image to the servlet s output stream.

You need to write a servlet which writes image (byte stream) into the output stream to the client. There are no need for creating files. Basically something like this should work:

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();
  }
}

Then map it to some url in your web.xml and use from "img" tag in HTML/JSP. Obviously you can pass parameters to it etc.

If you want to stay within the Stripes framework you can use a custom extension of the StreamingResolution, thusly:

Create a new normal ActionBean implementation that will represent the URL of your chart (to be included in your img tag):

@DefaultHandler
public Resolution view() {
    JFreeChart chart = ...
    return new ChartStreamingResolution(chart);
}

The custom StreamingResolution then looks like this:

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
        }
    }
}




相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...

热门标签