Как передать два разных атрибута одному и тому же » tr «с одним и тем же» th:каждый » в SpringBoot с ThymeLeaf?

#java #spring-boot #thymeleaf

Вопрос:

Я использую базовую пружинную загрузку с шаблоном ThymeLeaf.

Это базовый и простой класс контроллера. Я не создавал много классов или MVC.

 @Controller
public class HomeController 
{

@GetMapping("/")
 public String home(Model model)
 {
  int[] days = IntStream.range(1, 46).toArray();
  int golds[] = {15000, 12000, 11000, 9000, 7200, 16400, 6600, 5400, 7000, 6300, 4700, 5400, 10600, 7000, 4400, 4500, 4400, 4400, 4400, 6300, 3400, 3600, 5100, 3600, 3700, 3800, 5700, 3700, 3500, 16700, 3600, 3700, 3500, 36000, 3400, 3500, 4000, 3500, 3700, 4000, 4800, 4400, 3600, 4300, 3500};

  model.addAttribute("days", days);
  model.addAttribute("golds", golds);

  return "home";
 }
}
 

Я попытался отобразить оба days и golds в двух ячейках данных одной и той же строки таблицы th:each .

Я уже думал о том, чтобы создать объект и сохранить на нем два атрибута, чтобы я назначил их одному списку и повторил список. Но это создает много ненужных классов. Я счел это чрезмерным. Я попробовал это один раз, и это не сработало.

 <table>
  <thead>
      <tr>
          <th> Dia </th>
          <th> Ouros </th>
      </tr>
  </thead>
  <tbody>
      <tr th:each="day, gold : ${days}">
          <td>[[${day}]]</td>
          <td>[[${gold}]]</td>
      </tr>
  </tbody>
</table>
 

Обновление 2

Я следил за перепроектированием @andrewjames, но это не работает:

 @Controller
public class HomeController implements Serializable 
{
  public static class GoldData 
  {
    private int[] day;
    private int[] gold;

    public int[] getDay() {
      return day;
    }

    public int[] getGold() {
      return gold;
    }

    public void setGold(int[] gold) {
      gold = new int[]{15000, 12000, 11000, 9000, 7200, 16400, 6600, 5400, 7000, 6300, 4700, 5400, 10600, 7000, 4400, 4500, 4400, 4400, 4400, 6300, 3400, 3600, 5100, 3600, 3700, 3800, 5700, 3700, 3500, 16700, 3600, 3700, 3500, 36000, 3400, 3500, 4000, 3500, 3700, 4000, 4800, 4400, 3600, 4300, 3500};
      this.gold = gold;
    }

    public void setDay(int[] day) {
      day = IntStream.range(1, 46).toArray();
      this.day = day;
    }

  }

  List<GoldData> goldData = new ArrayList<>();

  @GetMapping("/")
  public String home(Model model) 
  {
    int total = Arrays.stream(golds).sum();
    int reais = total / 10000;

    model.addAttribute("soma", total);
    model.addAttribute("reais", "R$"   reais);
    model.addAttribute("goldData", goldData);

    return "home";
  }
}
 

Обновление 3

Выхода нет:

 @Controller
public class HomeController implements Serializable 
{
  private int[] day;
  private int[] gold;

  day = IntStream.range(1, 46).toArray();
  gold = new int[]{15000, 12000, 11000, 9000, 7200, 16400, 6600, 5400, 7000, 6300, 4700, 5400, 10600, 7000, 4400, 4500, 4400, 4400, 4400, 6300, 3400, 3600, 5100, 3600, 3700, 3800, 5700, 3700, 3500, 16700, 3600, 3700, 3500, 36000, 3400, 3500, 4000, 3500, 3700, 4000, 4800, 4400, 3600, 4300, 3500};

  int total = stream(gold).sum();
  int reais = total / 10000;

  @GetMapping("/")
  public String home(Model model)
  {
    List<HomeController> goldData = new ArrayList<>();
    List<HomeController> total;
    List<HomeController> reais;

    model.addAttribute("soma", total);
    model.addAttribute("reais", "R$"   reais);
    model.addAttribute("goldData", goldData);

    return "home";
  }
}
 

Комментарии:

1. Этот шаблон называется параллельными массивами и обычно должен быть заменен классом записей, как рекомендует andrewjames.

2. Я применил обе альтернативы @andrewjames. Первая альтернатива несовместима с String[] . Во втором варианте я попытался установить, но это не работает. Смотрите 2-е обновление mu.

Ответ №1:

В этом случае, поскольку days это просто целочисленная последовательность, вам не нужно передавать ее в модель. Вместо этого вы можете использовать переменные отслеживания состояния итерации Thymeleaf. В этом случае переменная count (которая начинается с 1) делает то, что вам нужно:

 <table>
    <thead>
        <tr>
            <th> Dia </th>
            <th> Ouros </th>
        </tr>
    </thead>
    <tbody>
        <tr th:each="gold,iterStat : ${golds}">
            <td th:text="${iterStat.count}"></td>
            <td th:text="${gold}"></td>
        </tr>
    </tbody>
</table>
 

Вы можете увидеть iterStat.count значение в первой ячейке каждой строки.

В моем случае я поместил значения в стандартный th:text атрибут. Вы можете использовать свой альтернативный синтаксис [[...]] , если хотите.


Если бы у вас не было простой целочисленной последовательности days , я бы рекомендовал две возможные альтернативы:

1 — Использовать iterStat.index — который начинается с нуля (в отличие count от того, который начинается с 1) и использовать это значение в качестве значения индекса массива — например, ${days[iterStat.index]} .

2 — Перепроектируйте два отдельных массива в простой JavaBean, содержащий два поля, которые вам нужны (значение дня и золотое значение). Затем создайте список этих объектов. Затем повторение списка в Thymeleaf становится простым, и вам не понадобятся никакие iterStat переменные.


Обновить

Некоторые дополнительные примечания по альтернативному варианту 2:

Предположим, у вас есть очень простой POJO (обычный старый объект Java) с 2 полями:

 public static class GoldData {
    private int day;
    private int gold;
    // getters and setters not shown, but are needed.
}
 

Затем вы построили бы список таких объектов:

 List<GoldData> goldData = new ArrayList<>();
 

И заполните его так, чтобы каждый объект goldData содержал одну пару ваших данных, которые в настоящее время хранятся в ваших массивах.

Затем добавьте это в свою модель вместо 2 (или более) массивов:

 model.addAttribute("goldData", goldData);
 

Затем ваша таблица HTML может использовать этот объект и напрямую ссылаться на его поля:

 <tr th:each="goldDataItem : ${goldData}">
    <td th:text="${goldDataItem.day}"></td>
    <td th:text="${goldDataItem.gold}"></td>
</tr>
 

Теперь нет необходимости в каких-либо счетчиках/переменных отслеживания итераций.

В более общем плане, если вам не нужно хранить свои данные в массивах Java, с объектами может быть намного проще/гибче работать.


Обновление 2

В своем ответе на ваш вопрос вы просто переместили два своих массива в отдельный класс. Это не то, что делает мой пример.

В моем примере класса я полностью избавился от массивов.

В идеале у вас не было бы этих двух массивов в первую очередь. Но для простоты давайте предположим, что вы начинаете с этих 2 массивов.

Чтобы создать один из моих GoldData объектов, вы можете сделать это:

 GoldData gd = new GoldData();
gd.setDay(days[0]);
gd.setGold(gold[0]);
 

(Я игнорирую улучшение, которое можно было бы сделать, добавив соответствующие конструкторы, только для этой демонстрации.)

Теперь это создает один GoldData объект, содержащий одно day значение и одно gold значение.

Вы добавляете это в List следующее:

 List<GoldData> goldData = new ArrayList<>();
goldData.add(gd);
 

Теперь представьте, что вы одновременно повторяете каждый элемент в двух массивах, создаете 45 таких объектов и добавляете каждый из них в свой список.

Посмотрите, можете ли вы использовать приведенные выше примечания, чтобы создать свой List so, содержащий эти объекты. Вы увидите, что в конечном результате нигде не задействованы массивы.


Окончательное Обновление

Вот GoldData класс, но на этот раз я добавил геттеры и сеттеры. Я также добавил конструкторы, на этот раз:

 public static class GoldData {

    private int day;
    private int gold;

    public GoldData() {
    }

    public GoldData(int day, int gold) {
        this.day = day;
        this.gold = gold;
    }

    public int getDay() {
        return day;
    }

    public void setDay(int day) {
        this.day = day;
    }

    public int getGold() {
        return gold;
    }

    public void setGold(int gold) {
        this.gold = gold;
    }

}
 

А вот код, который берет данные вашего массива и загружает их в список GoldData объектов:

 // Here is your array data, from the question:
int[] days = IntStream.range(1, 46).toArray();
int[] golds = {15000, 12000, 11000, 9000, 7200, 16400, 6600, 5400, 7000, 6300, 4700, 5400, 10600, 7000, 4400, 4500, 4400, 4400, 4400, 6300, 3400, 3600, 5100, 3600, 3700, 3800, 5700, 3700, 3500, 16700, 3600, 3700, 3500, 36000, 3400, 3500, 4000, 3500, 3700, 4000, 4800, 4400, 3600, 4300, 3500};

// Here is what we actually want to send to the Thymeleaf template, instead of your arrays:
List<GoldData> goldDataList = new ArrayList<>();

// Here is how we transfer your array data into the above list:
for (int i = 0; i < days.length; i  ) {
    goldDataList.add(new GoldData(days[i], golds[i]));
}

model.addAttribute("goldDataList", goldDataList);
 

Вот текст таблицы шаблона Thymeleaf, в которой используется goldDataList :

 <tbody>
    <tr th:each="goldData : ${goldDataList}">
        <td th:text="${goldData.day}"></td>
        <td th:text="${goldData.gold}"></td>
    </tr>
</tbody>
 

Обратите внимание, что в этом коде нигде нет массивов, за исключением двух исходных массивов из вашего вопроса.

Комментарии:

1. Что касается второй альтернативы, вы имеете в виду List<Int|String> ? Если я сяду String nomes[] = {"Gustavo", "Mark", "Matthew", "Roberto"} , будет ли все по-прежнему <td th:text="${names[iterStat.index]}"></td> ?

2. Не совсем, нет. Я добавил несколько заметок, чтобы попытаться прояснить, что я имею в виду.

3. Чтобы получить значения, я создаю public void HomeController(){ day = IntStream.range(1, 46).toArray(); } внутри public static class GoldData ?

4. Я применил ваш новый дизайн, но он пока не работает.

5. Ваш подход сильно отличается от того, что я предлагаю. Все дело в том, чтобы больше не «думать массивами», а вместо этого «думать объектами». Я попытался добавить дополнительные примечания, чтобы помочь прояснить подход.

Ответ №2:

Пока ваши Arrays размеры всегда одинаковы, вы можете перебирать их следующим образом:

 <tr th:each="i : ${#numbers.sequence(0, #lists.size(days) - 1)}">
  <td>[[${days[i]}]]</td>
  <td>[[${golds[i]}]]</td>
</tr>
 

Комментарии:

1. Не совсем понимаю, что ты имеешь в виду. Я протестировал его с помощью String[] и int[] и List<>, и все сработало для меня. Какую ошибку вы получаете?

2. Это слишком длинный журнал ошибок. Я могу просто сказать , что я поставил просто String[] names = {"Gustavo", "Mark", "Matthew", "Robert", "Washington"} , model.addAttribute("names", names) и <td>[[${names[i]}]]</td> .