Dynamic Content

There are two options to generate content dynamically based on data provided by the current application state:

  • You can use a StreamResource which will handle URLs automatically.

  • You can build a custom URL including parameters with String type parameters. In this case you will need one more servlet which handles the URL.

The first option is preferable since it doesn’t require additional servlet and allows to use data with any type from the application state.

Using custom servlet and request parameters

You can create a custom servlet which handles "image" as a relative URL:

@WebServlet(urlPatterns = "/image", name = "DynamicContentServlet")
public class DynamicContentServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        resp.setContentType("image/svg+xml");
        String name = req.getParameter("name");
        if (name == null) {
            name = "";
        }
        String svg = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
                + "<svg  xmlns='http://www.w3.org/2000/svg' "
                + "xmlns:xlink='http://www.w3.org/1999/xlink'>"
                + "<rect x='10' y='10' height='100' width='100' "
                + "style=' fill: #90C3D4'/><text x='30' y='30' fill='red'>"
                + name + "</text>" + "</svg>";
        resp.getWriter().write(svg);
    }
}

The following code should be used in the application (which has its own servlet). It generates the resource URL on the fly based on the current application state. The property value of the input component is used here as a state:

Input name = new Input();

Element image = new Element("object");
image.setAttribute("type", "image/svg+xml");
image.getStyle().set("display", "block");

NativeButton button = new NativeButton("Generate Image");
button.addClickListener(event -> {
    String url = "image?name=" + name.getValue();
    image.setAttribute("data", url);
});

UI.getCurrent().getElement().appendChild(name.getElement(), image,
    button.getElement());

Using StreamResource

Use StreamResource to generate dynamic content within the same servlet. In this case the application will generate the URL transparently for you and register an internal handler for this URL. The code below shows how to implement the same functionality as above using StreamResource.

Input name = new Input();

Element image = new Element("object");
image.setAttribute("type", "image/svg+xml");
image.getStyle().set("display", "block");

NativeButton button = new NativeButton("Generate Image");
button.addClickListener(event -> {
    StreamResource resource = new StreamResource("image.svg",
            () -> getImageInputStream(name));
    image.setAttribute("data", resource);
});

UI.getCurrent().getElement().appendChild(name.getElement(), image,
    button.getElement());

The data attribute value is set to the StreamResource, which will automatically be converted into a URL. A StreamResource uses a dynamic data provider to produce the data. The file name given to a StreamResource is used as a part of the URL and will also become the filename if the user selects to download the resource. And here is an example how to create a data provider:

private InputStream getImageInputStream(Input name) {
    String value = name.getValue();
    if (value == null) {
        value = "";
    }
    String svg = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
        + "<svg  xmlns='http://www.w3.org/2000/svg' "
        + "xmlns:xlink='http://www.w3.org/1999/xlink'>"
        + "<rect x='10' y='10' height='100' width='100' "
        + "style=' fill: #90C3D4'/><text x='30' y='30' fill='red'>"
        + value + "</text>" + "</svg>";
    return new ByteArrayInputStream(svg.getBytes(StandardCharsets.UTF_8));
}