Погуглив это, я наткнулся на множество примеров, одним из которых был $q из Angular, чтобы избежать рекурсивного обращения к моей серверной части, чтобы проверить, заполнен ли запрос данными или нет.
Я наткнулся на эту ссылку: https://stackoverflow.com/questions/37354881/recursive-http-get-in-for-loop
Что предложило использовать $q, но я не думаю, что это решит мою проблему.
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) {
});
}
Контроллер:
@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:
<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 © 2017</p>
</p>
</footer>
<script type="application/javascript">
</script>
</body>
Это делается для того, чтобы избежать тайм-аута, он отправляет сообщение Still Processing
клиенту, так как лимит тайм-аута составляет 30000 мс, я знаю, что первое, что приходит на ум, это сделать ленивую загрузку с примерно 30 данными на запрос, но поверьте мне, я не могу .
Я создал инструмент проверки кода, поэтому при попадании по URL-адресу он запускает проверку кода для всех классов с фоновым потоком, а затем возвращает ответ в CompletableFuture
через 120–150 секунд. Этот ответ неизвестен клиенту, пока страница не будет обновлена снова.
Даже после обновления страницы, так как данные превышают 7 МБ, для отображения результата требуется почти 13-35 секунд.
Код отлично работает на моем локальном компьютере, но когда я размещался на героку, который является общим сервером, я начал получать тайм-ауты. Есть две проблемы:
1) Как angularJS может обнаруживать изменения в ответе RestAPI? (Поскольку будет отправлено два ответа, первый немедленный на «Все еще обрабатывается», а второй - реальный результат. Это тот, который я должен использовать).
2) Как лениво загрузить данные, которые уже находятся в формате JSON, из контроллера?
Обновление 1:
Я тоже пытался использовать OutputStream:
Контроллер:
@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);
}
};
}
Но теперь ответ изменяется на XML, и строка JS console.log('Data from server');
не печатается до тех пор, пока со стороны сервера не будет получен полный ответ.
Когда ответ изменяется на XML, как я могу проанализировать его в формате JSON, поскольку мой полный JS зависит от JSON?
После потоковой передачи, почему угловой результат отображения после завершения полного запроса?