Say I want to access an object that is called post. Post has a instance variable called Category of type Category.
In the Java controller class
model.addAttribute("posts", postRepository.findPostsByUser(user));
In the thymeleaf html file I have
<tr data-th-each="post : ${posts}">
I am wondering if it is it possible to access the below?
{post.category.name}
For clarification I have included the java classes below. Each instance has associated setters and getters.
#Entity
public class Post {
#ManyToOne
#JoinColumn(name = "category_id")
private Category category;
#Entity
public class Category {
private String name;
you have to make a condition:
<tr th:each="post:${posts}">
<td th:text="${post.category}!=null? ${post.category.name}:''"></td>
</tr>
:)
I think you need to change your entity code
#Entity
public class Post {
private Category category;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "category_id", nullable = false)
public Category getCategory () {
return this.category;
}
public void setCategory (Category category ) {
this.category = category ;
}
}
you need implement thymeleaf html page as per following
<tr th:each="post : ${posts}">
<td> <span th:utext="{post.category.name}" /></td>
</tr>
Hope its help to you!
Related
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.
In My spring boot Application, I want to see total userlist like below:
username
role
admin
ADMIN
But i got like:
username
role
admin
[com.test.springCRUD.model.Role#3e39aaf6]
My User model:
#Entity
#Table(name = "users")
public class User {
#Id
#Column(name="user_id")
#GeneratedValue(strategy =GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private boolean enabled;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name ="users_roles", joinColumns = #JoinColumn (name="user_id"), inverseJoinColumns = #JoinColumn (name="role_id"))
private Set<Role> roles=new HashSet<>();
Role model:
#Entity
#Table(name = "roles")
public class Role {
#Id
#Column(name="role_id")
#GeneratedValue(strategy =GenerationType.IDENTITY)
private Integer id;
private String name;
UserService Class:
#Service
public class UserServices {
#Autowired
private UserRepository userRepository;
public List<User> listAll(){
return (List<User>) userRepository.findAll();
}
Controller:
#RequestMapping("/userlist")
public String viewUserList(Model model) {
List<User> listUsers = userServices.listAll();
model.addAttribute("listUsers", listUsers);
return "userList";
}
thymleaf page:
<tbody>
<tr th:each="user : ${listUsers}">
<td th:text="${user.id}">User ID</td>
<td th:text="${user.username}">User Name</td>
<td th:text="${user.roles}">User Role</td>
<td>
</td>
</tr>
</tbody>
How to get userlist with rolename.
I am on a similar project.
'roles' is defined as a Set of Roles, so you are seeing the identifiers of that object, rather than the values.
You will need to iterate through the roles themselves if the intent is to display the list of names of roles.
Also remember, the role has a name and Id since it in itself is an entity/model, so you will want to iterate the roles and show role name, something like:
- <el th:each="role : ${user.getRoles()}"/>
- <el th:text="${role.getName()}"/>
If you are liking the Table, I would recommend a span for each role name.
There are alternatives depending on how you want it shown. You may also do this in your controller or UserDetails class depending on what the desired functionality/application or display is beyond verifying it within a thymeleaf page for users or Admins.
I am trying to make a Recipe Builder form using Thymeleaf.
The functionality I am trying to implement involves adding a List of selected objects (ingredients) to the bound recipe.
Here is a snippet of the Form from the Template file:
<form action="#" th:action="#{/recipes/userRecipes/new/save}" th:object="${userRecipe}"
method="post">
...
<td>Ingredients:</td>
<td>
<ul>
<li th:each="ingredient : ${allIngredients}">
<input type = "checkbox" th:name="sel_ingredients" th:value="${ingredient.id}" />
<label th:text="${ingredient.name}">Ingredient</label>
</li>
</ul>
</td>
</tr>
...
</table>
</form>
Here is a snippet from my controller:
#RequestMapping("/userRecipes/new")
public String createNewUserRecipe(Model model){
UserRecipe userRecipe = new UserRecipe();
model.addAttribute("userRecipe", userRecipe);
return "new-recipe";
}
#RequestMapping(value = "/userRecipes/new/save", method = RequestMethod.POST)
public String saveRecipe(
#ModelAttribute("userRecipe") UserRecipe userRecipe,
#RequestParam(value = "sel_ingredients", required = false) int[] sel_ingredients,
BindingResult bindingResult, Model model){
for(int i : sel_ingredients){
Ingredient ing = new Ingredient();
ing = ingredientRepo.getOne((long)i);
userRecipe.addIngredient(ing);
}
userRecipeRepo.save(userRecipe);
return "redirect:../";
}
Along with a #ModelAttribute to set Ingredients:
#ModelAttribute
public void populateIngredients(Model model){
List<Ingredient> ingredientList = this.ingredientRepo.findAll();
//Iterator<Ingredient> itr = ingredientList.iterator();
model.addAttribute("allIngredients", ingredientList);
}
Entities:
#Entity
#Table(name = "user_recipes")
public class UserRecipe extends AuditModel{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
#Size(max = 100)
#Column(unique = true)
private String title;
#NotNull
#Size(max = 250)
private String description;
#ManyToMany
#JoinTable(
name = "used_ingred",
joinColumns = #JoinColumn(name = "user_recipe_id"),
inverseJoinColumns = #JoinColumn(name = "ingredientid")
)
private List<Ingredient> ingredients;
public void addIngredient(Ingredient i){
this.ingredients.add(i);
}
#NotNull
#Lob
private String preparation;
#Entity
#Table(name = "ingredients_master")
public class Ingredient extends AuditModel{
#Column(name = "ingredient")
private String name;
#Column(name="description")
private String description;
#Id
#GeneratedValue
private long id;
// public Ingredient(String n, String d){
// this.setName(n);
// this.setDescription(d);
// }
// public Ingredient(int id, String n, String d){
// this.setId(id);
// this.setName(n);
// this.setDescription(d);
// }
#ManyToMany(mappedBy = "ingredients")
Set<UserRecipe> recipes;
#ManyToMany
Set<Tag> tags;
Originally, I tried to grab the Ingredient objects directly, but couldn't figure out how to do that, so instead opted to grab the ids, and then reference them from the Repository; however,
I get the following error when I click the save button:
There was an unexpected error (type=Internal Server Error, status=500).
No message available
java.lang.NullPointerException
at com.donovanuy.mixmix.entities.UserRecipe.addIngredient(UserRecipe.java:85)
at com.donovanuy.mixmix.controllers.RecipeController.saveRecipe(RecipeController.java:103)
If possible, I'd like to be able to grab the Ingredient object directly, and add it to the List field of my userRecipe.
I am considering making a separate RecipeMakerForm, that I can instead pass into a service. Something like:
public class RecipeMakerForm{
String newTitle;
Long[] ingredientIds;
Long[] tagIds;
and the service would like like:
public class RecipeMaker{
void makeRecipe(RecipeMakerForm form){
Recipe r = new Recipe(form.getNewTitle());
if (ingredientIds != null){
for (Long id : ingredientIds){
r.addIngredient(ingredientRepo.getOne(l));
}
//etc
recipeRepo.save(r);
}
Even still, I suspect my errors have something to do with the way Thymeleaf is passing the model data back to the controller, so my new RecipeMaker & RecipeMakerForm methods wouldn't work. I'm still new to using Thymeleaf and working with Spring.data, so I expect my solution to be somewhere in my Thymeleaf or Controller methods.
I have two models, Patient and Study. In the Study model, I want to use Patient's Id as a foreign key. My Study Model (without getter/setter) is as below
#Entity
#Table(name = "Study")
public class Study {
#Id
#Column(name = "study_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotNull
#ManyToOne
#JoinColumn(name = "patient_id")
private Patient patient;
#NotNull
#Column(name = "description")
private String description;
#NotNull
#Column(name = "status")
private String status;
}
EDIT : Adding Patient class (without getter/setter) as well
#Entity
#Table(name="Patient")
public class Patient {
#Id
#Column(name="patient_id")
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#NotNull
#Column(name="name")
private String name;
#Column(name="sex")
private String sex;
#Column(name="date_of_birth")
private Date dateOfBirth;
}
I am using Thymeleaf and selection of patient in my scheduleStudy.html is shown below
<form method="POST" th:action="#{/scheduleStudy}" th:object="${study}">
<p>
Select Patient<select th:field="*{patient}"
required="required" class="form-control">
<option th:each="patient: ${patientList}" th:value="${patient.id}"
th:text="${patient.name}"></option>
</select>
</p>
The form is loading successfully with list of Patients in dropdown. However, when I am submitting the form after filling out all the fields, I am receiving:
Validation failed for object='study'. Error count: 1 error on browser.
Also the controller entries for Study form
#GetMapping("/scheduleStudy")
public String addSchedule(Model model) {
List<Patient> patientList = patientService.getPatients();
model.addAttribute("patientList", patientList);
model.addAttribute("study", new Study());
return "scheduleStudy";
}
#PostMapping("/scheduleStudy")
public void processAddSchedule(#ModelAttribute Study study) {
studyService.addStudy(study);
}
I have just started using Thymeleaf and I think I have dome some mistake in the patient field. Could anyone please help?
EDIT 2: I have updated the method for POST request, but patient is still null in controller. The previous browser error is gone of course.
#RequestMapping(value = "/scheduleStudy", method = RequestMethod.POST)
public String processAddSchedule(Model model, #Valid #ModelAttribute("study") Study study,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
} else {
studyService.addStudy(study);
}
}
I was working on a similar task. As far as I learned when you post the study form Thymeleaf sends all fields as parameters to a POST request. It converts the Patient object to a String with toString(). Then when assembling the Study object it must convert the Patient back to the Object form. I solved this by registering 2 converters (toString and fromString) with the standard conversionService for Patient.
If we are creating a backend for website. We will obviously create categories and posts/products. To add/edit/delete categories we will obviously create a table like structure. for example:This is category listing as table
Category would have a child category in a same table, number of child category could be 1 - many. I would like to show the number of child category as i have mentioned in above image.
As a CI developer i use to do that by using Query in the view,
Here is the example
<?php
if(sizeof($results)>0)
{
$i=1;
foreach($results as $key => $list)
{
if($i%2==0)$cls="row1"; else $cls="row2";
?>
<tr id="<?php echo $list->id;?>" class="<?php echo $cls; ?>">
<td> <?php echo $list->title, anchor("admin/categories/update/".$list->id."/", '<i class="fa fa-pencil rtrt"></i>' ); ?></td>
<td>
<?php
// it will return number of childs
echo anchor ('admin/categories/category/'.$list->id, $this->Common->select_child ('tbl_category', $list->id) );
?>
</td>
Right now i am using Spring-mvc, hibernate, Jpa, and Mysql DB. I am known that doing sql query from a jsp would be a bad practice.
Here is my Jsp Code for table like structure,
<table class="table table-striped">
<thead>
<tr>
<th><i class="fa fa-pencil"></i></th>
<th>Category Name</th>
<th>Child</th>
<th>Created</th>
<th>Updated</th>
<th><input type="checkbox" /></th>
</tr>
</thead>
<tbody>
<c:if test="${not empty category}">
<c:forEach var="cat" items="${category}">
<tr>
<td><i class="fa fa-pencil"></i></td>
<td>${cat.title}</td>
<td><i class="fa fa-folder-open"></i></td>
<td>${cat.created}</td>
<td>${cat.updated}</td>
<td><input type="checkbox" /></td>
</tr>
</c:forEach>
</c:if>
Here is the category POjo class
#Entity
#Table(name = "categories")
public class Categories {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
private Long parent_id;
private String title;
private String url_title;
private String description;
private String created;
private String updated;
/*
* # At the time of Creating new user
* Auto persist created date
* Auto persist updated for first time
*/
#PrePersist
protected void onCreate (){
// Date conversion to string
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd h:mm:s");
sdf.setLenient(false);
String now = sdf.format(date);
created = now;
updated = now;
}
/*
* Respective Getter and Setter Methods
*
*/
public Long getId() {
return id;
}public void setId(Long id) {
this.id = id;
}
public Long getParent_id() {
return parent_id;
}public void setParent_id(Long parent_id) {
this.parent_id = parent_id;
}
public String getTitle() {
return title;
}public void setTitle(String title) {
this.title = title;
}
public String getUrl_title() {
return url_title;
}public void setUrl_title(String url_title) {
this.url_title = url_title;
}
public String getCreated() {
return created;
}public void setCreated(String created) {
this.created = created;
}
public String getUpdated() {
return updated;
}public void setUpdated(String updated) {
this.updated = updated;
}
public String getDescription() {
return description;
}public void setDescription(String description) {
this.description = description;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Categories other = (Categories) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
The Question is
how can i get children count without doing sql query from Jsp ?
Please Help me i need a suggestion.
to get a List count on jsp side use jstl functions like below :
declare the taglibe of jstl.functions
<%# taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
then you can try this
<c:set var="count" value="${fn:length(you_array)}" />
this will create a variable "count" taking as value : you_array.size()
Hope it will help someone like me,
Modified entity class
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
private Long parent_id;
private String title;
private String url_title;
private String description;
private Long status;
private String created;
private String updated;
#ManyToOne
#JoinColumn(
name="parent_id",
insertable=false,
updatable=false)
#NotFound(action = NotFoundAction.IGNORE)
private Categories parentCategory;
#OneToMany(
fetch = FetchType.EAGER,
mappedBy="parentCategory",
cascade=CascadeType.REMOVE,
orphanRemoval=true )
private Set<Categories> child = new HashSet<Categories>();
Since i am new to Jpa/orm/hibernate/spring when i posted this question i did not knew about entity relationship which we can manage in hibernate. I did some research and found out about hibernate 'Uni/Bi directional' association using annotation like (one to many, many to one, many to many). I suggest if you are new to JPA and hibernate then please visit This link before wasting your time.
What I have done
Bidirectional associations with join : using #ManyToOne #Onetomany #joinColumn
Solve Notfound exception using #NotFound(NotFoundAction.IGNORE)
I have a categories (eg. Base category) which wont have any parent category so its 'parent_id' will be 0 in database but Hibernate will throw exception while querying records from database with id 0, after a successfull association.
Used insertable/updatable = false : set this properties to false if you are inserting and updating only one category at a time.
Used "cascade=cascadetype.remove" "orphanremoval=true" : set this properties, if you want to delete child categories when you delete parent category. When you invoke your serviceImplementation.delete(category cat) method, if "cat:object" is parent for other categories hibernate will automatically delete it's children categories before deleting cat:object itself.
At last the Answer for my question
After the successful association with annotation, when you will query category rows from database. If it's a parent category for other categories hibernate will add "child Collection" in your object like this.
03:20:16.490 [http-bio-8080-exec-5] DEBUG
o.h.internal.util.EntityPrinter -
com.pack.librarymanagementsystem.model.Categories
{created=2016-06-10 7:45:32, parent_id=38, url_title=Bhm 5th sem,
description=<p>asd</p>,
parentCategory=com.pack.librarymanagementsystem.model.Categories#38,
id=43, title=Bhm 5th sem, updated=2016-06-10 7:45:32, child=[], status=1}
Check It in your console log if you are using eclipse. The child collection hibernate just added wont have any data. Hibernate will store only proxys.
The solution is to get the size of a child collection.
If you will do isEmpty() check on that child collection the result will be true. Thats where the "fetch = FetchType.EAGER" Kicks in. By default fetchtype is set to lazy. After changing fetchtype to eager hibernate will add objects as a child instead of adding proxy.
If you will do isEmpty check on that child collection now, the result will be false. Which means we can get the size of a collection.
This is the jsp
<c:if test="${not empty category}">
<c:forEach var="cat" items="${category}">
<tr>
<td><i class="fa fa-pencil"></i></td>
<td>${cat.title}</td>
<td>
// Child count
<c:if test="${not empty cat.child}" >
<a href="${pageContext.request.contextPath}/category/show/${cat.id}">
<i class="fa fa-folder-open"></i> ${ fn:length(cat.child)}
</a>
</c:if>
<c:if test="${empty cat.child}" >
<i class="fa fa-folder"></i> 0
</c:if>
</td>
<td>${cat.created}</td>
<td>${cat.updated}</td>
<td>
<c:choose>
<c:when test="${cat.status == 1}">Published</c:when>
<c:otherwise>Unpublished</c:otherwise>
</c:choose>
</td>
<td><input type="checkbox" name="ids[]" id="ids[]" value="${cat.id}" /></td>
</tr>
</c:forEach>
And this is the controller
#RequestMapping(value = "/show/", method = RequestMethod.GET)
public String viewCategory( Map<String, Object> model) {
List<Categories> category = categoryService.getAllCategoriesByParent(Id);
model.put("category",category);
return "category/view";
}
I hope this would help someone on saving his/her time.
Thank you