How to Write Elegant Spring Controllers and Slash Your Blood Pressure

The article shows how cluttered Spring controllers filled with try‑catch blocks, manual field checks, and business logic can be refactored into concise, readable code by using @Valid, assertion utilities, and a global exception handler, cutting the code size roughly in half.

java1234
java1234
java1234
How to Write Elegant Spring Controllers and Slash Your Blood Pressure

Many developers end up with controllers that contain thousands of lines of code, extensive try‑catch blocks, repetitive field validation, and even business logic, which makes the code hard to read and maintain.

Un‑elegant controller example

@RestController
@RequestMapping("/user/test")
public class UserController {
    private static Logger logger = LoggerFactory.getLogger(UserController.class);
    @Autowired private UserService userService;
    @Autowired private AuthService authService;

    @PostMapping
    public CommonResult userRegistration(@RequestBody UserVo userVo) {
        if (StringUtils.isBlank(userVo.getUsername())) {
            return CommonResult.error("用户名不能为空");
        }
        if (StringUtils.isBlank(userVo.getPassword())) {
            return CommonResult.error("密码不能为空");
        }
        logger.info("注册用户:{}", userVo.getUsername());
        try {
            userService.registerUser(userVo.getUsername());
            return CommonResult.ok();
        } catch (Exception e) {
            logger.error("注册用户失败:{}", userVo.getUsername(), e);
            return CommonResult.error("注册失败");
        }
    }

    @PostMapping("/login")
    @PermitAll
    @ApiOperation("使用账号密码登录")
    public CommonResult<AuthLoginRespVO> login(@RequestBody AuthLoginReqVO reqVO) {
        if (StringUtils.isBlank(reqVO.getUsername())) {
            return CommonResult.error("用户名不能为空");
        }
        if (StringUtils.isBlank(reqVO.getPassword())) {
            return CommonResult.error("密码不能为空");
        }
        try {
            return success(authService.login(reqVO));
        } catch (Exception e) {
            logger.error("注册用户失败:{}", reqVO.getUsername(), e);
            return CommonResult.error("注册失败");
        }
    }
}

This version mixes validation, logging, and error handling, resulting in a bulky controller.

Elegant controller after refactoring

@RestController
@RequestMapping("/user/test")
public class UserController1 {
    private static Logger logger = LoggerFactory.getLogger(UserController1.class);
    @Autowired private UserService userService;
    @Autowired private AuthService authService;

    @PostMapping
    public CommonResult userRegistration(@RequestBody @Valid UserVo userVo) {
        userService.registerUser(userVo.getUsername());
        return CommonResult.ok();
    }

    @PostMapping("/login")
    @PermitAll
    @ApiOperation("使用账号密码登录")
    public CommonResult<AuthLoginRespVO> login(@RequestBody @Valid AuthLoginReqVO reqVO) {
        return success(authService.login(reqVO));
    }
}

By moving validation to the data layer with @Valid and removing explicit if checks, the controller shrinks dramatically.

Improved validation approach

Instead of manual if statements, use Spring’s validation annotations:

public class AuthLoginReqVO {
    @ApiModelProperty(value = "账号", required = true, example = "user")
    @NotEmpty(message = "登录账号不能为空")
    @Length(min = 4, max = 16, message = "账号长度为 4-16 位")
    @Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母")
    private String username;

    @ApiModelProperty(value = "密码", required = true, example = "password")
    @NotEmpty(message = "密码不能为空")
    @Length(min = 4, max = 16, message = "密码长度为 4-16 位")
    private String password;
}

Using Assert.notNull or similar assertion utilities can also replace repetitive checks.

Global exception handling

@ResponseBody
@RestControllerAdvice
public class ExceptionHandlerAdvice {
    protected Logger logger = LoggerFactory.getLogger(getClass());

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public CommonResult<Object> handleValidationExceptions(MethodArgumentNotValidException ex) {
        logger.error("[handleValidationExceptions]", ex);
        StringBuilder sb = new StringBuilder();
        ex.getBindingResult().getAllErrors().forEach(error -> {
            String fieldName = ((org.springframework.validation.FieldError) error).getField();
            String errorMessage = error.getDefaultMessage();
            sb.append(fieldName).append(":").append(errorMessage).append(";");
        });
        return CommonResult.error(sb.toString());
    }

    @ExceptionHandler(Exception.class)
    public CommonResult<?> defaultExceptionHandler(Throwable ex) {
        logger.error("[defaultExceptionHandler]", ex);
        return CommonResult.error(INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg());
    }
}

The advice captures validation failures and any uncaught exceptions, returning a unified error response.

Takeaways

Keep controllers thin: delegate validation to @Valid and business logic to services.

Replace manual if checks with annotation‑driven validation or assertion utilities.

Use a global @RestControllerAdvice to handle validation and system exceptions consistently.

Following these practices can halve the amount of controller code and improve readability, maintainability, and developer health.

JavaException HandlingValidationSpring BootController@Valid
java1234
Written by

java1234

Former senior programmer at a Fortune Global 500 company, dedicated to sharing Java expertise. Visit Feng's site: Java Knowledge Sharing, www.java1234.com

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.