利用ajax实现服务端异步任务状态监听

项目中为了改善用户体验,一些耗时操作常常会使用异步方式执行,但是一旦将任务放入后台,用户就不能及时得到任务执行的结果。所以需要涉及一种方式能够持续跟踪任务的进行情况。每个监听任务会被分配一个任务ID,在任务监听结束后被释放。

全局监听器的实现

基于单例模式设置一个HashMap能被系统全局访问用于存放任意任务的监听数据。同时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,其他脚本亦类似):

第一步:调用异步服务并获取监听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
            }
        });
    }

第二步:监听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 + "\n";
                        });
                        $scope.pingResults = text;
                    } else {
                        //监听资源释放后,停止interval
                        console.log('canceling observer');
                        $interval.cancel(timer);
                    }
                }
            });
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值