ajaxによるサービス側非同期タスクステータスリスニングの実現
プロジェクトでは、ユーザー体験を改善するために、時間のかかる操作は非同期で実行されることが多いが、タスクをバックグラウンドに入れると、ユーザーはタスク実行の結果をタイムリーに得ることができない.したがって、タスクの進行状況を継続的に追跡できる方法が必要である.各リスニングタスクには、タスクIDが割り当てられ、タスクリスニングが終了した後に解放されます.
グローバルリスナーの実装
一例のモードに基づいて、任意のタスクを格納するためにシステムによってグローバルにアクセス可能なリスニングデータを設定する.同時にValue部分は特殊特殊な構造を使用します.
こうぞうせっけい
つまり、HashMapのValueに格納されている部分です.
リスナー
プログラムの任意の場所に傍受IDを登録し、IDに対応する情報を更新、読み出しするためのものである.同時にIDの期限切れクリア、行為記録の読み取りなどをサポートすべきである.コードは次のとおりです.
使用方法
登録
非同期メソッドを実行する前に、リスニングIDが生成され、非同期実行体に入力される.実行ステータスの更新は非同期タスクによって更新されます.
更新
非同期タスクでいつでも呼び出す
読み取り
Controllerレイヤインタフェース
JAVAサービス側API実現
Controllerでデータ転送インタフェースを定義します.追加、削除、変更、検索、消去などの機能が含まれています.ここではクエリーを例に挙げます.Controllerコードは次のとおりです.
フロントエンドjs実装
インタフェースを介してサーバを呼び出してpingコマンドを実行し、pingをリスニングした結果を例にとると、jsコードは次のようになります(以下、AngularJsと組み合わせて、他のスクリプトも同様です).
ステップ1:非同期サービスを呼び出し、リスニングIDを取得する
約束により、非同期タスクの開始が呼び出された後に登録されたリスニングIDが返される.
ステップ2:IDデータの傍受
グローバルリスナーの実装
一例のモードに基づいて、任意のタスクを格納するためにシステムによってグローバルにアクセス可能なリスニングデータを設定する.同時にValue部分は特殊特殊な構造を使用します.
こうぞうせっけい
つまり、HashMapのValueに格納されている部分です.
public class ValueStruc {
private boolean expireable;
private Date expireTime;
private Object value;
private int readCount;
public ValueStruc(){}
public ValueStruc(Object value, Date expireTime){
this.value = value;
this.expireable = true;
this.expireTime = expireTime;
this.readCount = 0;
}
public ValueStruc(Object value){
this.value = value;
this.readCount = 0;
}
public Object readValue(){
readCount = readCount +1;
return this.value;
}
public boolean expired(){
if(expireable){
return new Date().after(expireTime);
} else {
return false;
}
}
public boolean isExpireable(){
return this.expireable;
}
public void setExpireable(boolean exb){
this.expireable = exb;
}
public Date getExpireTime(){
return expireTime;
}
public void setExpireTime(Date exd){
this.expireTime = exd;
}
public Object getValue(){
return value;
}
public void setValue(Object v){
this.value = v;
}
public int getReadCount(){
return readCount;
}
public void setReadCount(int readCount){
this.readCount = readCount;
}
}
リスナー
プログラムの任意の場所に傍受IDを登録し、IDに対応する情報を更新、読み出しするためのものである.同時にIDの期限切れクリア、行為記録の読み取りなどをサポートすべきである.コードは次のとおりです.
public class DataObserver {
private HashMap<String, ValueStruc> map;
private volatile static DataObserver instance;
private DataObserver(){
map = new HashMap<String, ValueStruc>();
}
public static DataObserver getInstance(){
if(instance == null){
synchronized(DataObserver.class){
if(instance == null){
instance = new DataObserver();
}
}
}
return instance;
}
/** * Key<br> * : ,key, value<br> * : , , ,0 <br> * Function: register * * @author wengshengyuan DateTime 2015-10-12 9:16:01 * @param key * @param value * @param Sec * @return ValueStruc, key null */
public ValueStruc register(String key, Object value, int Sec) {
if(map.containsKey(key))
return null;
Date now = new Date();
if(Sec > 0){
Date expireTime = DateUtils.addSeconds(now, Sec);
ValueStruc v = new ValueStruc(value, expireTime);
map.put(key, v);
return v;
} else {
ValueStruc v = new ValueStruc(value);
map.put(key, v);
return v;
}
}
/** * * Function: update * * @author wengshengyuan DateTime 2015-10-12 1:45:46 * @param key * @param value * @return , Key, null */
public ValueStruc update(String key, Object value){
if(map.containsKey(key)){
ValueStruc v = map.get(key);
v.setValue(value);
map.put(key, v);
return v;
} else {
return null;
}
}
/** * key<br> * Function: read * * @author wengshengyuan DateTime 2015-10-12 9:29:48 * @param key * @return Object, null */
public Object read(String key){
ValueStruc v = map.get(key);
if(v == null)
return null;
if(v.expired()){
map.remove(key);
return null;
}
return v.readValue();
}
/** * Key <br> * , , , null * Function: remove * * @author wengshengyuan DateTime 2015-10-12 11:09:39 * @param key * @return */
public ValueStruc remove(String key){
return map.remove(key);
}
/** * map * Function: clear * * @author wengshengyuan DateTime 2015-10-12 11:10:23 */
public void clear(){
map = new HashMap<String, ValueStruc>();
}
}
使用方法
登録
非同期メソッドを実行する前に、リスニングIDが生成され、非同期実行体に入力される.実行ステータスの更新は非同期タスクによって更新されます.
String observerID = "taskName_"+UUIDUtils.getUUID32();
DataObserver.getInstance().register(observerID,value,-1);
AsyncTask task = new AsyncTask(String observerID);
task.start();
更新
非同期タスクでいつでも呼び出す
DataObserver.getInstance().update(observerID, value);
読み取り
DataObserver.getInstance().read(observerID);
Controllerレイヤインタフェース
JAVAサービス側API実現
Controllerでデータ転送インタフェースを定義します.追加、削除、変更、検索、消去などの機能が含まれています.ここではクエリーを例に挙げます.Controllerコードは次のとおりです.
@Controller
@RequestMapping(value="/api/observer")
public class DataObserverAPI {
@ResponseBody
@RequestMapping(value = "observe/{key}", method = RequestMethod.GET)
public ResultInfo observe(HttpServletRequest request, @PathVariable("key") String key){
ResultInfo result = new ResultInfo();
Object o = DataObserver.getInstance().read(key);
if(o == null){
result.setStateId(-1);
result.setErrorMsg(" ");
} else {
result.addObj2Map("value", o);
}
return result;
}
@ResponseBody
@RequestMapping(value = "regester/{key}/{value}/{timeout}", method = RequestMethod.GET)
public ResultInfo testObserver(HttpServletRequest request, @PathVariable("key") String key, @PathVariable("value") String value
, @PathVariable("timeout") int timeout){
ResultInfo result = new ResultInfo();
ValueStruc v = DataObserver.getInstance().regester(key, value, timeout);
if(v == null){
result.setStateId(-1);
result.setErrorMsg(" ");
} else {
result.addObj2Map("value", v);
}
return result;
}
@ResponseBody
@RequestMapping(value = "update/{key}/{value}", method = RequestMethod.GET)
public ResultInfo update(HttpServletRequest request, @PathVariable("key") String key, @PathVariable("value") String value){
ResultInfo result = new ResultInfo();
ValueStruc v = DataObserver.getInstance().update(key, value);
if(v == null){
result.setStateId(-1);
result.setErrorMsg(" ");
} else {
result.addObj2Map("value", v);
}
return result;
}
@ResponseBody
@RequestMapping(value="remove/{key}", method = RequestMethod.GET)
public ResultInfo clear(HttpServletRequest request, @PathVariable("key") String key){
ResultInfo result = new ResultInfo();
ValueStruc v = DataObserver.getInstance().remove(key);
result.addObj2Map("value", v);
return result;
}
@ResponseBody
@RequestMapping(value = "clear", method = RequestMethod.GET)
public void clear(){
DataObserver.getInstance().clear();
}
}
フロントエンドjs実装
インタフェースを介してサーバを呼び出してpingコマンドを実行し、pingをリスニングした結果を例にとると、jsコードは次のようになります(以下、AngularJsと組み合わせて、他のスクリプトも同様です).
ステップ1:非同期サービスを呼び出し、リスニングIDを取得する
約束により、非同期タスクの開始が呼び出された後に登録されたリスニングIDが返される.
//
this.ping = function($scope){
var url = ctx + 'godmode/ping';
var data = {
ip : $scope.pingIP
};
$.ajax({
type:"post",
url:url,
async:false,
data :data,
success: function(r){
console.log(r);
$scope.observerID = r.map.observerID[0];
},
error:function(){
$interva
}
});
}
ステップ2:IDデータの傍受
//
var timer = $interval(function(){
myService.observePing($scope,$interval);
},1000);
//
this.observePing = function($scope,$interval){
console.log('observing:'+$scope.observerID);
$.ajax({
type : "get",
url: ctx + "api/observer/observe/"+$scope.observerID,
dataType: "json",
async: true,
timeout: 10000,
error: function(r) {
console.log('canceling observer');
$interval.cancel(timer);
},
success: function(r) {
if (r.stateId == 0) {
var text = "";
$.each(r.map.value[0], function(index, item) {
text = text + item + "
";
});
$scope.pingResults = text;
} else {
// , interval
console.log('canceling observer');
$interval.cancel(timer);
}
}
});
}