Spring MVC Parameter Binding: From Forms to JSON Payloads
Handling Standard Form Parameters
A basic HTML form submits data using URL-encoded parameters. The input field name attributes determine the parameter names transmitted to the server.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Role Management</title>
</head>
<body>
<form id="userForm" action="/api/roles/submit">
<table>
<tr>
<td><label for="roleName">Role Name</label></td>
<td><input id="roleName" name="roleName" /></td>
</tr>
<tr>
<td><label for="description">Description</label></td>
<td><input id="description" name="description" /></td>
</tr>
<tr>
<td></td>
<td align="right"><input type="submit" value="Submit"/></td>
</tr>
</table>
</form>
</body>
</html>
Controller methods can receive these parameters directly when the parameter names match the form field names.
@Controller
@RequestMapping("/api/roles")
public class RoleController {
@RequestMapping("/submit")
public ModelAndView processRoleForm(String roleName, String description) {
System.out.println("Received role: " + roleName);
System.out.println("Description: " + description);
ModelAndView response = new ModelAndView();
response.setViewName("confirmation");
return response;
}
}
POJO-Based Parameter Binding
Spring MVC automatically maps request parameters to POJO properties when names align. This approach reduces method signature complexity for forms with multiple fields.
public class RoleDTO {
private String roleName;
private String description;
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
@RequestMapping("/submitPojo")
public ModelAndView processPojoRole(RoleDTO roleData) {
System.out.println("Role: " + roleData.getRoleName());
System.out.println("Description: " + roleData.getDescription());
ModelAndView response = new ModelAndView();
response.setViewName("dashboard");
return response;
}
Handling Mismatched Parameter Names
When client-side parameter names differ from server-side method signatures, @RequestParam explicitly maps incoming parameters to method arguments.
@RequestMapping("/submitMapped")
public ModelAndView processMappedParams(
@RequestParam("roleName") String roleTitle,
@RequestParam("description") String roleNotes) {
System.out.println("Role title: " + roleTitle);
System.out.println("Notes: " + roleNotes);
ModelAndView response = new ModelAndView();
response.setViewName("confirmation");
return response;
}
Path Variable Extraction
RESTful URLs often embed parameters directly in the path. @PathVariable extracts these segments for use in controller methods.
@RequestMapping("/details/{roleId}")
public ModelAndView getRoleDetails(@PathVariable("roleId") Long identifier) {
System.out.println("Fetching role: " + identifier);
ModelAndView response = new ModelAndView();
response.setViewName("roleDetails");
response.addObject("roleId", identifier);
return response;
}
Access URL: /api/roles/details/42
JSON Payload Processing
Modern applications frequently transmit complex data structures as JSON. Spring MVC requires @RequestBody to bind JSON payloads to method parameters.
Nested Data Transfer Objects
public class PaginationConfig {
private int offset;
private int size;
// Accessor methods
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
}
public class RoleSearchRequest {
private String roleTitle;
private String notes;
private PaginationConfig pagination;
// Accessor methods
public String getRoleTitle() {
return roleTitle;
}
public void setRoleTitle(String roleTitle) {
this.roleTitle = roleTitle;
}
public String getNotes() {
return notes;
}
public void setNotes(String notes) {
this.notes = notes;
}
public PaginationConfig getPagination() {
return pagination;
}
public void setPagination(PaginationConfig pagination) {
this.pagination = pagination;
}
}
Client-Side JSON Transmission
$(document).ready(function() {
var searchPayload = {
roleTitle: "administrator",
notes: "system configuration",
pagination: {
offset: 0,
size: 25
}
};
$.ajax({
url: "./api/roles/search",
method: "POST",
contentType: "application/json",
data: JSON.stringify(searchPayload),
success: function(response) {
console.log("Search results received");
}
});
});
Server-Side JSON Handling
@RequestMapping(value = "/search", method = RequestMethod.POST)
public ModelAndView searchRoles(@RequestBody RoleSearchRequest request) {
System.out.println("Searching for: " + request.getRoleTitle());
System.out.println("Pagination: " + request.getPagination());
ModelAndView response = new ModelAndView();
response.setViewName("searchResults");
return response;
}
Array and Collection Processing
Deleting Multiple Records
$(document).ready(function() {
var removalList = [101, 102, 103, 104];
$.ajax({
url: "/api/roles/bulkDelete",
method: "POST",
contentType: "application/json",
data: JSON.stringify(removalList),
success: function(result) {
console.log("Deletion complete");
}
});
});
@RequestMapping("/bulkDelete")
public ModelAndView deleteSelected(@RequestBody List<Long> identifiers) {
ModelAndView response = new ModelAndView();
System.out.println("Deleting " + identifiers.size() + " records");
response.setView(new MappingJackson2JsonView());
response.addObject("deletedCount", identifiers.size());
return response;
}
Bulk Creation
$(document).ready(function() {
var newRoles = [
{ roleTitle: "moderator_01", notes: "content management" },
{ roleTitle: "moderator_02", notes: "user moderation" },
{ roleTitle: "moderator_03", notes: "review workflows" }
];
$.ajax({
url: "./api/roles/bulkCreate",
method: "POST",
contentType: "application/json",
data: JSON.stringify(newRoles),
success: function(response) {
console.log("Bulk creation successful");
}
});
});
@RequestMapping("/bulkCreate")
public ModelAndView createMultiple(@RequestBody List<RoleDTO> roles) {
ModelAndView response = new ModelAndView();
response.setView(new MappingJackson2JsonView());
response.addObject("createdCount", roles.size());
return response;
}
Form Serialization
JavaScript's serialize() method converts form data into URL-encoded strings. This approach maintains traditional form parameter structures while enabling AJAX submissions.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Serialized Form</title>
<script src="https://code.jquery.com/jquery-3.2.0.js"></script>
</head>
<body>
<form id="roleForm">
<table>
<tr>
<td><label for="roleName">Role Name</label></td>
<td><input id="roleName" name="roleName" /></td>
</tr>
<tr>
<td><label for="description">Description</label></td>
<td><input id="description" name="description" /></td>
</tr>
<tr>
<td></td>
<td align="right"><input id="submitBtn" type="button" value="Submit"/></td>
</tr>
</table>
</form>
<script>
$(document).ready(function() {
$("#submitBtn").click(function() {
var formData = $("#roleForm").serialize();
$.post({
url: "/api/roles/serializeSubmit",
data: formData,
success: function(response) {
console.log("Form submitted successfully");
}
});
});
});
</script>
</body>
</html>
Serialized data appears as: roleName=administrator&description=system+admin
@RequestMapping("/serializeSubmit")
public ModelAndView handleSerialized(String roleName, String description) {
System.out.println("Form submission received");
System.out.println("Role: " + roleName);
System.out.println("Description: " + description);
ModelAndView response = new ModelAndView();
response.setViewName("success");
return response;
}