java
44 lines · 9 steps
Customizing form binding in a Spring MVC controller
An @InitBinder method cleans and constrains request parameters before they populate a command object, then a POST handler validates and saves it.
Explained by
highlit
1@Controller
2@RequestMapping("/employees")
3public class EmployeeController {
4
5 private final EmployeeService employeeService;
6
7 public EmployeeController(EmployeeService employeeService) {
8 this.employeeService = employeeService;
9 }
10
11 @InitBinder
12 public void initBinder(WebDataBinder binder) {
13 binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
14
15 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
16 dateFormat.setLenient(false);
17 binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
18
19 binder.registerCustomEditor(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true) {
20 @Override
21 public void setAsText(String text) {
22 if (text == null || text.isBlank()) {
23 setValue(null);
24 return;
25 }
26 String normalized = text.trim().replace(",", "").replace("$", "");
27 setValue(new BigDecimal(normalized).setScale(2, RoundingMode.HALF_UP));
28 }
29 });
30
31 binder.setDisallowedFields("id", "createdAt");
32 }
33
34 @PostMapping
35 public String create(@Valid @ModelAttribute("employee") Employee employee,
36 BindingResult result, RedirectAttributes redirectAttributes) {
37 if (result.hasErrors()) {
38 return "employees/form";
39 }
40 Employee saved = employeeService.create(employee);
41 redirectAttributes.addFlashAttribute("message", "Employee created");
42 return "redirect:/employees/" + saved.getId();
43 }
44}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1@InitBinder lets you register per-controller editors that transform raw request strings before they reach your model.
- 2Blocking sensitive fields with setDisallowedFields defends against mass-assignment attacks where users forge unexpected parameters.
- 3Pairing @Valid with a BindingResult keeps validation errors on the form instead of throwing, preserving user input.
Related explainers
go
func (h *WebhookHandler) HandleBatch(c *gin.Context) { var payload BatchWebhookPayload if err := c.ShouldBindJSON(&payload); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid payload"})
Handling batched webhooks in Gin
webhooks
signature-verification
job-queue
Intermediate
7 steps
java
@Configuration @EnableKafka public class KafkaErrorHandlingConfig {
Kafka retry and dead-letter handling in Spring
kafka
error-handling
retry
Intermediate
7 steps
php
<?php namespace App\Http\Controllers\Api;
Building a cursor-paginated feed in Laravel
cursor-pagination
eager-loading
validation
Intermediate
8 steps
python
from starlette.middleware.base import BaseHTTPMiddleware from starlette.requests import Request from starlette.responses import JSONResponse, Response from starlette.status import HTTP_413_REQUEST_ENTITY_TOO_LARGE
Enforcing a max request body size in FastAPI
middleware
streaming
request-limits
Advanced
6 steps
ruby
require "phonelib" class PhoneNumber class InvalidNumber < StandardError; end
Wrapping phone parsing in a Ruby value object
value-object
memoization
validation
Intermediate
7 steps
java
package com.example.config.condition; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext;
A custom @Conditional feature flag in Spring
conditional beans
feature flags
annotations
Intermediate
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/customizing-form-binding-in-a-spring-mvc-controller-explained-java-ab52/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.