How can I embed one DropWizard (with freemarker) V

2019-05-23 21:46发布

问题:

I am using DropWizard and Freemarker to build up a view which displays different types of forms based on results from a webservice.

I have created the forms as views - each with their own ftl.

So, in my resource, I discover which form I need, then load the main.ftl, passing the form view as a parameter (see below).

This doesn't work. Can anyone see where we're going wrong? Or is there a completely different way to chain views together using DropWizard and freemarker?

@GET
public Form getForm() {
        FormView view = new FormView(service.getForm());
        return new MainView(view);
}

public class FormView extends View {
    private final Form form;

    public FormView(Form form) {
        super("formView.ftl");
        this.form = form;
    }

    public Form getForm() {
        return form;
    }
}

public class MainView extends View {
    private final FormView formView;

    public MainView(FormView formView) {
        super("main.ftl");
        this.formView = formView;
    }

    public FormView getFormView() {
        return formView;
    }
}

public class TextForm extends View implements Form {
    private int maxLength;
    private String text;

    public TextForm(int maxLength, String text) {
        super("textForm.ftl");
        this.maxLength = maxLength;
        this.text = text;
    }

    public int getMaxLength() {
        return maxLength;
    }

    public String getText() {
        return text;
    }
}

main.ftl
<#-- @ftlvariable formView="" type="MainView" -->
<html>
<body>
    <#include formView.templateName />  // This evaluates to formView.ftl, but it seems to create a new instance, and doesn't have the reference to textForm.ftl. How do we reference a dropwizard view here?
</body>
</html>

formView.ftl
<#-- @ftlvariable form type="FormView" -->
${form?html}   // also tried #include form.templateName

textForm.ftl
<#-- @ftlvariable text type="TextForm" -->
<div>${text?html}</div>

回答1:

Based on the discussion, I think you need something like this:

<#-- main.ftl -->
<html>
<body>
    <#include formView.templateName>
</body>
</html>

formView.templateName must evaluate to textForm.ftl, numberForm.ftl, complexForm.ftl or whatever form view you might have. There's no need for an intermediate file that chooses between these. I think you are running into problems because FormView.getTemplateName() is returning a hard-coded formView.ftl. I think that what you need is for this method to return the name of the actual template file containing the form type you want to display.



回答2:

I've figured out how to do this.

You make a TemplateView class (see below) that extends View.
Then all your View classes need to extend TemplateView instead.

The constructor takes an extra parameter, the "body" template file, that is the body to go inside the template.

Then, inside your template file, do something like this.

<html>
  <body>
      <h1>My template file</h1>
          <#include body>
      <footer>footer etc</footer>
  </body>
</html>

The TemplateView class.

public abstract class TemplateView extends View
{
    private final String body;

    protected TemplateView(String layout, String body)
    {
        super(layout);
        this.body = resolveName(body);
    }

    public String getBody()
    {
        return body;
    }

    private String resolveName(String templateName)
    {
        if (templateName.startsWith("/"))
        {
            return templateName;
        }
        final String packagePath = getClass().getPackage().getName().replace('.', '/');
        return String.format("/%s/%s", packagePath, templateName);
    }
}

Hope this helps someone.