-->

Is it posible to change upload path with a servlet

2019-08-20 07:17发布

问题:

I'm gonna try to explain what I want to do here and why I need to do it this way.

I know I can redirect my inside of context paths to outside of context paths using a servlet like the next that I got somewhere around here, which works beautifully:

@WebServlet("/images/*")
public class ImageServlet extends HttpServlet {

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

private String imagePath;

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

public void init() throws ServletException {

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

    // In a Windows environment with the Applicationserver running on the
    // c: volume, the above path is exactly the same as "c:\var\webapp\images".
    // In Linux/Mac/UNIX, it is just straightforward "/var/webapp/images".
}

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

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.setContentType(contentType);
    response.setHeader("Content-Length", String.valueOf(image.length()));

    // Write image content to response.
    Files.copy(image.toPath(), response.getOutputStream());
   }
}

So that whenever I use the path within context "/webApp/images/mypic.jpg", it actually gets the image from my outside of context images folder "/home/mycomp/images/".

And it's great, because I can't modify the original code, and I only had to add this servlet to redirect it outside of context. That's why I'm trying to do the same but for uploading. I got the next piece of code to get path where the image is saved and saves it, which at the moment is within context:

    String file = "imagen" + (1 + (int) (Math.random() * 100000));

    String path = httpServletRequest.getSession().getServletContext().getRealPath("/images/");

    InputStream in = imagen.getInputStream();
        OutputStream bos = new FileOutputStream(path + "/" + file);

        int byteRead = 0;
        byte[] buffer = new byte[8192];
        while ((byteRead = in.read(buffer, 0, 8192)) != -1) {
            bos.write(buffer, 0, byteRead);
        }
        bos.close();
        in.close();

(I know I' missing the part where I actually get the image, but I don't need to show that.) This saves the image in "/home/mycomp/project/webApp/images/", as that's the result of getRealPath, and it is obviously within context.

EDIT: This is done inside a struts1 action, which complicates things a little bit, since now I've come to understand that I can't call an action from within a servlet, or can I?

This leads us to the question, is it possible to save it outside of context without modifying the code that saves the images using something like the servlet, so that instead of saving it to "/home/mycomp/project/webApp/images/", it will save it to "/home/mycomp/images/"?

回答1:

Of course, You can change upload directory.
Use annotation:

@MultipartConfig(
    location="/tmp", // <-----
    fileSizeThreshold=1024*1024,    
    maxFileSize=1024*1024*5,    
    maxRequestSize=1024*1024*5*5   
)

or use web.xml

<multipart-config>
    <location>/tmp</location>
    <max-file-size>20848820</max-file-size>
    <max-request-size>418018841</max-request-size>
    <file-size-threshold>1048576</file-size-threshold>
</multipart-config>

Reference: https://docs.oracle.com/javaee/7/tutorial/servlets011.htm



回答2:

The answer is no, not the way I wanted to do, now that I understand better what a servlet is and how they work.

What I was trying to do was to overwrite the upload path in a struts action, with a servlet, which can't be done, since servlet would be executed INSTEAD of action. So no, you can't use a servlet to overwrite a upload path inside an action.