5

ユーザーが画像をアップロードできる簡単なアプリケーションを作成しています。アップロード後、ユーザーはそれらにタグを付けたり、削除したりできます。

ファイルをアップロードして、ファイルがアップロードされたら保存する方法を見つけました。画像が保存されているグローバルパスを追跡しています。データベースには、ファイル名やタグなどの画像に関するメタデータを保持しています。

私はJava/JSPを使用しています(具体的にはStripesフレームワークですが、私の問題は一般的です)。

私の質問は、アップロードされたこれらの画像ファイルをどこに保存するかです。

現在、Tomcatサーバーに2つのWebアプリケーションをデプロイしています。1つのメインWebアプリケーションともう1つは、画像をアップロードする場所です。

ただし、Tomcatを再デプロイ/再起動するまで、メインアプリケーションにアップロードされたイメージが表示されないため、これは機能しません。

Tomcatは新しくアップロードされた画像を自動的に選択しないようです。

誰かが解決策を持っていますか?

これは単純なプロジェクトなので、データベースに保存したり、画像にApacheを使用したりしたくありません。これは、この小さなプロジェクトには複雑すぎます。

ありがとう。

4

6 に答える 6

5

絶対にデータベースに画像を保存しないでください、しかしあなたはデータベースに画像パスを保存したいと思うでしょう。これにより、画像をほぼどこにでも保存できます。

2つのTomcatアプリケーションを使用しているため、Tomcatにファイルを管理させるのではなく、いずれかのアプリの外部に画像を保存してユーザーにストリーミングするのが最善の策です。それ以外の場合は、2つのWebアプリでこれを実行しようとしている理由を尋ねます。

于 2008-12-22T01:49:06.560 に答える
3

ただし、アップロードされた画像をweb-appディレクトリ内に保存することは賢明なことではなく、ご存知のとおりです。

ちなみに、最近画像を保存する場所について説明した、このスタックオーバーフロースレッドを確認することをお勧めします。それはあなたの問題を解決しないかもしれません、確かにあなたがしていることにもっと自信を与えるでしょう。

于 2008-12-22T02:05:45.807 に答える
2

私はこれをさまざまな方法で解決しました。

まず、移植性のない方法は、Glassfish (Tomcat も信じています) を使用すると、外部ディレクトリを webapps 階層にマップできることです。これは非常にうまく機能し、まさにあなたが望むことを行います。これにより、Web アプリケーションから離れた外部ディレクトリに画像を保存しながら、それらを提供することができます。

ただし、この手法は移植性がありません。

移植可能にする方法は、フィルターを作成することです。

「/images」など、わかりやすい場所にフィルターを配置します。

フィルターの機能は次のとおりです。

  • webapp 内の特別なディレクトリで画像 (または任意の静的リソースで動作するもの) をチェックします。この例では、URL「/webapp/images」を使用します。

  • ファイルが存在しない場合は、外部の場所から webapp 内の適切な場所にファイルをコピーします。したがって、リクエスト URL が「/images/banner.gif」であるとしましょう。また、ファイルはディスクの「/home/app/images」に保存されます。したがって、ソース ファイルは「/home/app/images/banner.gif」です。次に、それを webapp ツリー内の必要な場所にコピーします。これには「ServletContext.getRealPath」を使用します。したがって、宛先は "ServletContext.get RealPath("/webapp/images/banner.gif") になります。ソースを宛先にコピーするだけです。

  • ファイルが既に存在する場合、または現在存在する場合は、/webapp/images/banner.gif にある実際の画像に転送してください。

事実上、webapps デプロイメント ツリー内にファイル キャッシュが作成されます。マイナス面は、それがキャッシュであるため、維持する必要があることです (つまり、オリジナルがキャッシュよりも新しいかどうかを確認し、ソースが削除されている場合は必ず削除する必要があります)。また、リソースが複製されるため、イメージは最終的に 2 倍のディスク容量を消費します。最後に、立ち上げ時の初期コピー費用です。

ただし、それは機能し、独自のコードを使用して静的リソースを提供する必要がなくなります。(これは 3 番目のソリューションです。フィルター/サーブレットをマップして URL をインターセプトし、それを自分でストリーミングするだけです。)

マッピングを行うために、Tomcat 内のコンストラクト (存在すると仮定) を調べます。Glassfishに存在することは知っています。(Glassfish がどのように機能するかを確認するには、Google 代替ドキュメントルートを参照してください。)

于 2008-12-22T04:54:59.553 に答える
0

新しいメインアプリケーションのwarファイルを再デプロイする場合に備えて、アップロードされたイメージを上書きしないように、2つのWebアプリケーションを使用していました。

しかし、あなたが言うように、サーブレットまたは何かを介してそれらをストリーミングする以外に他のオプションはありません。私はそれらをtomcatディレクトリの外に保持できると思います。

このストリーミングサーブレットを作成することは避けたかったのです。ストリーミングサーブレットの作成中にすべての混乱(適切なコンテンツタイプ、404など)を処理するにはプロジェクトが小さすぎます。

于 2008-12-22T02:00:19.017 に答える
0
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;

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

/**
 * Image streaming Servlet.
 */
public class ImageDisplayServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public ImageDisplayServlet() {
        super();
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String relativePath = trimToEmpty(request.getPathInfo());

        // Make sure no one try to screw with us. 
        // This is important as user can literally access any file if we are not careful
        if(isXSSAttack(relativePath) == false) {
            String pathToFile = this.getServletContext().getRealPath(request.getPathInfo());
            File file = new File(pathToFile);

            System.out.println("Looking for file " + file.getAbsolutePath());

            // show a 404 page
            if(!file.exists() || !file.isFile()) {
                httpError(404, response);
            } else {
                try {
                    streamImageFile(file, response);
                } catch(Exception e) {
                    // Tell the user there was some internal server error.\
                    // 500 - Internal server error.
                    httpError(500, response);
                    e.printStackTrace();
                }
            }
        } else {
            // what to do if i think it is a XSS attack ?!?
        }
    }

    private void streamImageFile(File file, HttpServletResponse response) {
        // find the right MIME type and set it as content type
        response.setContentType(getContentType(file));
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            response.setContentLength((int) file.length());

            // Use Buffered Stream for reading/writing.
            bis = new BufferedInputStream(new FileInputStream(file));
            bos = new BufferedOutputStream(response.getOutputStream());

            byte[] buff = new byte[(int) file.length()];
            int bytesRead;

            // Simple read/write loop.
            while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
                bos.write(buff, 0, bytesRead);
            }
        } catch (Exception e) {

            throw new RuntimeException(e);
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    // To late to do anything about it now, we may have already sent some data to user.
                }
            }
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    // To late to do anything about it now, we may have already sent some data to user.
                }
            }
        } 
    }

    private String getContentType(File file) {
        if(file.getName().length() > 0) {
            String[] parts = file.getName().split("\\.");
            if(parts.length > 0) {
                // only last part interests me
                String extention = parts[parts.length - 1];
                if(extention.equalsIgnoreCase("jpg")) {
                    return "image/jpg";
                } else if(extention.equalsIgnoreCase("gif")) {
                    return "image/gif"; 
                } else if(extention.equalsIgnoreCase("png")) {
                    return "image/png";
                }
            }
        }
        throw new RuntimeException("Can not find content type for the file " +  file.getAbsolutePath());
    }

    private String trimToEmpty(String pathInfo) {
        if(pathInfo == null) {
            return "";
        } else {
            return pathInfo.trim();
        }
    }

    private void httpError(int statusCode, HttpServletResponse response) {
        try {
            response.setStatus(statusCode);
            response.setContentType("text/html");
            PrintWriter writer = response.getWriter();
            writer.append("<html><body><h1>Error Code: " + statusCode + "</h1><body></html>");
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private boolean isXSSAttack(String path) {
        boolean xss = false;
        // Split on the bases of know file separator
        String[] parts = path.split("/|\\\\");

        // Now verify that no part contains anything harmful
        for(String part : parts) {
            // No double dots .. 
            // No colons :
            // No semicolons ;
            if(part.trim().contains("..") || part.trim().contains(":") || part.trim().contains(";")) {
                // Fire in the hole!
                xss = true;
                break;
            }
        }
        return xss;
    }

    /**
     * @see HttpServlet#doPost(Ht/promotions/some.jpgtpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

OK ここに、画像をストリーミングできるサーブレットを簡単に作成しました。

制限事項と既知の問題のリストは次のとおりです。

  • XSS の脆弱性がある可能性があります。注意して使用してください
  • リファレンスとして使用する準備が整っていない
  • 画像は Web アプリケーション ディレクトリにある必要があります。簡単に変更できますが、私はあまりにも怠け者です (プロジェクトが小さすぎるのは価値がありません)
  • jpg、gif、または png ファイルのみをストリーミングします。

使用法:

この images という Web アプリケーションを別のアプリケーションとしてデプロイするとします。

http://www.example.com/images/promotions/promo.jpg

は、この画像 Web アプリケーション内の画像「promo.jpg」を含む「プロモーション」ディレクトリが必要であることを意味します。

PS: なぜ私がこの Servlet Container のみの解決策を実行しているのかは聞かないでください。

于 2008-12-22T03:46:29.863 に答える
0
  <servlet>
    <description></description>
    <display-name>ImageDisplayServlet</display-name>
    <servlet-name>ImageDisplayServlet</servlet-name>
    <servlet-class>com.example.images.ImageDisplayServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>ImageDisplayServlet</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>

最良の結果を得るには、上記のようにサーブレットを構成してください:P

于 2008-12-22T03:47:50.453 に答える