hey so I wanted to have a form:select that looks like this so far:
<form:select id="constants" path="constant" class="form-control chosen-select" size="2"
items="${constants}" itemValue="id" itemLabel="description" multiple="true" />
I retrieve constants from the db, they are 4/5 rows of constant values. I wanted to do such that if I select "Other" a form:input/ below pops up/becomes active and usable
so at the end onSubmit I just send the optional form:input value that the user writes manually. How do I achieve that? I've been trying to use jquery but I end up not sending the right data as I really cannot "turn off" the <form:select /> and "turn on" the <form:input />. Hope you can help me out!
This is the Constant Entity:
#Entity
#Table(name = "constant", schema = BaseEntity.SCHEMA_NAME)
public class Constant {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_constant")
#SequenceGenerator(name = "seq_constant", sequenceName = "seq_constant", allocationSize = 1)
#Column(name = "ID_CONSTANT")
private Long id;
#Column(name = "name")
private String name;
#Column(name = "description")
private String description;
}
Related
I'm curious to find a solution for this but couldn't find anything relatable and useful so far.
I have a table Transaction:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "transaction_id")
private Long id;
#Column(name = "user_id", nullable = false)
private Long userId;
#Column(name = "wallet_name", nullable = false)
private String walletName;
#NotNull(message = "Please, insert a amount")
#Min(value = 0, message = "Please, insert a positive amount")
private Double amount;
private String note;
#DateTimeFormat(pattern = "yyyy-MM-dd")
#Column(name = "date")
private LocalDate date;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "wallet_id", nullable = false)
private Wallet wallet;
#Enumerated(EnumType.STRING)
#Column(name = "transaction_type", columnDefinition = "ENUM('EXPENSE', 'INCOME')")
private TransactionType transactionType;
#Nullable
#Enumerated(EnumType.STRING)
#Column(name = "expense_categories", columnDefinition = "ENUM('FOOD_AND_DRINK', 'SHOPPING', 'TRANSPORT', 'HOME'," +
" 'BILLS_AND_FEES', 'ENTERTAINMENT', 'CAR', 'TRAVEL', 'FAMILY_AND_PERSONAL', 'HEALTHCARE'," +
" 'EDUCATION', 'GROCERIES', 'GIFTS', 'BEAUTY', 'WORK', 'SPORTS_AND_HOBBIES', 'OTHER')")
private ExpenseCategories expenseCategories;
#Nullable
#Enumerated(EnumType.STRING)
#Column(name = "income_categories", columnDefinition = "ENUM('SALARY', 'BUSINESS', 'GIFTS', 'EXTRA_INCOME', 'LOAN', 'PARENTAL_LEAVE', 'INSURANCE_PAYOUT', 'OTHER')")
private IncomeCategories incomeCategories;
Now, to display that data on Thymeleaf I created controller with model that I'm passing on Thymeleaf .
And that looks like this:
#GetMapping("/userTransactions/{user_id}")
public String getUserTransactions(#PathVariable("user_id") long user_id, Model model) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserDetailsImpl user = (UserDetailsImpl) authentication.getPrincipal();
long userId = user.getId();
model.addAttribute("userId", userId);
model.addAttribute("transactions", transactionService.findDistinctIdByUserId(user_id));
return "transactions";
}
As you can see, Transaction is connected with User so user actually can create a Transaction, and on that controller I'm just getting all transaction from each User and this is how I display it on Thymeleaf:
<div th:each="transactions : ${transactions}">
<h2>Amount: <span th:text="${transactions.amount}"></span></h2>
<br>
<h2>Note: <span th:text="${transactions.note}"></span></h2>
<br>
<h2>Date: <span th:text="${transactions.date}"></span></h2>
<br>
<h2>Wallet name: <span th:text="${transactions.walletName}"></span></h2>
<br>
<h2>Expense Category: <span th:text="${transactions.expenseCategories}"></span></h2>
<br>
<h2>IncomeCategory: <span th:text="${transactions.incomeCategories}"></span></h2>
</div>
Don't mind the way I formatted it, point is that works fine so far, I got all data displayed on page but I want to achieve one thing:
As you can see, while creating transaction user also pick a date, and what I want?
Lets say user have two transactions for today, I mean 18/01/2023
I want to have a heading for example like <div and to pass today date and each transaction from today, and below down for example 15/01/2023 because user also have a transactions on that date.
This is an example, as you can see I have today section because user made a transaction on today date, also for yesterday and then back on January 14, so I want to separate transactions for each that like that.
Example
Sorry for SS, I tried to add code snippet but cant find option on this updated SO.
I don't know from where to start, I found some options like to sort from ascending and descending order date but I want to avoid something like that and to give my best to achieve this. So any resource, tutorial or any help here will be fine. Thanks.
If you want to break it up by date, you should do that in the Java beforehand. Instead of passing a List<Transaction>, you should pass a List<TransactionGroup> where a TransactionGroup contains all the transactions for a day. It might look something like:
class TransactionGroup {
private LocalDate date;
private List<Transaction> transactions;
/* Getters and setters */
}
Then your html becomes simple.
<div th:each="group : ${transactionGroup}">
<h1 th:text="${group.date}" />
<div th:each="transaction : ${group.transactions}">
<h2>Amount: <span th:text="${transactions.amount}"></span></h2><br>
<h2>Note: <span th:text="${transactions.note}"></span></h2><br>
<h2>Wallet name: <span th:text="${transactions.walletName}"></span></h2><br>
<h2>Expense Category: <span th:text="${transactions.expenseCategories}"></span></h2><br>
<h2>IncomeCategory: <span th:text="${transactions.incomeCategories}"></span></h2>
<div>
</div>
I am writing a spring boot application to perform certain jobs on a MySQL database. One of the things I am having trouble with is getting the average temperature per day from the database.
My #entity looks as follows:
#Entity
public class SensorData {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long sensorDataId;
#Column(
name = "timestamp"
)
private LocalDateTime timestamp;
#Column(
name = "temperature"
)
private Float temperature;
#Column(
name = "humidity"
)
private Float humidity;
#ManyToOne(
fetch = FetchType.LAZY,
optional = false,
cascade = CascadeType.ALL
)
#JoinColumn(
name = "department_id",
nullable = false
)
private Department department;
}
And department entity as follows. I am working with department (1)"A", (2)"B" and (3)"C".
#Entity
public class Department {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long departmentId;
#Column(
name = "department",
unique = true
)
private String department;
#OneToMany(
mappedBy = "department",
fetch = FetchType.LAZY
)
private List<SensorData> sensorData;
}
The problem I am facing is that I need to make a query that returns average temperature per day per department. In my attempts to do this I have written the following JpaRepository function:
#Query(value = "select round((dc.temperature),3) as temperature
,dc.department_id,dc.timestamp from db_uppg.sensor_data dc group by department_id,dc.timestamp",nativeQuery = true)
List<?> findTemperature();
And a controller function that returns a thymeleaf template averageTemperature.html:
#Controller
public class IndexController {
#Autowired
private SensorDataRepository sensorDataRepository;
#GetMapping("/averageHumidity")
public String avgHumidity(Model model) {
List<?> list = sensorDataRepository.findHumidity();
model.addAttribute("allHumidity", list);
return "averageHumidity";
}
}
And finally my thymeleaf template:
<table class="table table-dark table-hover">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Average Temperature</th>
<th scope="col">Date</th>
</tr>
</thead>
<tbody>
<tr th:each="humidityList : ${allHumidity}">
<th scope="row">-</th>
<td th:text="${humidityList.humidity}"></td>
<td th:text="${humidityList.datetime}"></td>
</tr>
</tbody>
</table>
My IDE warns me that it cannot resolve humidity and datetime in my thymeleaf template. I assume it's because I am using List<?>, and Java cannot understand the data this list contains?
I am not sure what other ways I can achieve displaying a result where the columns requested do not match any of my original entities.
That query returns List<Object[]> as the actual type, so use that instead of ?. Then in your service layer (or the controller if you don't have a service layer), convert the rows to suitable DTOs with those fields (humidity and datetime).
The resulting code could look something like
List<HumidityDTO> list = sensorDataRepository.findHumidity().stream()
.map(h -> new (HumidityDTO(h)))
.collect(Collectors.toList());
If HumidityDTO has a constructor taking an Object[] parameter.
I have a problem with a Thymeleaf form with a nested class. I'm working on Calorie Counter Application and when I'm trying to add a new FoodProduct to an existing meal I get an exception. FoodProduct is a class that handles the template of all FoodProduct i.e.: Apple, Chicken Breast, etc.
FoodProduct class:
#Entity
#Table(name = "food_products")
public class FoodProduct {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#Column(name = "product_name")
private String productName;
#Column(name = "proteins")
private Double proteins;
#Column(name = "fats")
private Double fats;
#Column(name = "carbohydrates")
private Double carbohydrates;
#Column(name = "calories")
private Double calories;
// ...
}
MealFoodProduct class:
#Entity
#Table(name = "meals_food_products")
#IdClass(MealFoodProductPK.class)
public class MealFoodProduct {
#Id
#ManyToOne
#JoinColumn(name = "meal_id")
private Meal meal;
#Id
#ManyToOne
#JoinColumn(name = "food_product_id")
private FoodProduct foodProduct;
#Column(name = "food_product_weight")
private double weight;
//...
}
HTML Form:
<form action="#" th:action="#{/saveMealFoodProduct}" th:object="${mealFoodProduct}" method="post">
<div>
<label>Product name</label>
<div>
<select th:field="*{foodProduct}">
<option th:each="foodProduct : ${foodProducts}" th:text="${foodProduct}" th:value="${foodProduct.id}"></option>
</select>
</div>
</div>
<div>
<label>Weight</label>
<div>
<input type="number" th:field="*{weight}" placeholder="Enter weight">
</div>
</div>
<br>
<div>
<div>
<button type="submit">Save</button>
</div>
</div>
</form>
When I confirm a form I have this exception and I have no idea, what's wrong:
Failed to convert property value of type 'java.lang.Integer' to required type 'pl.sosinski.nutritioncounter.model.FoodProduct' for property 'foodProduct';
nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.Integer' to required type 'pl.sosinski.nutritioncounter.model.FoodProduct' for property 'foodProduct': no matching editors or conversion strategy found
org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'java.lang.Integer' to required type 'pl.sosinski.nutritioncounter.model.FoodProduct' for property 'foodProduct'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.Integer' to required type 'pl.sosinski.nutritioncounter.model.FoodProduct' for property 'foodProduct': no matching editors or conversion strategy found
If you change the foodProduct selection code to the following, the problem will be fixed.
<select th:field="*{foodProduct.id}">
<option th:each="foodProduct : ${foodProducts}"
th:text="${foodProduct}"
th:value="${foodProduct.id}"></option>
</select>
OR
You need to indicate to your app how convert a Id of FoodProduct returned inside form (String Type) to a FoodProduct entity. For that you have to use a Converter.
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
#Component
public class StringToFoodProductConverter implements Converter<String, FoodProduct> {
#Override
public FoodProduct convert(String arg0) {
Integer id = Integer.valueOf(arg0);
FoodProduct foodProduct = new FoodProduct();
foodProduct.setId(id);
return foodProduct;
}
}
How can I populate a dropdown list based on selections of other dropdown lists?
I have a Unit class, a Size class and a City class. The user must first select a country from a dropdown list of countries, the municipalities list will then display only the municipalities in that country, after that the user must select a city size, and at the end of it all, the user must select a city from a list of cities which are of the selected size, and belong to the selected municipality and country.
My code:
Unit.java
public class Unit {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable=false)
private String name
#ManyToOne
#JoinColumn
#ToString.Exclude
private UnitType unitType;
#OneToOne
#JoinColumn
private Unit unit;
#OneToMany(mappedBy = "unit", cascade = CascadeType.ALL)
private Set<City> cities;
}
UnitType.java
public class UnitType {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable=false)
#Enumerated(EnumType.STRING)
private UnitName uName;
#OneToMany(mappedBy = "unitType", cascade = CascadeType.ALL)
private Set<Unit> units;
public enum UnitName {
COUNTY, MUNICIPALITY
}
}
CitySize.java
public class CitySize {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="naziv", nullable=false)
#Enumerated(EnumType.STRING)
private Size name;
#OneToMany(mappedBy = "citySize", cascade = CascadeType.ALL)
private Set<City> sizes;
public enum Size {
SMALL, MEDIUM, LARGE
}
}
City.java
public class City {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable=false)
private String name;
#ManyToOne
#JoinColumn
#ToString.Exclude
private CitySize citySize;
#ManyToOne
#JoinColumn
#ToString.Exclude
private Unit unit;
#OneToMany(mappedBy = "city", cascade = CascadeType.ALL)
private Set<Event> events;
}
Event.java
public class Event {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable=false)
private String name;
#Column(nullable=false)
private LocalDateTime time;
#ManyToOne
#JoinColumn
#ToString.Exclude
private City city;
}
EventController.java
public class EventController {
....
#GetMapping("/citySearch")
public String citySearch(Model model) {
model.addAttribute("event", new Event());
model.addAttribute("unit", new Unit());
model.addAttribute("citySize", new CitySize());
model.addAttribute("counties", unitRepository.findByUnitTypeId(50001L));
model.addAttribute("municipalities", unitRepository.findByUnitTypeId(50002L));
model.addAttribute("sizes", CitySize.Size.values());
model.addAttribute("cities", cityRepository.findAll());
return "citySearch";
}
#PostMapping("/citySearch")
public String citySearch(Event event, Model model, City city, Unit unit,
CitySize citySize) {
List<Event> foundEvents = eventRepository.findByCity(city);
model.addAttribute("unit", new Unit());
model.addAttribute("citySize", new CitySize());
model.addAttribute("counties", unitRepository.findByUnitTypeId(50001L));
model.addAttribute("municipalities", unitRepository.findByUnitTypeId(50002L));
model.addAttribute("sizes", CitySize.Size.values());
model.addAttribute("cities", cityRepository.findAll());
model.addAttribute("foundEvents", foundEvents);
return "citySearch";
}
}
citySearch.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" th:href="#{/css/style.css}" >
<title>City search</title>
</head>
<body>
<h1>Event search by city</h1>
<form th:object="${unit}" method="post">
<div class="form-group">
<label for="unit">County: </label>
<select th:id="countyOption" th:field="*{unit}">
<option value="" >choose counties</option>
<option th:each="county : ${counties}" th:value="${county.id}" th:text="${county.name}"></option>
</select>
</div>
<div class="form-group">
<label for="unit">Municipality: </label>
<select th:id="municipalityOption" th:field="*{unit}">
<option value="" >choose municipilaties</option>
<option th:each="municipality : ${municipilaties}" th:value="${municipality.id}" th:text="${municipality.name}"></option>
</select>
</div>
</form>
<form th:object="${citySize}" method="post">
<div class="form-group">
<label for="name">City size: </label>
<select th:field="*{name}">
<option value="" >choose a city size</option>
<option th:each="name : ${sizes}" th:value="${id}" th:text="${name}"></option>
</select>
</div>
</form>
<form th:object="${event}" method="post">
<div class="form-group">
<label for="city">City: </label>
<select th:field="*{city}">
<option value="" >choose cities</option>
<option th:each="city : ${cities}" th:value="${city.id}" th:text="${city.name}"></option>
</select>
</div>
<input type="submit" th:value="Search">
</form>
<table>
<tr>
<th>Name</th>
<th>City</th>
<th>Time</th>
</tr>
<tr th:each="event : ${foundEvents}">
<td><span th:text="${event.name}" >EVENT.NAME</span></td>
<td><span th:text="${event.city.name}" >CITY.NAME</span></td>
<td><span th:text="${#temporals.format(event.time, 'dd.MM.yyyy. HH:mm')}" >EVENT.TIME</span></td>
</tr>
</table>
<p><a th:href="#{/search}">Return</a></p>
</body>
</html>
So far, my web search provided information that this can't be done by using only Spring boot and Thymeleaf, only with jQuery. Since I don't know jQuery, I would require some instructions on how to write and implement the method in jQuery. Also, I don't have a WebConfig.java class, since I had no need for it so far in my app, but if I need it now, what does it have to contain?
Spring Boot and Thymeleaf can't do anything client-side, but you can still achieve what you are trying to do without Javascript / JQuery:
You can submit the selected country to the backend, where you calculate the possible municipalities for that country, which you can add to the model and only display those (Or disable all other options). However, you will have to do that for every step that limits the options, that means reloading the page everytime, which can be painful to use.
If you want to accomplish the same without reloading the page, you will have to resort to some client-side code - that means Javascript / JQuery.
Is it possible to select whole Java Object from Spring Form's drop down menu? I used LinkedHashMap, but it doesn't work.
I have relation Many To One between table Agent and table Roles (every Agent has one role eg. user, admin). I use hibernate so I have to operate on Object, not Id's from database. My problem is that I want to create drop down menu with list of all roles from my database and when I pick one element, this Object goes to my Agent Object and save in my database.
I have List with my Roles Objects
List<Roles> rolesList = rolesService.getAllRoles();
Which comes from this:
public List<Roles> getAllRoles() {
return session().createQuery("from Roles").list();
}
and I tried something like this:
In my AgentController:
#RequestMapping("/createagent")
public String createAgent(Model model) {
Agent agent = new Agent();
List<Roles> rolesList = rolesService.getAllRoles();
Map<Roles, String> rolesMap = new LinkedHashMap<Roles,String>();
for (int i=0; i<rolesList.size(); i++){
rolesMap.put(rolesList.get(i), rolesList.get(i).getRole());
}
model.addAttribute("rolesMap", rolesMap);
model.addAttribute("agent", agent);
return "createagent";
}
In my jsp file:
<tr><td>Roles:</td><td>
<sf:select path="roles" multiple="false">
<sf:options items="${rolesMap}"></sf:options>
</sf:select>
</td></tr>
My Roles Object:
#Entity
#Table(name = "roles")
public class Roles {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "roles_seq_gen")
#SequenceGenerator(name = "roles_seq_gen", sequenceName = "roles_id_seq")
#Column(name = "id")
private long id;
#Column(name = "role")
private String role;
It shows excactly what I want but when I click position in my drop down menu and submit it, my form don't save my Object properly. It nested it ... I don't know how to subscribe this, maybe my toString() function output clear little bit.
Agent [id=0, username=TestUsername, password=TestPassword, roles=Roles[id=0, roles=Roles[id=0, roles=user]] ...
My Agent Object:
#Entity
#Table(name="agent")
public class Agent {
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="agent_seq_gen")
#SequenceGenerator(name="agent_seq_gen", sequenceName="agent_id_seq")
#Column(name="id")
private long id;
#Column(name="username")
private String username;
#Column(name="password")
private String password;
#ManyToOne
#JoinColumn(name="roles_id")
private Roles roles;
My jUnit test runs fine, it's something wrong with my Spring Form or with my controllers... I don't know.
I would suggest to use ModelAttribute and reference the form object to the said properties, like, agent.getRoles().
createAgent(#ModelAttribute("agent") Agent agent) should work in what you're trying to accomplish.