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

イントラネットシステムの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>

Source: https://habr.com/ru/post/J66772/


All Articles