Tomcat在服务器启动后未从上下文路径加载新映像



在我的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}">

这样,您就可以提供动态生成的图像。

最新更新