Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Write an HTML page in the servlet response properly

I have a servlet deployed under http://ip:8080/simple
The servlet is under package a.b.c
I have an html page in a.b.resources named Test.html.

The html has an img tag for an image.

In the servlet I do:

htmlFile = MyServlet.class.getResourceAsStream("/a/b/resources/Test.html");
resp.setContentType("text/html");
PrintWriter writer = resp.getWriter();
byte[] bytes=new byte[htmlFile.available()];
htmlFile.read(bytes);
resp.setContentLength(bytes.length);
writer.print(new String(bytes));
writer.flush();
writer.close();

The html page appears on the browser but in the place of the image I see its alt description.
I have tried:

<img alt="Company A" src="./CompanyLogo.jpg">

<img alt="Company A" src="/a/b/resources/CompanyLogo.jpg">

<img alt="Company A" src="CompanyLogo.jpg">

But none of these works.
The jpg image is under /a/b/c/resources i.e. in the same directory as the HTML page.
I am using embedded Jetty.

What am I messing here?

like image 496
Cratylus Avatar asked Sep 11 '11 18:09

Cratylus


People also ask

Can we write html code in servlet?

It can either redirect to a page or directly write any content from the servlet itself. So, in short, yes, you can directly generate any content from servlet without creating any jsp or html. Just get the writer by calling response. getWriter() and write your HTML content to it.

Where do we create html file in servlet?

Now let's explore this project. For creating a html file, right click on WebRoot -> New -> html -> write your html file name e.g. MyHtml. html -> Finish. As you can see that a html file is created named MyHtml.

What is servlet response?

Defines an object to assist a servlet in sending a response to the client. The servlet container creates a ServletResponse object and passes it as an argument to the servlet's service method. To send binary data in a MIME body response, use the ServletOutputStream returned by getOutputStream() .


2 Answers

The browser is trying to resolve those resources relative to the current request URI (as you see in browser address bar). Those resources of course does not exist in your public web content as you seem to have placed them in the classpath.

In order to solve this, you would really need to parse the HTML and change all domain-relative src and/or href attributes of <a>, <img>, <base>, <link>, <script>, <iframe>, etc elements to let them point to a servlet which streams those resources from the classpath to the HTTP response.

It's a bit of work, but Jsoup makes it easy. Here's an example which assumes that your servlet is mapped on an URL pattern of /proxy/*.

String proxyURL = request.getContextPath() + "/proxy/";
InputStream input = MyServlet.class.getResourceAsStream("/a/b/resources" + request.getPathInfo());

if (request.getRequestURI().endsWith(".html")) { // A HTML page is been requested.
    Document document = Jsoup.parse(input, "UTF-8", null);

    for (Element element : document.select("[href]")) {
        element.attr("href", proxyURL + element.attr("href"));
    }

    for (Element element : document.select("[src]")) {
        element.attr("src", proxyURL + element.attr("src"));
    }

    response.setContentType("text/html;charset=UTF-8");
    response.setCharacterEncoding("UTF-8");
    response.getWriter().write(document.html());
}
else { // Other resources like images, etc which have been proxied to this servlet.
    response.setContentType(getServletContext().getMimeType(request.getPathInfo()));
    OutputStream output = response.getOutputStream();
    byte[] buffer = new byte[8192];

    for (int length = 0; (length = input.read(buffer)) > 0;) {
        output.write(buffer, 0, length);
    }
}

input.close();

Open it by http://yourdomain:yourport/contextname/proxy/test.html.

like image 143
BalusC Avatar answered Oct 03 '22 08:10

BalusC


There is no way to do this without implementing a servlet that will read the image out of the resources file. Try this:

public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
  byte[] bbuf = new byte[8192];
  resp.setContentType(req.getSession().getServletContext().getMimeType( req.getPathInfo()));
  InputStream in = MyImageServlet.class.getResourceAsStream("/"+req.getPathInfo());
  OutputStream op = resp.getOutputStream();
  int length;
  while ((in != null) && ((length = in.read(bbuf)) != -1)){
      op.write(bbuf,0,length);
      op.flush();
  }
  in.close();
  op.close();  
}

then register it in your web.xml like so

<servlet-mapping>
  <servlet-name>fetchimage</servlet-name>
  <url-pattern>/fetchimage/*</url-pattern>
</servlet-mapping>

and then use it like so

<img alt="Company A" src="/fetchimage/a/b/resources/CompanyLogo.jpg">

You WILL need to implement a lot of error checking (A LOT OF ERROR CHECKING, just to clarify :)), filter the paths to make sure that someone can't just read your class files using the same technique, but some variation on this should work for you.

like image 33
Femi Avatar answered Oct 03 '22 08:10

Femi