Thymeleaf error : An error happened during template parsing - spring

I don't know what is wrong with my view but it is impossible for it to work, the view always gives an error even if idStudent is set correctly.I don't know if there is also another way to do it, but thymeleaf always fail
here is the error - > Exception evaluating SpringEL expression: "student.id == {idStudent}" (template: "/content/course/list-course-student" - line 55, col 24)
here is my controller
#GetMapping("/list-courses-student")
public String listCoursesByUser(#RequestParam(required = false) int page,Model model) {
User currentUser = userService.findByName(this.currentUser.getUsername());
int numberPages = coursesService.getNumberPages();
List<Course> courses = coursesService.findAllCourses(page,true);
model.addAttribute("coursesDisponibles",courses);
model.addAttribute("numberPages",numberPages);
model.addAttribute("currentPage",page);
model.addAttribute("idStudent",currentUser.getStudent().getId());
return "/content/course/list-course-student";
}
My view
<div class="card-body table-responsive p-0">
<table class="table table-hover text-nowrap">
<thead>
<tr>
<th>Profesor</th>
<th>Nombre</th>
<th>Description</th>
<th>Code</th>
<th>Inicio</th>
<th>Final</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
<th:block th:each="course : ${coursesDisponibles}">
<tr>
<td
th:text="${course.teacher == null} ? 'No Asignado' : ${course.teacher.nombre}"></td>
<td th:text="${course.nombre}"></td>
<td th:text="${course.descripcion}"></td>
<td th:text="${course.code}"></td>
<td
th:text="${#temporals.format(course.inicioDate, 'dd/MM/yyyy')}"></td>
<td
th:text="${#temporals.format(course.finalDate, 'dd/MM/yyyy')}"></td>
<td>
<th:block th:each="student : course.Estudiantes">
<th:block th:if="${student != null}">
<th:block th:if="${student.id == {idStudent}}">
<a class="btn btn-success btn-sm" href="">Añadido</a>
<a class="fas fa-inbox ml-3"
th:href="${'/tareas/list-tareas-student?page=1&course=' + {course.id}}"></a>
</th:block>
</th:block>
<th:block th:unless="${student == null}">
<a
th:classappend="${course.teacher == null} ? 'btn btn-primary btn-sm disabled':'btn btn-primary btn-sm' "
th:href="${'/courses/add?idCourse=' + {course.id} + '&idStudent=' + {idStudent}}">Añadir</a>
</th:block>
</th:block>
</td>
</th:block>
</tr>
</tbody>
</table>
</div>

The exception you're most likely experience is NullPointerException, because I think you have a wrong th:each declaration:
<th:block th:each="student : course.Estudiantes">
instead of
<th:block th:each="student : ${course.Estudiantes}">
Thus, expression th:if=${student.id == idStudent} throws NullPointerException as it tries to access the id property on a null student object.
Also note that in order to preventer other NPE's you can use a ? operator in your expressions, like this: ${student?.id}.

Related

Service layer doesn't delete entity?

I have a controller that must delete my entity:
#GetMapping ("/delete")
#PreAuthorize ("hasAuthority ('Admin')")
public String deleteStudent (Long studentId, String keyword) {
studentService.removeStudent(studentId);
return "redirect:/students/index?keyword="+keyword;
}
and HTML page that represent my entity:
<div class="container mt-3">
<div class="card-header">List of Students</div>
<div class="card-body">
<table class="table mt-3">
<thead>
<tr class="text-center">
<th>Student Id</th>
<th>Student First Name</th>
<th>Student Last Name</th>
<th>Student Level</th>
</tr>
</thead>
<tbody>
<tr class="text-center" th:each="student: ${list}">
<td th:text="${student.getStudentId()}"></td>
<td th:text="${student.getFirstName()}"></td>
<td th:text="${student.getLastName()}"></td>
<td th:text="${student.getLevel()}"></td>
<td>
<a onclick="confirm ('Are you sure')" class="btn btn-danger"
th:href="#{students/delete(studentId=${student.getStudentId()}, keyword=${keyword})}"> Delete </a>
</td>
</tr>
</tbody>
</table>
</div>
My Service
public interface StudentService {
void removeStudent (Long studentId);
I run application, open http://localhost:8071/students/index everything work okay, but when I delete my entity I'm getting:
ERROR PAGE There was an unexpected error (type=Not Found, status=404).
-> http://localhost:8071/students/students/delete?studentId=1&keyword=
You have students duplicated in the path, hence 404:
http://localhost:8071/students/students/delete
Your line
th:href="#{students/delete(studentId=${student.getStudentId()}, keyword=${keyword})}"
Should be:
th:href="#{delete(studentId=${student.getStudentId()}, keyword=${keyword})}"

Thymeleaf and th:if not skipping text when null

I understand that you should be able to "skip" text printing if Object is null, in thymeleaf, using th:if.
However my page throws Null error at line 23. (second div)
<div th:if="${Brackets}">
<th:block th:each="brackets : ${Brackets}">
<div th:if="${brackets.brackets}">
<tr th:each="bracket : ${brackets.brackets}">
<td th:text="${bracket.lower}"></td>
<td th:text="${bracket.higher}"></td>
<td th:text="${bracket.prc}"></td>
</tr>
</div>
</th:block>
</div>
What am i missing here?
Solved with "?"
Many thanks to Patrick!
<div th:if="${Brackets} != null">
<th:block th:each="brackets : ${Brackets}">
<div th:if="${brackets?.brackets} != null">
<tr th:each="bracket : ${brackets?.brackets}">
<td th:text="${bracket.lower}"></td>
<td th:text="${bracket.higher}"></td>
<td th:text="${bracket.prc}"></td>
</tr>
</div>
</th:block>
</div>
Its strange that the null check does not work. It could be that the naming has some issues. Anyway, a short way to use null objects savely is to use save navigation. You use it with the ? operator:
<div th:if="${brackets?.brackets} != null">

Getting the selected values from a checkbox list to the controller with Spring Boot

I'm using Spring Boot with Thymeleaf as viewer, and I want to delete all selected items from a table. Therefore, I need to pass to the controller a list with the values from the selected checkboxes.
This is my approach for the controller:
#PostMapping("/admin/rates/prices/delete")
public String delete(#ModelAttribute Rate price, ServletWebRequest request){
if(request.getParameterValues("idChecked") != null){
for(String idCheckedStr : request.getParameterValues("idChecked")){
int idrate = Integer.getInteger(idCheckedStr);
rateRepository.deleteRate(idrate);
}
}
return "redirect:/admin/rates/prices";
}
I get a Null Pointer Exception:
java.lang.NullPointerException: null
at com.rentalwebs.controllers.rates.PriceListController.delete(PriceListController.java:42)
I think this method should collet the values::
request.getParameterValues("idChecked")
This is the line at the form, which creates each checkbox with the Thymeleaf annotations:
<input type="checkbox" th:name="idChecked" th:value="${price.idrate}"/>
That's the view code for the form:
<form th:action='#{/admin/rates/prices/delete}'
method="POST"
th:object="${rate}">
<button type="submit" name='delete' value="delete"
class='btn btn-secondary btn-sm'
th:text="#{delete}"
data-toggle="tooltip" data-placement="right"
th:title="#{delete.selected}">
</button>
<p></p>
<table class='table table-sm responsive'>
<thead class='thead-default'>
<tr>
<th><input type="checkbox" id="checkAll"/></th>
<th th:text='#{from}'></th>
<th th:text='#{to}'></th>
<th th:text='#{price}'></th>
</tr>
</thead>
<tbody>
<tr th:each="price : ${prices}">
<td>
<input type="checkbox" th:name="idChecked" th:value="${price.idrate}"/>
</td>
<td th:text="${#temporals.format(price.datefrom, 'dd/MM/yyyy')}"></td>
<td th:text="${#temporals.format(price.dateto, 'dd/MM/yyyy')}"></td>
<td th:text="${price.price} + ' €'"></td>
</tr>
</tbody>
</table>
</form>
Thank you in advance for your help :-)
This is the code with the solution, taken from the comments:
#PostMapping("/admin/rates/prices")
public String delete(#RequestParam("idChecked") List<String> idrates){
if(idrates != null){
for(String idrateStr : idrates){
int idrate = Integer.parseInt(idrateStr);
rateRepository.deleteRate(idrate);
}
}
return "redirect:/admin/rates/prices";
}

How to get more results by clicking on a button?

I want to inquire about the way I can get more results when I click on a "show more" button, without loading the page and without repeating the same results.
For example, I have a result set from the database and suppose it has 10 results. Under them I have a button named "show more". When I click on it I'll see another 10 results, and so on.
Also here is an image:
My view:
#model SmartBookLibrary.ViewModel.UserVm
<table class="table table-striped table-bordered table-advance table-hover">
<thead>
<tr>
<th>
<i class="fa fa-image"></i> Image
</th>
<th class="hidden-xs">
<i class="fa fa-book"></i> Book Name
</th>
<th class="hidden-xs">
<i class="fa fa-eye"></i> Views
</th>
<th> </th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.ReadLaters)
{
<tr>
<td>
<img class="img-thumbnail circle" src="~/Images/#item.Book.Book_Image" style="width:75px;height:75px" />
</td>
<td class="hidden-xs">
<h4><b>#item.Book.Book_name</b></h4>
</td>
<td>
700
<span class="label label-success label-sm"> Views </span>
</td>
<td>
<a class="btn btn-sm grey-salsa btn-outline" href="~/book/#item.Book_Id/#item.Book.UrlSlug"> View </a>
</td>
</tr>
}
</tbody>
</table>
<input type="submit" class="btn green-sharp btn-outline btn-block sbold uppercase" value="Load More">
My controller method:
[HttpGet]
public ActionResult Index()
{
//Get current user id to check
var x = User.Identity.GetUserId();
var vm = new UserVm();
//ReadLater Books
var ReadLaterBooks = db.ReadLaters.Where(p => p.User_Id == x).ToList();
var ReadLaterBooksResult = ReadLaterBooks.Take(5).ToList();
if (ReadLaterBooks != null)
{
vm.ReadLaters = ReadLaterBooksResult;
}
return View(vm);
}
So, how can I make that work using ajax or whatever? Thanks!

I cannot pass the message to my jsp

my controller
#RequestMapping("/")
public String loadHome(#RequestParam(value="tab",defaultValue="pending_users") String tab,Model model) {
UsersManager um = new UsersManager();
TagsManager tm = new TagsManager();
if(tab.equals("pending_users"))
model.addAttribute("pending_users",um.getPendingUsers(""));
else if(tab.equals("registered_users"))
model.addAttribute("registered_users",ForumUserUtility.sortPointEarned(um.getUsers(0,um.getNoOfUsers(""),"")));
else if(tab.equals("suspended_users"))
model.addAttribute("suspended_users",ForumUserUtility.sortPointEarned(um.getSuspendedUsers(0,um.getNoOfUsers(""),"")));
else if(tab.equals("tags"))
model.addAttribute("tags",tm.getTagsPopular(""));
else if(tab.equals("admins")){
model.addAttribute("admins",ForumUserUtility.sortPointEarned(um.getAdminList(0,um.getNoOfUsers(""),"")));
}
model.addAttribute("tab",tab);
return "admin_view";
}
#RequestMapping("/DeleteAdmin")
public String deleteAdmin(#RequestParam(value="user_id") String userId, Model model){
UsersManager um = new UsersManager();
um.deleteAdmin(Integer.parseInt(userId));
model.addAttribute("messageAdmin", "Admin Successfully Deleted");
return loadHome("admins", model);
}
my jsp
<c:if test="${loggedInUserType == 'master_admin' }">
<c:if test="${tab == 'admins'}">
${messageAdmin }
<div>
<input onkeyup="showAdmins(this.value)" placeholder="Search Admin" type="text"/>
<div id="admin_box">
<c:if test="${not empty admins}">
<table class='table table-bordered' id="admins">
<tr>
<th colspan='6' style='text-align:center'>Admins</th>
</tr>
<tr>
<th style='text-align:center'>Username</th>
<th style='text-align:center'>First Name</th>
<th style='text-align:center'>Last Name</th>
<th style='text-align:center'>Email</th>
<th style='text-align:center' colspan="2">Action</th>
</tr>
<c:forEach var="user" items="${admins}">
<tr>
<td>${user.username}</td>
<td>${user.firstName}</td>
<td>${user.lastName}</td>
<td>${user.emailAddress}</td>
<td>
<a href="" onclick="return suspendUser(${user.userId})">
Suspend
</a>
</td>
<td>
<a href="" onclick="return deleteAdmin(${user.userId})">
Delete Admin
</a>
</td>
</tr>
</c:forEach>
</table>
</c:if>
</div>
<c:if test="${empty admins}">
<h1>No Suspended User</h1>
</c:if>
</div>
</c:if>
</c:if>
i need to send a message in my jsp notifying the user that the admin was already deleted but the ${messageAdmin} cannot be seen in my view. what do you think is wrong in my code? here is my jsp too.

Resources