I am trying to learn how to handle multi-part request in controller using spring framework/mvc.
And here I got stuck where i wanted to get 2 things from the user 1) Id and 2) pic (image file).
Therefore I had created a simple form like this.
Name:check.jsp
<%# page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="finaltest" method="post" enctype='multipart/form-data' >
id: <input type="text" name="id">
Pic: <input type="file" name="pic">
<input type="submit">
</form>
</body>
</html>
Controller file
(one of the method) which is relevant to this jsp page
#RequestMapping(path="/finaltest",method=RequestMethod.POST)
public String handlepic(#RequestParam("id")int id,#RequestBody String name) {
return "showform";
}
The Error i am getting is:
Required int parameter 'id' is not present (by tomcat)
WARNING: Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required int parameter 'id' is not present](by java console)
Related
I'm new to spring and I've tried coding a prototype.
I've tried making a form. Whenever I press the submit-button, nothing happens.
I'm using Spring Boot 2.4.3 with Oracle OpenJDK 15.0.2. I've tried Firefox and Chrome. The js-console is empty.
This is my model (Patient.java):
public class Patient implements Serializable {
private long id;
private String firstname;
private String lastname;
// Geters and seters
}
My Controller (PatientController.java):
#Controller
public class PatientController {
#GetMapping("/patient")
public String patientForm(Model model) {
model.addAttribute("patient", new Patient());
return "addPatient";
}
#PostMapping("/patient")
public String patientSubmit(#ModelAttribute("patient") Patient patient, Model model) {
model.addAttribute("patient", patient);
return "addedPatient";
}
}
My addPatient.html:
<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>HTL-Testet Prototype</title>
</head>
<body>
<h1>Add a patient</h1>
<from action="#" th:action="#{/patient}" th:object="${patient}" method="post">
<p>Id: <input type="number" th:field="*{id}"/></p>
<p>Firstname: <input type="text" th:field="*{firstname}"/></p>
<p>Lastname : <input type="text" th:field="*{lastname}"/></p>
<button type="submit">Register</button>
</from>
</body>
</html>
My addedPatient.html:
<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>HTL-Testet Prototype</title>
</head>
<body>
<h1>Add a patient</h1>
<p th:text="'Added ' + '[' + ${patient.id} + ']' + ${patient.firstname} + ' ' + ${patient.lastname}"></p>
Add another patient
</body>
</html>
The from tag on the addPatient.hmtl page is wrong, if you change it to form tag as below, the problem is solved:
<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>HTL-Testet Prototype</title>
</head>
<body>
<h1>Add a patient</h1>
<form action="#" th:action="#{/patient}" th:object="${patient}" method="post">
<p>Id: <input type="number" th:field="*{id}"/></p>
<p>Firstname: <input type="text" th:field="*{firstname}"/></p>
<p>Lastname : <input type="text" th:field="*{lastname}"/></p>
<button type="submit">Register</button>
</form>
</body>
</html>
Is it possible to create a dynamic replace in Thymeleaf?
I have the following controller:
#Controller
public class LoginController {
#RequestMapping("/login")
public String getLogin(Model model){
model.addAttribute("template","login");
return "index";
}
}
And the following view:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" >
<head></head>
<body>
<div th:replace="fragments/${template} :: ${template}"></div>
</body>
</html>
And i'm getting the following error:
Error resolving template "fragments/${template}", template might not exist or might not be accessible by any of the configured Template Resolvers
UPDATE
I tried to preprocess my variables like this:
<div th:replace="fragments/${__#{${template}}__} :: ${__#{${template}}__}"></div>
How ever now ${template} is getting replaced with login i have the following error now:
Exception evaluating SpringEL expression: "??login_en_US??"
Although Joe Essey's solution is working as well i solved with following code:
<div th:replace="#{'fragments/' + ${template}} :: ${template}"></div>
I believe the appropriate method to manage this behavior in thymeleaf is to use layout:fragment tags. Please correct me if I'm wrong. Here is a simple example of my layout page, and the login page which is 'dynamically' loaded:
layout.html
<html xmlns:layout="http://www.w3.org/1999/xhtml" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<title layout:title-pattern="$DECORATOR_TITLE - $CONTENT_TITLE">Layout</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=Edge"/>
</head>
<body>
<div>
<div class="app-container">
<div th:fragment="content">
</div>
</div>
</div>
<div th:fragment="script"></div>
</body>
</html>
Then, when login gets loaded, it replaces the th:fragment div with the associated div in the html view which matches the string returned by the controller method, in this case login.html:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.w3.org/1999/xhtml"
layout:decorator="layout">
<head>
<title>Login</title>
</head>
<body>
<div th:fragment="content">
<form th:action="#{/login}" method="post">
<div><label> User Name : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
</div>
</body>
</html>
Now, if you want to load another fragment conditionally, the approach I take is to add replace tags with th:if cases. Here's an example of a Form that displays different questions based on an attribute of the current user:
<div th:if="${foo.type)} == 'type_1'">
<div th:replace="fragments/custom-questions :: type-1-checkboxes"></div>
</div>
<div th:if="${foo.type} == 'type_2'">
<div th:replace="fragments/custom-questions :: type-2-checkboxes"></div>
</div>
Then the associated div gets loaded from the file custom-questions.html:
<div th:fragment="type-1-checkboxes">
//stuff
</div>
<div th:fragment="type-2-checkboxes">
//stuff
</div>
I am just encountering this issue (this is my first time with thymeleaf/spring). This is what solved it for me:
<div class="col-md-12" th:include="__${template}__ :: body" ...
In Thymeleaf 3.0, the following solution has worked for me:
<div th:replace="('fragments/' + ${template}) :: (${template})">
(Note however, that I use it with fixed name of the fragment and dynamic name of the template, so the parantheses around :: (${template}) might be optional.)
The solution is inspired by documentation for Thymeleaf in https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#fragment-specification-syntax
Both templatename and selector in the above examples can be fully-featured expressions (even conditionals!) like:
<div th:insert="footer :: (${user.isAdmin}? #{footer.admin} : #{footer.normaluser})"></div>
Note again how the surrounding ~{...} envelope is optional in th:insert/th:replace
<div th:insert=“${subpage}::fragementName”>
Just change subpage names and you will dynamic behaviour in thymleaf
If I don't use <% # taglibprefix = "sf" uri = "http://www.springframework.org/tags/form"%>
the application works the same. The User user object is filled with the fields of the form. Is it correct to use this approach?
Is the use of <sf:form method="POST"modelAttribute="user"> more correct?
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!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=ISO-8859-1">
<title>Inserisci nuovo utente</title>
</head>
<body>
<h2>Dati utente</h2>
<form action="/SpringMVCFormHibernate/add" method="post">
<label>Cognome</label><br/><input type="text" name="cognome"/><br/>
<label>Nome</label><br/><input type="text" name="nome"/><br/>
<label>Eta</label><br/><input type="text" name="eta"/><br/><br/>
<input type="submit" value="submit"/>
</form>
<p>Visualizza utenti</p>
<sf:label path=""></sf:label>
</body>
</html>
#Controller
public class UtenteController {
#Autowired
UtenteDAO utenteDAO;
#RequestMapping(value="/add",method=RequestMethod.POST)
public String addUtente(#ModelAttribute Utente user){
utenteDAO.inserisciUtente(user);
return "index";
}//addUtente
}//UtenteController
The major use of spring:form tag is formbacking object . If you wish to bind the model attribute object with the view fields , you can go for it .
For simple form objects you can use html forms instead . Also you can make use of spring:form tags error attributes as well.
for ex,
path attribute binds the model field name . so changes made to them are can be easily updated in the server side with your model attribute.
simply they provide dyanamic binding of objects easily . spring does those instead of manual works
A nice example to understand form handling and model attribute usage.
I am facing an issue with the flash attributes which I have not able to retrieve it in the GET phase of POST/redirect/GET scenario. This is only happening when I use the ResourceBundleViewResolver.
view resolver
<bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
<property name="basename" value="spring-views" /> </bean>
view properties
form.(class)=org.springframework.web.servlet.view.JstlView
form.url=/WEB-INF/pages/form.jsp
home.(class)=org.springframework.web.servlet.view.JstlView
home.url=/WEB-INF/pages/home.jsp
home_redirect.(class)=org.springframework.web.servlet.view.RedirectView
home_redirect.url=home
form.jsp
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!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=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<form action="register" method="post">
Name: <input type="text" name="name"/> <br/>
<input type="submit" value="Submit"/>
</form>
</body>
</html>
home.jsp
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<body>
<h2> ${status} </h2>
</body>
</html>
so in this page, home.jsp, the status should contain the value set as the flash attribute.
controller
#Controller
public class WebController {
#RequestMapping(value="/form", method=RequestMethod.GET)
public String showFormPage(){
return "form";
}
#RequestMapping(value="/register", method=RequestMethod.POST)
public ModelAndView login(#RequestParam("name") String name, RedirectAttributes flashMap){
System.out.println("name = " + name);
flashMap.addFlashAttribute("status", "Registered successfully");
//return new RedirectView("home"); -- with this returned its working
return new ModelAndView("home_redirect"); //-- with this returned its not working
//return "redirect:home"; // -- not working
}
#RequestMapping(value="/home")
public String showHomePage(){
return "home";
}
}
on the whole this is the observation made:
if used resource bundle view resolver
return view names as string - not working
return ModelAndView - not working
return RedirectAndView - working
if used internal view resolver
return view names as string - working
2 return modelandview - cannot be used to redirect
return RedirectAndView - working
I searched for this problem and as I got it has some problems with naming conflicts, but again I could not find the reason. I would appreciate the helps. following is the line in the .jsp which calls the controller:
<td>
<a href="message/createMessage">
Reply
</a>
<input type="hidden" name="receiver" value="${message.fromUser}">
</td>
${message.fromUser} gets the required property from the model. I am sure it is not the reason for the problem because of other link in this page which works and uses the same model. The controller is as follow:
#Controller
#RequestMapping("/message")
public class MessageController
{
#RequestMapping("createMessage")
public String createMessage(
#RequestParam("receiver") String receiver,
HttpSession session,
Model model)
{
try
{
MessageDAO mDao = new MessageDAO();
Message message = new Message();
String fromUser = (String) session.getAttribute("userName");
message.setFromUser(fromUser);
message.setUserName(receiver);
Message message2 = mDao.create(message);
model.addAttribute(message);
return "newMessage";
}
catch (Exception e)
{
model.addAttribute("message", "Can't create message!");
return "redirect:/"; // ?? should add a dialog box for error
}
}
}
Thank you for your help!
as an attempt to solve the problem and based on the first answer I tried to use url-rewriting. used #PathVariable("receiver") in my controller. still the same problem. I have added the full revised jsp here: error happens when I click reply link for a message.
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/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=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<h1>welcome ${sessionScope.user.userName}</h1>
<form:form method="POST" action="message/deleteMessage">
<table border="1">
<tr>
<th>Message ID</th>
<th>From User</th>
<th>Message</th>
<th>Date</th>
<th>Reply to User</th>
<th>Delete</th>
</tr>
<c:forEach items="${messages}" var="message" >
<tr>
<td>${message.messageID}</td>
<td>${message.fromUser}</td>
<td>${message.message}</td>
<td>${message.messageDate}</td>
<td>Reply</td>
<td><input type="checkbox" name="delete" value="${message.messageID}"> </td>
</tr>
</c:forEach>
<tr><td colspan="6"><input type="submit" value="Delete selected messages"></td></tr>
</table>
</form:form>
In your "form" you have a plain html hyperlink that doesn't do any form submit(so the value of the hidden field is never being sent.
So you need to declare a <FORM action= 'message/createMessage' > element.
Then you need to either submit the form with AJAX or create a submit button. Another way is to pass receiver value manually by appending the value of the form createMessage?receiver=someValue(I added this as example I don't think it's a recommended way, everything has its pros n' cons anyway).
So there are many ways to pass the parameter.
See http://www.w3.org/TR/html401/interact/forms.html