web-dev-qa-db-ja.com

Java Webアプリケーションでアプリケーションサーバーの外部から静的データを提供する最も簡単な方法

TomcatでJava Webアプリケーションを実行しています。 Web UIとアプリケーションによって生成されたPDFファイルの両方に表示される静的画像をロードしたい。また、Web UIを介してアップロードすることにより、新しい画像が追加および保存されます。

静的データをWebコンテナー内に格納することでこれを行うことは問題ではありませんが、Webコンテナーの外部からそれらを格納およびロードすることは頭痛の種です。

この時点で静的データを提供するために、Apacheのような別個のWebサーバーを使用したくないです。また、画像をデータベースにバイナリで保存するという考え方も好きではありません。

画像ディレクトリをWebコンテナ外のディレクトリを指すシンボリックリンクにするなどの提案を見てきましたが、このアプローチはWindows環境と* nix環境の両方で機能しますか?

画像提供を処理するためのフィルターまたはサーブレットの作成を提案する人もいますが、これらの提案は非常に曖昧で高レベルであり、これを実現する方法に関する詳細情報へのポインターはありません。

127
Janne

Webディレクトリ外のディレクトリを指すシンボリックリンクであるイメージディレクトリなどのいくつかの提案を見てきましたが、このアプローチはWindows環境と* nix環境の両方で機能しますか?

* nixファイルシステムパスルールを順守している場合(つまり、/path/to/filesのようにスラッシュのみを使用している場合)、いFile.separator文字列連結をいじる必要なく、Windowsでも動作します。ただし、このコマンドが呼び出された場所と同じ作業ディスクでのみスキャンされます。たとえば、TomcatがC:にインストールされている場合、/path/to/filesは実際にC:\path\to\filesを指します。

ファイルがすべてwebappの外部にあり、TomcatのDefaultServletを使用してそれらを処理する場合、Tomcatで基本的に必要なことは、/conf/server.xml内の<Host>タグ:

<Context docBase="/path/to/files" path="/files" />

これにより、http://example.com/files/...からアクセスできます。 GlassFish/Payaraの構成例は here にあり、WildFlyの構成例は here にあります。

自分でファイルの読み取り/書き込みを制御したい場合は、Servletを作成する必要があります。これは基本的に、たとえばInputStreamのフレーバーでFileInputStreamを取得するだけです。 OutputStreamHttpServletResponseに書き込みます。

応答では、Content-Typeヘッダーを設定して、クライアントが提供されたファイルに関連付けるアプリケーションを認識できるようにする必要があります。また、クライアントがダウンロードの進行状況を計算できるようにContent-Lengthヘッダーを設定する必要があります。そうでない場合、不明になります。また、名前を付けて保存ダイアログが必要な場合は、Content-Dispositionヘッダーをattachmentに設定する必要があります。そうでない場合、クライアントはインラインで表示します。最後に、ファイルのコンテンツを応答出力ストリームに書き込みます。

このようなサーブレットの基本的な例を次に示します。

@WebServlet("/files/*")
public class FileServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
        String filename = URLDecoder.decode(request.getPathInfo().substring(1), "UTF-8");
        File file = new File("/path/to/files", filename);
        response.setHeader("Content-Type", getServletContext().getMimeType(filename));
        response.setHeader("Content-Length", String.valueOf(file.length()));
        response.setHeader("Content-Disposition", "inline; filename=\"" + file.getName() + "\"");
        Files.copy(file.toPath(), response.getOutputStream());
    }

}

たとえばurl-pattern/files/*にマッピングされている場合、http://example.com/files/image.pngで呼び出すことができます。この方法では、デフォルトの画像(つまりif (!file.exists()) file = new File("/path/to/files", "404.gif")など)を提供するなど、DefaultServletよりもリクエストをより細かく制御できます。また、request.getPathInfo()を使用することは、request.getParameter()よりも優先されます。なぜなら、それはSEOフレンドリであり、そうでなければ、IEは

データベースからファイルを提供するために同じロジックを再利用できます。 new FileInputStream()ResultSet#getInputStream()に置き換えるだけです。

お役に立てれば。

こちらもご覧ください:

156
BalusC

画像を固定パス(例:/ var/images、またはc:\ images)に配置し、アプリケーション設定に設定を追加して(私の例ではSettings.classで表されます)、ロードします。あなたのHttpServletで:

String filename = Settings.getValue("images.path") + request.getParameter("imageName")
FileInputStream fis = new FileInputStream(filename);

int b = 0;
while ((b = fis.read()) != -1) {
        response.getOutputStream().write(b);
}

または、画像を操作する場合:

String filename = Settings.getValue("images.path") + request.getParameter("imageName")
File imageFile = new File(filename);
BufferedImage image = ImageIO.read(imageFile);
ImageIO.write(image, "image/png", response.getOutputStream());

htmlコードは<img src="imageServlet?imageName=myimage.png" />になります

もちろん、ファイル拡張子に基づいて、「image/jpeg」などのさまざまなコンテンツタイプを提供することを検討する必要があります。また、キャッシュを提供する必要があります。

さらに、幅と高さのパラメーターを引数として指定し、image.getScaledInstance(w, h, Image.SCALE_SMOOTH)を使用して、当然ながらパフォーマンスを考慮して、このサーブレットを使用して画像の品質を再調整できます。

9
Bozho

これは私の職場の話です:
-Struts 1とTomcat 7.xを使用して、複数の画像とドキュメントファイルをアップロードしようとしています。
-アップロードされたファイルをファイルシステム、ファイル名、データベースレコードへのフルパスに書き込みます。
-個別のファイルフォルダー外部Webアプリディレクトリを試みます。 (*)

以下のソリューションは非常にシンプルで、要件に効果的です(*):

ファイルMETA-INF/context.xml以下の内容のファイル:(たとえば、アプリケーションはhttp://localhost:8080/ABCで実行され、アプリケーション/プロジェクトはABCという名前です)。 (これはファイルcontext.xmlの完全なコンテンツでもあります)

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/ABC" aliases="/images=D:\images,/docs=D:\docs"/>

(Tomcatバージョン7以降で動作します)

結果: 2つのエイリアスが作成されました。たとえば、画像をD:\images\foo.jpgに保存し、リンクから表示するか、画像タグを使用します:

<img src="http://localhost:8080/ABC/images/foo.jsp" alt="Foo" height="142" width="142">

または

<img src="/images/foo.jsp" alt="Foo" height="142" width="142">

(Netbeans 7.xを使用していますが、NetbeansはファイルWEB-INF\context.xmlを自動作成しているようです)

6
D Vy

要件:WEBROOTディレクトリの外部またはローカルディスクから静的リソース(画像/ビデオなど)にアクセスする

ステップ1 :
Tomcatサーバーのwebappsの下にフォルダーを作成します。フォルダー名がmyprojであるとしましょう。

ステップ2 :
myprojの下にWEB-INFフォルダーを作成し、この下に単純なweb.xmlを作成します

web.xmlの下のコード

<web-app>
</web-app>

上記の2つのステップのディレクトリ構造

c:\programfile\apachesoftwarefoundation\Tomcat\...\webapps
                                                            |
                                                            |---myproj
                                                            |   |
                                                            |   |---WEB-INF
                                                                |   |
                                                                    |---web.xml

ステップ3:
次の場所にmyproj.xmlという名前のxmlファイルを作成します。

c:\programfile\apachesoftwarefoundation\Tomcat\conf\catalina\localhost

Myproj.xmlのコード:

<Context path="/myproj/images" docBase="e:/myproj/" crossContext="false" debug="0" reloadable="true" privileged="true" /> 

ステップ4:
4 A)次に、ハードディスクのEドライブにmyprojという名前のフォルダーを作成し、新しいフォルダーを作成します

画像に名前を付けて、いくつかの画像を画像フォルダに配置します(e:myproj\images\)

Myfoto.jpgがe:\myproj\images\myfoto.jpgの下に配置されているとします

4 B)e:\myproj\WEB-INFにWEB-INFという名前のフォルダーを作成し、WEB-INFフォルダーにweb.xmlを作成します

Web.xmlのコード

<web-app>
</web-app>

ステップ5:
次に、index.htmlという名前の.htmlドキュメントを作成し、e:\ myprojの下に配置します。

Index.htmlの下のコードMyprojへようこそ

上記のステップ4とステップ5のディレクトリ構造は次のとおりです。

E:\myproj
    |--index.html
    |
    |--images
    |     |----myfoto.jpg
    |
    |--WEB-INF
    |     |--web.xml

ステップ6:
Apache Tomcatサーバーを起動します

ステップ7:
ブラウザを開き、次のようにURLを入力します

http://localhost:8080/myproj    

次に、index.htmlで提供されるコンテンツを表示します

ステップ8:
ローカルハードディスク(webrootの外部)の下のイメージにアクセスするには

http://localhost:8080/myproj/images/myfoto.jpg
6
sbabamca

Server.xmlに追加します。

 <Context docBase="c:/dirtoshare" path="/dir" />

Web.xmlのdirファイルリストパラメータを有効にします。

    <init-param>
        <param-name>listings</param-name>
        <param-value>true</param-value>
    </init-param>
5
blue-sky

FileServletにディスパッチすることにした場合は、FileServletがシンボリックリンクを通過できるようにするために、allowLinking="true"内のcontext.xmlも必要になります。

http://Tomcat.Apache.org/Tomcat-6.0-doc/config/context.html を参照してください

2
cherouvim

JAX-RS(例:RESTEasy)で作業したい場合は、これを試してください:

@Path("/pic")
public Response get(@QueryParam("url") final String url) {
    String picUrl = URLDecoder.decode(url, "UTF-8");

    return Response.ok(sendPicAsStream(picUrl))
            .header(HttpHeaders.CONTENT_TYPE, "image/jpg")
            .build();
}

private StreamingOutput sendPicAsStream(String picUrl) {
    return output -> {
        try (InputStream is = (new URL(picUrl)).openStream()) {
            ByteStreams.copy(is, output);
        }
    };
}

javax.ws.rs.core.Responseおよびcom.google.common.io.ByteStreamsを使用

0
electrobabe

ファイルのInputStreamを読み取り、バイナリデータをクライアントに送信するために ServletOutputStream に書き込みます。

  • ローカルファイルFileInputStream( 'path/image.png')を使用してファイルを直接読み取ることができます。
  • MongoデータベースファイルのGridFSを使用してInputStreamを取得
@WebServlet("/files/URLStream")
public class URLStream extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public URLStream() {
        super();
    }

    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        File source = new File("D:\\SVN_Commit.PNG");
        long start = System.nanoTime();

        InputStream image = new FileInputStream(source);

        /*String fileID = request.getParameter("id");
        System.out.println("Requested File ID : "+fileID);
        // Mongo DB GridFS - https://stackoverflow.com/a/33544285/5081877
        image = outputImageFile.getInputStream();*/

        if( image != null ) {
            BufferedInputStream bin = null;
            BufferedOutputStream bout = null;
            ServletOutputStream sos = response.getOutputStream();
            try {
                bin = new BufferedInputStream( image );
                bout = new BufferedOutputStream( sos );
                int ch =0; ;
                while((ch=bin.read())!=-1) {
                    bout.write(ch);
                }
            } finally {
                bin.close();
                image.close();
                bout.close();
                sos.close();
            }

        } else {
            PrintWriter writer = response.getWriter();
            writer.append("Something went wrong with your request.");
            System.out.println("Image not available.");
        }
        System.out.println("Time taken by Stream Copy = "+(System.nanoTime()-start));
    }
}

src属性へのURLを直接生成します。

<img src='http://172.0.0.1:8080/ServletApp/files/URLStream?id=5a575be200c117cc2500003b' alt="mongodb File"/>
<img src='http://172.0.0.1:8080/ServletApp/files/URLStream' alt="local file"/>

<video controls="controls" src="http://172.0.0.1:8080/ServletApp/files/URLStream"></video>
0
Yash

受け入れられた回答で問題を解決できない場合は、以下の考慮事項に注意してください。

  1. localhost:<port>属性で<img> srcに言及する必要はありません。
  2. eclipseはローカルcontext docBaseファイル内にserver.xmlエントリを独自に作成するため、Eclipseの外部でこのプロジェクトを実行していることを確認してください。
0
JPG