Spring and hibernate persist() not working - java

Hello I am developing a CMS using Spring and Hibernate. I have a page displaying existing products and a form which should add a new product to the database. However when I fill out the form and submit it nothing gets saved to the database. Additionally System.out.println does not print anything to the console so I have no idea where is the problem.
jsp page
<form:form class="form-horizontal" method="post" modelAttribute="productForm">
<div class="form-group">
<label class="col-sm-2 control-label"> Product Name:</label>
<div class="col-sm-10">
<form:input class="form-control" type="text" id="productName" name="product name" path="name" />
<br></div></div>
<div class="form-group">
<label class="col-sm-2 control-label"> Serial number:</label>
<div class="col-sm-10">
<form:input class="form-control" type="text" id="productSerial" name="serial number" path="serial" value=" " /></div></div>
<input type="submit" value="Submit">
</form:form>
controller
#RequestMapping(value = "/saveNewContact", method = RequestMethod.POST)
public ModelAndView saveContact(#ModelAttribute("userForm") Product product,
BindingResult result, Model model) {
System.out.println(product);
productService.saveOrUpdate(product);
return new ModelAndView("redirect:/");
}
Service
#Override
public void saveProduct(Product product) {
productDao.saveProduct(product);
}
DAO
the interface implementation has #Transactional(readOnly = false)
public void saveNewProduct(Product product) {
persist(product);
}

The problem was in the form just adding action="saveNewContact" fixed the issue.

Related

Cannot get value from simple form user input in Spring boot application?

I'm trying to implement a login form in a Spring boot application. It has an email and a password field. The email field failed to get user input, here is the form:
<form th:action="#{/login}" method="get" th:object="${loginForm}" style="max-width: 600px; margin: 0 auto;">
<div class="m-3">
<div class="form-group row">
<label class="col-4 col-form-label">E-mail: </label>
<div class="col-8">
<input type="text" th:field="*{email}" name="q" class="form-control" required />
</div>
</div>
<div class="form-group row">
<label class="col-4 col-form-label">Password: </label>
<div class="col-8">
<input type="password" th:field="*{password}" class="form-control" required/>
</div>
</div>
<div>
<button type="submit" class="btn btn-primary">Log in</button>
</div>
</div>
</form>
Here is the controller:
#GetMapping("login")
public ModelAndView login(Model model, #RequestParam(name = "q", required = false) Optional<String> email) {
Optional<UserDto> aUser;
System.out.println(email);
if (email.isPresent()) {
aUser = userService.getAUserByEmail(email.get());
model.addAttribute("user", aUser);
var mv = new ModelAndView("user/user-list", model.asMap());
return mv;
} else {
model.addAttribute("loginForm", new LoginForm());
return new ModelAndView("/login/login-form", model.asMap());
}
}
I thought the #RequestParam(name = "q") and name="q" in html would do the job, but I always get Optional.empty for email. Any idea what's wrong here?
UPDATE:
From the answers I changed controller to this:
#GetMapping("login")
public ModelAndView login(Model model, LoginForm loginForm) {
Optional<UserDto> aUser;
if (loginForm.getEmail() != null) {
aUser = userService.getAUserByEmail(loginForm.getEmail());
model.addAttribute("user", aUser);
var mv = new ModelAndView("user/user-list", model.asMap());
return mv;
} else {
model.addAttribute("loginForm", new LoginForm());
return new ModelAndView("/login/login-form", model.asMap());
}
}
login-form.html to this:
<form th:action="#{/login}" method="get" th:object="${loginForm}" style="max-width: 600px; margin: 0 auto;">
<div class="m-3">
<div class="form-group row">
<label class="col-4 col-form-label">E-mail: </label>
<div class="col-8">
<input type="text" th:field="*{email}" class="form-control" required />
</div>
</div>
<div class="form-group row">
<label class="col-4 col-form-label">Password: </label>
<div class="col-8">
<input type="password" th:field="*{password}" class="form-control" required/>
</div>
</div>
<div>
<button type="submit" class="btn btn-primary">Log in</button>
</div>
</div>
</form>
I also have LoginForm.java like this
#Data
#AllArgsConstructor
#NoArgsConstructor
public class LoginForm {
private String email;
private String password;
}
but still not getting user email field input?
The way you have set up your form, it's mapping the value of your email input field to the property email (that's what th:field="*{email}" means) of an object called loginForm (that's what th:object="${loginForm}" means). Neither of these seem to be used or even exist in your login() method. You need to either change what you use in your controller to match what you have in your Thymeleaf template, or change your Thymeleaf template to actually reference what you are using in your controller.
The problem in your code is located under th:object="${loginForm}"
With this you inform spring to bind the data sent from the form into an object named loginForm.
So Spring actually expects the controller to be
#GetMapping("login")
public ModelAndView login(Model model, LoginForm loginForm) {
....
and inside LoginForm a field named email will contain the value sent from the form, as you have declared with <input type="text" th:field="*{email}" .... >
If you don't want the data to be bound into an object from Spring Mvc then
remove the th:object="${loginForm}"
use the
<input type="text" th:name="q" class="form-control" required />
and then the controller will receive the sent value as a query parameter
#GetMapping("login")
public ModelAndView login(Model model, #RequestParam(name =
"q", required = false) Optional<String> email) {

Spring MVC + Thymeleaf Post Single Object to Controller

I'm sort-of shocked that I can't find an example of how to do this. Every time I google it, I get info on how to post a collection of objects, or other unrelated stuff. The thymeleaf documentation (what I can find of it) seems to not explain much either, like there is a lot of assumed knowledge.
Getting back to my question, I just want to post a single object (bean) from a form. I would like my controller mapping method to bind to this "pojo" bean and not to a bunch of strings/integers.
The only thing that I have found that comes close is stuff on StackOverflow where half of the code is in the question, the other half is in the answer, and there are always a few comments from people saying it didn't work for them.
Can anyone offer any relief here with a plain old boring example?
Can find the below code snippet might helpful for you.
Controller GET/POST mapping:
#RequestMapping(value = "/registration", method = RequestMethod.GET)
public String registartionPage(Model model) {
Registration registration = new Registration();
model.addAttribute("registration", registration);
return "registarion/registarion";
}
#RequestMapping(value = "/user/new-user-registrn", method = RequestMethod.POST)
public String newUserRegistrn(Model model, #ModelAttribute("registration")
Registration registration, RedirectAttributes redirectAttributes) {
try {
StarUser user = starSecurityService.findSysUserName(registration.getUserName());
if (user != null) {
throw new Exception("User Already Exist. Please try with different User Name");
}
user = (StarUser) starUtilService.save(setStarUser(registration));
model.addAttribute("registration", registration);
if (user != null) {
redirectAttributes.addAttribute("starMessage",
"Your Account is successfully created !! Login to Access the Application");
return "redirect:/";
}
} catch (Exception e) {
model.addAttribute(STAR_MESSAGE, e.getMessage());
}
return "registarion/registarion";
}
Thymeleaf Content:
<form class="form-horizontal col-sm-12" method="POST" th:action="#{/user/new-user-registrn}" th:object="${registration}">
<div class="row">
<div class="form-group col-md-12">
<div class="star-reg-header">New User Registration</div>
</div>
<div class="star-reg-body">
<div class="form-group col-sm-4">
<label class="required">First Name: </label>
<input type="text" class="form-control required" th:field="*{firstName}" required="required" />
</div>
<div class="form-group col-sm-4">
<label class="required">Last Name: </label>
<input type="text" class="form-control" th:field="*{lastName}" required="required" />
</div>
<div class="form-group col-sm-4">
<label class="required">User Name: </label>
<input type="text" class="form-control" th:field="*{userName}" required="required" />
</div>
<div class="form-group col-sm-4">
<label class="required">Password: </label>
<input type="password" class="form-control" th:field="*{password}" required="required" />
</div>
<div class="form-group col-sm-4">
<label class="required">Email: </label>
<input type="text" class="form-control" th:field="*{email}" required="required" />
</div>
</div>
</div>
<div class="form-group col-md-12">
<label class="col-sm-2"></label>
<div class="col-sm-10">
<button type="submit" class="btn btn-info">Submit</button>
</div>
</div>
Java Bean class
public class Registration {
protected String firstName;
protected String lastName;
protected String userName;
protected String password;
protected String email;
//Setter and Getter
}
Use #ModelAttribute annotation in the parameter.
Something like this.
#RequestMapping(value = "/someurl", method = RequestMethod.POST)
public String savePojo(#ModelAttribute PojoClass pojo, Model model) {
//Code
}
Edit: This answer has very good info on this.
What is #ModelAttribute in Spring MVC?

Send values from thymeleaf to a spring boot service class

I am testing a spring boot application which uses thymeleaf, but I could not find any docs explaining how to send select options values from thymeleaf to a spring boot service class.
Basically, what I am trying to achieve is get values from the select tag so that I can insert them to the database through the method below:
Please note: this method is in the service class => it has both get and post mapping in the controller class.
public void addNewJob(JobPostEntity jobPostEntity, #RequestParam(value="selectCategory") String selectCategory) {
jobPostEntity.setJobcategory("test");
jobPostRepository.save(jobPostEntity);
}
the thymeleaf file is:
<form th:action="#{/newjob}" th:object="${addNewJob}" method="post">
<div class="form-group">
<label for="">Offer Title</label>
<input type="text" th:field="*{jobtitle}" class="form-control" placeholder="Entre Offer Title">
<small class="form-text text-muted">We'll never share your email
with anyone else.</small>
</div>
<div class="form-group">
<label >Company Name</label>
<input type="text" th:field="*{jobcompany}" class="form-control" placeholder="Enter Company Name">
</div>
<div class="form-group dropdown">
<label for="sel1">Choose Category (select one):</label>
<select name="*selectCategory"
class="form-control" id="selectCategory"
onchange="getSelectedValue();" th:field="*{selectCategory}">
<option value="">Select Option</option>
<option value="software_engineer">Software Engineer</option>
<option value="graphic_design ">Graphic Design</option>
<option value="customer_service ">Customer Service</option>
<option value="marketing" >Marketing</option>
<option value="healthcare">Health Care</option>
</select>
</div>
<div class="form-group">
<label for="exampleInputPassword1">Offer</label>
<textarea class="form-control" th:field="*{jobtext}" placeholder="Describe your job offer"></textarea>
</div>
<button type="submit" class="btn btn-primary">Submit Offer</button>
</form>
First, you need to properly configure your controller class. I assume this is where your addNewJob method is located, so I use this in my example.
You need to have a #GetMapping (which is the same as #RequestMapping(method = RequestMethod.GET) that returns the name of the view (this is your thymeleaf file - in the example below I used jobForm.html for this) and maps to a specific path (/test in example).
#GetMapping("/test")
public String getTestView() {
return "jobform";
}
You will also need a method which creates/retrieve the model object you use to fill the form with. This is mapped as th:object=${addNewJob} in the form:
#ModelAttribute(value = "addNewJob")
public JobPostEntity newEntity() {
return new JobPostEntity();
}
Finally, you will need a method with #PostMapping, that's called when you submit your form. In your example, that's mapped to /newjob, so I used this too:
#PostMapping(value = "/newjob")
public void addNewJob(
#ModelAttribute("addNewJob") final JobPostEntity myEntity) {
System.out.println("got dto: " + myEntity);
System.out.println("selectCategory: " + myEntity.getSelectedCategory());
}
To summarize the controller would look something like this:
#Controller
public class TestController {
#GetMapping("/test")
public String getTestView() {
return "jobform";
}
#PostMapping(value = "/newjob")
public void addNewJob(
#ModelAttribute("addNewJob") final JobPostEntity myEntity) {
System.out.println("got dto: " + myEntity);
System.out.println("selectCategory: " + selectCategory);
}
#ModelAttribute(value = "addNewJob")
public JobPostEntity newEntity() {
return new JobPostEntity();
}
}
As for the select option to work, I'd also put that field in the modelAttribute, so you don't have to treat them separately:
public class JobPostEntity {
private String jobtitle;
private String jobcompany;
private String jobtext;
private String selectCategory;
//getters/setters
}
Your pasted html code also contains a few issues:
you don't have the opening tags for form
the select tag doesn't have thymeleaf mapping for it (th:field)
the input tags doesn't have closing elements
The fixed version, which works for me, looks something like this (excluding the body/head/etc wrapper tags):
<form th:action="#{/newjob}" th:object="${addNewJob}" method="post">
<div class="form-group">
<label for="">Offer Title</label>
<input type="text" th:field="*{jobtitle}" class="form-control" placeholder="Entre Offer Title" />
<small class="form-text text-muted">We'll never share your email
with anyone else.</small>
</div>
<div class="form-group">
<label >Company Name</label>
<input type="text" th:field="*{jobcompany}" class="form-control" placeholder="Enter Company Name"/>
</div>
<div class="form-group dropdown">
<label for="sel1">Choose Category (select one):</label>
<select name="*selectCategory"
class="form-control" id="selectCategory"
onchange="getSelectedValue();"
th:field="*{selectCategory}">
<option value="">Select Option</option>
<option value="software_engineer">Software Engineer</option>
<option value="graphic_design ">Graphic Design</option>
<option value="customer_service ">Customer Service</option>
<option value="marketing" >Marketing</option>
<option value="healthcare">Health Care</option>
</select>
</div>
<div class="form-group">
<label for="exampleInputPassword1">Offer</label>
<textarea class="form-control" th:field="*{jobtext}" placeholder="Describe your job offer"></textarea>
</div>
<button type="submit" class="btn btn-primary">Submit Offer</button>
</form>
if you start your application and type http://localhost:8080/test (if you use the default context path / port ) in your browser, the form should appear and work as expected.
also, you can find a pretty good tutorial on here http://www.baeldung.com/thymeleaf-in-spring-mvc

Send each list to controller (thymeleaf Spring Boot)

I need sone help to send the List produtos as parameter to my controller.
<div class="panel-body">
<div th:each="produto : ${produtos}" class="form-group" id="produtos">
<label th:text="${produto.nome}" class="col-sm-2 control-label">
</label>
<div class="col-sm-1">
<input type="text" class="form-control js-number" id="quantPedido"
th:field="*{produto.quantPedido}"/>
</div>
</div>
</div>
My Controller
#RequestMapping(method = RequestMethod.POST)
public String salvar(#Validated Pedido pedido, List<Produto> produtos, Errors errors, RedirectAttributes attributes) {
}
Thanks so Much!
You need to warp yours products list into some bean, then send that bean to the html and fill it. Example:
Bean:
public class Pedido{
#Getter #Setter
private List<Product> products = new ArrayList();
//extra attributes
}
In your controller:
ModelAndView mav = new ModelAndView("yourView");
Pedido pedido = new Pedido();
mav.addObject("pedido", pedido);
In your html:
<form th:object="${pedido}" th:action="#{/savePedido}" method="POST">
//...
<div th:each="produto : ${produtos}" class="form-group" id="produtos">
<label th:text="${produto.nome}" class="col-sm-2 control-label">
</label>
<div class="col-sm-1">
<input class="form-control js-number" id="quantPedido" th:field="*{products[__${produtoStat.index}__].quantPedido}"/>
</div>
</div>
//...
</form>

hibernate validator doesn't show error message

Hibernate Validator doesn't show error message. What did i miss? Please see my code below.
Here is a dependency:
<!-- Hibernate Validator -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.2.0.Final</version>
</dependency>
And Entity with annotated column:
#Entity
#Table(name = "transport")
public class Transport {
....
#NotEmpty
#Column(name = "name")
private String name;
....
}
Here are methods from controller:
//show all and add form
#RequestMapping (value = "/admin/transports", method = RequestMethod.GET)
public String findAll(ModelMap map){
List<Transport> transports = transportService.findAll();
map.put("transport", new Transport());
map.put("transports", transports);
return "admin/transports/list";
}
//add new
#RequestMapping(value = "/admin/transport/add", method = RequestMethod.POST)
public String addTypeShop(#ModelAttribute("type") #Valid Transport transport, BindingResult result) {
if (result.hasErrors()) {
return "redirect:/admin/transports";
} else {
this.transportService.addTransport(transport);
return "redirect:/admin/transports";
}
}
And jsp page:
<form:form role="form" action="/admin/transport/add" method="post" commandName="transport">
<div class="row">
<div class="col-lg-6">
<div class="form-group">
<label for="name">Name</label>
<form:input type="text" path="name" class="form-control input-sm" id="name" autofocus="true"/>
<form:errors path="name"/>
</div>
</div>
<input type="submit" class="btn btn-sm btn-primary" value="Add" onclick="loading()"/>
</form:form>
You do not have any code showing the errors back to the end user.
Please see the following link for an example:
http://www.mkyong.com/spring-mvc/spring-mvc-form-errors-tag-example/
Also, It doesn't look like you actually set your command object in your form. You might not have shown that code though.
Small side note, I would not do a redirect if you have validation errors, just send them directly back to the page they came from.
EDIT
After further review, I do see that you have . Normally this goes outside and above the form itself.
<form:errors path="transport"/>
<form:form role="form" action="/admin/transport/add" method="post" commandName="transport">
<div class="row">
<div class="col-lg-6">
<div class="form-group">
<label for="name">Name</label>
<form:input type="text" path="name" class="form-control input-sm" id="name" autofocus="true"/>
</div>
</div>
<input type="submit" class="btn btn-sm btn-primary" value="Add" onclick="loading()"/>
</div>
</form:form>

Categories