I have a form that can be dynamically edited - the user can add/remove rows and information
The structure is this:
every element in the multidimensional array has the following elements:
id_material
id_detail
and in the rows that can be added/removed within the form:
name
quantity
file
the form:
<input type="hidden" name="myData[id_material][0]" value="123">
<input type="hidden" name="myData[id_detail][0]" value="456">
<input type="text" name="myData[ime_detail][0][1]" value="foo">
<input type="text" name="myData[quantity][0][1]" value="1">
<input type="file" name="myData[file][0][1]" accept=".pdf, .jpg, .dxf">
<input type="hidden" name="myData[id_material][1]" value="123">
<input type="hidden" name="myData[id_detail][1]" value="456">
<input type="text" name="myData[ime_detail][1][1]" value="foo">
<input type="text" name="myData[quantity][1][1]" value="1">
<input type="file" name="myData[file][1][1]" accept=".pdf, .jpg, .dxf">
<input type="text" name="myData[ime_detail][1][2]" value="bar">
<input type="text" name="myData[quantity][1][2]" value="2">
<input type="file" name="myData[file][1][2]" accept=".pdf, .jpg, .dxf">
My Spring controller:
#RequestMapping(value = myURL, method = RequestMethod.POST, consumes = {"multipart/form-data"})
public #ResponseBody error save(ModelMap model, HttpServletRequest req,
HttpSession session, HttpServletResponse resp,
#PathVariable("locale") String loc,
#RequestParam Map<String, Object> params) {
System.out.println("save() method invoked");
return null;
}
However, the controller method is never invoked when the form is submited. I have tried wrapping the parameters in a class like this:
public class CustomWrapper {
private Map<String, Object> customMap= new HashMap<String, Object>();
public Map<String, Object> getCustomMap() {
return customMap;
}
public void setCustomMap(Map<String, Object> customMap) {
this.customMap = customMap;
}
}
still its not invoked. Do you guys have any idea how to properly submit the form?
Related
In my thymeleaf template I add a hidden field for a field on my form object:
<form action="#" th:action="#{/admin/endpoint}" th:object="${monkey}" method="post" class="form-horizontal" role="form">
<input type="hidden" th:field="*{id}" />
<input type="hidden" th:field="*{banana}" />
...
</form>
Created html output:
<input type="hidden" id="id" name="id" value="55">
<input type="hidden" id="banana" name="banana" value="3">
Posting this form through a web browser works as expected, but
when I try to test this with MockMvc only the id field gets set:
mvc.perform(post("/endpoint")
.param("id", String.valueOf(monkey.getId()))
.param("banana", String.valueOf(monkey.getBanana().getId())))
In my controller I let Spring transform the form for me:
#RequestMapping(value = { "/admin/endpoint" }, method = RequestMethod.POST)
public String updateMonkey(Model model, #Valid Monkey monkey, BindingResult br) {
System.out.println(monkey.getId()) // -> 55
System.out.println(monkey.getBanana()) // -> null
...
}
What do I have to change so the field "banana" gets properly initialized from the id in my test?
I have a page with two forms, and want to add object from first form when submitting second one. Basically it looks like this:
First form:
<form action="#" method="POST" enctype="multipart/form-data" th:action="#{/foo}" th:object="${prop1}" id="form1">
<input type="file" name="file" class="form-control"/>
<input type="text" th:value="${prop1.taskSheetName}" name="taskSheetName"/>
<input type="number" th:value="${prop1.descriptionColumnPosition}" name="descriptionColumnPosition"/>
</form>
Second form:
<form th:if="${resourceId}" action="#" method=" th:object="${prop2}" id="prop2" th:action="#{/foo/{id}(id=${resourceId})}">
<input type="url" th:value="${prop2.url}" name="url"/>
<input type="text" th:value="${prop2.username}" name="username"/>
<input type="password" th:value="${prop2.password}" name="password"/>
</form>
And controller methods:
#RequestMapping(value = "/foo", method = POST)
public String uploadFile(#RequestParam("file") MultipartFile file, final ExcelProperties properties, final Model model) {
//some logic here
}
#RequestMapping(value = "/process/{id}", method = POST)
public String processResource(#PathVariable("id") String id, final Prop2 prop2, final Prop1 prop1, final Model model) {
}
And I need to pass the values from first form values to second method with second form values, but it passes empty form object. I tried to add
<div th:with="p1=${prop1}">
since I know that this data is present in page, but it didn't help.
If this even possible or should I just give up and write custom submit handler in javascript?
According to MDN, it's impossible to attach 1 input into 2 forms,
You need to do some work with JavaScript.
I'm trying to implement LTI in our education platform to connect with QTIWoks in Java.
I have a simple tool consumer that generates the following HTML Form:
<html>
<head> </head>
<body>
<form action="http://192.168.0.114:8080/qtiworks-engine/lti/domainlaunch" name="ltiLaunchForm" id="ltiLaunchForm" method="post" target="basicltiLaunchFrame" enctype="application/x-www-form-urlencoded" style="display: block;">
<input type="hidden" name="context_id" value="cid-00113">
<input type="hidden" name="context_label" value="SI106">
<input type="hidden" name="context_title" value="Design of Personal Environments 1">
<input type="hidden" name="ext_note" value="Instructor from first course">
<input type="hidden" name="launch_presentation_locale" value="en_us">
<input type="hidden" name="lis_person_contact_email_primary" value="sian#imscert.org">
<input type="hidden" name="lis_person_name_family" value="Instructor">
<input type="hidden" name="lis_person_name_given" value="Siân">
<input type="hidden" name="lis_person_sourcedid" value="school.edu:user">
<input type="hidden" name="resource_link_description" value="This learning space is private">
<input type="hidden" name="resource_link_id" value="res-0012612">
<input type="hidden" name="resource_link_title" value="My Weekly Wiki">
<input type="hidden" name="roles" value="Instructor">
<input type="hidden" name="tool_consumer_info_product_family_code" value="sakai-unit">
<input type="hidden" name="tool_consumer_info_version" value="0.9">
<input type="hidden" name="tool_consumer_instance_description" value="University of School (LMSng)">
<input type="hidden" name="tool_consumer_instance_guid" value="lmsng.school.edu">
<input type="hidden" name="user_id" value="user-0016">
<input type="hidden" name="oauth_callback" value="about:blank">
<input type="hidden" name="custom_simple_key" value="custom_simple_value">
<input type="hidden" name="custom_complex____________key" value="Complex!##$^*(){}[]½Value">
<input type="hidden" name="lti_version" value="LTI-1p0">
<input type="hidden" name="lti_message_type" value="basic-lti-launch-request">
<input type="hidden" name="oauth_version" value="1.0">
<input type="hidden" name="oauth_nonce" value="Z2WVNEPUZkzsolOe4hRvKbkXtOSmYiyw">
<input type="hidden" name="oauth_timestamp" value="1429793062">
<input type="hidden" name="oauth_consumer_key" value="feras">
<input type="hidden" name="oauth_signature_method" value="HMAC-SHA1">
<input type="hidden" name="oauth_signature" value="g908qTtVGh8MsOgVUdarVlSBmC0=">
<input type="hidden" name="ext_submit" value="Finish Launch">
</form><iframe name="basicltiLaunchFrame" id="basicltiLaunchFrame" src="" width="100%" height="900" scrolling="auto" frameborder="1" transparency="">
</iframe>
<script type="text/javascript">
document.getElementById("ltiLaunchForm").style.display = "none";
nei = document.createElement('input');
nei.setAttribute('type', 'hidden');
nei.setAttribute('name', 'ext_submit');
nei.setAttribute('value', 'FinishLaunch');
document.getElementById("ltiLaunchForm").appendChild(nei);
document.ltiLaunchForm.submit();
</script>
</body>
</html>
then it calls the dominlaunch from qtiworks
#RequestMapping(value="/domainlaunch", method=RequestMethod.POST)
public String ltiDomainLevelLaunch(final HttpSession httpSession, final HttpServletRequest request,
final HttpServletResponse response)
throws IOException {
/* Decode LTI launch request, and bail out on error */
final DecodedLtiLaunch decodedLtiLaunch = ltiLaunchService.decodeLtiLaunchData(request, LtiLaunchType.DOMAIN);
if (decodedLtiLaunch.isError()) {
response.sendError(decodedLtiLaunch.getErrorCode(), decodedLtiLaunch.getErrorMessage());
return null;
}
final LtiLaunchData ltiLaunchData = decodedLtiLaunch.getLtiLaunchData();
/* Make sure this is a domain launch */
final LtiUser ltiUser = decodedLtiLaunch.getLtiUser();
final LtiDomain ltiDomain = ltiUser.getLtiDomain();
if (ltiDomain==null) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "The tool consumer has attempted a domain-level launch using a link-level key");
return null;
}
/* Extract/create the corresponding LtiResource for this launch */
final LtiResource ltiResource = ltiLaunchService.provideLtiResource(decodedLtiLaunch); /* (May be null for candidates) */
final UserRole userRole = ltiUser.getUserRole();
if (userRole==UserRole.INSTRUCTOR) {
/* If user is an instructor, we'll forward to the LTI instructor MVC after
* "authenticating" the user by creating and storing an LtiDomainTicket
* in the session */
final LtiAuthenticationTicket ltiDomainTicket = new LtiAuthenticationTicket(ltiUser.getId(), ltiResource.getId(),ltiLaunchData.getLaunchPresentationReturnUrl());
LtiResourceAuthenticationFilter.authenticateUserForResource(httpSession, ltiDomainTicket);
return "redirect:/lti/resource/" + ltiResource.getId();
}
else if (userRole==UserRole.CANDIDATE) {
/* If user is a candidate, then we'll launch/reuse a candidate session */
if (ltiResource==null) {
return "candidateLaunchError";
}
/* Extract relevant data */
final String returnUrl = ltiLaunchData.getLaunchPresentationReturnUrl();
final String lisOutcomeServiceUrl = ltiLaunchData.getLisOutcomeServiceUrl();
final String lisResultSourcedid = ltiLaunchData.getLisResultSourcedid();
/* Launch and redirect to session */
try {
final CandidateSessionTicket candidateSessionTicket = candidateSessionLaunchService.launchDomainLevelLtiCandidateSession(httpSession,
ltiUser, ltiResource, returnUrl, lisOutcomeServiceUrl, lisResultSourcedid);
return GlobalRouter.buildSessionStartRedirect(candidateSessionTicket);
}
catch (final CandidateException e) {
return "candidateLaunchError";
}
}
else {
throw new QtiWorksLogicException("Unexpected LTI userRole " + userRole);
}
}
the problem is decodedLtiLaunch.isError() returns true and my request is not performed.
I debugged the problem and found that HttpServletRequest request has no item in parameterMap
however, it's working well when the request comes from moodle (request's parameterMap has the passed params)
how can I solve this please?
thanks in advance.
Without knowing what the exact error code you are seeing is, I am going to make a very strong guess that your signature is bad
Since you are using JAVA I would suggest that you utilize the basiclti-util library that IMSGlobal provides to generate a signature
Add the following dependency
<dependency>
<groupId>org.imsglobal</groupId>
<artifactId>basiclti-util</artifactId>
<version>1.1.2</version>
</dependency>
Then use the following code to generate the signature
Map<String, String> signedParameters = new LtiOauthSigner()
.signParameters(parameters, key, secret, url, "POST");
Then take all of the key-value pairs in the signedParameters map, and use that to construct the form input tags you have in your example.
I'm new to servlets and jsp files, and I encountered the following problem:
I have the following jsp form file:
<FORM action="http://myApp/register" method="post">
<P>
First name: <INPUT type="text" name="firstname"><BR>
Last name: <INPUT type="text" name="lastname"><BR>
email: <INPUT type="text" name="email"><BR>
<INPUT type="radio" name="sex" value="Male"> Male<BR>
<INPUT type="radio" name="sex" value="Female"> Female<BR>
<INPUT type="submit" value="Send"> <INPUT type="reset">
</P>
</FORM>
and a servlet which handles a doPost request on the url above.
I want to give the values of the form (such as the first name and last name) to the doPost request.
Any ideas?
Thanks a lot! :)
You can get all the parameters by their name as request.getParameters("firstname") to get the value of the input fields.
public class ServletClass extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastName");
// and so on.....
}
}
I have this html spring form:
<form:form action="addVacancy" modelAttribute="myVacancy">
<form:label path="name">name</form:label>
<form:input path="name" ></form:input>
<form:errors path="name" cssClass="error" />
<br>
<form:label path="description">description</form:label>
<form:input path="description" id="nameInput"></form:input>
<form:errors path="description" cssClass="error" />
<br>
<form:label path="date">date</form:label>
<input type="date" name="date" />
<form:errors path="date" cssClass="error" />
<br>
<input type="submit" value="add" />
</form:form>
I handle this form by this method:
#RequestMapping("/addVacancy")
public ModelAndView addVacancy(#ModelAttribute("myVacancy") #Valid Vacancy vacancy,BindingResult result, Model model,RedirectAttributes redirectAttributes){
if(result.hasErrors()){
model.addAttribute("message","validation error");
return new ModelAndView("vacancyDetailsAdd");
}
vacancyService.add(vacancy);
ModelAndView mv = new ModelAndView("redirect:goToVacancyDetails");
mv.addObject("idVacancy", vacancy.getId());
redirectAttributes.addAttribute("message", "added correctly at "+ new Date());
return mv;
}
How to make the same request, which is obtained after submitting the form. This must be done by means of MockMvc.
#Test
public void testMethod(){
MockHttpServletRequestBuilder request = MockMvcRequestBuilders.get("/addVacancy");
//what must I write here?
ResultActions result = mockMvc.perform(request);
}
I very confused.
When a browser needs to submit a form, it typically serializes the form <input> fields as url-encoded parameters. Therefore, when you want to mock an HttpServletRequest, you need to add those same parameters to the request.
request.param("name", "some value")
.param("description", "description value")
.param("date", "some acceptable representation of date");
The DispatcherServlet will use these parameters to create a Vacancy instance to pass as an argument to your handler method.
You can pass in the required #ModelAttribute object with the .flashAttr() method like so:
request.flashAttr("myVacancy", new Vacancy()));