可能性のあるエラーの処理を伴うサーバーからのファイルの受信

イントラネットシステムの1つについて、公式文書に添付されたファイルの内容を簡単に検索しました。 検索の結果、ファイル名とサーブレットへのリンクのリストが作成され、これらのファイルがアンロードされました。 サーブレットは、リポジトリから識別子によってファイルを読み取り、「Content-Type:application / octet-stream」またはファイルに対応するMIMEタイプで発行します。 しかし、サーバーでエラーが発生した場合、どうすればよいですか?オペレーターに伝えるにはどうすればよいですか? メッセージを含むページへのリダイレクトを手配することは可能ですが、これは不便です-フォームに入力されたデータが失われた場所に戻る必要があります。

一方、AJAX XmlHttpRequestを介してサーブレットを呼び出してエラーメッセージを表示できますが、ファイルを返す方法はありますか? XHRオブジェクトのコールバック関数は、サーバーから受信したバイナリデータでは機能せず、標準の「ファイルの保存/読み込み」ブラウザダイアログを表示できません。



私たちはこの方法から抜け出しました。 クライアントはサーブレットを2回呼び出します。 ステップ1で、彼はサーバーストレージからファイルをダウンロードするように要求し(これに必要なすべてのパラメーターを渡すAJAXテクノロジーを使用)、サーブレットはファイルを読み取り、そのコンテンツ、名前、MIMEタイプ、およびその他の属性をセッションに入れ、クライアントに応答します( JSON応答形式 )特定のsession_id



(ドキュメントが正常に受信され、クライアントを待機している)、またはJavaScriptがwindow.alert()



介してクライアントに簡単に表示できるエラー文字列のいずれか。 ステップ1でsession_idを受信すると、クライアントは2番目の移動を行います。フォームの通常の転送を使用します example.com/servletname?session_id=123456



example.com/servletname?session_id=123456



は、このパラメーターを使用して同じサーブレットにすぐに次のリクエストを行い、 Content-Type: application/octet-stream



を受信します。応答としてContent-Type: application/octet-stream



同志。これにより、最終的にブラウザーに標準ダイアログが表示されます。 その後、ドキュメントはセッションから削除され、スペースが解放されます。



いくつかの短いメモ:





作業の追加の説明は、提示されたコードで取得できます。



AbstractGetFileAJAXWay.java



作業の大部分を行う抽象Javaクラス。 特定の継承クラスは、各ケースに固有の2つのメソッドを実装する必要があります。



package unchqua.getfileajaxway;



import java.io.BufferedOutputStream;

import java.io.IOException;

import java.io.OutputStream;

import java.io.Serializable;



import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;



import java.util.Random;



/**

* .

*

* <p> :</p>

* <dl>

* <dt>populateIdentity(HttpServletRequest)</dt>

* <dd> ,

* .</dd>

* <dt>getDocument(HttpServletRequest, Object)</dt>

* <dd> .</dd>

* </dl>

*

* <p>

* : EJB (

* ),

* AbstractGetFileAJAXWay#DSID (,

* ) .

* </p>

*

* <p> JSON- :</p>

* <ul>

* <li> EJB:<br/>

* <pre>{"result":"success","dsid":"362547383846347775"}</pre>

* </li>

* <li> EJB:<br/>

* <pre>{"result":"failure","reason":" !"}</pre>

* </li>

* </ul>

*/

public abstract class AbstractGetFileAJAXWay extends HttpServlet {



public static final String DSID = "dsid";



public class GetFileAJAXWayException extends Exception {

public GetFileAJAXWayException() { super(); }

public GetFileAJAXWayException(String msg) { super(msg); }

public GetFileAJAXWayException(Throwable thw) { super(thw); }

public GetFileAJAXWayException(String msg, Throwable thw) { super(msg, thw); }

}



public interface IFileContainer extends Serializable {

public String getFileName();

public String getContentType();

public long getFileLength();

public byte[] getFileContent();

}



/**

* .

*

* @param req HTTP-.

* @param resp HTTP-.

* @throws ServletException

* @throws IOException

*/

public void doGet(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, IOException {



// .

String dsid = req.getParameter(DSID);



// .

if (dsid != null && dsid.length() > 0) {

try {

deliverDocument(dsid, req, resp);

} catch (GetFileAJAXWayException e) {

e.printStackTrace();

throw new ServletException(e);

}

}

// .

else if (req.getParameterMap().size() > 0) {

try {

Object identity = populateIdentity(req);

retrieveDocument(identity, req, resp);

} catch (GetFileAJAXWayException e) {

e.printStackTrace();

throw new ServletException(e);

}

}

// .

else {

final String err = " !";

log(err);

sendFailureReply(err, resp);

return;

}

}



/**

* .

* @param identity , . * @param req HTTP-.

* @param resp HTTP-.

* @throws ServletException

* @throws IOException

*/

private void retrieveDocument

(Object identity, HttpServletRequest req, HttpServletResponse resp)

throws IOException {



// .

HttpSession session = req.getSession(false);



// , .

IFileContainer cont;

try {

cont = getDocument(req, identity);

} catch (Exception e) {

final String err = " : "

+ e.getMessage() + "!";

log(err);

sendFailureReply(err, resp);

return;

}



// .

final String dsid = dsid(

new long[]{ cont.hashCode(),

cont.getFileLength(),

session.hashCode() });



// .

session.setAttribute(dsid, cont);



// .

sendSuccessReply(dsid, resp);

}



/**

* .

* @param dsid .

* @param req HTTP-.

* @param resp HTTP-.

* @throws ServletException

* @throws IOException

*/

private void deliverDocument

(String dsid, HttpServletRequest req, HttpServletResponse resp)

throws GetFileAJAXWayException, IOException {



// .

HttpSession session = req.getSession(false);



// ?

Object sessobj = session.getAttribute(dsid);

if (sessobj == null) {

throw new GetFileAJAXWayException(" \"" + DSID + "\" !");

} else if (!(sessobj instanceof IFileContainer)) {

throw new GetFileAJAXWayException(" \"" + DSID + "\" !");

}



// .

session.removeAttribute(dsid);



// .

IFileContainer document = (IFileContainer) sessobj;



// .

resp.setStatus(HttpServletResponse.SC_OK);

resp.setContentLength((int) document.getFileLength());

resp.setContentType(document.getContentType());

resp.setHeader("Content-Transfer-Encoding", "binary");

/* // -- IE

String filename = "=?windows-1251?Q?" + new org.apache.commons.codec.net.QuotedPrintableCodec().encode(document.getFileName(), "Cp1251") + "?=";

resp.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");

*/

/* // IE --

String filename = java.net.URLEncoder.encode(document.getFileName(), "Cp1251").replaceAll("\\+", " ");

resp.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");

*/

/**/ // -

String filename = document.getFileName();

int dotpos = filename.lastIndexOf('.');

if (dotpos > -1)

filename = "file." + filename.substring(dotpos + 1);

else

filename = "file.dat";

resp.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");

/**/

OutputStream out = resp.getOutputStream();

out.write(document.getFileContent());

out.flush();

out.close();

}



/**

* , .

*

* @param trashheap .

* <tt>null</tt>, .

* @return .

*/

private String dsid(long[] trashheap) {

long dsid = System.currentTimeMillis();

if (trashheap != null && trashheap.length > 0)

for (int i = 0; i < trashheap.length; i++)

dsid ^= trashheap[i];

return Long.toString(Math.abs(new Random(dsid).nextLong()), 10);

}



/**

* JSON.

* @param subject .

* @return .

*/

private String escapeJSON(String subject) {

if (subject == null || subject.length() == 0)

return "";

return subject.replaceAll("\"", "\\\"")

.replaceAll("\\\\", "\\\\")

.replaceAll("[\n\r]", "\\\\n");

}



/**

* JSON- .

* @param dsid , () .

* @param resp HTTP-.

* @throws ServletException

* @throws IOException

*/

private void sendSuccessReply(String dsid, HttpServletResponse resp)

throws IOException {

String dsidJSON = "{\"result\":\"success\",\"dsid\":\""

+ escapeJSON(dsid) + "\"}";



sendAnyReply(dsidJSON, resp);

}



/**

* JSON- .

* @param reason .

* @param resp HTTP-.

* @throws ServletException

* @throws IOException

*/

private void sendFailureReply(String reason, HttpServletResponse resp)

throws IOException {

String reasonJSON = "{\"result\":\"failure\",\"reason\":\""

+ escapeJSON(reason) + "\"}";



sendAnyReply(reasonJSON, resp);

}



/**

* .

* @param json .

* @param resp HTTP-.

* @throws IOException

*/

private void sendAnyReply(String json, HttpServletResponse resp)

throws IOException {



final byte[] result_bytes = json.getBytes("UTF-8");

final int CHUNK = 1024;

final BufferedOutputStream output = new BufferedOutputStream(

resp.getOutputStream(), CHUNK);



resp.setStatus(HttpServletResponse.SC_OK);

resp.setHeader("Content-Encoding", "UTF-8");

resp.setContentType("text/plain; charset=UTF-8");

resp.setContentLength(result_bytes.length);



int bytes_pos = 0, bytes_chunk = 0;

do {

bytes_chunk = bytes_pos + CHUNK <= result_bytes.length

? CHUNK

: result_bytes.length - bytes_pos;

output.write(result_bytes, bytes_pos, bytes_chunk);

bytes_pos += bytes_chunk;

} while (bytes_pos < result_bytes.length);

output.flush();

output.close();

}



/**

* .

* @param req HTTP-.

* @return , {@link #getDocument(Object)}

* .

* @throws GetFileAJAXWayException

* .

*/

protected abstract Object populateIdentity(HttpServletRequest req)

throws GetFileAJAXWayException;



/**

* ,

* .

* @param req HTTP-.

* @param identity .

* @return .

* @throws GetFileAJAXWayException .

*/

protected abstract IFileContainer getDocument(HttpServletRequest req,

Object identity) throws GetFileAJAXWayException;



}








ConcreteDocumentRetrievalServlet.java



特定のケースに必要なロジックを実装する継承クラス。



package unchqua.getfileajaxway;



public class ConcreteDocumentRetrievalServlet extends AbstractGetFileAJAXWay {



public ConcreteDocumentRetrievalServlet() {

super();

}



public Object populateIdentity(HttpServletRequest req)

throws GetFileAJAXWayException {

// .

return null;

}



public IFileContainer getDocument(HttpServletRequest req, Object identity)

throws GetFileAJAXWayException {

// .

return null;

}

}








GetFileAJAXWay.jsp



サーブレットと対話するJSPファイルの例。



<?xml version="1.0" encoding="UTF-8"?>



<!DOCTYPE html

PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">



<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru" lang="ru">

<head>

<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8"/>

<meta http-equiv="Expires" content="Tue, Feb 07 1978 15:30:00 GMT"/>

<meta http-equiv="Content-Style-Type" content="text/css"/>

<meta http-equiv="Content-Script-Type" content="text/javascript"/>

<title>GetFileAJAXWay example</title>



<!-- MochiKit. -->

<script type="text/javascript" src="/MochiKit-1.3.1/Base.js"></script>

<script type="text/javascript" src="/MochiKit-1.3.1/Iter.js"></script>

<script type="text/javascript" src="/MochiKit-1.3.1/DOM.js"></script>

<script type="text/javascript" src="/MochiKit-1.3.1/Async.js"></script>



<script type="text/javascript">

<!--



// .

var SERVLET_PATH = "/servletname"; // unchqua.ConcreteDocumentRetrievalServlet .

// URL .

var SERVLET_URL = document.location.protocol + '//'

+ document.location.hostname

+ (document.location.port > 0 ? ':' + document.location.port : '')

+ SERVLET_PATH;



/**

* AJAX-.

*/

function JS_AJAX_GetElFAFile(reqid) {



// .

var parameters = {};

parameters["reqid"] = reqid; // reqid – .

parameters["rand"] = new Date().getTime(); // .



// .

loadJSONDoc(SERVLET_URL, parameters)

.addCallbacks(

JS_AJAX_GetElFAFile_Success,

JS_AJAX_GetElFAFile_Failure);

}



/**

* AJAX- .

*/

function JS_AJAX_GetElFAFile_Success(jsondata) {



// ?

if (JS_AJAX_GetElFAFile_Is_response_error(jsondata)) {

JS_AJAX_GetElFAFile_Failure(jsondata);

return;

}

else if (typeof(jsondata.dsid) == "undefined") {

JS_AJAX_GetElFAFile_Failure("Document is not received!");

return;

}



// .

window.location.href = SERVLET_URL + "?dsid=" + jsondata.dsid;



}



/**

* AJAX- .

*/

function JS_AJAX_GetElFAFile_Failure(jsondata) {



var error_text =

(typeof(jsondata.result) != "undefined"

&amp;&amp; jsondata.result == "failure"

&amp;&amp; typeof(jsondata.reason) != "undefined"

&amp;&amp; jsondata.reason.length > 0)

? jsondata.reason

: jsondata.message + " (" + jsondata.number + ")";



window.alert(error_text);



}



/**

* Is response error?

*

* jsonadata: JSON object just received.

*

* Returns flag (true/false).

*/

function JS_AJAX_GetElFAFile_Is_response_error(jsondata) {



// ( ).

var artifical_error = typeof(jsondata.result) != "undefined"

&amp;&amp; jsondata.result == "failure";



// Internal server error.

var hard_error = typeof(jsondata.number) != "undefined"

&amp;&amp; typeof(jsondata.message) != "undefined"

&amp;&amp; jsondata.number == 500;



return artifical_error || hard_error;



}



//-->

</script>

</head>

<body>



<a href="javascript:JS_AJAX_GetElFAFile(/*docid=*/123);"> !</a>



</body>

</html>







All Articles