您的位置:首页 > 其它

关于image标签无法获取本地图片

2013-04-05 23:41 302 查看
If you have stored images in a path outside of the web container or in a database, then the client cannot access the images directly by a relative URI. A good practice is to create a Servlet which loads the image from a path outside of the web container
or from a database and then streams the image to the HttpServletResponse. You can pass the file name or the file ID as a part of the request URI. You can also consider to pass it as a request parameter, but that would cause problems
with getting the filename right when the user want to save the image in certain web browsers by rightclicking and saving it (Internet Explorer and so on).

ImageServlet serving from absolute path

Here is a basic example of a ImageServlet which serves a image from a path outside of the web container.

package mypackage;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLDecoder;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* The Image servlet for serving from absolute path.
* @author BalusC
* @link http://balusc.blogspot.com/2007/04/imageservlet.html */
public class ImageServlet extends HttpServlet {

// Constants ----------------------------------------------------------------------------------

private static final int DEFAULT_BUFFER_SIZE = 10240; // 10KB.

// Properties ---------------------------------------------------------------------------------

private String imagePath;

// Actions ------------------------------------------------------------------------------------

public void init() throws ServletException {

// Define base path somehow. You can define it as init-param of the servlet.
this.imagePath = "/images";

// In a Windows environment with the Applicationserver running on the
// c: volume, the above path is exactly the same as "c:\images".
// In UNIX, it is just straightforward "/images".
// If you have stored files in the WebContent of a WAR, for example in the
// "/WEB-INF/images" folder, then you can retrieve the absolute path by:
// this.imagePath = getServletContext().getRealPath("/WEB-INF/images");
}

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
// Get requested image by path info.
String requestedImage = request.getPathInfo();

// Check if file name is actually supplied to the request URI.
if (requestedImage == null) {
// Do your thing if the image is not supplied to the request URI.
// Throw an exception, or send 404, or show default/warning image, or just ignore it.
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
return;
}

// Decode the file name (might contain spaces and on) and prepare file object.
File image = new File(imagePath, URLDecoder.decode(requestedImage, "UTF-8"));

// Check if file actually exists in filesystem.
if (!image.exists()) {
// Do your thing if the file appears to be non-existing.
// Throw an exception, or send 404, or show default/warning image, or just ignore it.
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
return;
}

// Get content type by filename.
String contentType = getServletContext().getMimeType(image.getName());

// Check if file is actually an image (avoid download of other files by hackers!).
// For all content types, see: http://www.w3schools.com/media/media_mimeref.asp if (contentType == null || !contentType.startsWith("image")) {
// Do your thing if the file appears not being a real image.
// Throw an exception, or send 404, or show default/warning image, or just ignore it.
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
return;
}

// Init servlet response.
response.reset();
response.setBufferSize(DEFAULT_BUFFER_SIZE);
response.setContentType(contentType);
response.setHeader("Content-Length", String.valueOf(image.length()));
response.setHeader("Content-Disposition", "inline; filename=\"" + image.getName() + "\"");

// Prepare streams.
BufferedInputStream input = null;
BufferedOutputStream output = null;

try {
// Open streams.
input = new BufferedInputStream(new FileInputStream(image), DEFAULT_BUFFER_SIZE);
output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);

// Write file contents to response.
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
} finally {
// Gently close streams.
close(output);
close(input);
}
}

// Helpers (can be refactored to public utility class) ----------------------------------------

private static void close(Closeable resource) {
if (resource != null) {
try {
resource.close();
} catch (IOException e) {
// Do your thing with the exception. Print it, log it or mail it.
e.printStackTrace();
}
}
}

}

In order to get the ImageServlet to work, add the following entries to the Web Deployment Descriptor
web.xml:

<servlet>
<servlet-name>imageServlet</servlet-name>
<servlet-class>mypackage.ImageServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>imageServlet</servlet-name>
<url-pattern>/image/*</url-pattern>
</servlet-mapping>

Of course you can change the url-pattern of the servlet-mapping as you like it.

Here are some basic use examples:

<!-- XHTML or JSP -->
<img src="image/test.jpg" />
<img src="image/test.gif" />

<!-- JSF -->
<h:graphicImage value="image/test.jpg" />
<h:graphicImage value="image/test.gif" />
<h:graphicImage value="image/#{myBean.imageFileName}" />

ImageServlet serving from database

First prepare a DTO (Data Transfer Object) for Image which can be used to hold information about the image. You can map this DTO to the database and use a DAO class to obtain it. You can get the image as
byte[] from the database using ResultSet#getBytes().

The data layer and the DAO pattern is explained in this tutorial:
DAO tutorial - the data layer.

package mymodel;

public class Image {

// Init ---------------------------------------------------------------------------------------

private String id;
private String name;
private String contentType;
private byte[] content;

// Implement default getters and setters here.

}

Here is a basic example of a ImageServlet which serves a image from a database.

package mypackage;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import mydao.DaoFactory;
import mydao.ImageDAO;
import mymodel.Image;

/**
* The Image servlet for serving from database.
* @author BalusC
* @link http://balusc.blogspot.com/2007/04/imageservlet.html */
public class ImageServlet extends HttpServlet {

// Constants ----------------------------------------------------------------------------------

private static final int DEFAULT_BUFFER_SIZE = 10240; // 10KB.

// Statics ------------------------------------------------------------------------------------

private static ImageDAO imageDAO = DAOFactory.getImageDAO();

// Actions ------------------------------------------------------------------------------------

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
// Get ID from request.
String imageId = request.getParameter("id");

// Check if ID is supplied to the request.
if (imageId == null) {
// Do your thing if the ID is not supplied to the request.
// Throw an exception, or send 404, or show default/warning image, or just ignore it.
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
return;
}

// Lookup Image by ImageId in database.
// Do your "SELECT * FROM Image WHERE ImageID" thing.
Image image = imageDAO.find(imageId);

// Check if image is actually retrieved from database.
if (image == null) {
// Do your thing if the image does not exist in database.
// Throw an exception, or send 404, or show default/warning image, or just ignore it.
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
return;
}

// Init servlet response.
response.reset();
response.setBufferSize(DEFAULT_BUFFER_SIZE);
response.setContentType(image.getContentType());
response.setContentLength(image.getContent().length);
response.setHeader("Content-Disposition", "inline; filename=\"" + image.getName() + "\"");

// Prepare streams.
BufferedOutputStream output = null;

try {
// Open streams.
output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);

// Write file contents to response.
output.write(image.getContent());
} finally {
// Gently close streams.
close(output);
}
}

// Helpers (can be refactored to public utility class) ----------------------------------------

private static void close(Closeable resource) {
if (resource != null) {
try {
resource.close();
} catch (IOException e) {
// Do your thing with the exception. Print it, log it or mail it.
e.printStackTrace();
}
}
}

}

In order to get the ImageServlet to work, add the following entries to the Web Deployment Descriptor
web.xml:

<servlet>
<servlet-name>imageServlet</servlet-name>
<servlet-class>mypackage.ImageServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>imageServlet</servlet-name>
<url-pattern>/image/*</url-pattern>
</servlet-mapping>

Of course you can change the url-pattern of the servlet-mapping as you like it.

Here are some basic use examples:

<!-- XHTML or JSP -->
<img src="image?id=250d7f5086d02a46f9aeec9c51d43c63" />
<img src="image?id=0412c29576c708cf0155e8de242169b1" />

<!-- JSF -->
<h:graphicImage value="image?id=250d7f5086d02a46f9aeec9c51d43c63" />
<h:graphicImage value="image?id=0412c29576c708cf0155e8de242169b1" />
<h:graphicImage value="image?id=#{myBean.imageId}" />

Security considerations

In the last example of an ImageServlet serving from database, the ID is encrypted by MD5. It's your choice how you want to implement the use of ID, but keep in mind that plain numeric ID's like 1, 2, 3 and so on makes the hacker easy to guess for another
images in the database, which they probably may not view at all. Then rather use a MD5 hash based on a combination of the numeric ID, the filename and the filesize for example. And last but not least, use
PreparedStatement instead of a basic
Statement to request the image by ID from database, otherwise you will risk an SQL injection when a hacker calls for example
"image?id=';TRUNCATE TABLE Image--".
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: