8
votes

I have got one very simple java spring boot + swagger project.

Only for test purposes I've created two mapping classes: Names.java and NamesContainer.java

public class Names {

@XmlAttribute(name="ref")
@ApiModelProperty(notes = "The auto-generated version of the product...")
private String key;

@XmlValue
@ApiModelProperty(notes = "The auto-generated version of the product...")
private String name;....-> rest of the class(Default constuctor and getters and setters)

...........

    @XmlRootElement(name="root")
public class NamesContainer {

    @XmlElement(name="listNames")
    @ApiModelProperty(notes = "The auto-generated version of the product")
    private List<Names> listNames;....-> rest of the class(Default constuctor and getters and setters)

For response I use one @Get method:

    @RequestMapping(method = RequestMethod.GET, value = "/api/javainuse")
    @ApiOperation(value = "Get a scheduled process by id.",notes = "This is note ;)",response = NamesContainer.class,code = HttpURLConnection.HTTP_OK, produces="text/html")
    @ApiResponses(value = {@ApiResponse(code = HttpURLConnection.HTTP_OK, message = "set in case of success. Returns the requested scheduled process",  response = NamesContainer.class)})

    public NamesContainer sayHello() {

        Map<String, String> mapNames = new HashMap<String, String>();
        mapNames.put("Name1", "Docnho");
        mapNames.put("Name2", "Silvia");
        mapNames.put("Name3", "Pepa");
        mapNames.put("Name4", "Mima");
        mapNames.put("Name5", "Mohamed");

        List<Names> listNames = new ArrayList<Names>();

    for(Map.Entry<String, String> entryName : mapNames.entrySet())
    {
        listNames.add(new Names(entryName.getKey(), entryName.getValue()));
    }

    NamesContainer container = new NamesContainer(listNames);


    return container;
}

If I use produces="application/json" or produces="application/xml", the result is as expected: enter image description here

enter image description here

But if I try to use produces="text/html"

The response is not as expected: enter image description here

and Response Body is;

<html><body><h1>Whitelabel Error Page</h1><p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p><div id='created'>Fri Mar 15 18:43:55 EET 2019</div><div>There was an unexpected error (type=Not Acceptable, status=406).</div><div>Could not find acceptable representation</div></body></html> 

The question is is it possible to map my existing object NamesContainer.java in way in which I can generate HTML response and how to do that?

4
spent some time on this, this could be useful github.com/springfox/springfox/issues/1180Sharan

4 Answers

3
votes

There is no way (no already existing way) to map POJO fields to html with annotations.

Instread one can bind POJOs (model) to html using other means Spring proposes out of the box: Thymleaf temlates, Freemarker templates and JSP pages.

Here is an example of one of the possible solutions:

  1. Create HTML page using html Thymleaf template. For example a table.html view:

<body>
    <table>
    <tr>
        <th>Key</th>
        <th>Name</th>
    </tr>
    <tr th:each="mapEnty: ${mapNames}">
        <td th:text="${mapEnty.key}" />
        <td th:text="${mapEnty.value}" />
    </tr>
    </table>
</body>
  1. Create a @RequestMapping for 'text/html' Content type in a Spring @Controller, fill in the Model and return the 'table' view. For example:
    @GetMapping(value = "/api/javainuse", produces = MediaType.TEXT_HTML_VALUE)
    public String table(Model model) {
        Map<String, String> mapNames = new HashMap<String, String>();
        ...
        model.addAttribute("mapNames", mapNames);
        return "table";
    }
0
votes

Your Pojo may need more explicit mappings/annotations to produce HTML. I assume you're looking for something like

<table>
  <tr>
    <th>Name1</th>
    <th>Name2</th>
    <th>Name3</th>
    <th>Name4</th>
  </tr>
  <tr>
    <td>Peppa</td>
    <td>Mima</td>
    <td>Mohamed</td>
    <td>Docnho</td>
  </tr>
</table>

Im not sure which annotation can help, but thats where I would start

0
votes

TLDR: Yes, it is possible. Create Jackson data format module for HTML.

I believe Spring Boot is using Jackson for data output, and Jackson supports that formats:

  • JSON
  • HTML
  • SMILE
  • YAML
  • Avro
  • CSV

and many more (https://github.com/FasterXML/jackson), but there is no format like HTML supported (how this could be possible?).

HTML rendering requires templating. Read about Spring MVC https://spring.io/guides/gs/serving-web-content/.

Please read also about Content Negotiation (https://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc)

You can use the RESTful @ResponseBody approach and HTTP message converters, typically to return data-formats like JSON or XML.

(...) views are perfectly capable of generating JSON and XML if you wish , views are normally used to generate presentation formats like HTML for a traditional web-application.

0
votes

I have found several opportunities for solving this issue, but I think that these two are best:

The first is makes sense for jetty server oriented applications. Here is the explanation - here. The major thing in produces="text/html, ..., ..." is MessageBodyWriter interface. If you can customized it you can do everithink with it.

The second, and my final solution is just to create .xsl file for my .xml file. I transformed my .xml file to HTML and then response is done.

** If someone wants to do all in one method can use this:

@RequestMapping(method = RequestMethod.GET, value = "/api/javainuse")
@ApiOperation(value = "Get a scheduled process by id.",notes = "This is note ;)",response = NamesContainer.class,code = HttpURLConnection.HTTP_OK, produces="text/html" /*add produces->xml*/)
@ApiResponses(value = {@ApiResponse(code = HttpURLConnection.HTTP_OK, message = "set in case of success. Returns the requested scheduled process",  response = NamesContainer.class)})

public Response sayHello(HttpServletResponse response) {
    switch (request.getHeader("accept"))
    {

        case MediaType.APPLICATION_XML:

            response = Response.ok().entity(/*yourEntity here (for me it was NamesContainer)*/).type(MediaType.APPLICATION_XML).build();
            break;

        case MediaType.TEXT_HTML:

            response = Response.ok().entity(/*Transform xml to HTML with xsl and return it here as String*/).type(MediaType.TEXT_PLAIN).build();
            break;
    }
}