I'd like to add an error flag in my web page.
How can I to check if a Spring Model attribute is true or false with Thymeleaf?
The boolean literals are true and false.
Using the th:if you will end up with a code like:
<div th:if="${isError} == true">
or if you decide to go with the th:unless
<div th:unless="${isError} == false">
There is also a #bools utility class that you can use. Please refer to the user guide: http://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf.html#booleans
You can access model attributes by using variable expression (${modelattribute.property}).
And, you can use th:if for conditional checking.
It looks like this:
Controller:
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
public class MyController {
#RequestMapping("/foo")
public String foo(Model model) {
Foo foo = new Foo();
foo.setBar(true);
model.addAttribute("foo", foo);
return "foo";
}
}
HTML:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
</head>
<body>
<div th:if="${foo.bar}"><p>bar is true.</p></div>
<div th:unless="${foo.bar}"><p>bar is false.</p></div>
</body>
</html>
Foo.java
public class Foo {
private boolean bar;
public boolean isBar() {
return bar;
}
public void setBar(boolean bar) {
this.bar = bar;
}
}
Hope this helps.
Related
I just create simple template by the help of thmeleaf, When I try to
access the variable from controller class by the help of variable
Expression , But I get Issue on variable expression ,In the time of
variable expression access . Showing below type of error
cannot Resolve variable name
My variable name is today which I define in my controller class
Homecontroller.kt
package com.nilmani.thymeleafdemo.controller
import org.springframework.web.bind.annotation.RestController
import org.thymeleaf.ITemplateEngine
import org.thymeleaf.context.WebContext
import java.text.SimpleDateFormat
import java.util.*
import javax.servlet.ServletContext
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
#RestController
class HomeController : IGTVGController() {
#Throws(Exception::class)
fun process(request:HttpServletRequest,response: HttpServletResponse,
servletContext: ServletContext,templateEngine: ITemplateEngine){
val dateForm:SimpleDateFormat= SimpleDateFormat("dd-mm-yyyy")
val calendar:Calendar = Calendar.getInstance()
val ctx : WebContext = WebContext(request,response,servletContext,request.locale)
ctx.setVariable("today",dateForm.format(calendar.time))
templateEngine.process("home",ctx,response.writer)
}
}
home.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Welcome TO our WebPage</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" media="all"
href="../../css/gtvg.css" th:href="#{/css/gtvg.css}" />
</head>
<body>
<p th:utext="#{home.welcome}">Welcome to our website</p>
<p>Today is: <span th:text= "${today}"></span></p>
</body>
</html>
error shows at this point below point
th:text= "${today}"
What is the reason for not support of variable expression . I already
added thymeleaf gradle depedency in my project.But the variable
expression not working
I don't know Kotlin, so I hope you can convert my Java answer to it.
I see you use #RestController, but if you are using Thymeleaf, use #Controller
You can have Spring Boot inject the Model class and add your attributes there
The easiest is to return a String value that represents the name of the Thymeleaf template.
Using all that, you get something like this:
#Controller
public class HomeController {
public String process(Model model) {
model.addAttribute("today", ...);
return "home"; //this refers to home.html like this
}
}
PS: You should not use Calendar anymore, see https://www.baeldung.com/java-8-date-time-intro for more info on the "new" date/time API introduced in Java 8.
package com.example.servingwebcontent;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
#Controller
public class GreetingController {
#GetMapping("/greeting")
public String greeting(#RequestParam(name="name", required=false, defaultValue="World") String name, Model model) {
model.addAttribute("name", name);
return "greeting";
}
}
<!DOCTYPE HTML>
<html>
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p>Get your greeting here</p>
</body>
</html>
The examples from the official guide: https://spring.io/guides/gs/serving-web-content/
We can see that the url, that is greeting, is hardcoded.
Suppose, I write that url in 50 places. And now I want to change the url.
Is it somehow possible to escape hardcoding?
The HTTP request can be GET, POST, PUT, DELETE, and PATCH.
To map the HTTP request with your definition, you need to use #GetMapping, #PostMapping, #PutMapping, #DeleteMapping, and #PatchMapping in the controller class.
So, URL /greeting can be used in those 5 requests only. So, we can't write the same URL in 50 places in the controller class.
I'm trying to create a registration page. The website is very simple, homepage will be returning signup page and when clicked "Submit" it should save it to the database. But I'm having trouble with getting the page.
Applicant.java
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import java.util.Date;
#Entity
#Table(name = "bayilik_basvuru")
public class Applicant {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#NotBlank(message = "İsim Soyisim Girilmelidir.")
#Column(name = "isim_soyisim")
private String adSoyad;
public Applicant() {
}
public String getAdSoyad() {
return adSoyad;
}
public void setAdSoyad(String adSoyad) {
this.adSoyad = adSoyad;
}
}
Controller
#Controller
public class HomeContoller {
#Autowired
private ApplicantDAO dao;
#RequestMapping("/")
public ModelAndView getApplicationPage(){
ModelAndView model = new ModelAndView();
Applicant applicant = new Applicant();
model.addObject("applicant",applicant);
model.setViewName("index");
return model;
}
#PostMapping("/save")
public String saveApplicant(#Valid Applicant applicant, BindingResult result){
if (result.hasErrors()) {
return "add-student";
}
dao.save(applicant);
return "index";
}
}
Index.html -> form's piece,
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<title>Bayilik Ön Başvuru Formu</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <link rel="stylesheet" type="text/css" th:href="#{../css/style.css}" />
<link rel="stylesheet" type="text/css" th:href="#{../css/bootstrap-datetimepicker.min.css}" />
<link rel="stylesheet" type="text/css" th:href="#{../css/roboto-font.css}" />
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</head>
<body>
<form class="form-horizantal" th:action="#{/save}" th:object="${applicant}"
method="POST">
<div class="form-group">
<label class="col-md-4 control-label">İsim Soyisim</label>
<div class="col-md-8">
<input type="text" th:field="*{adSoyad}" class="form-control" /> <!-- it gives error at this line at the start of the th:field-->
<span th:if="${#fields.hasErrors('adSoyad')}" th:errors="*{adSoyad}" class="text-danger"></span>
</div>
</div>
</body>
</html>
I have been dealing with this for hours. I've compared it to many examples and html file looks good, controller looks good I don't know what I'm doing wrong.
In my pom file I have thymeleaf;
<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
...
<dependendcies>
By the way the error is this;
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Thu Oct 31 01:40:47 EET 2019
There was an unexpected error (type=Internal Server Error, status=500).
Error during execution of processor 'org.thymeleaf.spring5.processor.SpringInputGeneralFieldTagProcessor' (template: "index" - line 27, col 56) // this line is the same line I showed on the index.html file
You are not using the annotation #ModelAttribute on your /save endpoint . try using it like :
#PostMapping("/save")
public String saveApplicant( #Valid #ModelAttribute("applicant") Applicant applicant, BindingResult result){
if (result.hasErrors()) {
return "add-student";
}
dao.save(applicant);
return "index";
}
In your thymeleaf template th:object="${applicant}" expression declares the model object to use for collecting the form data. So , in your controller you have to use the annotation #ModelAttribute to bind the Applicant object to the incoming form content.
Change your get method to properly add the object:
#GetMapping("/") //simpler, more informative
public String getApplicationPage(Model model){
model.addAttribute("applicant", new Applicant()); //note method name
return "index";
}
Look at Project Lombok to greatly simplify your beans. You are missing a getter and setter for your id property and an annotation of #Getter and #Setter on the class would remove a lot of boilerplate.
You would also want the #ModelAttribute annotation on your post method for the Applicant parameter.
In the future, also please post your full stack trace.
It seems like there was an hierarchy problem on the project. Code worked after I fixed the hierarchy of files.
Thanks to repliers for their attempt to help but they couldn't know the core of the problem since I didn't attach the hierarchy's screenshot on the question.
In trying to move from JSP to Thymeleaf- in the former a Spring Boot initial class (with the main method) performed some validation on a user logging in, and if valid would present a banner.jsp. On agreeing to the banner.jsp's statement the user would click the "Ok" (on the banner.jsp), which called an index.jsp that used
<c:if test='${empty Validated}'><jsp:forward page="/do/Index" /></c:if>.
This ultimately brought up the webapp.
In converting to Thymeleaf I can get
<c:if test='${empty Validated}'><jsp:forward page="/do/Index" /></c:if> piece within the index (now .html). I'd figure something like
<div th:if="${empty Validated}" th:action="#{/do/Index}"></div>
might work, but it returns a 404 error. I'm wondering if I would , instead, need to call a controller. If that's the case I'm unsure of the syntax.
I've tried some syntax variations of the <div th:if="${empty Validated}" th:action="#{/do/Index}"></div> without success.
Index.html (as Thymeleaf)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<!--<c:if test='${empty Validated}'><jsp:forward page="/do/Index" /></c:if>-->
<div th:if="${empty Validated}" th:action="#{/do/Index}"></div>
</body>
</html>
I would want the forward functionality to be successfully mimicked in Thymeleaf so that the index.html opens the webapp
Controller
package mil.dfas.springmvc.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
/**
* #author David Higgins
*/
#Controller
public class LMSSpringController {
private static final Logger log = LoggerFactory.getLogger(LMSSpringController.class);
#Value("${messages.banner:default-value}")
private String message = "HelWd";
#RequestMapping("/banner")
public String welcome(Model model) {
log.info("Config Example");
System.out.println("LMS Controller");
model.addAttribute("msg","Forward Handled");
return "banner";
}
/* #GetMapping("/index")
public String indexHandler() {
System.out.println("index cont");
return "forward:/do/Index";
}*/
#RequestMapping(value = "/index", method = RequestMethod.POST)
public ModelAndView indexHandler(ModelMap model) {
model.addAttribute("attribute", "index");
System.out.println("index cont");
return new ModelAndView("forward:/do/Index", model);
}
#RequestMapping("/")
public void handleRequest() {
throw new RuntimeException("test exception");
}
}
In the struts.xml:
<action name="User_UserFormSubmit" class="actions.UserManager">
<result name="input" >/jsp/user_form.jsp</result>
<result name="success" type="redirectAction"> success_register</result>
</action>
My class:
public class UserManager extends ActionSupport implements ModelDriven<User>{
private User user = new User();
#Override
public User getModel() {
return user;
}
public String validate() {
addActionError("blabla");
}
public String execute() {
return SUCCESS;
} ...
then in the jsp:
<s:property value="getActionErrors()"/>
I expect in the input result :
<li> blabla </li>
I succefully arrived to user_form.jsp, but the actionError does not appear
I tried without the "implements ModelDriven" and it work
The model driven erase the actionErrors (I supposed)
I want to use validate and modeldriven ¿any idea?
Not a big fan of model driven... but here is an example.
Before the example please note that using validate() does not make much sense in terms of ModelDriven. The reason is that the Model should be used over several actions and so the validation should probably be consistent. You don't use model driven just to make property names a bit shorter (to do that you use the struts2 push tag). As such validation should be done with xml as the model is bigger than any one action. Each action which uses that model uses the Visitor validator. This validator merely looks up the xml validation file for the model. The following example however will use the validate() method in the action to save time.
The following example will use the struts2-conventions-plugin to reduce the example size (adding it to your project is simply a matter of adding one jar).
create: com.quaternion.action.AddUser
package com.quaternion.action;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class AddUser extends ActionSupport implements ModelDriven<User>{
User user = new User();
#Override
public User getModel() {
return user;
}
#Override
public void validate(){
if (user.age != 12) {
super.addActionError("bla bla bla");
}
}
}
create: com.quaternion.action.User
package com.quaternion.action;
public class User {
public String name;
public int age;
}
create: /WEB-INF/content/add-user-input.jsp
<%#taglib prefix="s" uri="/struts-tags"%>
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>Form</title>
</head>
<body>
<h1>Form</h1>
<s:actionerror/>
<s:form action="add-user">
<s:textfield name="name"/>
<s:textfield name="age"/>
<s:submit/>
</s:form>
</body>
</html>
create: /WEB-INF/content/add-user-success.jsp
<%#taglib prefix="s" uri="/struts-tags"%>
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>Success</title>
</head>
<body>
<h1>Success</h1>
</body>
</html>
To test:
Add /add-user-input as the action name on your context path. If you enter an age of 12 you will get the success page, if you enter anything else you will get an action error. This has been tested to work. It is possible a typo was made, but the main thing to take away is there is an error in your application, using both conventions or xml there should be no issues with what you are doing.
You can also validate with #validations too, you have access to model driven object in the validator.
#Action(value = "save-user")
#Validations(
stringLengthFields = {
#StringLengthFieldValidator(fieldName = "name", trim = true, key = "validate.required.string.length"),
#StringLengthFieldValidator(fieldName = "age", trim = true, key = "validate.required.string.length"),
#StringLengthFieldValidator(fieldName = "address.addLine1", trim = true, key = "validate.required.string.length")
})
public String save() {