#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>
.