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
php
<?php namespace App\Services\Checkout;
Validating coupons with Laravel's Pipeline
pipeline
chain of responsibility
transactions
Intermediate
7 steps
java
@Component @Converter public class EncryptedStringConverter implements AttributeConverter<String, String> {
Transparent column encryption in Spring & JPA
encryption
aes-gcm
jpa-converter
Advanced
10 steps
php
<?php namespace App\Services;
How a password strength validator works in PHP
validation
regular-expressions
data-driven
Intermediate
8 steps
java
package com.acme.billing.config; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties;
Feature-flagged beans with Spring @ConditionalOnProperty
feature-flags
conditional-beans
strategy-pattern
Intermediate
5 steps
rust
use chrono::{Duration, NaiveDate}; #[derive(Debug)] pub struct DateRange {
Parsing and iterating date ranges in Rust
error-handling
iterators
parsing
Intermediate
7 steps
java
public static Map<String, String> parseCookieHeader(String header) { Map<String, String> cookies = new LinkedHashMap<>(); if (header == null || header.isBlank()) { return cookies;
Parsing an HTTP Cookie header in Java
string-parsing
http
url-decoding
Intermediate
6 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.