我现在面临一个巨大的问题,因为我有一个包含一个包含大量数据的列表的片段。我到现在为止的工作如下:
当用户单击按钮时,我将执行如下JavaScript文章:
function loadEvaluations() {
$.ajax({
url : "/evaluation/data",
type : "POST",
headers : createAuthorizationTokenHeader(),
async : !1,
data : {
from: rangeFrom,
to: rangeTo
},
success : function(data) {
$("#portal_container").html(data);
},
error : function(data) {
$("#portal_container").html(data);
}
});
}
在Spring后端中,我从数据库中选择数据,将其放入模型中并返回片段:
@RequestMapping(HelperUrls.URL_WEB_EVALUATION_DATA)
public String data(Model model, HttpServletRequest request,
@RequestParam(value = Params.PARAM_FROM, required = true) long from,
@RequestParam(value = Params.PARAM_TO, required = true) long to) {
final IDM_USER user = this.idm_user_repository.findByEmail(request.getUserPrincipal().getName());
if (user != null) {
final int unit = user.getUnit();
final Locale locale = LocaleContextHolder.getLocale();
final String unitValue = HelperShortcuts.getUnitForShortcut(this.messageSource, locale, unit);
Set<IDM_BREAD> breads = this.idm_bread_repository.findByDatesBetweenAndUser(new Date(from), new Date(to), user);
Set<IDM_FOOD> foods = this.idm_food_repository.findByDatesBetweenAndUser(new Date(from), new Date(to), user);
Set<IDM_INSULIN> insulins = this.idm_insulin_repository.findByDatesBetweenAndUser(new Date(from), new Date(to), user);
Set<IDM_MEASURE> measures = this.idm_measure_repository.findByDatesBetweenAndUser(new Date(from), new Date(to), user);
Set<IDM_MOOD> moods = this.idm_mood_repository.findByDatesBetweenAndUser(new Date(from), new Date(to), user);
Set<IDM_NOTE> notes = this.idm_note_repository.findByDatesBetweenAndUser(new Date(from), new Date(to), user);
Set<IDM_SPORT> sports = this.idm_sport_repository.findByDatesBetweenAndUser(new Date(from), new Date(to), user);
List<DatatransferListEntry> entries = new ArrayList<>();
entries.addAll(breads);
entries.addAll(foods);
entries.addAll(insulins);
entries.addAll(measures);
entries.addAll(moods);
entries.addAll(notes);
entries.addAll(sports);
entries = this.initHeaders(entries, locale);
model.addAttribute(ReturnKeys.TIME, Helper.getDateTimePatternEvaluation(this.messageSource, locale, from, to));
model.addAttribute(ReturnKeys.ENTRIES, entries);
model.addAttribute(ReturnKeys.USER_UNIT_VALUE, unitValue);
}
return Htmls.WEB_FRAGMENT_EVALUATION_DATA_F;
}
片段中的内容如下所示:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<body>
<div th:fragment="fragment_evaluations_data" class="margin-top-100 margin-bottom-100">
<div th:each="entry: ${ENTRIES}">
<div class="container page-small page-small-header" th:if="${entry.type == 0}">
<div class="row page-row-evaluation">
<span th:text="${entry.timestampLabel}"></span>
</div>
<div class="row page-row-evaluation"></div>
</div>
<div class="container page-small page-small-header-sub" th:if="${entry.type == 1}">
<div class="row page-row-evaluation">
<span th:text="${entry.timestampLabel}"></span>
</div>
<div class="row page-row-evaluation"></div>
</div>
<div class="container page-small" th:if="${entry.type == 2}">
<div class="row page-row-evaluation">
<div class="col-md-12">
<span class="evaluation-font" th:text="${entry.value} + ' ' + ${USER_UNIT_VALUE}"></span>
</div>
<div class="col-md-12 margin-top-5">
<span th:text="${entry.timestampLabel} + ' '"></span>
<span th:if="${entry.mealtime == 0}" th:text="'- ' + #{label.meal_before}"></span>
<span th:if="${entry.mealtime == 1}" th:text="'- ' + #{label.meal_after}"></span>
</div>
</div>
<div class="row page-row-evaluation"></div>
</div>
<div class="container page-small" th:if="${entry.type == 3}">
<div class="row page-row-evaluation">
<div class="col-md-12">
<span class="evaluation-font" th:text="${entry.units} + ' ' + #{label.insulin_units}"></span>
</div>
<div class="col-md-12 margin-top-5">
<span th:text="${entry.timestampLabel}"></span>
</div>
</div>
<div class="row page-row-evaluation"></div>
</div>
<div class="container page-small" th:if="${entry.type == 4}">
<div class="row page-row-evaluation">
<div class="col-md-12">
<span class="evaluation-font" th:text="${entry.units} + ' ' + #{label.bread}"></span>
</div>
<div class="col-md-12 margin-top-5">
<span th:text="${entry.timestampLabel}"></span>
</div>
</div>
<div class="row page-row-evaluation"></div>
</div>
<div class="container page-small" th:if="${entry.type == 5}">
<div class="row page-row-evaluation">
<div class="col-md-12">
<span class="evaluation-font" th:text="${entry.sporttype.sporttype}"></span>
</div>
<div class="col-md-12 margin-top-5">
<span th:if="${entry.intensity == 0}" th:text="#{label.intensity_easy}"></span>
<span th:if="${entry.intensity == 1}" th:text="#{label.intensity_moderate}"></span>
<span th:if="${entry.intensity == 2}" th:text="#{label.intensity_hard}"></span>
<span th:if="${entry.intensity == 3}" th:text="#{label.intensity_very_hard}"></span>
</div>
<div class="col-md-12 margin-top-5">
<span th:text="${entry.duration} + ' ' + #{label.minutes}"></span>
</div>
<div class="col-md-12 margin-top-5">
<span th:text="${entry.timestampLabel}"></span>
</div>
</div>
<div class="row page-row-evaluation"></div>
</div>
<div class="container page-small" th:if="${entry.type == 6}">
<script>
function loadFoodImage(id) {
$.ajax({
url : "/rest/evaluation/foodiamgeid",
type : "POST",
headers : createAuthorizationTokenHeader(),
async : 1,
data : {
image_id: id
},
success : function(data) {
var image = JSON.parse(data).USER_IMAGE;
if (image != null) {
var selector = "#evaluation_food_image_" + id;
$(selector).attr("src", image);
}
},
error : function(data) {
}
});
}
</script>
<div class="row page-row-evaluation">
<div class="col-md-12">
<span class="evaluation-font" th:text="#{label.food}"></span>
</div>
<div class="col-md-12 margin-top-5">
<span th:text="${entry.timestampLabel}"></span>
</div>
<div class="col-md-12 margin-top-5">
<img th:id="'evaluation_food_image_' + ${entry.imageId}" src="/img/ic_rolling.gif" class="center-block img-responsiv image-upload-image" th:onload="|loadFoodImage('${entry.imageId}')|" />
</div>
</div>
<div class="row page-row-evaluation"></div>
</div>
<div class="container page-small" th:if="${entry.type == 7}">
<div class="row page-row-evaluation">
<div class="col-md-12">
<span class="evaluation-font" th:text="#{label.note}"></span>
</div>
<div class="col-md-12 margin-top-5">
<span th:text="${entry.timestampLabel}"></span>
</div>
<div class="col-md-12 margin-top-5">
<span th:text="${entry.note}"></span>
</div>
</div>
<div class="row page-row-evaluation"></div>
</div>
<div class="container page-small" th:if="${entry.type == 8}">
<div class="row page-row-evaluation">
<div class="col-md-12">
<span class="evaluation-font" th:text="#{label.mood}"></span>
</div>
<div class="col-md-12 margin-top-5">
<span th:text="${entry.timestampLabel}"></span>
</div>
<div class="col-md-12 text-center">
<img th:if="${entry.mood == 1}" class="image-mood" src="/img/ic_mood_very_bad_red.png"></img>
<img th:if="${entry.mood == 2}" class="image-mood" src="/img/ic_mood_bad_orange.png"></img>
<img th:if="${entry.mood == 3}" class="image-mood" src="/img/ic_mood_neutral_yellow.png"></img>
<img th:if="${entry.mood == 4}" class="image-mood" src="/img/ic_mood_good_green.png"></img>
<img th:if="${entry.mood == 5}" class="image-mood" src="/img/ic_mood_very_good_green.png"></img>
</div>
</div>
<div class="row page-row-evaluation"></div>
</div>
</div>
</div>
</body>
</html>
问题
这种方式加载数据是非常糟糕的用户体验,因为加载过程大约需要10秒钟,并且ui冻结,并且用户无法执行某些操作。他停留在旧页面上,必须等待10秒钟,然后“导航”到新片段。
我需要的
我需要一个百里香/弹簧解决方案来异步加载数据。因此,我希望用户单击链接后立即看到新页面,然后在从服务器收集数据的同时呈现某种加载动画。服务器完成后,视图应自动更新。
那可能吗?
最佳答案
您可以有两个单独的控制器,以便在另一页面上单击按钮时,它仅调用URL来显示该页面:
@RequestMapping(HelperUrls.URL_WEB_EVALUATION)
public String page(Model mode, HttpServletRequest request){
model.addAttribute(ReturnKeys.TIME, new Date());
model.addAttribute(ReturnKeys.ENTRIES, new ArrayList<>());
model.addAttribute(ReturnKeys.USER_UNIT_VALUE, "");
return Htmls.WEB_FRAGMENT_EVALUATION_DATA_F;
}
@RequestMapping(HelperUrls.URL_WEB_EVALUATION_DATA)
public String data(Model model, HttpServletRequest request,
@RequestParam(value = Params.PARAM_FROM, required = true) long from,
@RequestParam(value = Params.PARAM_TO, required = true) long to) {
final IDM_USER user = this.idm_user_repository.findByEmail(request.getUserPrincipal().getName());
if (user != null) {
final int unit = user.getUnit();
final Locale locale = LocaleContextHolder.getLocale();
final String unitValue = HelperShortcuts.getUnitForShortcut(this.messageSource, locale, unit);
Set<IDM_BREAD> breads = this.idm_bread_repository.findByDatesBetweenAndUser(new Date(from), new Date(to), user);
Set<IDM_FOOD> foods = this.idm_food_repository.findByDatesBetweenAndUser(new Date(from), new Date(to), user);
Set<IDM_INSULIN> insulins = this.idm_insulin_repository.findByDatesBetweenAndUser(new Date(from), new Date(to), user);
Set<IDM_MEASURE> measures = this.idm_measure_repository.findByDatesBetweenAndUser(new Date(from), new Date(to), user);
Set<IDM_MOOD> moods = this.idm_mood_repository.findByDatesBetweenAndUser(new Date(from), new Date(to), user);
Set<IDM_NOTE> notes = this.idm_note_repository.findByDatesBetweenAndUser(new Date(from), new Date(to), user);
Set<IDM_SPORT> sports = this.idm_sport_repository.findByDatesBetweenAndUser(new Date(from), new Date(to), user);
List<DatatransferListEntry> entries = new ArrayList<>();
entries.addAll(breads);
entries.addAll(foods);
entries.addAll(insulins);
entries.addAll(measures);
entries.addAll(moods);
entries.addAll(notes);
entries.addAll(sports);
entries = this.initHeaders(entries, locale);
model.addAttribute(ReturnKeys.TIME, Helper.getDateTimePatternEvaluation(this.messageSource, locale, from, to));
model.addAttribute(ReturnKeys.ENTRIES, entries);
model.addAttribute(ReturnKeys.USER_UNIT_VALUE, unitValue);
}
return Htmls.WEB_FRAGMENT_EVALUATION_DATA_F;
}
那么当页面加载时,您可以在body标签中或页面中的某个地方具有onload函数,该函数调用javascript函数,并在页面中的某处显示动画图像,并在ajax调用返回时将其隐藏:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<body onload="loadEvaluations()">
<img src="animation-image.jpg" style="display:none" id="animationImage"/>
<div th:fragment="fragment_evaluations_data" class="margin-top-100 margin-bottom-100">
<div th:each="entry: ${ENTRIES}">
<div class="container page-small page-small-header" th:if="${entry.type == 0}">
<div class="row page-row-evaluation">
<span th:text="${entry.timestampLabel}"></span>
</div>
<div class="row page-row-evaluation"></div>
</div>
<div class="container page-small page-small-header-sub" th:if="${entry.type == 1}">
<div class="row page-row-evaluation">
<span th:text="${entry.timestampLabel}"></span>
</div>
<div class="row page-row-evaluation"></div>
</div>
<div class="container page-small" th:if="${entry.type == 2}">
<div class="row page-row-evaluation">
<div class="col-md-12">
<span class="evaluation-font" th:text="${entry.value} + ' ' + ${USER_UNIT_VALUE}"></span>
</div>
<div class="col-md-12 margin-top-5">
<span th:text="${entry.timestampLabel} + ' '"></span>
<span th:if="${entry.mealtime == 0}" th:text="'- ' + #{label.meal_before}"></span>
<span th:if="${entry.mealtime == 1}" th:text="'- ' + #{label.meal_after}"></span>
</div>
</div>
<div class="row page-row-evaluation"></div>
</div>
<div class="container page-small" th:if="${entry.type == 3}">
<div class="row page-row-evaluation">
<div class="col-md-12">
<span class="evaluation-font" th:text="${entry.units} + ' ' + #{label.insulin_units}"></span>
</div>
<div class="col-md-12 margin-top-5">
<span th:text="${entry.timestampLabel}"></span>
</div>
</div>
<div class="row page-row-evaluation"></div>
</div>
<div class="container page-small" th:if="${entry.type == 4}">
<div class="row page-row-evaluation">
<div class="col-md-12">
<span class="evaluation-font" th:text="${entry.units} + ' ' + #{label.bread}"></span>
</div>
<div class="col-md-12 margin-top-5">
<span th:text="${entry.timestampLabel}"></span>
</div>
</div>
<div class="row page-row-evaluation"></div>
</div>
<div class="container page-small" th:if="${entry.type == 5}">
<div class="row page-row-evaluation">
<div class="col-md-12">
<span class="evaluation-font" th:text="${entry.sporttype.sporttype}"></span>
</div>
<div class="col-md-12 margin-top-5">
<span th:if="${entry.intensity == 0}" th:text="#{label.intensity_easy}"></span>
<span th:if="${entry.intensity == 1}" th:text="#{label.intensity_moderate}"></span>
<span th:if="${entry.intensity == 2}" th:text="#{label.intensity_hard}"></span>
<span th:if="${entry.intensity == 3}" th:text="#{label.intensity_very_hard}"></span>
</div>
<div class="col-md-12 margin-top-5">
<span th:text="${entry.duration} + ' ' + #{label.minutes}"></span>
</div>
<div class="col-md-12 margin-top-5">
<span th:text="${entry.timestampLabel}"></span>
</div>
</div>
<div class="row page-row-evaluation"></div>
</div>
<div class="container page-small" th:if="${entry.type == 6}">
<script>
function loadFoodImage(id) {
$.ajax({
url : "/rest/evaluation/foodiamgeid",
type : "POST",
headers : createAuthorizationTokenHeader(),
async : 1,
data : {
image_id: id
},
success : function(data) {
var image = JSON.parse(data).USER_IMAGE;
if (image != null) {
var selector = "#evaluation_food_image_" + id;
$(selector).attr("src", image);
}
},
error : function(data) {
}
});
}
</script>
<div class="row page-row-evaluation">
<div class="col-md-12">
<span class="evaluation-font" th:text="#{label.food}"></span>
</div>
<div class="col-md-12 margin-top-5">
<span th:text="${entry.timestampLabel}"></span>
</div>
<div class="col-md-12 margin-top-5">
<img th:id="'evaluation_food_image_' + ${entry.imageId}" src="/img/ic_rolling.gif" class="center-block img-responsiv image-upload-image" th:onload="|loadFoodImage('${entry.imageId}')|" />
</div>
</div>
<div class="row page-row-evaluation"></div>
</div>
<div class="container page-small" th:if="${entry.type == 7}">
<div class="row page-row-evaluation">
<div class="col-md-12">
<span class="evaluation-font" th:text="#{label.note}"></span>
</div>
<div class="col-md-12 margin-top-5">
<span th:text="${entry.timestampLabel}"></span>
</div>
<div class="col-md-12 margin-top-5">
<span th:text="${entry.note}"></span>
</div>
</div>
<div class="row page-row-evaluation"></div>
</div>
<div class="container page-small" th:if="${entry.type == 8}">
<div class="row page-row-evaluation">
<div class="col-md-12">
<span class="evaluation-font" th:text="#{label.mood}"></span>
</div>
<div class="col-md-12 margin-top-5">
<span th:text="${entry.timestampLabel}"></span>
</div>
<div class="col-md-12 text-center">
<img th:if="${entry.mood == 1}" class="image-mood" src="/img/ic_mood_very_bad_red.png"></img>
<img th:if="${entry.mood == 2}" class="image-mood" src="/img/ic_mood_bad_orange.png"></img>
<img th:if="${entry.mood == 3}" class="image-mood" src="/img/ic_mood_neutral_yellow.png"></img>
<img th:if="${entry.mood == 4}" class="image-mood" src="/img/ic_mood_good_green.png"></img>
<img th:if="${entry.mood == 5}" class="image-mood" src="/img/ic_mood_very_good_green.png"></img>
</div>
</div>
<div class="row page-row-evaluation"></div>
</div>
</div>
</div>
</body>
</html>
那么您的javascript可以做到:
function loadEvaluations() {
$('#animationImage').show();
$.ajax({
url : "/evaluation/data",
type : "POST",
headers : createAuthorizationTokenHeader(),
async : !1,
data : {
from: rangeFrom,
to: rangeTo
},
success : function(data) {
$('#animationImage').hide();
$("#portal_container").html(data);
},
error : function(data) {
$('#animationImage').hide();
$("#portal_container").html(data);
}
});
}