CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-springframework-boot--spring-boot-starter-web

Starter for building web, including RESTful, applications using Spring MVC with embedded Tomcat server.

Pending
Overview
Eval results
Files

controllers.mddocs/

Controller Development

RESTful web services and traditional MVC controllers using Spring annotations for web application development.

Capabilities

Controller Annotations

Mark classes and methods as web controllers with request mapping capabilities.

/**
 * Marks a class as a Spring MVC controller
 */
@Controller
public class WebController {
    // Controller methods
}

/**
 * Combination of @Controller and @ResponseBody for REST APIs
 */
@RestController
public class ApiController {
    // REST endpoint methods
}

/**
 * Global REST controller advice for exception handling and model attributes
 */
@RestControllerAdvice
public class GlobalRestControllerAdvice {
    // Global REST exception handling
}

/**
 * Maps HTTP requests to handler methods
 */
@RequestMapping(value = "/path", method = RequestMethod.GET)
public ResponseEntity<String> handleRequest();

/**
 * HTTP method-specific mapping annotations
 */
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id);

@PostMapping("/users")
public User createUser(@RequestBody User user);

@PutMapping("/users/{id}")
public User updateUser(@PathVariable Long id, @RequestBody User user);

@DeleteMapping("/users/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id);

@PatchMapping("/users/{id}")
public User partialUpdate(@PathVariable Long id, @RequestBody Map<String, Object> updates);

Usage Examples:

@RestController
@RequestMapping("/api/v1")
public class ProductController {
    
    @GetMapping("/products")
    public List<Product> getAllProducts(
        @RequestParam(defaultValue = "0") int page,
        @RequestParam(defaultValue = "10") int size) {
        return productService.findAll(page, size);
    }
    
    @GetMapping("/products/{id}")
    public ResponseEntity<Product> getProduct(@PathVariable Long id) {
        Product product = productService.findById(id);
        return product != null ? ResponseEntity.ok(product) : ResponseEntity.notFound().build();
    }
    
    @PostMapping("/products")
    public ResponseEntity<Product> createProduct(@Valid @RequestBody Product product) {
        Product created = productService.save(product);
        return ResponseEntity.status(HttpStatus.CREATED).body(created);
    }
}

Parameter Binding

Bind HTTP request data to method parameters using annotations.

/**
 * Binds request parameters to method parameters
 */
@RequestParam(value = "name", required = false, defaultValue = "default") String paramName;

/**
 * Binds URI template variables to method parameters
 */
@PathVariable("id") Long id;
@PathVariable Map<String, String> pathVars; // All path variables

/**
 * Binds HTTP request body to method parameter
 */
@RequestBody User user;

/**
 * Binds request headers to method parameters
 */
@RequestHeader("User-Agent") String userAgent;
@RequestHeader Map<String, String> headers; // All headers

/**
 * Binds cookie values to method parameters
 */
@CookieValue("JSESSIONID") String sessionId;

/**
 * Binds session attributes to method parameters
 */
@SessionAttribute("user") User currentUser;

/**
 * Binds request attributes to method parameters
 */
@RequestAttribute("startTime") Long startTime;

/**
 * Binds multipart files to method parameters
 */
@RequestParam("file") MultipartFile file;
@RequestParam("files") List<MultipartFile> files;

/**
 * Binds specific parts of multipart requests
 */
@RequestPart("metadata") RequestMetadata metadata;
@RequestPart("file") MultipartFile file;

/**
 * Binds form data to model objects
 */
@ModelAttribute User user;
@ModelAttribute("product") Product product;

/**
 * Binds URI matrix variables to method parameters
 */
@MatrixVariable String action;
@MatrixVariable(pathVar="petId") int petId;
@MatrixVariable Map<String, String> matrixVars; // All matrix variables

Usage Examples:

@RestController
public class FileController {
    
    @PostMapping("/upload")
    public ResponseEntity<String> handleFileUpload(
        @RequestParam("file") MultipartFile file,
        @RequestParam(value = "description", required = false) String description) {
        
        if (file.isEmpty()) {
            return ResponseEntity.badRequest().body("File is empty");
        }
        
        String filename = fileService.store(file, description);
        return ResponseEntity.ok("File uploaded: " + filename);
    }
    
    @GetMapping("/search")
    public List<Product> searchProducts(
        @RequestParam String query,
        @RequestParam(defaultValue = "name") String sortBy,
        @RequestParam(defaultValue = "asc") String sortDir,
        @RequestHeader(value = "Accept-Language", defaultValue = "en") String language) {
        
        return productService.search(query, sortBy, sortDir, language);
    }
}

Response Handling

Control HTTP responses with status codes, headers, and content types.

/**
 * Marks method return value as response body
 */
@ResponseBody
public User getUser();

/**
 * Sets HTTP response status
 */
@ResponseStatus(HttpStatus.CREATED)
public void createResource();

/**
 * Generic HTTP response wrapper
 */
public class ResponseEntity<T> {
    public static <T> ResponseEntity<T> ok(T body);
    public static <T> ResponseEntity<T> ok().build();
    public static <T> ResponseEntity<T> status(HttpStatus status);
    public static <T> ResponseEntity<T> created(URI location);
    public static <T> ResponseEntity<T> noContent().build();
    public static <T> ResponseEntity<T> badRequest().build();
    public static <T> ResponseEntity<T> notFound().build();
    
    public ResponseEntity<T> header(String name, String value);
    public ResponseEntity<T> headers(HttpHeaders headers);
}

/**
 * HTTP status enumeration
 */
public enum HttpStatus {
    // 2xx Success
    OK(200), CREATED(201), ACCEPTED(202), NO_CONTENT(204),
    // 4xx Client Error  
    BAD_REQUEST(400), UNAUTHORIZED(401), FORBIDDEN(403), NOT_FOUND(404),
    // 5xx Server Error
    INTERNAL_SERVER_ERROR(500), SERVICE_UNAVAILABLE(503);
}

Usage Examples:

@RestController
public class OrderController {
    
    @PostMapping("/orders")
    public ResponseEntity<Order> createOrder(@Valid @RequestBody Order order) {
        Order created = orderService.create(order);
        URI location = ServletUriComponentsBuilder
            .fromCurrentRequest()
            .path("/{id}")
            .buildAndExpand(created.getId())
            .toUri();
        return ResponseEntity.created(location).body(created);
    }
    
    @GetMapping("/orders/{id}")
    public ResponseEntity<Order> getOrder(@PathVariable Long id) {
        return orderService.findById(id)
            .map(order -> ResponseEntity.ok()
                .header("Last-Modified", order.getLastModified().toString())
                .body(order))
            .orElse(ResponseEntity.notFound().build());
    }
    
    @DeleteMapping("/orders/{id}")
    public ResponseEntity<Void> deleteOrder(@PathVariable Long id) {
        boolean deleted = orderService.deleteById(id);
        return deleted ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build();
    }
}

Content Negotiation

Handle different request/response content types automatically.

/**
 * Specify consumable media types
 */
@PostMapping(value = "/data", consumes = "application/json")
public void handleJson(@RequestBody Data data);

@PostMapping(value = "/data", consumes = "application/xml")
public void handleXml(@RequestBody Data data);

/**
 * Specify producible media types
 */
@GetMapping(value = "/data", produces = "application/json")
public Data getDataAsJson();

@GetMapping(value = "/data", produces = "application/xml")
public Data getDataAsXml();

/**
 * Multiple content types
 */
@GetMapping(value = "/data", produces = {"application/json", "application/xml"})
public Data getData();

Usage Examples:

@RestController
@RequestMapping("/api/reports")
public class ReportController {
    
    @GetMapping(value = "/{id}", produces = {"application/json", "application/pdf"})
    public ResponseEntity<?> getReport(
        @PathVariable Long id,
        @RequestHeader(value = "Accept", defaultValue = "application/json") String accept) {
        
        Report report = reportService.findById(id);
        
        if (accept.contains("application/pdf")) {
            byte[] pdf = reportService.generatePdf(report);
            return ResponseEntity.ok()
                .contentType(MediaType.APPLICATION_PDF)
                .body(pdf);
        }
        
        return ResponseEntity.ok(report);
    }
    
    @PostMapping(consumes = {"application/json", "application/xml"})
    public ResponseEntity<Report> createReport(@RequestBody Report report) {
        Report created = reportService.create(report);
        return ResponseEntity.status(HttpStatus.CREATED).body(created);
    }
}

Bean Validation

Automatic validation of request data using JSR-303/349/380 Bean Validation annotations.

/**
 * Request body validation with @Valid
 */
@PostMapping("/users")
public ResponseEntity<?> createUser(@Valid @RequestBody User user, BindingResult result) {
    if (result.hasErrors()) {
        List<String> errors = result.getAllErrors().stream()
            .map(DefaultMessageSourceResolvable::getDefaultMessage)
            .collect(Collectors.toList());
        return ResponseEntity.badRequest().body(errors);
    }
    return ResponseEntity.ok(userService.save(user));
}

/**
 * Request parameter validation
 */
@GetMapping("/users")
public List<User> getUsers(
    @RequestParam @Min(0) int page,
    @RequestParam @Min(1) @Max(100) int size) {
    return userService.findAll(page, size);
}

/**
 * Path variable validation
 */
@GetMapping("/users/{id}")
public User getUser(@PathVariable @Min(1) Long id) {
    return userService.findById(id);
}

/**
 * Common validation annotations
 */
@NotNull(message = "Value cannot be null")
@NotBlank(message = "Value cannot be blank")
@Size(min = 2, max = 50, message = "Size must be between 2 and 50")
@Email(message = "Invalid email format")
@Pattern(regexp = "\\d{5}", message = "Must be 5 digits")
@Min(value = 0, message = "Must be non-negative")
@Max(value = 100, message = "Must not exceed 100")
@Past(message = "Date must be in the past")
@Future(message = "Date must be in the future")

Usage Examples:

@RestController
@Validated  // Enable method-level validation
public class ProductController {
    
    @PostMapping("/products")
    public ResponseEntity<?> createProduct(@Valid @RequestBody Product product, BindingResult result) {
        if (result.hasErrors()) {
            Map<String, String> errors = new HashMap<>();
            result.getFieldErrors().forEach(error -> 
                errors.put(error.getField(), error.getDefaultMessage())
            );
            return ResponseEntity.badRequest().body(errors);
        }
        
        Product saved = productService.save(product);
        return ResponseEntity.status(HttpStatus.CREATED).body(saved);
    }
    
    @GetMapping("/products/search")
    public List<Product> searchProducts(
        @RequestParam @NotBlank @Size(min = 3) String query,
        @RequestParam(defaultValue = "0") @Min(0) int page) {
        return productService.search(query, page);
    }
}

Cross-Origin Resource Sharing (CORS)

Configure CORS support for cross-domain requests.

/**
 * CORS configuration at class or method level
 */
@CrossOrigin(origins = "http://localhost:3000", maxAge = 3600)
@RestController
public class ApiController {
    
    @CrossOrigin(origins = "*", allowedHeaders = "*")
    @GetMapping("/public-data")
    public Data getPublicData() {
        return dataService.getPublicData();
    }
}

/**
 * Global CORS configuration
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOrigins("http://localhost:3000", "https://mydomain.com")
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(3600);
    }
}

Data Binding and Validation

Configure data binding behavior and validation rules.

/**
 * Initialize data binding for specific controllers
 */
@InitBinder
public void initBinder(WebDataBinder binder) {
    binder.setRequiredFields("name", "email");
    binder.setAllowedFields("name", "email", "age");
    binder.setDisallowedFields("id", "createdDate");
    
    // Custom validator
    binder.addValidators(new UserValidator());
}

/**
 * Controller with session attributes
 */
@Controller
@SessionAttributes({"user", "preferences"})
public class SessionController {
    
    @ModelAttribute("user")
    public User initUser() {
        return new User();
    }
    
    @PostMapping("/update-profile")
    public String updateProfile(@ModelAttribute("user") User user, Model model) {
        userService.update(user);
        return "redirect:/profile";
    }
}

Types

// Multipart file handling
public interface MultipartFile {
    String getName();
    String getOriginalFilename();
    String getContentType();
    boolean isEmpty();
    long getSize();
    byte[] getBytes() throws IOException;
    InputStream getInputStream() throws IOException;
    void transferTo(File dest) throws IOException;
}

// HTTP headers utility
public class HttpHeaders {
    public static final String ACCEPT = "Accept";
    public static final String CONTENT_TYPE = "Content-Type";
    public static final String AUTHORIZATION = "Authorization";
    
    public void add(String headerName, String headerValue);
    public void set(String headerName, String headerValue);
    public String getFirst(String headerName);
    public List<String> get(String headerName);
}

// URI builder utility
public class ServletUriComponentsBuilder {
    public static ServletUriComponentsBuilder fromCurrentRequest();
    public ServletUriComponentsBuilder path(String path);
    public UriComponents buildAndExpand(Object... uriVariableValues);
}

// Model and session attribute handling
public interface Model {
    Model addAttribute(String attributeName, Object attributeValue);
    Model addAttribute(Object attributeValue);
    Map<String, Object> asMap();
    boolean containsAttribute(String attributeName);
}

// Data binding and validation
public class WebDataBinder {
    public void setValidator(Validator validator);
    public void setRequiredFields(String... requiredFields);
    public void setAllowedFields(String... allowedFields);
    public void setDisallowedFields(String... disallowedFields);
}

// Session attribute configuration
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SessionAttributes {
    String[] value() default {};
    Class<?>[] types() default {};
}

// Cross-origin resource sharing configuration
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CrossOrigin {
    String[] value() default {};
    String[] origins() default {};
    String[] allowedHeaders() default {};
    String[] exposedHeaders() default {};
    RequestMethod[] methods() default {};
    String allowCredentials() default "";
    long maxAge() default -1;
}

// Data binding customization
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface InitBinder {
    String[] value() default {};
}

// Bean Validation types
public interface BindingResult {
    boolean hasErrors();
    boolean hasGlobalErrors();
    boolean hasFieldErrors();
    List<ObjectError> getAllErrors();
    List<FieldError> getFieldErrors();
    FieldError getFieldError(String field);
}

public class FieldError extends ObjectError {
    public String getField();
    public Object getRejectedValue();
    public String getDefaultMessage();
}

// Validation annotations
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Valid {
}

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Validated {
    Class<?>[] value() default {};
}

// Common validation constraint annotations
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface NotNull {
    String message() default "";
}

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface NotBlank {
    String message() default "";
}

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Size {
    int min() default 0;
    int max() default Integer.MAX_VALUE;
    String message() default "";
}

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Email {
    String message() default "";
}

Install with Tessl CLI

npx tessl i tessl/maven-org-springframework-boot--spring-boot-starter-web

docs

configuration.md

controllers.md

embedded-server.md

error-handling.md

http-clients.md

index.md

json-processing.md

static-resources.md

testing.md

tile.json