Error while moving HTML form from jsp to ThymeLeaf - spring-mvc

I am trying to follow this as reference Serving Static content in SpringBoot
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.ui.Model;
/**
* Created by Eric on 11/25/2015.
*/
#org.springframework.stereotype.Controller
public class Controller {
#RequestMapping("/appPage")
public String greeting(#RequestParam(value="name", required=false, defaultValue="World") String name, Model model) {
model.addAttribute("name", name);
model.addAttribute("title", "Best Of the App");
model.addAttribute("basecontext", "Best Of the App");
return "appPage";
}
}
My HTML form being below
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:text="${title}" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="'Hello, ' + ${name} + '!'" />
<input type="hidden" type="text" id="basecontext" value='${basecontext}'/>
</body>
</html>
I am trying to set value in hidden input field. But that gives me error
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateInputException: Exception parsing document: template="appPage", line 9 - column 33
I am trying to move this html page which was getting loaded in a JSP application to Spring Boot + ThymeLeaf.
If I simply place this content in index.html without a Context handler in Controller. the page is loaded just fine. Thymeleaf does not throw any error.

ThymeLeaf uses xml and not html and you are not allowed to have attributes of the same name in xml type="hidden" type="text"
You actually should get SAXParseException: Attribute "type" was already specified for element in your spring log

Related

Why does GetMapping with #RestController annotation not show the html page, but everything works with #Controller?

I have two html pages:
greeting.html
<!DOCTYPE HTML>
<html xmlns:th="https://www.thymeleaf.org">
<head>
<title>Getting Started: Handling Form Submission</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h1>Form</h1>
<form action="#" th:action="#{/greeting}" th:object="${greeting}" method="post">
<p>Id: <input type="text" th:field="*{ch}" /></p>
<p>Message: <input type="number" th:field="*{count}" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
</body>
</html>
result.html
<!DOCTYPE HTML>
<html xmlns:th="https://www.thymeleaf.org">
<head>
<title>Getting Started: Handling Form Submission</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h1>Result</h1>
<p th:text="'symbol: ' + ${greeting.ch}" />
<p th:text="'count: ' + ${greeting.count}" />
Submit another message
</body>
</html>
And a simple controller:
package com.example.secMVC.Controller;
import com.example.secMVC.Entity.CharacteristicsEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
#Controller
public class UserController {
#GetMapping("/greeting")
public String greetingForm(Model model){
model.addAttribute("greeting",new CharacteristicsEntity());
return "greeting";
}
#PostMapping("/greeting")
public String greetingSubmit(#ModelAttribute CharacteristicsEntity charEntity,Model model){
model.addAttribute("greeting",charEntity);
return "result";
}
}
And now if I run the program with the #Controller annotation, it shows what is needed, i.e. a page with input fields and 2 buttons.But if you change it to #RestContoller, then just a page with the text "greeting" is shown.
I'm a beginner and apparently I don't understand something, but I saw that they wrote that these should be equivalent annotations in theory.I would be glad to help figure out this issue.
Entity just in case:
package com.example.secMVC.Entity;
public class CharacteristicsEntity {
private String ch;
private Integer count;
public String getCh() {
return ch;
}
public void setCh(String ch) {
this.ch = ch;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
}
Well #RestContoller annotation is used when someone creates a RESTful webservices (REST APIs). #RestContoller actually takes care of all the boilerplate code when you creating a RESTful webservice.
Theoretically #Controller and #RestContoller is not equal. But yet you can use both of these annotation if you are creating RESTful webservices in following combination.
#RestContoller
public class ClassName{}
or
#Controller
#ResponseBody
public class ClassName{}
But when you use template engine like Thymeleaf, you better use #Controller rather than #RestContoller.
For more info - Here

Unable to serve static resources with spring, receive index instead

I have a simple Spring web application.
#Controller
public class GreetingController {
#Autowired
GreetingRepository repository;
#GetMapping("/greeting")
public String greetingForm(Model model) {
model.addAttribute("greeting", new Greeting());
return "greeting";
}
#PostMapping("/greeting")
public String greetingSubmit(#ModelAttribute Greeting greeting) {
repository.save(greeting);
return "result";
}
}
The HTML is:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Greeting Sample</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" th:href="#{/css/style.css}"/>
</head>
<body>
<h1>Form</h1>
<form action="#" th:action="#{/greeting}" th:object="${greeting}" method="post">
<p>Id: <input type="text" th:field="*{id}" /></p>
<p>Message: <input type="text" th:field="*{content}" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
</body>
</html>
This is the css file that is referenced in the HTML:
p {
color: #ff5588;
}
However, the css is not applied.
In fact, when I query localhost:8080/css/style.css it returns the HTML content of the index page.
It might be a security configuration issue. Is there a security implementation (SpringSecurity or custom) on your project? If so, does your user have access to /css/* url or this url has public access? The redirection might be occur if user doesn't have access to url or there is an exception while processing request.
The security configuration turned out to be blocking all requests to resources. In stead, it was redirecting those requests to the index page (which was configured).
The solution turned out to be simple, authorize all requests to the resources of the website (/images/** and /css/** and /js/**).
Once that was configured, the web-application worked as expected.

Displaying text in Thymeleaf

I'm totally new in Thymeleaf. Just read about it earlier, now, I'm trying to display some text using Thymeleaf in the front end, getting the values from Spring MVC in back-end.
File successPwd.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
<meta charset="UTF-8"/>
<title>Password Change</title>
</head>
<body>
<h2>Password Changed</h2>
Your password has been changed. Your account information is below.
Username: [[${account.username}]] <br/>
First Name: [[${account.firstName}]] <br/>
Last Name: [[${account.surname}]] <br/>
</body>
</html>
File PasswordResetController.java
#RequestMapping(value= "/user/new_password", method = RequestMethod.POST)
public String saveNewPassword(#RequestParam(value="new_password",required=false) String password, #RequestParam(value="hash") String hash, Model model)
{
//some codes to check hash
AccountInfo account = accountInfoService.getAccount(hash);
model.addAttribute("account", account);
return "/successPwd";
}
What I'm getting is like this:
Password Changed
Your password has been changed. Your account information is below.
Username: [[${account.username}]]
First Name: [[${account.firstName}]]
Last Name: [[${account.surname}]]
Thymeleaf is not converting to the proper values, most likely I missed something very very basic here.
In this case, you should use th:text. For example, Username: <p th:text=${account.username}>Username will be rendered here</p>. Note that, the text inside p tag won't be shown.
See here for more details: Standard thymeleaf syntax
If you want to get rid of the "awkward" Html tag you can do as follows.
<span th:text="${account.username}" th:remove="tag">userName</span>

How to pass a map in thymeleaf (spring 4)

I want to pass a map from a properties file using the thymeleaf template engine.
Exception:
org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'title' cannot be found on object of type 'java.lang.String' - maybe not public?
provider.html:
<!DOCTYPE>
<html th:include="receiver :: receiver(#{site})"></html>
receiver.html:
<!DOCTYPE HTML>
<html th:fragment="receiver(map)">
<head>
<title th:text="${map.title}">title</title>
</head>
<body th:text="${map.body}">
body
</body>
</html>
messages.properties:
site.title = Any title
site.body = Any body
Controller:
#Controller
public class StartController {
#RequestMapping(value = "/", method = RequestMethod.GET)
public String start(Model model) {
return "provider";
}
}
It simply like in Java. Key and value of the Map
<div th:each="userEnrty: ${userMap}">
<p th:text="${userEntry.key}">No Id!</p>
<p th:text="${userEntry.value}">No Name!</p>
</div>
So I figured out that property-files are processed as Map. So 'site' wasn't a map at all.
My solution now is to pass the name of the variable-prefi and get the keys by thymeleaf preprocessing.
provider.html:
<!DOCTYPE>
<html th:include="receiver :: receiver('site')"></html>
receiver.html:
<!DOCTYPE HTML>
<html th:fragment="receiver(mapname)">
<head>
<title th:text="#{__${mapname}__.title}">title</title>
</head>
<body th:text="#{__${mapname}__.body}">
body
</body>
</html>
messages.properties
site.title = Any title
site.body = Any body

HTTP Status 404 - Servlet .... is not available

I use eclise to create a servlet like this :
package hello;
public class NewServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("doPost");
String name = request.getParameter("textField");
response.setContentType("text/html");
PrintWriter pw = response.getWriter();
pw.print("<html><head></head><body><center>");
pw.print("Hello " + name + "!");
pw.print("</center></body></html>");
}
}
and a html file like :
<!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>Insert title here</title>
</head>
<body>
<form method="post" action="NewServlet">
<p align="center">
<font>Input some text</font> <br> <input type="text"
name="textFiled"> <br> <input type="submit"
value="submit"> <br>
</p>
</form>
</body>
</html>
when i run the servlet, met an error :
HTTP Status 404 - Servlet NewServlet is not available
--------------------------------------------------------------------------------
type Status report
message Servlet NewServlet is not available
description The requested resource (Servlet NewServlet is not available) is not available.
i checked the folder : WEB-INF or any folder else and can't see file .class
How is this caused and how can I solve it?
You should check web-inf folder in your IDE and map your servlet in web.xml file
<servlet>
<servlet-name>NewServlet</servlet-name>
<servlet-class>NewServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>NewServlet</servlet-name>
<url-pattern>/NewServlet</url-pattern>
</servlet-mapping>
make sure that this mapping is done properly and also your servlet is not in any package or folder if so then in servlet tag write that class name followed by . and your servlet name.
If problem still arises just make sure that you delete that .class file of your servlet and build your project again.(Net beans have an option of clean and build and then run) haven't use eclipse but i am sure it has similar option as well
Servlets needs to be registered and mapped on a specific URL pattern in order to be able to execute them by a HTTP request. Given your HTML code you seem to expect the servlet to listen on an URL of /NewServlet.
If you're using Tomcat 7, then just put the #WebServlet annotation on the class with exactly that URL pattern:
#WebServlet("/NewServlet")
public class NewServlet extends HttpServlet {
// ...
}
If you're still on Tomcat 6 or older for some reason, then you'd need to do it by the old fashioned web.xml way. A concrete example can be found in our servlets wiki page.
Eclipse won't show .class files in the project explorer. It will only show them in the navigator, in the /build folder. But this should not be something to worry about right now.
Format in web.xml should be like this.
<servlet-name>NewServlet</servlet-name>
<servlet-class>PackageName.JavaClass</servlet-class>
which in your case is
<servlet-name>NewServlet</servlet-name>
<servlet-class>Hello.NewServlet</servlet-class>
edite this:
form method="post" action="NewServlet"
to this
form method="post" action="/(your project name ) /NewServlet"
i had the same problem and this worked for me

Resources