I have created a simple Spring Boot Application that adds Dog information into the MySql database.
The controller class for this Application is DogController.java
package com.dog.resue.controller;
import com.dog.resue.dao.DodRepository;
import com.dog.resue.service.DogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Date;
#Controller
#RequestMapping(path="/")
public class DogController {
#Autowired
private DodRepository dodRepository;
#Autowired
private DogService dogService;
#RequestMapping(value ="/home",method = {RequestMethod.POST,RequestMethod.GET})
public String adddog(#RequestParam("name") String name,
#RequestParam("rescued") #DateTimeFormat(pattern = "yyyy-MM-dd") Date rescued,
#RequestParam("vaccinated") Boolean vaccinated, Model model)
{
dogService.addADog(name, rescued, vaccinated);
System.out.println("name = " + name + ",rescued = " + rescued + ", vaccinated = " + vaccinated);
return "index";
}
}
and the corresponding Service class is
package com.dog.resue.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.util.Date;
#Service
public class DogServiceImpl implements DogService {
#Autowired
private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.jdbcTemplate=new JdbcTemplate(dataSource);
}
#Override
public void addADog(String name, Date rescued, Boolean vaccinated) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("INSERT INTO dog(name,rescued,vaccinated) VALUES(?,?,?)",name,rescued,vaccinated );
}
}
And the thymeleaf HTML File is
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<!-- META SECTION -->
<title>Dog Rescue</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- END META SECTION -->
<!-- BEGIN STYLE -->
<style>
table, th, td {
border: 1px solid black;
padding: 1px;
}
</style>
<!-- END STYLE -->
</head>
<body>
<h2>Current Dogs In Rescue</h2>
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Rescue Date</th>
<th>Vaccinated</th>
</tr>
</thead>
<tbody>
<tr th:each="dogs : ${dogs}">
<td th:text="${dogs.id}">Text ...</td>
<td th:text="${dogs.name}">Text ...</td>
<td th:text="${dogs.rescued}">Text ...</td>
<td th:text="${dogs.vaccinated}">Text...</td>
</tr>
</tbody>
</table>
</div>
<h2>Add A Dog</h2>
<form action="#" th:action="#{/home}" >
<label>Name<input type="text" name="name" id="name"></input></label>
<label>Vaccinated<input type="text" name="vaccinated" id="vaccinated"></input></label>
<label>Rescued<input type="text" name="rescued" id="rescued"></input></label>
<input type="submit" value="Submit"></input>
</form>
</body>
</html>
While running this code i am getting following Error
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Sun Jul 22 21:50:32 IST 2018
There was an unexpected error (type=Bad Request, status=400).
Required String parameter 'name' is not present
url is http://localhost:8080/home
Kindly help me to solve this issues
Your Request parameters are missing in URL( name,rescued,vaccinated)
Your url should be
http://localhost:8080/home?name=ARULSUJU&rescued=2012-12-12&vaccinated=true
because all the parameters are required
Looking at your controller
Why you have rescued as Date Type you can change it as String.
So your controller will be
#RequestMapping(value ="/home",method = {RequestMethod.POST,RequestMethod.GET})
public String adddog(#RequestParam("name") String name,
#RequestParam("rescued") String rescued,
#RequestParam("vaccinated") Boolean vaccinated, Model model)
{
dogService.addADog(name, rescued, vaccinated);
System.out.println("name = " + name + ",rescued = " + rescued + ", vaccinated = " + vaccinated);
return "index";
}
Now try this URL
http://localhost:8080/home?name=test&rescued=2014-12-12&vaccinated=true
in your thymeleaf html file add this xmlns :
xmlns:th="http://www.thymeleaf.org"
Related
create.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" type="text/css" href="/css/main.css" />
</head>
<body>
<a th:href="#{/admin/}">Admin</a>
<br>
<br>
<br>
<h1>Add core phrases to the database</h1>
<br>
<br>
<form method="POST" th:object="${corePhrasesCreateForm}">
<table>
<tr>
<td>Quotation cluster (" "):</td>
<td><input
type="number"
id="quotation-cluster"
name="quotation-cluster"
th:value="${quotationCluster}"/></td>
<td th:if="${#fields.hasErrors('quotationCluster')}" th:errors="*{quotationCluster}">quotationCluster</td>
</tr>
<tr>
<td>Quotation Exclamation cluster ("!")</td>
<td><input
type="number"
id="quotation-exclamation-cluster"
name="quotation-exclamation-cluster"
th:value="${quotationExclamationCluster}"/></td>
<td th:if="${#fields.hasErrors('quotationExclamationCluster')}" th:errors="*{quotationExclamationCluster}">quotationExclamationCluster</td>
</tr>
<tr>
<td>Phrases</td>
<td><textarea rows="5" cols="60" name="value" placeholder="Key phrases" th:text="${value}"></textarea></td>
<td class="error" th:if="${#fields.hasErrors('value')}" th:errors="*{value}">value</td>
</tr>
</table>
<br/>
<input type="submit" value="submit"/>
</form>
</body>
</html>
Validator
import com.example.marketing3.semantics.semanticsClusters.repositories.ClusterRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
#RequiredArgsConstructor
#Service
public class CorePhraseFormValidator implements Validator {
private final ClusterRepository clusterRepository;
#Override
public boolean supports(Class<?> clazz) {
return false;
}
#Override
public void validate(Object target, Errors errors) {
System.out.println();
}
Controller
#Controller
#RequestMapping("/semantics/phrases/core")
#RequiredArgsConstructor
public class CorePhraseController {
#GetMapping({"/create", "/create/"})
public String createGet(CorePhrasesCreateForm corePhrasesCreateForm) {
return "semantics/phrases/core/create";
}
#PostMapping({"/create", "/create/"})
public String createPost(#Valid CorePhrasesCreateForm corePhrasesCreateForm,
BindingResult bindingResult,
RedirectAttributes atts) {
corePhraseFormValidator.validate(corePhrasesCreateForm, bindingResult);
if (bindingResult.hasErrors()) {
return "semantics/phrases/core/create";
}
atts.addAttribute("message", "Core phrases created");
String result = "";
return "redirect:/general/message";
}
}
The form has been rendered.
I entered
Quotation cluster (" "): 1
Quotation Exclamation cluster ("!"): 2
And some text for phrases.
Like this:
The problem:
To createPost quotationCluster and quotationExclamationCluster came as zeroes.
But I entered 1 and 2 respectively.
Could you help me understand what I have don wrongly and correct the situation.
Change
<input type="number" id="quotation-cluster"
name="quotation-cluster" th:value="${quotationCluster}"/>
To:
<input type="number" id="quotation-cluster" th:field="*{questionCluster}"
name="quotationCluster" th:value="${quotationCluster}"/>
the name and th:field should be same as the declared attribute in your java class CorePhraseForm. Repeat this for the the next input (Textarea).
I always get this error, nonetheless whether I create the getter/setter manually or doing it via Lombok.
So, I guess the error has nothing to do with the Getters/Setters but I cannot find the answer to my problem.
This is my error message:
Invalid property 'person' of bean class [java.util.ArrayList]: Bean property 'person' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
This is my Enttiy class:
#Data
#Getter
#Setter
#Entity
#Table(name="incomeoutgo", schema = "public")
public class IncomeOutgo extends AbstractPersistable<Long> {
#Version
#NotNull
#Column(name ="id")
private Long id;
#Column(name="dayofweek")
private Date dayofweek;
#Column(name="location")
private String location;
#Size(min = 5, max = 50)
#Column(name ="person")
private String person;
#Min(0)
#Column(name ="version")
private Integer version;
#Column(name="income")
private int income;
#Column(name="outgo")
private int outgo;
}
And this is my Controller class
#RequiredArgsConstructor
#Controller
#RequestMapping(value = "/incomeoutgo")
public class IncomeOutgoController {
private static final String INCOMEOUTGO_VIEW = "incomeoutgo";
private final IncomOutgoService incomeoutgoService;
#GetMapping
public String showShop(Model model) {
List<IncomeOutgo> incomeOutgoList = incomeoutgoService.getIncomeOutgoList();
model.addAttribute(INCOMEOUTGO_VIEW, incomeOutgoList);
return INCOMEOUTGO_VIEW;
}
#PostMapping("/incomeoutgo")
public String addUser(#ModelAttribute("incomeoutgo") IncomeOutgo incomeoutgo, BindingResult bindingResult) {
incomeoutgoService.addIncomeOutgo(incomeoutgo);
return "incomeoutgo";
}
}
And last but not least my Thymeleaf template:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Incomes / Expenses</title>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body>
<table>
<tr>
<th>Id</th>
<th>Day of Week</th>
<th>Name</th>
<th>Location</th>
<th>Income</th>
<th>Expense</th>
</tr>
<tr th:each="incomeoutgo : ${incomeoutgo}">
<td th:text="${incomeoutgo.id}">id</td>
<td th:text="${incomeoutgo.dayofweek}">dayofweek</td>
<td th:text="${incomeoutgo.person}">person</td>
<td th:text="${incomeoutgo.location}">location</td>
<td th:text="${#numbers.formatCurrency(incomeoutgo.income)}">"${#numbers.formatCurrency(incomeoutgo.income)}"</td>
<td th:text="${#numbers.formatCurrency(incomeoutgo.outgo)}">"${#numbers.formatCurrency(incomeoutgo.outgo)}"</td>
</tr>
</table>
<form action="#" th:action="#{/incomeoutgo}" th:object="${incomeoutgo}" method="post">
<table>
<tr>
<td>Name:</td>
<td><input type="text" th:field="*{person}" /></td>
<td th:if="${#fields.hasErrors('person')}" th:errors="*{person}">Name Error</td>
</tr>
<tr>
<td><button type="submit">Submit</button></td>
</tr>
</table>
</form>
</body>
</html>
The error is explained: Invalid property 'person' of bean class [java.util.ArrayList]. You're trying to call getPerson() on a java.util.ArrayList (which doesn't have that property). I suspect it's in your form:
<form ... th:object="${incomeoutgo}">
You've added incomeoutgo to your model as a List<IncomeOutgo>, but you're trying to treat it as an IncomeOutgo instead. You need to create a single object and use that instead when trying to bind form field values.
model.addAttribute(INCOMEOUTGO_VIEW, incomeOutgoList);
model.addAttribute("page", new IncomeOutgo());
.
.
.
<form ... th:object="${page}">
<input type="text" th:field="*{person}" />
(Side node, reusing the same variable name multiple times makes the code confusing. You have the model attribute ${incomeoutgo}, the temporary loop variable th:each="incomeoutgo : ${incomeoutgo}" and the bound thymeleaf object th:object="${incomeoutgo}" which may or may not be related.)
I do an example with login page - Spring Security.
Shortly:
There's root page ("localhost:8080/") - here's a link on the main page.
Click a link on the main page go to main.html(localhost:8080/main/
If User doesn't authorize he is redirected to login page
When the user authorizes the main page is opened
The main page show messages and filter by tag
I enter a tag in input and push the button Search(Найти), messages are filtered by tag
When I have added authorization filter has stopped work.
This is my source code:
root page - have link on Main page
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Gretting start: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<div>Hello, user</div>
<a th:href="#{/main}">Main page</a>
</body>
</html>
Main page
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<div>
<form method="post">
<input type="text" name="text" placeholder="Введите сообщение" />
<input type="text" name="tag" placeholder="Тэг">
<button type="submit">Добавить</button>
</form>
</div>
<div>Список сообщений</div>
<form method="post" action="filter">
<input type="text" name="filter">
<button type="submit">Найти</button>
</form>
<div th:each = "message : ${messages}">
<b th:text = "${message.id}"></b>
<span th:text = "${message.text}"></span>
<i th:text = "${message.tag}"></i>
</div>
</body>
</html>
Controller processes all mapping
package com.example.sweater;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.example.sweater.domain.Message;
import com.example.sweater.repos.MessageRepo;
#Controller
public class GreetingController {
#Autowired
private MessageRepo messageRepo;
#GetMapping("/")
public String greeting(Model model) {
return "greeting";
}
#GetMapping("/main")
public String main(Model model) {
Iterable<Message> messages = messageRepo.findAll();
model.addAttribute("messages", messages);
return "main";
}
#PostMapping("/main")
public String add(#RequestParam String text, #RequestParam String tag, Model model) {
Message message = new Message(text, tag);
messageRepo.save(message);
Iterable<Message> messages = messageRepo.findAll();
model.addAttribute("messages", messages);
return "main";
}
#PostMapping("/filter")
public String filter(#RequestParam String filter, Model model) {
Iterable<Message> messages;
if (filter != null && !filter.isEmpty()) {
messages = messageRepo.findByTag(filter);
} else {
messages = messageRepo.findAll();
}
model.addAttribute("messages", messages);
return "main";
}
}
WebSecurityConfig have one In Memory User. antMathcers("/") permitAll and anyRequest authenticated
package com.example.sweater.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
#Bean
#Override
public UserDetailsService userDetailsService() {
UserDetails user =
User.withDefaultPasswordEncoder()
.username("u")
.password("p")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
My screenshots
root page
Main page
When I enter filter tag and push Button "Найти"(= Search), I've got an error:
#PostMapping("/filter") doesn't catch the action in the form. I checked in the debugger. I can't catch an error and don't know why does this happen.
I have GitHub repository: https://github.com/aalopatin/sweater
Commit with the comment "Add messages" - filter work
Commit with the comment "Add remote repository and Login" - filter doesn't work and add login
I found solving. In a form on the main page need to add 'th' attribute because I use Thymeleaf so template engine. It's needed for _csrf defending which auto insert token in a form if you use Thymeleaf:
<form method="post" th:action="filter">
<input type="text" name="filter">
<button type="submit">Найти</button>
</form>
I created a Spring project with STS, using MySql with MyBatis.
I'm trying to make a function for Members to Sign up, but it only keep visiting Homecontroller.java instead of MemberController, when I click the submit button.
This is the arrangement of my files and codes.
This is from index.jsp
<%# page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%# page session="false" %>
<html>
<head>
<title>Home</title>
</head>
<body>
<P> The time on the server is ${serverTime}. </P>
<h1> This is the first page to Log In</h1>
<form id="form1" action="members/logIn">
LogIn <p>
ID: <input type="text" name="id" id="id">
Password: <input type="password" name="pwd" id="pwd">
<input type="button" onclick="logIn()" value="press to LogIn">
</form>
<p><br><br><h3>Move to SignUp page</h3>
<input type="button" onclick="window.location='views/signUp.jsp'" value="Move to Sign Up page">
<h1> This is to Sign Up </h1>
<form id="form2" action="members/join">
ID:
<input type="text" placeholder="Insert ID">
Name:
<input type="text" placeholder="Insert Name"> <p>
PWD:
<input type="text" placeholder="Insert your PWD"> <p>
PWD Check:
<input type="text" placeholder="Confirm your PWD"><p>
Address:
<input type="text" placeholder="Insert Address."> <p>
<input type="submit" value="Sign Up">
</form>
</body>
</html>
and HomeController.java
package kr.co.promptech.controller;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* Handles requests for the application home page.
*/
#Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
/**
* Simply selects the home view to render by returning its name.
*/
#RequestMapping(value = "", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome home! The client locale is {}.", locale);
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate );
System.out.println("Arrived at HomeController.");
return "index";
}
}
MemberController.java
package kr.co.promptech.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import kr.co.promptech.model.Members;
import kr.co.promptech.service.MemberService;
#Controller
#RequestMapping(value="/members")
public class MemberController {
#Autowired
private MemberService memberService;
#RequestMapping(value="join")
public String memberJoin(#RequestParam("id") String id, #RequestParam("pwd") String pwd,
#RequestParam("name") String name, #RequestParam("address") String address){
System.out.println("We have arrived at MemberController");
memberService.memberJoin(new Members(id, pwd, name, address));
return "main";
}
}
Why the Sign Up button keep brings me to HomeController instead MemberController?
also, can anyone help me how to make a button that brings me to main.jsp from index.jsp?
this is not working...
Hope someone can help me here...
OMG, I just found out that all the tags of index.jsp did not have name properties.
It was all my faults... sorry, and Thanks for your answer,
This has been asked a few times but all of them did not answer my question. I have been trying to get different functionalities to work with Thymeleaf for two days now and been very unsuccessful. I have only been able to get it to work with spring-boot, however right now I am using spring-MVC.
First I will show you my dependencies
<%# taglib prefix="sf" uri="http://www.springframework.org/tags/form" %>
<%# page contentType="text/html;charset=UTF-8" language="java" %>
<html xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Create a New Account</title>
<link th:href="#{/resources/css/loginForm.css}" href="/resources/css/loginForm.css" rel="stylesheet"
type="text/css"/>
</head>
<body>
<form action="#" th:action="#{/createNewAccount}" th:object="${user}" method="post">
<table>
<tr>
<td>Name:</td>
<td><input type="text" th:field="*{username}" /></td>
<td th:if="${#fields.hasErrors('name')}" th:errors="*{username}">Name Error</td>
</tr>
<tr>
<td>Password:</td>
<td><input type="text" th:field="*{password}" /></td>
<td th:if="${#fields.hasErrors('age')}" th:errors="*{password}">Password Error</td>
</tr>
<tr>
<td><button type="submit">Submit</button></td>
</tr>
</table>
</form>
</body>
</html>
Now so you can see the errors my intellij IDE is showing:
User.java
package com.practice.domain;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
/**
* Created by DrewJocham on 8/30/15.
*/
public class User {
#NotNull
#Size(min = 2, max = 30)
private String username;
#NotNull
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
The field name you call hasErrors with needs to match the field name in the object. Like so:
<td th:if="${#fields.hasErrors('username')}" th:errors="*{username}">Name Error</td>
Note that hasErrors('name') became hasErrors('username'), and:
<td th:if="${#fields.hasErrors('password')}" th:errors="*{password}">Password Error</td>
Note that hasErrors('age') became hasErrors('password').
As for the errors being highlighted in Intellij, I think they're misleading, and are related to this open issue: https://youtrack.jetbrains.com/issue/IDEA-132738