Accessing Model attributes in Thymleaf and Spring boot - spring

I am learning to use thymeleaf templates for a project I am completing and seem to be missing something.
I am trying to create a very simple Hello type app, here is my code (note I am using groovy):
Controller:
#Controller
class TestController {
#RequestMapping("/")
String homePage(#RequestParam("name") String name, ModelAndView modelAndView){
modelAndView.addObject("name", name)
return "home"
}
}
home.html:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title></title>
</head>
<body>
<h1>Hello</h1>
<p th:text="${name}" />
</body>
</html>
What have I missed? I just get "Hello" and nothing else when I hit:
http://localhost:8080/app-0.0.1-SNAPSHOT/?name=Sam

you have alternate option with access controller data with view name returning
#Controller
class TestController {
#RequestMapping("/")
public String homePage(#RequestParam("name") String name,Model model){
model.addAttribute("name", name)
return "home"
}
}
in your html file
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title></title>
</head>
<body>
<h1>Hello</h1>
<p th:text="${name}" />
</body>
</html>
bind model object with parameter and now you need to set addAttribute with key and value par you can access data without using ModelAndView object.

I'm not sure but you can to change ModelAndView by Model:
#Controller
class TestController {
#RequestMapping("/")
String homePage(#RequestParam("name") String name, Model model){
model.addAttribute("name", name)
return "home"
}
}

To answer my own question, if I change the controller to return a ModelAndView, like so:
#Controller
class TestController {
#RequestMapping("/")
ModelAndView homePage(#RequestParam("name") String name){
ModelAndView mav = new ModelAndView()
mav.addObject("name", name)
mav.setViewName("home")
return mav
}
}
Then all is good, although the tutorials show it working like my original example - I'm quite happy to do it this way.

#Controller
#RequestMapping("/")
class TestController {
#GetMapping
public String homePage(#RequestParam(name = "name") String name,Model model){
model.addAttribute("name", name);
return "home";
}
}

Related

Springboot homepage after login

I just want to display the homepage and the users name after login but I keep getting a 404 not found error.
here is the index.html page
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 th:action="#{/index}">Hello<h1 th: th:text="${name}"></h1> </h1>
</body>
</html>
And here is my controller
#Controller
#AllArgsConstructor
public class UserController {
private final UserService userService;
private final ConfirmationTokenService confirmationTokenService;
#GetMapping("/sign-in")
String signIn() {
return "sign-in";
}
#GetMapping("/sign-up")
String signUpPage(User user) {
return "sign-up";
}
#PostMapping("/sign-up")
String signUp(User user) {
userService.signUpUser(user);
return "redirect:/sign-in";
}
#GetMapping("/sign-up/confirm")
String confirmMail(#RequestParam("token") String token) {
Optional<ConfirmationToken> optionalConfirmationToken = confirmationTokenService.findConfirmationTokenByToken(token);
optionalConfirmationToken.ifPresent(userService::confirmUser);
return "redirect:/sign-in";
}
#RequestMapping(value = {"/index"}, method = RequestMethod.GET)
public String welcome(User user, Model model) {
model.addAttribute("Name", user.getName());
return "index";
}
I've been trying this for a while now and I don't know what I'm doing wrong. The websecurity config is configured so that the default succesuful URL is index.html
Try changing the request mapping to
#RequestMapping(value = {"/index", "/"}, method = RequestMethod.GET)
Also, try calling localhost:9090/index (without the .html) as Eleftheria Stein-Kousathana said.

Returning HTML page in a JSON property in Spring Boot conditionally

So I'm in a scenario writing Restful Services where based on request data, I've to return either a short string or HTML page IN A JSON variable. lets say like this:
response {
result : YourRequestedString
}
OR
response {
result : <html>...</html>
}
The decision of what will be returned is on server side.
So, is there a way that I can render my Thymeleaf (or any other maybe plain HTML) templates while I'm in the same controller method (directly or by calling some controller method that returns me the rendered page). That I can send back to the client.
Thanks to #Leffchik I got it working, here's my setup with Thymeleaf so it can help others.
Setup htmlTemplateEngine
#Bean
public TemplateEngine htmlTemplateEngine() {
final SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(htmlTemplateResolver());
return templateEngine;
}
private ITemplateResolver htmlTemplateResolver() {
final ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setResolvablePatterns(Collections.singleton("html/*"));
templateResolver.setPrefix("/templates/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCharacterEncoding("utf-8");
templateResolver.setCacheable(false);
return templateResolver;
}
Here's the html page in src/main/resources/templates/html/hello.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="'Hello, ' + ${name} + '!'" />
</body>
</html>
RestController goes like this
#RestController
public class TestController {
#Autowired
TemplateEngine htmlTemplateEngine;
#RequestMapping("/testHello")
public ResponseEntity<?> test(#RequestParam(value = "name", required = false, defaultValue = "World") String name) {
final org.thymeleaf.context.Context ctx = new org.thymeleaf.context.Context();
ctx.setVariable("name", name);
// Rendered template in String, You can now return in a JSON property
final String htmlContent = this.htmlTemplateEngine.process("html/hello.html", ctx);
return ResponseEntity.ok().body(htmlContent);
}
}
Hope it helps !
Returning an HTML Page in a REST Api is not encouraged. But if you fancy you can return a ResponseEntity<Response> from your controller.
#GetMapping("/mymethod")
public ResponseEntity<Response> myMethod() {
ResponseEntity responseEntity = null;
if(string) {
responseEntity = new ResponseEntity(getString(), HttpStatus.OK);
} else {
responseEntity = new ResponseEntity(getHtml(), HttpStatus.OK);
}
return responseEntity;
}

Error during execution of processor 'org.thymeleaf.spring4.processor.attr.SpringInputGeneralFieldAttrProcessor'

Trying to change value inside my model class which contains a private String name and I wanted to change the name using Thymeleaf in HTML page then see the change in another url response body.
When I try to access my ("/myname") page in localhost I got the error:
Error during execution of processor 'org.thymeleaf.spring4.processor.attr.SpringInputGeneralFieldAttrProcessor'
Here is my Model:
public class Name {
public String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Here is my Controller
#Controller
public class MainController {
#RequestMapping("/name")
#ResponseBody
public String showName() {
Name myname = new Name();
return myname.getName();
}
#RequestMapping("/myname")
public String setName() {
return "myname";
}
#RequestMapping(value = "myname", method = RequestMethod.POST)
public String showName(#ModelAttribute Name iko, BindingResult errors, Model model) {
return "name";
}
}
Here is my html thymeleaf pages:
myname.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1"/>
<title>Insert title here</title>
</head>
<body>
<form action="#" th:action="#{/myname}" th:object="${iko}" method="post">
<label>Enter the name</label><br/>
<input type="text" th:field="*{name}"/>
<button type="submit">SUBMIT</button>
</form>
</body>
</html>

Spring Social with Spring Boot not getting user email id

I am new as developer, trying hands on Spring social facebook integration. Followed this link
I am getting data like user's name', 'gender', 'locale'. Which can be given as constructor value to User class(see took help).
But I want to get user "email-id", somehow that's not possible the way i am getting data for 'name', 'locale' and 'gender.
We need to use method getEmail() as per docs. But I am not able to do it.
("A simple app with OAuth security implemented")
Here is the snippet....
My controller class code is
#Controller
#RequestMapping("/")
public class HelloController {
private Facebook facebook;
private ConnectionRepository connectionRepository;
public HelloController(Facebook facebook, ConnectionRepository connectionRepository) {
this.facebook = facebook;
this.connectionRepository = connectionRepository;
}
#GetMapping
public String helloFacebook(Model model) {
if (connectionRepository.findPrimaryConnection(Facebook.class) == null) {
return "redirect:/connect/facebook";
}
String [] fields = {"name", "gender", "locale"};
User userProfile = facebook.fetchObject("me", User.class, fields);
model.addAttribute("feed", userProfile);
//String email = facebook.getEmail();
/*this above one "facebook.getEmail()" gives Internal server error 500 */
return "hello";
}
}
Model class is ...
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8"/>
<title>Title</title>
</head>
<body>
<h3>Hello, <span th:text="${feed.name}">Some User</span>!</h3>
<h4>Your gender is : <span th:text="${feed.gender}"></span></h4>
<h4>Your locale is : <span th:text="${feed.locale}"></span></h4>
<h4>Your email is : <span th:text="${feed.getEmail()}"></span></h4>
</body>
</html>
Main class is as...
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Any help is appreciated. Thanks.

Spring Framework <form:errors/> tag not showing errors

I know there are many similar questions here, but none of them solved my problem.
I'm using Spring 4.0.3 and Hibernate Validator 5.1.0.
The problem occurs when I try to omit the path attribute of the <form:errors/> tag, so:
<form:errors path="contato.nome" /> works
<form:errors path="*" /> works
<form:errors /> doesn't work
I don't know why it happens. Spring javadocs (org.springframework.web.servlet.tags.form.ErrorsTag) says it should work like that:
Field only - set path to the field name (or path)
Object errors only - omit path
All errors - set path to *
Can you help me, please?
The interested code is in the 'edicao.jsp' and in the method 'confirmarEdicao' of the ContatoController.java. Sorry if my english is bad.
ContatoController.java
#Controller
#RequestMapping("/contatos")
public class ContatoController {
#Autowired
private ContatoService contatoService;
#Autowired
private MessageSource messageSource;
#RequestMapping(value = "/confirmarEdicao", method = RequestMethod.POST)
public String confirmarEdicao(#Valid Contato contato, BindingResult bindingResult) {
if(bindingResult.hasErrors()) {
return "contatos/edicao";
}
contatoService.save(contato);
return "redirect:/contatos";
}
#RequestMapping(method = RequestMethod.GET)
public ModelAndView form(HttpServletRequest request) {
String message = messageSource.getMessage("teste", null, new Locale("pt", "BR"));
System.out.println(message);
return new ModelAndView("contatos/listagem")
.addObject("contatos", contatoService.list());
}
#RequestMapping("/remover/{id}")
public String remover(Contato contato) {
contatoService.delete(contato);
return "redirect:/contatos";
}
#RequestMapping("/editar/{id}")
public ModelAndView formEdicao(Contato contato) {
contato = contatoService.find(contato.getId());
return new ModelAndView("contatos/edicao")
.addObject(contato);
}
#RequestMapping(value = "/cadastrar")
public String formCadastro() {
return "contatos/cadastro";
}
#RequestMapping(value = "/confirmarCadastro", method = RequestMethod.POST)
public String confirmarCadastro(#Valid Contato contato, BindingResult bindingResult,
RedirectAttributes redirectAttributes) {
if (bindingResult.hasFieldErrors()) {
return "contatos/cadastro";
}
contatoService.save(contato);
redirectAttributes.addFlashAttribute("mensagem", "Contato cadastrado com sucesso.");
return "redirect:/contatos";
}
#ResponseBody
#RequestMapping(value = "/pesquisar/{nome}", method = RequestMethod.GET,
produces="application/json")
public List<Contato> pesquisar(#PathVariable String nome) {
return contatoService.findByName(nome);
}
}
edicao.jsp
<%# page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%# taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Editar contato</title>
</head>
<body>
<c:set var="context">${pageContext.request.contextPath}</c:set>
<script type="text/javascript">var context = "${context}";</script>
<script src="${context}/resources/js/jquery-2.1.0.min.js"></script>
<script src="${context}/resources/js/contatos/edicao.js"></script>
<form:form commandName="contato" action="${context}/contatos/confirmarEdicao" method="post">
<form:errors/>
<table>
<form:hidden path="id"/>
<tr>
<td>Nome:</td>
<td><form:input path="nome" /></td>
</tr>
<tr>
<td>Telefone:</td>
<td><form:input path="telefone"/></td>
</tr>
<tr>
<td><input type="button" value="Voltar" id="btn_voltar"/><input type="submit" value="Salvar"/></td>
</tr>
</table>
</form:form>
</body>
</html>
Contato.java
package com.handson.model;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.NotEmpty;
public class Contato {
private Long id;
#Size(min = 3, message = "Nome deve ter no mínimo 3 caracteres")
#NotEmpty(message = "O nome deve ser preenchido")
private String nome;
private String telefone;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getTelefone() {
return telefone;
}
public void setTelefone(String telefone) {
this.telefone = telefone;
}
public Contato withId(Long id) {
setId(id);
return this;
}
public Contato withTelefone(String telefone) {
setTelefone(telefone);
return this;
}
public Contato withNome(String nome) {
setNome(nome);
return this;
}
#Override
public String toString() {
return "Contato [id=" + id + ", nome=" + nome + ", telefone="
+ telefone + "]";
}
}
There are some keywords which should be defined:
path - EL-like path to an object or to a field of an object (e.g. foo, foo.bar or foo.bar.baz)
nested path - current path context stored as nestedPath request attribute (new paths are relative to this path)
object error - error connected with object itself (e.g. path is equal to foo)
field error - error connected with object field (e.g. path is foo.bar)
The tag <form:form commandName="foo"> defines nested path as nestedPath=foo. When you write <form:errors path="bar"> it tries to find errors defined for path foo.bar.
Lets say that you have errors connected with foo (object error), foo.bar and foo.bar.baz (nested field error). What this means:
if you enter <form:errors>, only errors bound to foo path are displayed => 1 message
if you enter <form:errors path="bar">, only errors bound to foo.bar path are displayed => 1 message
if you enter <form:errors path="*">, errors bound to foo and its child paths are displayed => 3 messages
if you enter <form:errors path="bar.*">, only child errors for foo.bar are diplayed => 1 message
if you enter <form:errors path="bar*">, errors bound to foo.bar and its child paths are diplayed => 2 messages
Checking on Errors class JavaDoc might give you additional insight.

Resources