I've been trying to add dateOfBirth fields to registration form. I want to separate the date to 3 fields: day, month and year.
When I enter the date to fields, I get in the controller current date and strange year - "3890".
my HTML code:
<div class="form-group row">
<label for="confirm" class="col-sm-2 col-form-label">Date of Birth</label>
<div class="col-sm-10">
<input id="day" type="text" th:field="*{dateOfBirth.day}"/>
</div>
</div>
<div class="form-group row">
<label for="confirm" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<input id="month" type="text" th:field="*{dateOfBirth.month}"/>
</div>
</div>
<div class="form-group row">
<label for="confirm" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<input id="year" type="text" th:field="*{dateOfBirth.year}"/>
</div>
</div>
my controllers code:
#GetMapping(value = "/register")
public String showRegistrationForm(WebRequest request, Model model) {
ChannelDTO channelData = new ChannelDTO();
model.addAttribute("channel", channelData);
return "registration";
}
#PostMapping(value = "/register")
public ModelAndView registerUserAccount(#ModelAttribute("channel") #Valid ChannelDTO channelData, BindingResult result,
HttpServletRequest request, Errors errors, RedirectAttributes redirectAttributes) {
Channel channel = null;
if (!result.hasErrors()) {
channel = createUserAccount(channelData, result);
}
// logic...
return new ModelAndView("redirect:/register/select-interests");
}
my ChannelDTO:
#PasswordMatches
public class ChannelDTO {
#NotNull
#NotEmpty
#Email
private String email;
#NotNull
#NotEmpty
private String name;
//#NotNull
//#NotEmpty
#DateTimeFormat(pattern="yyyy-MM-dd")
private Date dateOfBirth;
#NotNull
#NotEmpty
private String password;
#NotNull
#NotEmpty
private String matchingPassword;
}
I would appreciate any help, thank you.
You're using the original Date class (it's not related to java 8's datetime API):
java.util.Date
The documentation states that setYear:
Sets the year of this Date object to be the specified value plus 1900.
So you need to subtract your year value by 1900.
Probably you can do it with th:value, or in the controller you can subtract the dateOfBirth by 1900 before the logic part.
Or you can use a Thymeleaf java8 datetime API module, like this one:
Thymeleaf - Module for Java 8 Time API compatibility
If you want to subtract your date by 1900, try this out:
#PostMapping(value = "/register")
public ModelAndView registerUserAccount(#ModelAttribute("channel") #Valid ChannelDTO channelData, BindingResult result, HttpServletRequest request, Errors errors, RedirectAttributes redirectAttributes) {
Calendar cal = Calendar.getInstance();
cal.setTime(channelData.getDateOfBirth());
cal.set(Calendar.YEAR, cal.get(Calendar.YEAR) - 1900);
channelData.setDateOfBirth(cal.getTime());
Channel channel = null;
if (!result.hasErrors()) {
channel = createUserAccount(channelData, result);
}
//logic...
return new ModelAndView("redirect:/register/select-interests");
}
Also modify this line:
<input id="day" type="text" th:field="*{dateOfBirth.day}"/>
To this:
<input id="day" type="text" th:field="*{dateOfBirth.date}"/>
You can also try to use not Date type for dateOfBirth, but Calendar.
EDIT
There are 2 options that you can try:
Option 1:
Leave ChannelDTO as is and modify your controller like so:
#PostMapping(value = "/register")
public ModelAndView registerUserAccount(#ModelAttribute("channel") #Valid ChannelDTO channelData,
BindingResult result, HttpServletRequest request, Errors errors, RedirectAttributes redirectAttributes) {
Calendar cal = Calendar.getInstance();
cal.setTime(channelData.getDateOfBirth());
cal.set(Calendar.YEAR, cal.get(Calendar.YEAR) - 1900);
cal.set(Calendar.MONTH, cal.get(Calendar.MONTH) - 1);
channelData.setDateOfBirth(cal.getTime());
Channel channel = null;
if (!result.hasErrors()) {
channel = createUserAccount(channelData, result);
}
//logic...
return new ModelAndView("redirect:/register/select-interests");
}
Modify your html to this:
<div class="form-group row">
<label for="confirm" class="col-sm-2 col-form-label">Date of Birth</label>
<div class="col-sm-10">
<input id="day" type="text" th:field="*{dateOfBirth.date}" />
</div>
</div>
<div class="form-group row">
<label for="confirm" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<input id="month" type="text" th:field="*{dateOfBirth.month}" />
</div>
</div>
<div class="form-group row">
<label for="confirm" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<input id="year" type="text" th:field="*{dateOfBirth.year}" />
</div>
</div>
Option 2:
Create a new class, which will be used to hold the year, month and day values:
public class CustomDate {
public CustomDate() {
}
private int year;
private int month;
private int day;
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month -1;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
}
Modify ChannelDTO class like so:
public class ChannelDTO {
public ChannelDTO() {
}
#NotNull
#NotEmpty
#Email
private String email;
#NotNull
#NotEmpty
private String name;
//#NotNull
//#NotEmpty
#DateTimeFormat(pattern="yyyy-MM-dd")
private Date dateOfBirth;
private CustomDate customDateOfBirth;
#NotNull
#NotEmpty
private String password;
#NotNull
#NotEmpty
private String matchingPassword;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getDateOfBirth() {
Calendar cal = Calendar.getInstance();
cal.set(customDateOfBirth.getYear(), customDateOfBirth.getMonth(), customDateOfBirth.getDay());
return cal.getTime();
}
public void setDateOfBirth(Date dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getMatchingPassword() {
return matchingPassword;
}
public void setMatchingPassword(String matchingPassword) {
this.matchingPassword = matchingPassword;
}
#Transient
public CustomDate getCustomDateOfBirth() {
return customDateOfBirth;
}
public void setCustomDateOfBirth(CustomDate customDateOfBirth) {
this.customDateOfBirth = customDateOfBirth;
}
}
Please note that there is a new field called customDateOfBirth, and the getter method of customDateOfBirth has a #Transient annotation which prevents JPA to insert it into the database. If you want to skip it from being serialized via Jackson, put a #JsonIgnore annotation on the getter method, too.
The getDateOfBirth method has a custom logic in it, which transforms the customDateOfBirth into Date type.
Modify your html like this:
<div class="form-group row">
<label for="confirm" class="col-sm-2 col-form-label">Date of
Birth</label>
<div class="col-sm-10">
<input id="day" type="text" th:field="*{customDateOfBirth.day}" />
</div>
</div>
<div class="form-group row">
<label for="confirm" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<input id="month" type="text" th:field="*{customDateOfBirth.month}" />
</div>
</div>
<div class="form-group row">
<label for="confirm" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<input id="year" type="text" th:field="*{customDateOfBirth.year}" />
</div>
</div>
Please note that customDateOfBirth is used in the html template.
Related
I am having a problem converting input String to money. I am creating a spring boot application with thymeleaf. I have a web page where user inputs the data and there is a particular field where he inputs the String and it needs to be converted to type joda.money as in my pojo class that field has money data type. This is a full governor_form.html:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>[[${pageTitleG}]]</title>
<link rel="stylesheet" type="text/css" th:href="#{/webjars/bootstrap/css/bootstrap.min.css}"/>
</head>
<body>
<div class="container-fluid">
<div class="text-center"><h2>[[${pageTitleG}]]</h2></div>
<form th:action="#{/governors/save}" method="post" th:object="${governor}" style="max-width: 550px; margin: 0 auto;">
<input type="hidden" th:field="*{idGovernor}">
<div class="border border-secondary rounded p-3">
<div class="form-group row">
<label class="col-sm-4 col-form-label">Full name:</label>
<div class="col-sm-8">
<input type="text" th:field="*{fullName}" class="form-control" required minlength="5" maxlength="70">
</div>
</div>
<div class="form-group row">
<label class="col-sm-4 col-form-label">Age</label>
<div class="col-sm-8">
<input type="number" step="0.01" th:field="*{age}" class="form-control" required>
</div>
</div>
<div class="form-group row">
<label class="col-sm-4 col-form-label">Position</label>
<div class="col-sm-8">
<input type="text" step="0.01" th:field="*{position}" class="form-control" required>
</div>
</div>
<div class="form-group row">
<label class="col-sm-4 col-form-label">Date of Intercession</label>
<div class="col-sm-8">
<input type="date" th:field="*{dateOfIntercession}" class="form-control">
</div>
</div>
<div class="form-group row">
<label class="col-sm-4 col-form-label">Date of Resignation</label>
<div class="col-sm-8">
<input type="date" th:field="*{dateOfResignation}" class="form-control">
</div>
</div>
<div class="form-group row">
<label class="col-sm-4 col-form-label">Per Capita Income</label>
<div class="col-sm-8">
<input type="number" step="0.01" th:field="*{perCapitaIncome}" class="form-control" required>
</div>
</div>
<div class="form-group row">
<label class="col-sm-4 col-form-label">Population Below Poverty</label>
<div class="col-sm-8">
<input type="number" step="0.01" th:field="*{populationBelowPoverty}" class="form-control" required min="0" max="99">
</div>
</div>
<div class="form-group row">
<label class="col-sm-4 col-form-label">State</label>
<div class="col-sm-8">
<select th:field="*{state}" class="form-control" required>
<th:block th:each="state : ${listStates}">
<option th:text="${state.officialStateName}" th:value="${state.idState}"/>
</th:block>
</select>
</div>
</div>
<div class="text-center">
<button type="submit" class="btn btn-primary m-2">Save</button>
<button type="button" class="btn btn-secondary m-2" onclick="cancelForm()">Cancel</button>
</div>
</div>
</form>
</div>
<script type="text/javascript">
function cancelForm() {
window.location = "[[#{/governors}]]";
}
</script>
</body>
</html>
This is where he inputs that data:
<div class="form-group row">
<label class="col-sm-4 col-form-label">Per Capita Income</label>
<div class="col-sm-8">
<input type="number" step="0.01" th:field="*{perCapitaIncome}" class="form-control" required>
</div>
</div>
So if i'm not mistaken Hibernate is having a problem converting a String input from thymeleaf to type money as I get the following error:
: Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors<EOL>Field error in object 'governor' on field 'perCapitaIncome': rejected value [1100]; codes [typeMismatch.governor.perCapitaIncome,typeMismatch.perCapitaIncome,typeMismatch.org.joda.money.Money,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [governor.perCapitaIncome,perCapitaIncome]; arguments []; default message [perCapitaIncome]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'org.joda.money.Money' for property 'perCapitaIncome'; Cannot convert value of type 'java.lang.String' to required type 'org.joda.money.Money' for property 'perCapitaIncome': no matching editors or conversion strategy found]]
This is the joda.money dependency:
<dependency>
<groupId>org.joda</groupId>
<artifactId>joda-money</artifactId>
<version>1.0.1</version>
</dependency>
This is a POJO class:
#Entity
#Table(name = "governor")
public class Governor implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_governor")
private Integer idGovernor;
#Column(name = "pib")
private String fullName;
#Column(name = "age")
private Integer age;
#Column(name = "position")
private String position;
#Column(name = "date_of_intercession")
private java.sql.Date dateOfIntercession;
#Column(name = "date_of_resignation")
private java.sql.Date dateOfResignation;
#Column(name = "per_capita_income")
private Money perCapitaIncome;
#Column(name = "population_below_poverty")
private Integer populationBelowPoverty;
#ManyToOne
#JoinColumn(name = "id_state", nullable = false)
private State state;
public State getState() {return state;}
public void setState(State state) {this.state = state;}
public Integer getIdGovernor() {
return this.idGovernor;
}
public void setIdGovernor(Integer idGovernor) {
this.idGovernor = idGovernor;
}
public String getFullName() {
return this.fullName;
}
public void setFullName(String fullName) {this.fullName = fullName;}
public Integer getAge() {
return this.age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getPosition() {
return this.position;
}
public void setPosition(String position) {
this.position = position;
}
public java.sql.Date getDateOfIntercession() {
return this.dateOfIntercession;
}
public void setDateOfIntercession(java.sql.Date dateOfIntercession) {
this.dateOfIntercession = dateOfIntercession;
}
public java.sql.Date getDateOfResignation() {
return this.dateOfResignation;
}
public void setDateOfResignation(java.sql.Date dateOfResignation) {
this.dateOfResignation = dateOfResignation;
}
public Money getPerCapitaIncome() {
return this.perCapitaIncome;
}
public void setPerCapitaIncome(Money perCapitaIncome) {
this.perCapitaIncome = perCapitaIncome;
}
public Integer getPopulationBelowPoverty() {
return this.populationBelowPoverty;
}
public void setPopulationBelowPoverty(Integer populationBelowPoverty) {
this.populationBelowPoverty = populationBelowPoverty;
}
}
This is a controller:
#Controller
public class GovernorController {
#Autowired
GovernorService governorService;
#Autowired
GovernorRepository governorRepository;
#Autowired
StateRepository stateRepository;
#Autowired
StateService stateService;
#GetMapping("/governors")
public String showAllGovernors(Model model){
List<Governor> listGovernors = governorService.findAllGovernors();
model.addAttribute("listGovernors", listGovernors);
return "governors";
}
#GetMapping("/governors/new")
public String showNewGovernorForm(Model model){
List <State> listStates = stateService.findAll();
model.addAttribute("listStates", listStates);
model.addAttribute("governor", new Governor());
model.addAttribute("pageTitleG", "Add New Governor");
return "governor_form";
}
#PostMapping("/governors/save")
public String saveGovernor (Governor requestGovernor, RedirectAttributes redirectAttributes){
governorRepository.save(requestGovernor);
redirectAttributes.addFlashAttribute("messageG", "The governor has been saved successfully!");
return "redirect:/governors";
}
#GetMapping("/governors/edit/{id}")
public String showEditGovernorForm(#PathVariable("id") Integer id, Model model, RedirectAttributes redirectAttributes){
try {
Governor governor = governorService.findGovernorById(id);
List <State> listStates = stateService.findAll();
model.addAttribute("listStates", listStates);
model.addAttribute("governor", governor);
model.addAttribute("pageTitleG", "Edit Governor (ID: " + id + ")");
return "governor_form";
} catch (EntityNotFoundException e) {
redirectAttributes.addFlashAttribute("messageG", e.getMessage());
return "redirect:/governors";
}
}
#GetMapping("/governors/delete/{id}")
public String deleteGovernor(#PathVariable("id") Integer id, Model model, RedirectAttributes redirectAttributes){
try {
governorService.deleteGovernor(id);
redirectAttributes.addFlashAttribute("messageG", "The governor ID " + id + " has been deleted!");
} catch (StateNotFoundException e) {
redirectAttributes.addFlashAttribute("messageG", e.getMessage());
}
return "redirect:/governors";
}
}
How do I convert String to Money?
One solution would be to create custom deserilizer for Money field, and then use Jackson to set it.
Here is code snippet:
MoneyDeserializer.java :
public class MoneyDeserializer extends StdDeserializer<BigMoney> {
private static final long serialVersionUID = 2518470236548239933L;
public MoneyDeserializer() {
super(Money.class);
}
#Override
public BigMoney deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException, JsonProcessingException {
return BigMoney.of(CurrencyUnit.USD, jp.readValueAs(Double.class));
}
}
Governor.java
import com.example.demo.filter.MoneyDeserializer;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import org.joda.money.BigMoney;
import org.joda.money.Money;
import java.io.Serializable;
public class Governor implements Serializable {
private Integer idGovernor;
private String fullName;
private Integer age;
private String position;
private java.sql.Date dateOfIntercession;
private java.sql.Date dateOfResignation;
private BigMoney perCapitaIncome;
private Integer populationBelowPoverty;
public Integer getIdGovernor() {
return this.idGovernor;
}
public void setIdGovernor(Integer idGovernor) {
this.idGovernor = idGovernor;
}
public String getFullName() {
return this.fullName;
}
public void setFullName(String fullName) {this.fullName = fullName;}
public Integer getAge() {
return this.age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getPosition() {
return this.position;
}
public void setPosition(String position) {
this.position = position;
}
public java.sql.Date getDateOfIntercession() {
return this.dateOfIntercession;
}
public void setDateOfIntercession(java.sql.Date dateOfIntercession) {
this.dateOfIntercession = dateOfIntercession;
}
public java.sql.Date getDateOfResignation() {
return this.dateOfResignation;
}
public void setDateOfResignation(java.sql.Date dateOfResignation) {
this.dateOfResignation = dateOfResignation;
}
public BigMoney getPerCapitaIncome() {
return this.perCapitaIncome;
}
#JsonDeserialize(using = MoneyDeserializer.class)
public void setPerCapitaIncome(BigMoney perCapitaIncome) {
this.perCapitaIncome = perCapitaIncome;
}
public Integer getPopulationBelowPoverty() {
return this.populationBelowPoverty;
}
public void setPopulationBelowPoverty(Integer populationBelowPoverty) {
this.populationBelowPoverty = populationBelowPoverty;
}
#Override
public String toString() {
return "Governor{" +
"idGovernor=" + idGovernor +
", fullName='" + fullName + '\'' +
", age=" + age +
", position='" + position + '\'' +
", dateOfIntercession=" + dateOfIntercession +
", dateOfResignation=" + dateOfResignation +
", perCapitaIncome=" + perCapitaIncome +
", populationBelowPoverty=" + populationBelowPoverty +
'}';
}
}
NOTE: On your form, you are passing age field as Double, but in your class it's declared as Integer. So you will get exception during deserilization process.
Same thing applys for populationBelowPoverty field . Also, your date format is dd/MM/YYYY and I think this is not supported format for jackson. It should be YYYY-MM-dd.
Anyway, for example, if you send a JSON like this:
{
"idGovernor":1,
"fullName":"Test",
"age":1,
"dateOfIntercession":"2022-06-09",
"dateOfResignation":"2022-06-17",
"perCapitaIncome":"123.932",
"position":"position",
"populationBelowPoverty":"98"
}
to this controller method:
#PostMapping(value = "/test/governor")
public Governor testGovernor(#RequestBody Governor governor) {
return governor;
}
You should get response like this :
{
"idGovernor": 1,
"fullName": "Test",
"age": 1,
"position": "position",
"dateOfIntercession": "2022-06-09",
"dateOfResignation": "2022-06-17",
"perCapitaIncome": {
"amount": 123.932,
"zero": false,
"negative": false,
"positive": true,
"amountMajorLong": 123,
"negativeOrZero": false,
"amountMinorLong": 12393,
"amountMinor": 12393,
"positiveOrZero": true,
"minorPart": 93,
"scale": 3,
"amountMinorInt": 12393,
"currencyUnit": {
"code": "USD",
"numericCode": 840,
"decimalPlaces": 2,
"symbol": "$",
"numeric3Code": "840",
"countryCodes": [
"PR",
"MP",
"IO",
"FM",
"PW",
"GU",
"BQ",
"TC",
"VG",
"AS",
"VI",
"TL",
"UM",
"MH",
"EC",
"US"
],
"pseudoCurrency": false
},
"currencyScale": false,
"amountMajorInt": 123,
"amountMajor": 123
},
"populationBelowPoverty": 98
}
In your case, since you are using thymeleaf you can adjust this idea to your needs.
Here is my form
<form th:action="#{/pages/org/create}" th:object="${org}" method="post" id="createOrgForm">
<div class="row">
<div class="form-group col-sm-12">
<label for="name">Name</label> <input class="form-control" id="name" type="text" th:field="*{name}" />
</div>
</div>
<div class="row">
<div class="form-group col-sm-12">
<label for="uuid">Uuid</label> <input class="form-control" id="uuid" type="text" th:field="*{uuid}" />
</div>
</div>
<div class="row">
<div class="form-group col-sm-12">
<label for="expiryDate">Expiry Date</label>
<input class="form-control" id="expiryDate" type="date" name="expiryDate" th:value="${#temporals.format(org.expiryDate, 'dd/MMM/yyyy HH:mm', 'en')}"/>/>
</div>
</div>
</form>
The object has name and uuid which are strings
It also has an expiryDate which is a zonedDateTime
I want to return expiryDate as a zoneddatetime but I can't find any examples of this
Any one Know how to do this?
If anymore details are needed let me know
I have this error
There was an unexpected error (type=Bad Request, status=400).
Validation failed for object='org'. Error count: 1
because org.expiryDate is a string and its expecting a zoneddatetime
public class OrganizationDto extends TemporallyScopedEntityFlatDto {
private static final long serialVersionUID = -2191341305487098272L;
public static OrganizationDto fromEntity(final Organization o) {
if (o == null) {
return null;
}
final OrganizationDto dto = new OrganizationDto();
DtoUtil.copyVersioned(o, dto);
DtoUtil.copyTemporallyScoped(o, dto);
dto.setName(o.getName());
dto.setUuid(o.getUuid());
return dto;
}
#ApiModelProperty(value = "The display name of this organization.")
private String name;
#ApiModelProperty(value = "The unique identifier of this organization.")
private String uuid;
private ZonedDateTime expiryDate;
public String getName() {
return name;
}
public String getUuid() {
return uuid;
}
public void setName(final String name) {
this.name = name;
}
public void setUuid(final String uuid) {
this.uuid = uuid;
}
}
Hi i want to add my photo to mysql database but it doesn't work, I have BLOB in workbench but when I open value in editor I see only name of image and binary values, I don't have look at the picture and size of BLOB do not agree with size of image. Text entites correctly save to rows.
MODEL:
#Entity
#Table(name = "skis")
public class Skis extends BaseEntity {
#Column(name = "company", length = 20)
private String company;
#Column(name = "model", length = 20)
private String model;
#Column(name = "description", length = 200)
private String description;
#Column(name = "photo", columnDefinition = "MEDIUMBLOB")
private byte[] photo;
public Skis(String company, String model, String description, byte[] photo) {
this.company = company;
this.model = model;
this.description = description;
this.photo = photo;
}
public Skis() {
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public byte[] getPhoto() {
return photo;
}
public void setPhoto(byte[] photo) {
this.photo = photo;
}
}
Controller:
#Controller
public class SkisController {
#Autowired
private SkisDAO skisDAO;
#RequestMapping(value = "/ski/save", method = RequestMethod.POST)
public String postCreateSki(#ModelAttribute Skis skis){
skisDAO.save(skis);
return "redirect:/skis";
}
#RequestMapping(value = "/ski-create", method = RequestMethod.GET)
public String getCreateSkisForm(Model model) {
model.addAttribute("skis", new Skis());
return "add-skis";
}
}
JSP:
<div class="container">
<div class="row">
<form:form commandName="skis" action="${createSkiURL}" method="post" role="form" class="form-horizontal">
<form:hidden path="id" />
<div class="form-group">
<label class="control-label col-sm-2" for="company">company:</label>
<div class="col-sm-6">
<form:input path="company" type="text" id="company" class="form-control" placeholder="Enter company" autofocus="autofocus" />
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="model">model:</label>
<div class="col-sm-6">
<form:input path="model" type="text" id="model" class="form-control" placeholder="Enter model" autofocus="autofocus" />
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="description">description:</label>
<div class="col-sm-6">
<form:input path="description" type="text" id="description" class="form-control" placeholder="Enter description" autofocus="autofocus" />
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="photo">photo:</label>
<form:input path="photo" type="file" id="photo" />
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-6">
<button type="submit" class="btn btn-primary">Zapisz</button>
</div>
</div>
</form:form>
</div>
</div>
DAO:
#Repository
public interface SkisDAO extends JpaRepository<Skis, Long> {
}
And another question:
How Can I display image at another jsp? I know how display text, but don't know how to display photo from database
When trying to submit my form to create a new auction this error appears in the browser:
Whitelabel Error Page:
This application has no explicit mapping for /error, so you are seeing
this as a fallback.
Thu Mar 30 21:00:15 BST 2017
There was an unexpected error (type=Bad Request, status=400)
Validation failed for object='auctionItem'. Error count: 2
I can't seem to find any specific errors within my log, so I am having trouble finding the two validation errors show on the error page. I am pretty lost at this point. Hopefully someone can help me out, its preventing me from making progress at the moment.
JSP File:
<body id="product" class="product">
<header>
<%#include file="../jsp/Header.jsp" %>
</header>
<div>
<div class="container">
<div class ="row">
<div class="center_column">
<h2 style=" ">Create New Listing</h2>
<mvc:form class="form-inline" action="sell" method="post" modelAttribute="newAuction" id="addNewAuc">
<div class="form-inline" cssClass="TitleBlock">
<label class="control-label">Title</label>
<div>
<mvc:input path="aTitle" type="text" required="true" cssClass="Title" class="form-control" placeholder="Please enter title of item" maxlength="55" minlength="40"/>
</div>
</div>
<div class="form-group ">
<label class="control-label">Item Condition</label>
<div style="padding-top: 4px;">
<mvc:select path="aCondition">
<mvc:option value="New">New</mvc:option>
<mvc:option value="Used">Used</mvc:option>
</mvc:select>
</div>
</div>
<div class="form-group ">
<label class="control-label" style = "padding-left: 15px;">Can the item be returned?</label>
<div style="padding-top: 4px; padding-left: 15px;">
<mvc:select path="aReturns">
<mvc:option value="You can return">Yes</mvc:option>
<mvc:option value="Seller does not offer returns">No</mvc:option>
</mvc:select>
</div>
</div>
<div class="form-inline">
<label class="control-label">Description</label>
<div>
<mvc:textarea path="aDescription" required="true" cssClass="Desc" class="form-control" rows="3" name="Description" placeholder="Item description"/>
</div>
</div>
<div class="form-inline">
<label class="control-label">Category</label>
<div style="padding-top: 4px;">
<mvc:select path="categories">
<mvc:option value="category1">Electronics</mvc:option>
<mvc:option value="category2">Fashion</mvc:option>
<mvc:option value="category3">Home & Gardens</mvc:option>
<mvc:option value="category4">Toys & Games</mvc:option>
<mvc:option value="category5">Sports & Leisure</mvc:option>
</mvc:select>
</div>
</div>
<div class="form-inline">
<label class="control-label ">Minimum Price</label>
<div style="padding-top: 4px;">
<mvc:input path="aBottomPrice" type="number" step="any" required="true" class="form-control" placeholder="?"/>
</div>
</div>
<div class="form-inline">
<label class="control-label ">Starting Price</label>
<div style="padding-top: 4px;">
<mvc:input path="aTopPrice" type="number" step="any" required="true" class="form-control" placeholder="?"/>
</div>
</div>
<div class="form-inline">
<label class="control-label">End of listing</label>
<div style="padding-top: 4px;">
<mvc:input path="aEnd" type="text" id="datetimepicker" required="true" class="form-control" placeholder="YYYY-MM-DD"/>
</div>
</div>
</mvc:form>
<div class="form-inline">
<div style="padding-top: 10px;">
<button type="submit" name="submit" class="btn btn-success" form="addNewAuc">Next</button>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
AuctionItem Class
#Entity
#Table(name = "auction_items")
public class AuctionItem {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int idauction;
#Column(name = "auctionTitle")
private String aTitle;
#Column(name = "auctionDescription")
private String aDescription;
#Column(name = "auctionStatus")
private String aStatus;
#Column(name = "auctionStart")
private Date aStart;
#Column(name = "auctionEnd")
private Date aEnd;
private String endTimeAsString;
#Column(name = "auctionCondition")
private String aCondition;
#Column(name = "auctionTopPrice")
private double aTopPrice;
#Column(name = "auctionBottomPrice")
private double aBottomPrice;
private long auctionDuration;
private String aReturns;
#ManyToOne
#JoinColumn(name = "owner")
private User owner;
#ManyToOne
#JoinColumn(name = "cId")
private Category categories;
public long getAuctionDuration() {
return auctionDuration;
}
public void setAuctionDuration(long auctionDuration) {
this.auctionDuration = auctionDuration;
}
public int getaID() {
return idauction;
}
public void setaID(int idauction) {
this.idauction = idauction;
}
public String getaTitle() {
return aTitle;
}
public void setaTitle(String aTitle) {
this.aTitle = aTitle;
}
public String getaDescription() {
return aDescription;
}
public void setaDescription(String aDescription) {
this.aDescription = aDescription;
}
public String getaStatus() {
return aStatus;
}
public void setaStatus(String aStatus) {
this.aStatus = aStatus;
}
public Date getaStart() {
return aStart;
}
public void setaStart(Date aStart) {
this.aStart = aStart;
}
public Date getaEnd() {
return aEnd;
}
public void setaEnd(Date aEnd) {
this.aEnd = aEnd;
}
public String getaCondition() {
return aCondition;
}
public void setaCondition(String aCondition) {
this.aCondition = aCondition;
}
public double getaTopPrice() {
return aTopPrice;
}
public void setaTopPrice(double aTopPrice) {
this.aTopPrice = aTopPrice;
}
public double getaBottomPrice() {
return aBottomPrice;
}
public void setaBottomPrice(double aBottomPrice) {
this.aBottomPrice = aBottomPrice;
}
public User getOwner() {
return owner;
}
public void setOwner(User owner) {
this.owner = owner;
}
public String getaReturns() {
return aReturns;
}
public void setaReturns(String aReturns) {
this.aReturns = aReturns;
}
public Category getCategories() {
return categories;
}
public void setCategories(Category categories) {
this.categories = categories;
}
public String getEndTimeAsString() {
return endTimeAsString;
}
public void setEndTimeAsString(String EndTimeAsString) {
this.endTimeAsString = EndTimeAsString;
}
}
Maybe you missed " BindingResult " in Controller.
Example:
import org.springframework.validation.BindingResult;
#RequestMapping(value = "/registration", method = RequestMethod.POST)
public String registration(
#ModelAttribute("userlogin") #Valid LoginProfile userlogin,
BindingResult userloginResult)
I'm trying to update data from Spring MVC's view. I could update data using tester object but failed when trying update from Spring MVC's view. POST request from view has no problem key/value were posting to server. It updated my table data but with null value (unless for id field).
Please help and thank you.
My Table (tx_surveyrequest)
CREATE TABLE tx_surveyrequest
(
id uuid NOT NULL,
id_person uuid,
id_surveyrequeststatus uuid,
id_validationstatus uuid,
id_employee_assistantgis uuid,
formcode character varying(64),
b_north character varying(32),
b_east character varying(32),
b_south character varying(32),
b_west character varying(32),
hectarage numeric(10,2),
is_priority boolean DEFAULT false,
requestdate date,
surveyplandate date,
surveyplantime time without time zone,
requestedby character varying(32),
requestedprice numeric(14,2),
CONSTRAINT pk_tx_surveyrequest PRIMARY KEY (id)
)
My domain object (SurveyRequest)
#Entity
#Table(name = "tx_surveyrequest")
public class SurveyRequest implements Serializable {
private UUID id;
private Person person;
private String formCode;
private String borderNorth;
private String borderEast;
private String borderSouth;
private String borderWest;
private Double hectarage;
private Boolean priority;
private DateTime requestDate;
private DateTime surveyPlanDate;
private LocalTime surveyPlanTime;
private String requestedBy;
private Double requestedPrice;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id")
#Type(type="pg-uuid")
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
#Column(name = "hectarage")
public Double getHectarage(){
return hectarage;
}
public void setHectarage(Double hectarage){
this.hectarage = hectarage;
}
#Column(name = "formcode")
public String getFormCode() {
return formCode;
}
public void setFormCode(String formCode) {
this.formCode = formCode;
}
#Column(name="is_priority")
public Boolean getPriority() {
return priority;
}
public void setPriority(Boolean priority) {
this.priority = priority;
}
#Column(name="b_north")
public String getBorderNorth() {
return borderNorth;
}
public void setBorderNorth(String border) {
this.borderNorth = border;
}
#Column(name="b_east")
public String getBorderEast() {
return borderEast;
}
public void setBorderEast(String border) {
this.borderEast = border;
}
#Column(name="b_south")
public String getBorderSouth() {
return borderSouth;
}
public void setBorderSouth(String border) {
this.borderSouth = border;
}
#Column(name="b_west")
public String getBorderWest() {
return borderWest;
}
public void setBorderWest(String border) {
this.borderWest = border;
}
// TODO replace pattern with i18n
#Type(type = "org.joda.time.contrib.hibernate.PersistentDateTime")
#DateTimeFormat(pattern = "dd/MM/yyyy")
#Column(name = "requestdate")
public DateTime getRequestDate() {
return requestDate;
}
public void setRequestDate(DateTime requestDate) {
this.requestDate = requestDate;
}
// TODO replace pattern with i18n
#Type(type = "org.joda.time.contrib.hibernate.PersistentDateTime")
#DateTimeFormat(pattern = "dd/MM/yyyy")
#Column(name = "surveyplandate")
public DateTime getSurveyPlanDate() {
return surveyPlanDate;
}
public void setSurveyPlanDate(DateTime surveyPlanDate) {
this.surveyPlanDate = surveyPlanDate;
}
// TODO replace pattern with i18n
#Type(type = "org.joda.time.contrib.hibernate.PersistentLocalTimeAsTime")
#DateTimeFormat(pattern = "HH:mm")
#Column(name = "surveyplantime")
public LocalTime getSurveyPlanTime() {
return surveyPlanTime;
}
public void setSurveyPlanTime(LocalTime surveyPlanTime) {
this.surveyPlanTime = surveyPlanTime;
}
Update success using SurveyRequestUpdate
public class SurveyRequestUpdate {
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:spring-data-app-context.xml");
ctx.load("classpath:datasource.xml");
ctx.refresh();
SurveyRequestService surveyRequestService = ctx.getBean(
"springJpaSurveyRequestService",SurveyRequestService.class);
UUID uid = UUID.fromString("0cd02976-1864-447b-b540-39d6e7ee3703");
SurveyRequest request = surveyRequestService.findById(uid);
System.out.println("Find by ID");
System.out.println(request);
request.setSurveyPlanDate (new DateTime(2014,7,1,0,0));
request.setSurveyPlanTime (new LocalTime(22,0));
surveyRequestService.save(request);
System.out.println(request);
}
Update Form View
<jsp:directive.page contentType="text/html;charset=UTF-8" />
<jsp:output omit-xml-declaration="yes" />
<spring:message code="l_surveyrequest_list" var="labelSurveyRequestList" />
<spring:message code="l_surveyrequest_title" var="labelSurveyRequestTitle" />
<spring:message code="l_surveyrequest_code" var="labelSurveyRequestCode" />
<spring:message code="l_surveyrequest_requestdate" var="labelSurveyRequestRequestDate" />
<spring:message code="l_surveyrequest_surveydate" var="labelSurveyRequestSurveyDate" />
<spring:message code="l_surveyrequest_surveytime" var="labelSurveyRequestSurveyTime" />
<spring:message code="l_surveyrequest_priority" var="labelSurveyRequestPriority" />
<spring:message code="l_surveyrequest_complete" var="labelSurveyRequestComplete" />
<spring:message code="l_surveyrequest_hectarage" var="labelSurveyRequestHectarage" />
<spring:message code="l_surveyrequest_north" var="labelSurveyRequestNorth" />
<spring:message code="l_surveyrequest_east" var="labelSurveyRequestEast" />
<spring:message code="l_surveyrequest_south" var="labelSurveyRequestSouth" />
<spring:message code="l_surveyrequest_west" var="labelSurveyRequestWest" />
<spring:message code="form_new" var="formNew" />
<spring:message code="form_edit" var="formEdit" />
<spring:message code="btn_save" var="buttonSave" />
<spring:message code="btn_cancel" var="buttonCancel" />
<spring:message code="long_date_format_pattern" var="formatDate" />
<spring:message code="time_format_pattern" var="formatDateTime" />
<spring:message code="short_time_format_pattern" var="formatShortTime" />
<spring:url value="/surveyrequest" var="showSurveyRequestUrl" />
<spring:eval expression="surveyRequest.id == null ? formNew:formEdit" var="formTitle"/>
<div class="row">
<div class="col-md-12">
<h1>${formTitle} ${labelSurveyRequestTitle}</h1>
</div>
</div>
<!-- /top action bar -->
<div class="row">
<div class="col-md-12">
<c:if test="${not empty surveyRequest}">
<form:form class="form-horizontal"
modelAttribute="surveyRequest" commandName="surveyRequest" method="post" enctype="multipart/form-data">
<div class="row">
<div class="col-md-12">
<button type="submit" class="btn btn-primary">${buttonSave}</button>
<button type="reset" class="btn btn-primary">${buttonCancel}</button>
</div>
</div>
<c:if test="${not empty message}">
<div id="message" class="${message.type}">${message.message}</div>
</c:if>
<div class="form-group">
<label class="col-md-3 control-label">${labelSurveyRequestCode}</label>
<div class="col-md-3">
<form:input type="text" class="form-control" path="formCode" />
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">${labelSurveyRequestRequestDate}</label>
<div class='col-md-3 input-group date datepicker'>
<form:input type='text' class="form-control" path="requestDate" />
<span class="input-group-addon"><span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">${labelSurveyRequestSurveyDate}</label>
<div class='col-md-3 input-group date datepicker'>
<form:input type='text' class="form-control" path="surveyPlanDate" />
<span class="input-group-addon"><span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
<div class="form-group">
<form:label class="col-md-3 control-label"
path="surveyPlanTime">${labelSurveyRequestSurveyTime}</form:label>
<div class='col-md-3 input-group date timepicker'>
<form:input type='text' class="form-control" path="surveyPlanTime" />
<span class="input-group-addon"><span class="glyphicon glyphicon-time"></span>
</span>
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">${labelSurveyRequestHectarage}</label>
<div class="col-md-3">
<form:input type="text" class="form-control" path="hectarage" />
</div>
</div>
<div class="form-group">
<p class="col-md-3"></p>
<div class="col-md-9">
<c:choose>
<c:when test="${surveyRequest.priority == true}">
${labelSurveyRequestPriority}
</c:when>
</c:choose>
</div>
</div>
<div class="form-group">
<p class="col-md-3"></p>
<div class="col-md-9">
<table class="table">
<thead>
<tr>
<th>${labelSurveyRequestNorth}</th>
<th>${labelSurveyRequestEast}</th>
<th>${labelSurveyRequestSouth}</th>
<th>${labelSurveyRequestWest}</th>
</tr>
</thead>
<tbody>
<tr>
<td>${surveyRequest.borderNorth}</td>
<td>${surveyRequest.borderEast}</td>
<td>${surveyRequest.borderSouth}</td>
<td>${surveyRequest.borderWest}</td>
</tr>
</tbody>
</table>
</div>
</div>
</form:form>
</c:if>
</div>
</div>
<script type="text/javascript">
$(function () {
$('.datepicker').datetimepicker({
pickTime: false,
language: 'id',
});
$('.timepicker').datetimepicker({
pickDate: false,
minuteStepping:15,
useSeconds: false,
language: 'id'
});
});
</script>
</div>
My Controller
#RequestMapping("/surveyrequest")
#Controller
public class SurveyRequestController {
private static final int PAGE_SIZE = 10;
private static final Logger logger = LoggerFactory
.getLogger(SurveyRequestController.class);
#Autowired
MessageSource messageSource;
#Autowired
private SurveyRequestService surveyRequestService;
// Others code omitted
#RequestMapping(value="/{id}", method = RequestMethod.GET)
public String show(#PathVariable("id") UUID id, Model model) {
SurveyRequest request = surveyRequestService.findById(id);
model.addAttribute("surveyRequest", request);
return "surveyrequest/show";
}
/*
* Edit a survey request
*/
#RequestMapping(value="/{id}", params="form", method = RequestMethod.GET)
public String updateForm(#PathVariable("id") UUID id, Model model) {
SurveyRequest request = surveyRequestService.findById(id);
model.addAttribute("surveyRequest", request);
return "surveyrequest/edit";
}
/*
* Update a survey request
*/
#RequestMapping(value = "/{id}", params = "form", method = RequestMethod.POST)
public String update(SurveyRequest surveyRequest, BindingResult bindingResult, Model uiModel,
HttpServletRequest httpServletRequest, RedirectAttributes redirectAttributes, Locale locale) {
if (bindingResult.hasErrors()) {
uiModel.addAttribute("message", new Message("error", messageSource.getMessage("surveyrequest_save_fail", new Object[]{}, locale)));
uiModel.addAttribute("surveyRequest", surveyRequest);
return "surveyrequest/update";
}
uiModel.asMap().clear();
redirectAttributes.addFlashAttribute("message", new Message("success", messageSource.getMessage("surveyrequest_save_success", new Object[]{}, locale)));
logger.info("Before paste: " + surveyRequest);
surveyRequestService.save(surveyRequest);
return "redirect:/surveyrequest/" + UrlUtil.encodeUrlPathSegment(surveyRequest.getId().toString(), httpServletRequest);
}
Updated:
I could resolve the problem with removing enctype="multipart/form-data" at edit.jspx. But it raised another issue, how if I'm going to upload file?
Add #ModelAttribute annotation to your model object parameter in the controller method that you're calling, so that Spring knows that's the object that you want to bind the form data to.
/*
* Update a survey request
*/
#RequestMapping(value = "/{id}", params = "form", method = RequestMethod.POST)
public String update(#ModelAttribute("surveyRequest") SurveyRequest surveyRequest,
BindingResult bindingResult, Model uiModel,
HttpServletRequest httpServletRequest,
RedirectAttributes redirectAttributes, Locale locale) {
[...]
}