关于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.
In order to get the ImageServlet to work, add the following entries to the Web Deployment Descriptor
web.xml:
Of course you can change the url-pattern of the servlet-mapping as you like it.
Here are some basic use examples:
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.
Here is a basic example of a ImageServlet which serves a image from a database.
In order to get the ImageServlet to work, add the following entries to the Web Deployment Descriptor
web.xml:
Of course you can change the url-pattern of the servlet-mapping as you like it.
Here are some basic use examples:
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--".
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 asbyte[] 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 anotherimages 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--".
相关文章推荐
- android红米等关于读取本地文件夹图片获取路径的问题的解决
- 关于Android7.0版本及其以上系统获取本地数据(图片和文件)报系统出现异常,正在退出问题
- express无法在页面中无法获取本地图片的解决方法
- 关于DEDE解决无法下载远程图片(远程抓图、存图)到本地?
- android红米等关于读取本地文件夹图片获取路径的问题的解决
- 【小程序】本地资源图片无法通过 WXSS 获取
- android红米等关于读取本地文件夹图片获取路径的问题的解决
- 小程序 | background-image无法获取本地资源图片
- 【小程序】background-image无法获取本地资源图片
- 关于Android开发保存bitmap获取图片到本地方法
- 关于AssetsLibrary无法获取本地所有相册的问题
- android获取本地图片或拍照图片
- 解决微信及360浏览器无法读取本地图片问题
- JSP img元素无法显示本地图片的问题(一)
- Unity获取本地图片并保存后使用
- android添加图片到本地,无法即使刷新的解决方法
- 使用fresco如何获取本地缓存图片的文件
- IOS -- 获取本地图片和网络图片的大小size
- 自动扫描所有本地磁盘,获取所有图片信息
- 获取本地时间时,关于时间的显示格式问题