How to edit request parameters received by post in SpringBoot in a handler method - spring

In a SpringBoot controller, is there a way to edit request parameters received in post in a handler method and forward them to another handler method?
sample.html
<form id="sample" method="post" th:action="#{/methodA}">
<input type="submit" name="dummykey" value="param_A" class="button" form="sample" />
</form>
Controller
// Handler Method A
#RequestMapping(value = "/methodA", params = "dummykey=param_A")
public String methodA(){
/* edit RequestParameter: dummykey = param_B */
return "forward:/methodB";
}
// Handler Method B
#RequestMapping(value = "/methodB", params = "dummykey=param_B")
public String methodB(){
...
}

Related

Spring mvc form submission bindingresult throws error

So my bindingresult throws an error but I'm not able to see it for some reason and I'm not able to figure out what the problem is. I'm guessing the problem lies with the variable targetDate where there is a problem the type. I've pasted my controller and JSP code below. Any help is appreciated!
#Controller
public class ToDoController {
#Autowired
private ToDoService service;
// All date parameters displayed as mm/DD/yyyy
#InitBinder
protected void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("mm/DD/yyyy");
binder.registerCustomEditor(Date.class, new CustomDateEditor(
dateFormat, false));
}
#RequestMapping(value = "/list-todo", method= RequestMethod.GET)
// HttpSession allows access to the session
public String showToDo(ModelMap model, HttpSession httpSession) {
String user = (String) httpSession.getAttribute("name");
model.addAttribute("todos", service.retrieveTodos(user));
return "list-todos";
}
// redirect to update form
#RequestMapping(value = "/update-todo", method= RequestMethod.GET)
public String getUpdateForm(ModelMap model, #RequestParam int id) {
System.out.println("ID " + id);
// To work with command bean
model.addAttribute("id", id);
model.addAttribute("todo", service.retrieveTodo(id-1));
return "updateToDo";
}
// What does Valid do?
#RequestMapping(value = "/update-todo", method= RequestMethod.POST)
public String submitUpdate(ModelMap model, #Valid ToDo todo, BindingResult result) {
if (result.hasErrors()) {
System.out.println("ERROR" + result.getAllErrors());
// Redirect and pass on the id value
return "redirect:/update-todo?id=" + todo.getId();
}
System.out.println("Update todo" + todo);
service.updateToDo(todo);
model.clear();
return "redirect:/list-todo";
}
// Will be executed first
#RequestMapping(value = "/add-todo", method= RequestMethod.GET)
public String showAddForm(ModelMap model) {
model.addAttribute("todo", new ToDo());
return "addToDo";
}
/*
* Will be executed after form is submitted
* #Valid ToDo - command bean from addToDo.jsp.
* #Valid to validate the information
* #BindingResult showcases the result of the validation
*/
#RequestMapping(value = "/add-todo", method= RequestMethod.POST)
public String submitAddForm(ModelMap model , #Valid ToDo todo, HttpSession httpSession, BindingResult result) {
System.out.println("running" + result);
// If there is validation error , return to addToDos page for user to fix the error
if (result.hasErrors()) {
return "redirect:/showAddForm?id=?" + todo.getId();
}
String user = (String) httpSession.getAttribute("name");
service.addTodo(user, todo.getDescription(), todo.getTargetDate(), false);
// Clears the url e.g. name?=jyj123
model.clear();
// return to the url which executes the showToDO
return "redirect:/list-todo";
}
// delete to do entry
#RequestMapping(value = "/delete-todo", method= RequestMethod.GET)
public String deleteToDo(ModelMap model, #RequestParam int id) {
service.deleteTodo(id);
model.clear();
return "redirect:/list-todo"; }
}
My JSP
<%# taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%# include file = "common/header.jspf" %>
<%# include file = "common/nav.jspf" %>
<div class="container">
<H1>Update your task!</H1>
<form:form method="POST" commandName="todo">
<!-- Carry on the id value -->
<form:hidden path = "id"/>
<form:hidden path = "user"/>
<fieldset class="form-group">
<form:label path="description">Description:</form:label>
<form:input path="description" type="text" class="form-control"
required="required" />
<form:errors path="description" cssClass="text-warning" />
</fieldset>
<fieldset class="form-group">
<form:label path="targetDate">Target Date</form:label>
<form:input path="targetDate" type="text" class="form-control"
required="required" />
<form:errors path="targetDate" cssClass="text-warning" />
</fieldset>
<fieldset class="form-group">
<form:radiobutton path="completion" value="true" />
<form:radiobutton path="completion" value="false" />
</fieldset>
<button type="submit" class="btn btn-success" >Submit Update</button>
</form:form>
<spring:hasBindErrors htmlEscape="true" name="todo">
<c:if test="${errors.errorCount gt 0}">
<h4>The error list :</h4>
<font color="red">
<c:forEach items="${errors.allErrors}" var="error">
<spring:message code="${error.code}"
arguments="${error.arguments}"
text="${error.defaultMessage}"/><br/>
</c:forEach>
</font>
</c:if>
</spring:hasBindErrors>
</div>
<%# include file = "common/footer.jspf" %>
EDIT: bindingresult throws this
ERROR[Field error in object 'todo' on field 'targetDate': rejected value [Tue Jan 05 00:00:00 SGT 2021]; codes [typeMismatch.todo.targetDate,typeMismatch.targetDate,typeMismatch.java.util.Date,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [todo.targetDate,targetDate]; arguments []; default message [targetDate]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date' for property 'targetDate'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.util.Date] for value 'Tue Jan 05 00:00:00 SGT 2021'; nested exception is java.lang.IllegalArgumentException]]
In your jsp you submit the form to "todo", not "update-todo". It would be nice to see your ToDo bean. Also: result.getAllErrors().

HttpStatus 406 "not acceptable" when returning Flux<String> on Spring 4.3.7 MVC Controller to a EventSource in html page

Im trying to make a timer of how much time a page is open via spring webflux, i had made this example work on springboot but with spring mvc is not working, so i know the code does work. may i have to set up something im not aware of?
Controller:
#Controller
public class HomeController {
#RequestMapping(value = "/", method = RequestMethod.GET)
public String home(){
return "home";
}
#RequestMapping(value = "/timer", method = RequestMethod.GET, produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public #ResponseBody Flux<String> startTimer(){
Instant startTime = Instant.now();
return Flux.fromStream(
Stream.generate(() -> calculateTimeMethod(startTime, Instant.now()))
).delayElements(Duration.ofSeconds(1));
}
}
JSP home.jsp :
<html>
<head>
<title> Home </title>
</head>
<body>
<label> tiempo trascurrido </label>
<label id="timer"></label>
<script>
var eventSource = new EventSource("url/timer");
eventSource.onmessage = function ( event ) {
document.getElementById("timer").innerText = event.data;
};
</script>
</body>
</html>
home page load but timer doesnt start, console output shows: Failed to load resource: the server responded with a status of 406 (No Aceptable)

how to pass binding result object in RedirectView

I am new to spring and I am trying to redirect to the same page if the form has errors. I am successful redirecting that but the problem is the form has a dynamic drop down and the values are not rendered when I return a model object. or when I do ModelAndView(new RedirectView("lookup")) I am able to render the dropdown values but I am unable to display the error messages.
code: jsp: lookup.jsp
<form:form name="lookupForm" method="POST" action="search.html" enctype="multipart/form-data" >
<div style= "color:red">
<form:errors path="empId" /></br>
<form:errors path="companyName" />
</div>
<form:label path="companyName">Company</form:label>
<select name= "companyList" path="companyName">
<option value="Select">Select</option>
<c:forEach var="element" items="${listCompany}">
<option value="${element.companyName}">${element.companyName}</option>
</c:forEach>
</select>
<form:label path="empId">Employee ID</form:label>
<form:textarea name="empId" path="empId" rows="5" cols="30"/>
<input type="submit" name="search" value="Search"/>
Controller:
#RequestMapping(value = "/lookup", method = RequestMethod.GET)
public ModelAndView lookupFormView(ModelAndView model,BindingResult result) {
List<Employee> listCompany = employeeDAO.getCompany();
Employee newContact = new Employee();
model.addObject("listCompany", listCompany);
model.addObject("command", newContact);
model.setViewName("lookup");
return model;
}
#RequestMapping(value = "/search", params = "search", method = RequestMethod.POST)
public ModelAndView lookupEmployee(HttpServletRequest request,HttpServletResponse response, #ModelAttribute("command") Employee emp,BindingResult result) throws Exception{
empValidator.validate(emp, result);
String lookupEmpId = null;
if (result.hasErrors()) {
return new ModelAndView(new RedirectView("lookup"));
//return new ModelAndView("lookup");
}
else{
-----
if i use this return new ModelAndView(new RedirectView("lookup")); its redirecting to lookup.jsp ,rendering the drop down valus but the error messages are not getting displayed.
if i use this return new ModelAndView("lookup"); its redirecting to lookup.jsp ,errors are displayed but the dynamic dropdown values are not rendered.
Please help me in finding which part of my code is wrong or Is their a way to display error messages and render dynamic dropdown values
Just return the view name and set the error message in the Model itself. Simply check the error message in the JSP if found then show it.
sample code:
#RequestMapping(value = "/search", params = "search", method = RequestMethod.POST)
public String lookupEmployee(HttpServletRequest request,HttpServletResponse response,
#ModelAttribute("command") Employee emp,BindingResult result) throws Exception{
empValidator.validate(emp, result);
String lookupEmpId = null;
if (result.hasErrors()) {
emp.setErrorMessage("Your error message.");
return "lookup";
}else{
...
return "successPage";
}
}

Spring portlet ajax call, No parameter found

I am trying to build a sample spring portlet, with LR 6.2 GA1.
Below is the source for the same https://docs.google.com/file/d/0By1kU5o_jlrublhUNXIxQ24wODQ/edit
On the ajax the parameters are not being fetched.The parameters always remain blank.
#Controller(value = "ProjectSearch")
#RequestMapping("VIEW")
public class ProjectSearch {
Log log_ = LogFactoryUtil.getLog(ProjectSearch.class);
#RenderMapping
public String handleRenderRequest(final RenderRequest request,
final RenderResponse response, Model model) {
System.out.println("ProjectSearch.handleRenderRequest()");
return "search_form";
}
#ResourceMapping("getProjectNameSuggestion")
public void getNameSuggestion(ResourceRequest request,
ResourceResponse response) throws IOException {
Map<String, String[]> map = request.getParameterMap();
for (Map.Entry<String, String[]> element : map.entrySet()) {
log_.info(element.getKey());
}
String entityName = ParamUtil.getString(request, "query");
log_.info("Entity name==>" + entityName);
}
}
#RenderMapping
public String handleRenderRequest(final RenderRequest request,
final RenderResponse response, Model model) {
System.out.println("ProjectSearch.handleRenderRequest()");
return "search_form";
}
#ResourceMapping("getProjectNameSuggestion")
public void getNameSuggestion(ResourceRequest request,
ResourceResponse response) throws IOException {
Map<String, String[]> map = request.getParameterMap();
for (Map.Entry<String, String[]> element : map.entrySet()) {
log_.info(element.getKey());
}
String entityName = ParamUtil.getString(request, "query");
log_.info("Entity name==>" + entityName);
}
}
Output-->05:23:24,148 INFO [http-bio-8080-exec-119][ProjectSearch:41] Entity name==>
Could any body tell me what is that I am doing wrong??
Solution:
Configure Requires Name Spaced Parameters to false in liferay-portlet.xml
Now need to do require Name spaced parameters to false then only form data is mapped in Action Request and Render Request. And also form data will be binding to model object or command object.
The following is configuration we need to do in liferay-portlet.xml file
<requires-namespaced-parameters>false</requires-namespaced-parameters>
Required Name Space Parameter Behavior in Liferay
Liferay 6.2 we have to append portlet Name space for every name of input element i.e. form input elements or request parameters names otherwise portlet action class ignore the parameters which does not have portlet name space to names.
Scenario
Jsp page
In the following form we are not appending portlet name space to form input element names.
<portlet:actionURL var="addEmployeeActionURL" name="addEmployee">
<portlet:param name="<%=ActionRequest.ACTION_NAME%>" value="addEmployee"/>
</portlet:actionURL>
<form action="<%=addEmployeeActionURL%>" name="emplyeeForm" method="POST">
Employee Name<br/>
<input type="text" name="employeeName" id="employeeName"/><br/>
Employee Address<br/>
<input type="text" name="employeeAddress" id="employeeName"/><br/>
<input type="submit" name="addEmployee" id="addEmployee" value="Add Employee"/>
</form>
Portlet Class Action Method
public class EmplyeePortletAction extends MVCPortlet {
public void addEmployee(ActionRequest actionRequest,
ActionResponse actionResponse) throws IOException, PortletException {
String employeeName=ParamUtil.getString(actionRequest,"employeeName");
String employeeAddress=ParamUtil.getString(actionRequest,"employeeAddress");
}
}
In above case employeeName and employeeAddress form input data not accessible in portlet class action .The form elements name are not appended with portlet name space such scenarios portlet class ignore those request parameters or form inputs
Solution:1
Need to append tag to every input element name.
Jsp page
<portlet:actionURL var="addEmployeeActionURL" name="addEmployee">
<portlet:param name="<%=ActionRequest.ACTION_NAME%>" value="addEmployee"/>
<portlet:param name="requestParam" value=" requestParamValue"/>
</portlet:actionURL>
<form action="<%=addEmployeeActionURL%>" name="emplyeeForm" method="POST">
Employee Name<br/>
<input type="text" name="<portlet:namespace/>employeeName" id="<portlet:namespace/>employeeName"/><br/>
Employee Address<br/>
<input type="text" name="<portlet:namespace/>employeeAddress" id="<portlet:namespace/>employeeName"/><br/>
<input type="submit" name="addEmployee" id="addEmployee" value="Add Employee"/>
</form>
Portlet Class Action Method
public class EmplyeePortletAction extends MVCPortlet {
public void addEmployee(ActionRequest actionRequest,
ActionResponse actionResponse) throws IOException, PortletException {
String employeeName=ParamUtil.getString(actionRequest,"employeeName");
String employeeAddress=ParamUtil.getString(actionRequest,"employeeAddress");
String requestParamValue=ParamUtil.getString(actionRequest,"requestParam");
}
}
Solution:2
We can make it false to following tag value in liferay-portlet.xml file
<requires-namespaced-parameters>false</requires-namespaced-parameters>
Solution:3
We can use alloy tag library form tags. When we use AUI tags it will append portlet name space to each input element name.
Jsp page
<%# taglib uri="http://liferay.com/tld/aui" prefix="aui" %>
<aui:input type="text" name="employeeAddress" id="employeeName"/><br/>
<aui:input type="submit" name="addEmployee" id="addEmployee" value="Add Employee"/
<input type="text" name="<portlet:namespace/>employeeAddress" id="<portlet:namespace/>employeeName"/>
Is same As
<aui:input type="text" name="employeeAddress" id="employeeName"/>
http://www.liferaysavvy.com/2013/12/liferay-spring-portlet.html
http://www.liferaysavvy.com/2014/04/liferay-mvc-portlet-development.html

Forward a POST request with additional params

Is there a way to forward a POST request from one controller to another with additional param(s)?
Let's say I have a form like this:
<form action"${contextPath}/controller1/post">
<input name="field1" type="text"/>
<input name="field2" type="text"/>
<input value="submit" type="submit"/>
</form>
This form will post to controller1.post() method.
But now I have another controller - controller2 also with a post method.
I now want to post to controller2.post so I could add some parameters to the request before forwarding to controller1.
Is there a way to do this?
You can try that if this is what you are looking for
#RequestMapping(value = "/controller1/{id}", method = RequestMethod.Post)
public void doSomething(
#PathVariable Long id,
HttpServletRequest request,
HttpServletResponse response) {
request.setAttribute("id",Id);
RequestDispatcher rd = request.getRequestDispatcher("your url/controller2");
rd.forward(request, response);
}
And after in controller2
#RequestMapping(value = "/controller2", method = RequestMethod.Post)
public string doSomething2(Model model,
HttpServletRequest request,
HttpServletResponse response) {
model.addAttribute("id", request.getAttribute("id"));
return "myView";
}

Resources