request sent by the client was syntactically incorrect - spring

I have 2 very similar web functions that use spring framework, Function 1 hits "request sent by the client was syntactically incorrect" while Function 2 works well. I show the one does not work below in the hope that someone can help me.
Function 1 JSP:
<form:form id="sform" action="DealMaintEdit.htm" method="POST" commandName="dmForm">
<table border="1">
<tr><td><spring:message code="label.DealID"/></td>
<td><form:input path="deal.dealId" readonly="true" size="6"/></td>
</tr>
<tr><td><spring:message code="label.Code"/></td>
<td><form:input path="deal.stkCode" maxlength="5" size="6"/>
<form:errors path="deal.stkCode" cssClass="error"/></td>
</tr> .....other fields skipped....
</table>
<form:hidden path="mode"/>
<form:hidden path="butt" value="Save"/>
<input form="sform" type="submit" value="<spring:message code="label.Save"/>"/>
</form:form>
Function 1 dmForm:
#Component
public class DealMaintForm {
private String mode;
private String butt;
#Valid
private Deal deal;
.....
Function 1 controller:
#RequestMapping(value = "/DealMaintEdit.htm")
public String dealMaintEdit(#ModelAttribute("dmForm") #Valid DealMaintForm form,
#RequestParam("butt") String butt, BindingResult result, Map model) {
I have if (result.hasErrors()) in the controller but it didn't execute before hitting the error.
Function 1 Deal:
public class Deal implements Serializable {
private Long dealId;
private DealType type;
#NotNull
#Min(1)
#Max(99999)
private int stkCode;
......
The funny thing is, if there is validation error, it hits the syntactically incorrect error before reaching the controller method. Say if I input 2 to stkCode it works fine, but if I change the #Min(1) in stkCode to #Min(5), input an 2 in stkCode will hit syntactically incorrect. Other fields are the same.
My other web form that works looks like this.
Function 2 JSP:
<form:form action="StockMaint2Edit.htm" method="POST" commandName="smForm">
<form:hidden path="mode"/>
<form:hidden path="stk.id"/>
<table border="1">
<tr>
<td><spring:message code="label.Code"/></td>
<td><form:input path="stk.code"/><form:errors path="stk.code" cssClass="error"/></td>
</tr>
<tr>
<td><spring:message code="label.Name"/></td>
<td><form:input path="stk.name" /><form:errors path="stk.name" cssClass="error"/></td>
</tr>
</table>
<form:hidden path="butt" value="Save"/>
<input type="submit" value="<spring:message code="label.Save"/>"/>
</form:form>
Function 2 smForm
#Component
public class StockMaintForm2 {
private String mode;
private String butt;
#Valid
private Stock stk;
.....
Function 2 Controller
#RequestMapping(value = "/StockMaint2Edit.htm")
public String stockMaintEdit(#ModelAttribute("smForm") #Valid StockMaintForm2 form,
BindingResult result, Map model) {
if (result.hasErrors()) {
System.out.println("edit has errors");
List<FieldError> errList = result.getFieldErrors();
for (FieldError fe : errList) {
......
Function 2 Stock
public class Stock implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
#NotNull
#Min(1)
#Max(99999)
private int code;
#NotBlank
private String name;
....
Function 2 works with all validation error msg displayed correctly. No syntactically incorrect error.
Compared them several times and still not able to spot the difference and the cause of the problem. Please let me know if I should provide more info.

I guess this causes the error,
<form:hidden path="butt" value="Save"/>
You can try with normal hidden field as ,
<input type="hidden" name="butt" value="Save"/>
in your Function 1 JSP .
As you have used the spring:form tag . butt will be not available explicitly in the request. you need to get it from the model attribute or you can make the input field simply with html tag. so that it will be available in the request.

Thank you for all the responses. I should reply individually, but after adding the first comment I am not able to add further comments. So I reply here. With your help I focused on the "butt". Since it is in both the form and the param, I delete the #RequestParam and obtain it from the form, and then it works.
#RequestMapping(value = "/DealMaintEdit.htm")
public String dealMaintEdit(#ModelAttribute("dmForm") #Valid DealMaintForm form,
BindingResult result, Map model) { ......
#SergeBallesta, tried your suggestion by moving the butt to the end and it also works. How can I add yours as useful comment?
#RequestMapping(value = "/DealMaintEdit.htm")
public String dealMaintEdit(#ModelAttribute("dmForm") #Valid DealMaintForm form,
BindingResult result, Map model, #RequestParam("butt") String butt) { ....
#SanKrish, tried the normal html "hidden" but it doesn't work. Furthermore, since the problem is missing param and my #RequestParam is redundant, I experimented it with this
#RequestMapping(value = "/DealMaintEdit.htm")
public String dealMaintEdit(#ModelAttribute("dmForm") #Valid DealMaintForm form,
#RequestParam("butt2") String butt2, BindingResult result, Map model) { ....
and in the jsp
<form:form id="sform" action="DealMaintEdit.htm?butt2=abcd" method="POST" commandName="dmForm">
it also doesn't work. Though the problem some how solved, there remains 2 questions:
Why "butt2" still has syntactically error?
If the original problem was due to missing param, why it only happens when there is validation error?

and I see that you're actually merging your annotations on the methods:
could you try to get a line break there:
public class Stock implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
#NotNull
#Min(1)
#Max(99999)
private int code;
#NotBlank
private String name;
....

Related

Spring MVC is constructing a child object upon form submission when it shouldn't

I'm having an issue where a child object is getting constructed even though my form does not specify one should be created. The issue I'm getting is that upon form submission, there are validation field errors with stating that secondary's last and first name is not present.
Ideally, I want secondary to stay null and hence, not validated upon form submission.
The HTML form (snipped for simplicity):
<form th:action="#{/quotes/save}" th:object="${quote}">
<input type="text" th:field="*{primary.lastName}" />
<input type="text" th:field="*{primary.firstName}" />
</form>
The Quote object:
#Entity
public class Quote {
#ManyToOne
#Valid
#NotNull(groups={Quote.ValidationPrimary.class})
private Person primary;
#ManyToOne
#Valid
private Person secondary;
}
The Person object:
#Entity
public class Person {
#NotEmpty
private String lastName;
#NotEmpty
private String firstName;
}
The QuoteController:
#Controller
public class QuoteController {
#PostMapping("/quotes/save")
public String save(#ModelAttribute #Validated({Quote.ValidationPrimary.class}) Quote quote, BindingResult bindingResult) {
quote.getPrimary(); // this contains a Person object... as expected
quote.getSecondary(); // this also contains a Person object... which is NOT EXPECTED
...
}
}
Don't use name when using th:object use th:field instead. And your controller is a bit different than what I have seen normally. I would recommend changing it for the following code.
Form
<form th:action="#{/quotes/save}" th:object="${quote}">
<input type="text" th:field="*{primary.lastName}" />
<input type="text" th:field="*{primary.firstName}" />
</form>
Controller
#PostMapping("/quotes/save")
public String save(#ModelAttribute Quote quote, BindingResult bindingResult) {
quote.getPrimary(); // this contains a Person object... as expected
quote.getSecondary(); // this also contains a Person object... which is NOT EXPECTED
...
}
}

How to transfer the list of strings in DTO using Thymeleaf

I'm developing Spring + Thymeleaf application. I'm implementing search with multiple params. I have a form with the corresponding DTO. Here is the code of the DTO:
public class ClassSearchDto {
private String searchParam;
private Long programId;
private List<String> teacherNames;
//getters, setters and constructor are omitted
}
As you see, I have a list of strings in my DTO called teacherNames. Here is the way I'm displaying my form:
<form th:action="#{/classes/search}" method="get" th:object="${classSearchDto}">
<div class="form-group">
<input type="hidden" class="form-control"
th:value="${classSearchDto.programId}" th:field="*{programId}"/>
<label for="searchParam">Search</label>
<input type="text" class="form-control" id="searchParam" placeholder="keyword"
th:value="${classSearchDto.searchParam}" th:field="*{searchParam}"/>
<div>
<th:block th:each="name, iter ${classSearchDto.teacherNames}">
<input th:value="${name}" th:field="*{teacherNames[__${iter.index}__]}/>
</th:block>
</div>
</div>
<button class="btn btn-default" type="submit">Find</button>
</form>
I want to implement my search with help of #RequestParam annotation on the back-end. This is my controller:
#RequestMapping(value = "/search")
public String findClassByName(#RequestParam("searchParam") final String searchParam,
#RequestParam("programId") final Long programId,
#RequestParam("teacherNames") final List<String> teacherNames,
final Model model) {
...
}
The problem is that I can't get the list of teacher names in this way. I get this exception:
org.springframework.web.bind.MissingServletRequestParameterException:Required List parameter 'teacherNames' is not present
Could you please help me to transfer the list of elements in DTO to my back-end with this approach? Maybe you know how to do it correctly in another way. Thank you in advance.
I can suggest you one thing, I don't know whether it works or not. Try changing
public String findClassByName(#RequestParam("searchParam") final String searchParam,#RequestParam("programId") final Long programId,#RequestParam("teacherNames") final List<String> teacherNames,final Model model)
to
public String findClassByName(#ModelAttribute("classSearchDto") ClassSearchDto classSearchDto,#RequestParam("searchParam") String searchParam,#RequestParam("programId") Long programId,#RequestParam("teacherNames") List<String> teacherNames,Model model)

How to proceed with complex object in POST request

Hello SO I had 2 entities
Main entity
#Entity
#Table(name = "Events")
public class Event {
//Some fields ...
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "event_eventtypes" ,
joinColumns = #JoinColumn(name = "event_id"),
inverseJoinColumns = #JoinColumn(name = "event_type_id"))
private Set<EventType> eventTypes;
//Getters and setters...
Now I have a form that is created using spring form-taglib
<form:form modelAttribute="event" method="post" action="/event/registerEvent" commandName="event">
<form:label path="name">Event display name</form:label>
<form:input path="name" type="text" cssClass="form-control" placeholder="Display name"/>
<form:label path="description" >Description</form:label>
<form:textarea path="description" cssClass="form-control"/>
<form:label path="priv" cssClass="">Make private? <span style="font-family:'Open Sans', sans-serif; font-size:11px; color: dodgerblue;">(It will be seen by your friends and people who you send invitation.)</span></form:label>
<form:checkbox path="priv" cssClass="form-check-input"/>
<form:label path="age">Age limit</form:label>
<form:select path="age">
<form:options items="${age}"/>
</form:select>
<form:hidden path="lng" id="formLang" />
<form:hidden path="lat" id="formLat"/>
<%--Question appear here--%>
<form:select path="eventTypes" items="${eventTypes}" multiple="true"/>
<input type="submit" value="Submit">
Controller
#Controller
public class EventController {
private static final Logger logger = LoggerFactory.getLogger(EventController.class);
#Autowired
private EventService eventService;
#Autowired
private UserService userService;
#Autowired
private EventTypeService eventTypeService;
#RequestMapping(path = "/event/create", method = RequestMethod.GET)
public String init(ModelMap modelMap) {
List<String> tags = eventTypeService.listEventTypes().stream().map(EventType::getName).collect(Collectors.toList());
ArrayList<Integer> ageArr = new ArrayList();
ageArr.add(0);
ageArr.add(6);
ageArr.add(12);
ageArr.add(16);
ageArr.add(18);
modelMap.addAttribute("event", new Event());
modelMap.addAttribute("age", ageArr);
modelMap.addAttribute("eventTypes", tags);
return "/event/create";
}
#RequestMapping(path = "/event/registerEvent", method = RequestMethod.POST)
public String createEvent(#ModelAttribute("event") Event event, #ModelAttribute("eventTypes1") List<String> eventTypes){
event.setDate(new Date());
event.setUser(userService.getUserByUsername(
AuthenticationService.getLoggedInUser())
);
eventService.addEvent(event);
return "redirect:/";
}
When complete form with values, click submit, get error
400 The request sent by the client was syntactically incorrect.
It's because eventTypes property is of String type. How can I send that list as another parameter in controller or what should I do it?
Maybe you need a DTO to include event and eventType list both.
When I have done this I send a DTO with a list of IDs/Strings for event types to the form and then create a new event from the DTO.
For the select statements loop round each option returned in the DTO and use a service findById to retrieve each eventType and then add this to the event model.
for (String tag : eventDTO.getEventTags()) {
EventType eventTag = eventTypeService.findById(Long.valueOf(tag));
if (eventTag != null) {
event.getEventTypes().add(eventTag );
}
}
Found soulution.
Just implement jsp-based form as :
<form:form modelAttribute="event" method="post" action="/event/registerEvent" commandName="event">
...
<%--There I'm not using more jsp tabs.--%>
<select multiple name="et" id="tags">
<c:forEach items="${eventTypes}" var="e">
<option value=${e}>${e}</option>
</c:forEach>
</select>
<input type="submit" value="Submit">
</form:form>
In Controller I get parameters as request.getParameterValues("et")) - that return String[] from HttpServletRequest

Replace only selected fields using binding

I'm building simple twitter clone in Spring MVC. I want to provide edit functionality to posted messages.
Message domain object looks like this (simplified)
public class Message {
long id;
String text;
Date date;
User user;
}
I created jps form
<form:form action="edit" method="post" modelAttribute="message">
<table>
<tr>
<td><label for="text">Message: </label></td>
<td><form:textarea path="text" id="text"/></td>
</tr>
<tr>
<td><input type="submit" name="commit" value="Save" /></td>
</tr>
</table>
</form:form>
and added those method in controller class
#RequestMapping(value = "/edit", method = RequestMethod.GET)
public String showEditMessage(#RequestParam long id, Model model) {
Message message = messageService.findMessage(id);
if (message == null) {
return "404";
}
model.addAttribute("message", message);
return "users/editMessage";
}
#RequestMapping(value = "/edit", method = RequestMethod.POST)
public String editMessage(#Valid #ModelAttribute Message message, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return "/users/editMessage";
}
messageService.updateMessage(message);
return "/users/editMessage";
}
The problem is that the Message received in editMessage() contains only text field. I assume that this is expected behaviour. Can it be configured to replace fields that are only in jsp form?
I know this is only one field and I could just use #RequestParam String message, but sooner or later I will face similar problem with more than just one field.
I also have side question.
Are attributes added in showEditMessage() are passed to editMessage() method? I tried to add "id" attribute in first method, but I couldn't retrive it using "#RequestParam long id" in second.
#SessionAttributes("message")
On top of controller class solved it.

Spring MVC: Error 400 The request sent was syntactically incorrect

In short, I have a Spring 3.1 MVC project and my controller doesn't respond to the POST request when I hit the submit button.
There is no error, just no response. The controller method is not being called. I have a logger in the method that displays an INFO message and nothing is displayed (other INFO messages do display). MVC is working (at least partial) because I get a response from a "home" JSP page, but nothing for a POST.
I'm including things that seem important; tell me if there's something you'd like to see.
Controller class:
#Controller
#RequestMapping(value = "/index")
public class Test {
#Autowired
private IAdminService service;
#RequestMapping(value = "/list", method = RequestMethod.GET)
public String lister(Model model) {
model.addAttribute("matieres", service.liserMatiere());
return "Action";
}
#RequestMapping(value="/saveMat", method = RequestMethod.POST)
public ModelAndView saveMat(#ModelAttribute("matiere") Matiere m) {
ModelAndView mav = new ModelAndView();
mav.addObject("mat", m);
service.ajouterMatiere(m);
mav.setViewName("Action");
return mav;
}
and this the NouvelleMat.jsp:
<%#taglib uri="http://www.springframework.org/tags/form" prefix="f"%>
<f:form class="form-horizontal" method="POST"
action="saveMat" modelAttribute="matiere">
<table>
<tr>
<td>Name:</td>
<td><f:input path="name" maxlength="30" /></td>
</tr>
<tr>
<td>Subject:</td>
<td><f:input path="subject" maxlength="50" /></td>
</tr>
<tr>
<td valign="top">Message:</td>
<td><f:textarea path="note" cols="70" rows="20" /></td>
</tr>
<tr>
<td><f:button type="submit" value="Submit matiere" name="submit" /></td>
<td> </td>
</tr>
</table>
</f:form>
I got Etat HTTP 400 The request sent by the client was syntactically incorrect
this is the matiere entity:
#Entity
public class Matiere implements Serializable{
#SuppressWarnings("unused")
private static final long serialVersionUID = 1L;
#Id
private String name;
private String subject;
private String note;
getters and setters....
}
First of all, i think slashes at the beginning of the method RequestMapping are unnecessary, they will be relative to classe's "/index".
But to debug such problem, You should check out the request your browser sends to the controller.
If You are using Chrome, go with ctrl+shift+c to open the console, or F12 for firebug in Firefox, or console in IE. Go to network, and check out what is Your browser sending. You will probably be able to tell what is the mistake by looking at the request body and headers.

Resources