简体   繁体   English

如何收听异步服务器端Java Controller?

[英]How to listen to async server side Java Controller?

Googling this I came across numerous examples, one of which was $q from Angular, to avoid recursively hitting my server side to check if request is complete with data or not. 仔细研究这个例子,我遇到了很多例子,其中之一是来自Angular的$ q,以避免递归地访问我的服务器端以检查请求是否包含数据。

I came across this link : Recursive $http.get in for loop 我碰到了这个链接: 递归$ http.get for循环

Which suggested to use $q, but I dont think that will resolve my issue. 建议使用$ q,但我认为这不会解决我的问题。

JS: JS:

function OrderFormController($scope, $http, $q) {

    $('#loaderImage').show();

    $http.get('/utilities/longProcess')
        .success(function(data, status, headers, config) {
            if(data != 'Still Processing'){
                console.log('Data from server');
                $scope.sampleJSON = data.pmdStructureWrapper;
                $scope.sampleJSONDuplicates = data.pmdDuplicates;
                $scope.$watch('sampleJSON', setTimeout(function() {
                    $('.panel-body li').each(function() {
                        if ($.trim($(this).text()) === "") {
                            $(this).hide();
                        }
                    });
                }, 1000));
            $('#loaderImage').hide();
            }else{
                console.log('rejected');
                $q.reject(data);
            }
        })
        .error(function(data, status, header, config) {

        });
}

Controller: 控制器:

@RequestMapping("/utilities/longProcess")
public CompletableFuture<String> asyncLongProcess(HttpServletResponse response, HttpServletRequest request) {
    HttpSession session = request.getSession();
    return CompletableFuture.supplyAsync(() -> session.getAttribute("CACHED_RESULT"))
            .thenComposeAsync(obj -> {
                if (obj == null) {
                    if(session.getAttribute("BACKGROUND_PROCESSING") == null) {
                        session.setAttribute("BACKGROUND_PROCESSING", true);
                        CompletableFuture.supplyAsync(() -> callURL(response, request))
                                .thenAccept(result -> session.setAttribute("CACHED_RESULT", result));
                    }
                    return CompletableFuture.completedFuture("Still Processing");
                }

                return CompletableFuture.completedFuture(obj.toString());
            });
}

HTML : HTML:

<body ng-app ng-controller="OrderFormController">
<header>
    <div class="container">
        <div id="branding">
            <h1><span class="highlight">Review  </span> Result</h1>
            <form class="form-logout" role="form" action="/logout">
                <input type="submit" value="Logout" id="logout" class="btn btn-primary btn-lg pull-right">
            </form>
        </div>

    </div>
</header>

<img src="../img/spinner.gif" id="loaderImage" style='display:none'>
<div class="col-md-12 col-lg-12" ng-cloak="">
    <div class="panel with-nav-tabs panel-default">
        <div class="panel-heading">
            <ul class="nav nav-tabs">
                <li class="active"><a href="#tab1default" data-toggle="tab">Classes</a></li>
                <li><a href="#tab2default" data-toggle="tab">Triggers</a></li>
                <li><a href="#tab3default" data-toggle="tab">Visualforce pages</a></li>
                <li><a href="#tab4default" data-toggle="tab">Duplicate Codes</a></li>
            </ul>
        </div>
        <div class="panel-body">
            <div class="tab-content">
                <div class="tab-pane fade in active" id="tab1default">
                    <ul class="col-md-12 col-lg-12">
                        <li ng-click="showErrorDetails(key)" class="col-sm-12 col-md-4 col-lg-4 eachClassCell"
                            ng-repeat='(key,value) in sampleJSON'>
                            <div ng-if="key.indexOf('.cls') > -1">
                                <div title="{{key}}" class="classNameLabel">{{key}}</div>
                                <div title="Error count" class="errorContainer">
                                    <span class="errorCount">{{value.pmdStructures.length}}</span>
                                    <span class="errorMeter"
                                          ng-repeat="eachClass in value.pmdStructures | limitTo: 10"></span>
                                </div>
                            </div>
                        </li>
                    </ul>
                </div>
                <div class="tab-pane fade" id="tab2default">
                    <ul class="col-md-12 col-lg-12">
                        <li ng-click="showErrorDetails(key)" class="col-sm-12 col-md-4 col-lg-4 eachClassCell"
                            ng-repeat='(key,value) in sampleJSON'>
                            <div ng-if="key.indexOf('.trigger') > -1">
                                <div title="{{key}}" class="classNameLabel">{{key}}</div>
                                <div title="Error count" class="errorContainer">
                                    <span class="errorCount">{{value.pmdStructures.length}}</span>
                                    <span class="errorMeter"
                                          ng-repeat="eachClass in value.pmdStructures | limitTo: 10"></span>
                                </div>
                            </div>
                        </li>
                    </ul>
                </div>
                <div class="tab-pane fade" id="tab3default">
                    <ul class="col-md-12 col-lg-12">
                        <li ng-click="showErrorDetails(key)" class="col-sm-12 col-md-4 col-lg-4 eachClassCell"
                            ng-repeat='(key,value) in sampleJSON'>
                            <div ng-if="key.indexOf('.page') > -1">
                                <div title="{{key}}" class="classNameLabel">{{key}}</div>
                                <div title="Error count" class="errorContainer">
                                    <span class="errorCount">{{value.pmdStructures.length}}</span>
                                    <span class="errorMeter"
                                          ng-repeat="eachClass in value.pmdStructures | limitTo: 10"></span>
                                </div>
                            </div>
                        </li>
                    </ul>
                </div>
                <div class="tab-pane fade" id="tab4default">
                    <ul class="col-md-12 col-lg-12">
                        <li ng-click="showDuplicateDetails(eachValue)" class="col-sm-12 col-md-4 col-lg-4 eachClassCell"
                            ng-repeat='eachValue in sampleJSONDuplicates'>
                            <div title="{{eachValue.duplicationInFile}}" class="classNameLabel">
                                {{eachValue.duplicationInFile}}
                            </div>
                        </li>
                    </ul>
                </div>
            </div>
        </div>
    </div>
</div>
<form>


</form>
<footer>
    <p>Salesforce Free Code Review, Copyright &copy; 2017</p>
    </p>
</footer>
<script type="application/javascript">


</script>
</body>

What this does is to avoid timeout, it sends a Still Processing message to the client, as the timeout limit is 30000ms, I know the first thing that comes to mind is do a lazy loading with some 30 data per request, but believe me I cant. 这样做是为了避免超时,它将超时Still Processing消息发送到客户端,因为超时限制为30000ms,因此我知道首先想到的是每个请求进行30个数据的延迟加载,但是相信我不能。

I have built a code review tool, so when the URL gets hit, it runs a code review on all the classes with a background thread and then returns the response in CompletableFuture after some 120 - 150 seconds. 我已经构建了一个代码审查工具,因此当URL被命中时,它将使用后台线程对所有类运行代码审查,然后在大约CompletableFuture秒后在CompletableFuture返回响应。 This response is unknown to the client until the page is refreshed again. 直到再次刷新页面,客户端才知道此响应。

Even after refreshing the page, as the data is over 7MB the page takes almost 13-35 seconds to display the result. 即使刷新页面后,由于数据超过7MB,该页面仍需要花费近13-35秒才能显示结果。

The code works fine in my local, but when I hosted in heroku, which is shared server, I started getting timeouts. 该代码在本地环境下工作正常,但是当我在共享服务器heroku上托管时,我开始超时。 There are two issues : 有两个问题:

1) How can angularJS detect changes in response of the RestAPI ?(As there will be two responses sent, first the immediate on "Still Processing" and second the real result. This is one which I have to consume). 1)angularJS如何检测RestAPI响应的变化?(由于将发送两个响应,第一个响应是“ Still Processing”的即时响应,第二个是实际结果。这是我必须使用的响应)。

2) How to lazy load the data which is already in JSON format from the Controller? 2)如何从Controller延迟加载JSON格式的数据?

在此处输入图片说明

Update 1: 更新1:

I tried using OutputStream too: 我也尝试使用OutputStream:

Controller : 控制器:

@RequestMapping("/utilities/longProcessStream")
public StreamingResponseBody asyncLongProcessStream(HttpServletResponse response, HttpServletRequest request) {
    return new StreamingResponseBody() {
        @Override
        public void writeTo(OutputStream outputStream) throws IOException {
            PMDController.this.callURL(response, request, outputStream);
        }
    };
}

But now the response changes to XML and the JS console.log('Data from server'); 但是现在响应更改为XML和JS console.log('Data from server'); line is not printed untill full response is gathered from the server side. 直到从服务器端收集到完整响应后,才会打印行。

When the response changes to XML how can I parse that to JSON format as my full JS depends on JSON? 当响应更改为XML时,由于完整的JS依赖于JSON,如何将其解析为JSON格式?

After streaming why angular displaying result after full request is completed? 流式传输后,为什么在完整请求完成后角度显示结果呢?

I found a library which reads StreamingBodyResponse, they internally change blob type to JSON which is exactly what i needed : 我发现一个读取StreamingBodyResponse的库,它们在内部将blob类型更改为JSON,这正是我需要的:

@RequestMapping("/utilities/longProcessStream")
public StreamingResponseBody asyncLongProcessStream(HttpServletResponse response, HttpServletRequest request) {
    response.addHeader("Content-Type", MediaType.APPLICATION_JSON);
    return new StreamingResponseBody() {
        @Override
        public void writeTo(OutputStream outputStream) throws IOException {
            PMDController.this.callURL(response, request, outputStream);
        }
    };
}

JS: JS:

$('#loaderImage').show();

$scope.sampleJSONClass = {};
$scope.sampleJSONTrigger = {};
$scope.sampleJSONPages = {};
oboe('/utilities/longProcessStream')
    .done(function(data) {
        var dataFromServer = data.pmdStructureWrapper;
        if (Object.keys(dataFromServer)[0].endsWith('.cls')) {
            $scope.sampleJSONClass[Object.keys(dataFromServer)[0]] = Object.values(dataFromServer)[0];
        }
        if (Object.keys(dataFromServer)[0].endsWith('.trigger')) {
            $scope.sampleJSONTrigger[Object.keys(dataFromServer)[0]] = Object.values(dataFromServer)[0];
        }
        if (Object.keys(dataFromServer)[0].endsWith('.page')) {
            $scope.sampleJSONPages[Object.keys(dataFromServer)[0]] = Object.values(dataFromServer)[0];
        }
        $scope.$apply();
        $('#loaderImage').hide();
    })
    .fail(function() {
        console.log('error');
    });

This works perfectly. 这很完美。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM