在我的tomcat文件夹的server.xml
中,我在<Host>
标签下有一个虚拟文件夹:
<Context docBase="C:app_files" path="/app_files"/>
因此,我可以通过以下网址访问该文件夹中的文件:http://localhost:8080/app_files/some_file.jpg
但只有在启动服务器之前图像或文件已经存在的情况下,这才有效。如果我转到一个指向服务器启动后创建的图像的URL,就会出现404错误。重新启动服务器后,映像将正确加载。
如何解决这个问题?
如果您使用Tomcat应用程序管理器,您可以在不重新启动整个服务器的情况下取消部署/部署单个应用程序(并且不会影响其他Web应用程序),或者,更残酷的是,您可以从Web应用程序目录中替换所需的战争(再次取消部署/展开)。如果您必须保证应用程序的正常运行时间,即使在这种情况下,您也必须进行并行部署(这里是tomcat 8的指南)
尝试将属性autoDeploy="true"
添加到您的上下文配置中,这将告诉catalina监视您的文档库位置以了解的更改
我实际上在不使用server.xml上的Context的情况下完成了我想要的操作。它基于BalusC通过servlet提供静态文件的解决方案方法如下:
- 首先,我在我的系统中创建了一个环境变量(可以在每个操作系统中完成,只需在谷歌上搜索"如何在windows、linux等上创建环境变量"),名为MANAGEMENT_FILES,在我的情况下,变量值为c:/MANAGEMENT_FILES/
- 然后,在创建应该显示给用户的图像的方法上,我将图像保存在此文件夹(这是上一步中环境变量的值)上:
public String imageUrl;
public void createAndShowImage() {
try {
String imageName = "/nice_images_folder/cool_image.jpg";
File imageFile = new File(System.getenv("MANAGEMENT_FILES") + imageName);
//Here goes your logic to create the file
createImage(imageFile);
//Here i use a fixed URL, you can do it as you see fit
this.imageUrl = "http://localhost:8080/MyCoolApp/" + CoolFileServlet.BASE_URL + imageName + "?delete=true";
} catch (Exception e) {
e.printStackTrace();
}
}
- 这是您必须创建的servlet,该servlet返回您放入文件夹中的图像或任何其他文件:
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.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(name="CoolFileServlet", urlPatterns={CoolFileServlet.BASE_URL + "*"})
public class CoolFileServlet extends HttpServlet {
public static final String BASE_URL = "/shiny_happy_files/";
private static final int DEFAULT_BUFFER_SIZE = 10240;
private String filePath;
public void init() throws ServletException {
this.filePath = System.getenv("MANAGEMENT_FILES");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String requestedFile = request.getPathInfo();
if (requestedFile == null) {
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
return;
}
File file = new File(filePath, URLDecoder.decode(requestedFile, "UTF-8"));
if (!file.exists()) {
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
return;
}
String contentType = getServletContext().getMimeType(file.getName());
if (contentType == null) {
contentType = "application/octet-stream";
}
response.reset();
response.setBufferSize(DEFAULT_BUFFER_SIZE);
response.setContentType(contentType);
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-Disposition", "attachment; filename="" + file.getName() + """);
BufferedInputStream input = null;
BufferedOutputStream output = null;
try {
input = new BufferedInputStream(new FileInputStream(file), DEFAULT_BUFFER_SIZE);
output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
} finally {
close(output);
close(input);
try {
if ("true".equals(request.getParameter("delete"))) {
if (!file.delete()) {
throw new RuntimeException("File could not be deleted");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private static void close(Closeable resource) {
if (resource != null) {
try {
resource.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
请注意,当访问url时,您可以在url中传递参数delete=true,以便在恢复后立即删除它(在不再需要它的情况下)。
在我的情况下,我需要在用户执行一些操作后在页面上显示图像,所以我所要做的就是显示图像url:
<h:graphicImage url="#{myManagedBean.imageUrl}"/>
就是这样,您可以用这个servlet为任何类型的文件提供服务,它会立即返回您想要的文件,并且该文件在服务器重新启动/重新部署之间将保持活动状态(如果它没有通过delete=true
.
如果您喜欢不同的方法,您也可以通过在控制器中映射一个函数来实现这一点,该函数在指定媒体类型时返回IOUtils对象,然后在img的src中调用函数的URL。
@ResponseBody
@RequestMapping(value="/load_photo", params = {"myPhoto"}, method = RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE)
public byte[] loadPhoto(@RequestParam(value = "myPhoto") String myPhoto) throws IOException {
File file = new File(servletContext.getRealPath("")+Constants.PATH_TO_FILE+myPhoto);
FileInputStream fis = new FileInputStream(file);
return IOUtils.toByteArray(fis);
}
然后在JSP中调用img:
<img class="photo" src="/app/controller/load_photo?myPhoto=${myPhoto}">
这样,您就可以提供动态生成的图像。