Spring Boot Cheatsheet
Controllers
Use this Spring Boot reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Controller Stereotypes
| Annotation | Returns | Use When |
|---|---|---|
@Controller | View name (Thymeleaf/Mustache) | Server-side HTML rendering |
@RestController | JSON/XML body directly | REST APIs |
@RestController = @Controller + @ResponseBody | — | — |
@RestController @RequestMapping("/api/users") public class UserController { // all handler methods return body, no @ResponseBody needed }
Basic CRUD Controller
@RestController @RequestMapping("/api/products") @RequiredArgsConstructor // Lombok — generates constructor injection public class ProductController { private final ProductService productService; @GetMapping public List<ProductDto> getAll() { return productService.findAll(); } @GetMapping("/{id}") public ResponseEntity<ProductDto> getById(@PathVariable Long id) { return ResponseEntity.ok(productService.findById(id)); } @PostMapping public ResponseEntity<ProductDto> create(@Valid @RequestBody CreateProductRequest req) { ProductDto created = productService.create(req); URI location = ServletUriComponentsBuilder.fromCurrentRequest() .path("/{id}").buildAndExpand(created.id()).toUri(); return ResponseEntity.created(location).body(created); } @PutMapping("/{id}") public ProductDto update(@PathVariable Long id, @Valid @RequestBody UpdateProductRequest req) { return productService.update(id, req); } @DeleteMapping("/{id}") public ResponseEntity<Void> delete(@PathVariable Long id) { productService.delete(id); return ResponseEntity.noContent().build(); } }
Handler Method Parameter Annotations
| Annotation | Source | Example |
|---|---|---|
@PathVariable | URL segment {id} | @PathVariable Long id |
@RequestParam | Query string ?page=0 | @RequestParam(defaultValue="0") int page |
@RequestBody | JSON request body | @RequestBody @Valid CreateDto dto |
@RequestHeader | HTTP header | @RequestHeader("X-API-Key") String key |
@CookieValue | Cookie | @CookieValue("session") String token |
@ModelAttribute | Form / multipart | @ModelAttribute UserForm form |
@MatrixVariable | Matrix params /users/42;role=admin | @MatrixVariable String role |
HttpServletRequest | Raw request | injected automatically |
Principal | Auth principal | Principal principal |
@AuthenticationPrincipal | Spring Security user | @AuthenticationPrincipal UserDetails u |
@SessionAttribute | HTTP session | @SessionAttribute("cart") Cart cart |
@RequestParam Options
// Optional with default @GetMapping public Page<Item> list( @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size, @RequestParam(required = false) String search ) { ... } // Multi-value: ?tag=java&tag=spring @GetMapping("/search") public List<Post> byTags(@RequestParam List<String> tag) { ... }
@PathVariable Options
// Name must match {variable} or use name attribute @GetMapping("/users/{userId}/orders/{orderId}") public Order get(@PathVariable Long userId, @PathVariable Long orderId) { ... } // Optional path variable @GetMapping({"/items", "/items/{id}"}) public Object getOrList(@PathVariable(required = false) Long id) { ... }
ResponseEntity Quick Reference
ResponseEntity.ok(body) // 200 ResponseEntity.created(uri).body(body) // 201 + Location header ResponseEntity.accepted().build() // 202, no body ResponseEntity.noContent().build() // 204 ResponseEntity.badRequest().body(errorDto) // 400 ResponseEntity.notFound().build() // 404 ResponseEntity.status(HttpStatus.CONFLICT).body(msg) // 409 // Custom headers return ResponseEntity.ok() .header("X-Custom", "value") .contentType(MediaType.APPLICATION_JSON) .body(data);
View Controllers (Thymeleaf / MVC)
@Controller @RequestMapping("/") public class PageController { @GetMapping("login") public String loginPage() { return "login"; // resolves to templates/login.html } @GetMapping("dashboard") public String dashboard(Model model) { model.addAttribute("user", currentUser()); return "dashboard"; } @PostMapping("register") public String register(@Valid @ModelAttribute RegisterForm form, BindingResult result, RedirectAttributes attrs) { if (result.hasErrors()) return "register"; userService.register(form); attrs.addFlashAttribute("message", "Account created!"); return "redirect:/login"; } }
Async Controllers
// Return CompletableFuture for servlet-thread offloading @GetMapping("/report") public CompletableFuture<Report> generateReport() { return CompletableFuture.supplyAsync(() -> reportService.build()); } // Reactive (WebFlux only) @GetMapping("/stream") public Flux<Event> streamEvents() { return eventService.stream(); }
File Upload / Download
// Upload @PostMapping("/upload") public ResponseEntity<String> upload(@RequestParam MultipartFile file) throws IOException { String url = storageService.store(file.getOriginalFilename(), file.getInputStream()); return ResponseEntity.ok(url); } // Download @GetMapping("/files/{name}") public ResponseEntity<Resource> download(@PathVariable String name) throws IOException { Resource resource = storageService.load(name); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"") .contentType(MediaType.APPLICATION_OCTET_STREAM) .body(resource); }
Set
spring.servlet.multipart.max-file-size=10MBandspring.servlet.multipart.max-request-size=10MBinapplication.properties.
Common Pitfalls
- Circular dependency — avoid field injection (
@Autowiredon field); use constructor injection so Spring fails loudly. @PathVariablename mismatch — the variable name in the URL template must exactly match the parameter name (or specifyname).@RequestBody+@Valid—@Validmust come before@RequestBodyto trigger validation; missing it silently skips constraints.HttpMediaTypeNotSupportedException— client must sendContent-Type: application/jsonfor@RequestBodyendpoints.- Returning
nullvsOptional— returnResponseEntity.notFound().build()instead ofnullto get a proper 404.