2016-08-07 46 views
1

Im Moment vor einem großen Problem, weil ich ein Fragment mit einer Liste mit sehr großen Datenmengen haben. Was ich bis jetzt zu tun ist folgende:Spring, Thymeleaf und asynchrone Daten laden

Wenn der Benutzer klickt auf eine Schaltfläche ich eine Javascript-Post wie folgt durchführen:

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); 
     } 
    }); 
} 

Im Frühjahr Backend i die Daten aus der Datenbank auswählen, lege es in der modellieren und senden Sie das Fragment:

@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; 
} 

im Fragment wie folgt dargestellt Dies ist immer:

<!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> 

Das Problem

die Daten auf diese Weise eine sehr schlechte Benutzererfahrung ist Laden, weil die Belastung rund 10 Sekunden und die ui gefriert nimmt, und der Benutzer ist nicht in der Lage, etwas zu tun. Er bleibt auf der alten Seite, muss 10 Sekunden warten und wird danach zum neuen Fragment "navigiert".

Was ich brauche

Ich brauche eine thymeleaf/Feder-Lösung die Daten asynchron zu laden. Also möchte ich, dass der Benutzer die neue Seite sofort sieht, nachdem er auf den Link geklickt hat und dann eine Art Lade-Animation präsentiert wird, während die Daten vom Server gesammelt werden. Wenn der Server fertig ist, sollte die Ansicht automatisch aktualisiert werden.

Ist das möglich?

Antwort

1

Sie zwei separate Controller haben können, so dass, wenn die Taste auf der anderen Seite angeklickt wird es einfach die URL ruft die Seite anzuzeigen:

@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; 
} 

dann beim Laden der Seite Sie eine onload Funktion haben können der Body-Tag oder irgendwo in der Seite, die Ihre Javascript-Funktion aufruft und eine Animation Bild auf der Seite irgendwo angezeigt werden und es verstecken, wenn der ajax-Aufruf kehrt somit:

<!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> 

dann Javascript tun können:

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); 
     } 
    }); 
} 
+0

Dies ist eine funktionierende Lösung. Ich kann 'loadEvaluations() 'nicht in' onLoad' des' body'-Tags aufrufen, weil es nie aufgerufen wird, aber ich kann es nach meinem ersten 'loadEvaluations'-Erfolg aufrufen :). Vielen Dank. – Mulgard

+0

@Mulgard das ist okk .. uwc – Sohlowmawn