Spring MVC 控制器和请求处理教程

Spring MVC 控制器和请求处理模块教程

目录

  1. 控制器概述
  2. @RequestMapping 注解详解
  3. 请求方法映射
  4. 参数绑定机制
  5. 路径变量处理
  6. 请求参数处理
  7. 请求体处理
  8. 返回值处理
  9. RESTful API 设计
  10. 控制器最佳实践
  11. 常见问题解决
  12. 总结

控制器概述

在Spring MVC中,控制器是处理用户请求的核心组件。它负责接收HTTP请求,处理业务逻辑,并返回适当的响应。

控制器的职责

  1. 请求路由: 根据请求URL和方法选择合适的处理函数
  2. 参数绑定: 将HTTP请求参数绑定到Java对象
  3. 业务调用: 调用相应的服务层方法
  4. 结果处理: 处理业务逻辑的执行结果
  5. 响应生成: 生成适当的HTTP响应

控制器类型

1. 传统Controller(推荐用于页面跳转)

@Controller
public class UserController {
    
    @RequestMapping("/user/list")
    public String listUsers(Model model) {
        List<User> users = userService.getAllUsers();
        model.addAttribute("users", users);
        return "user/list";  // 返回视图名
    }
}

2. RESTful Controller(推荐用于API开发)

@RestController
@RequestMapping("/api/users")
public class UserRestController {
    
    @GetMapping
    public ResponseEntity<List<User>> getAllUsers() {
        List<User> users = userService.getAllUsers();
        return ResponseEntity.ok(users);
    }
}

@RequestMapping 注解详解

基础使用

@RequestMapping是Spring MVC中最核心的注解,用于将HTTP请求映射到控制器方法。

基本语法

@Controller
public class BookController {
    
    // 基础映射
    @RequestMapping("/books")
    public String books() {
        return "book/list";
    }
    
    // 指定HTTP方法
    @RequestMapping(value = "/books", method = RequestMethod.GET)
    public String getBooks() {
        return "book/list";
    }
    
    // 指定多个HTTP方法
    @RequestMapping(value = "/books", method = {RequestMethod.GET, RequestMethod.POST})
    public String handleBooks() {
        return "book/list";
    }
}

类级别和方法级别

类级别@RequestMapping

@Controller
@RequestMapping("/admin")  // 类级别的路径前缀
public class AdminController {
    
    @RequestMapping("/users")  // 完整路径: /admin/users
    public String manageUsers() {
        return "admin/users";
    }
    
    @RequestMapping("/dashboard")  // 完整路径: /admin/dashboard
    public String dashboard() {
        return "admin/dashboard";
    }
}

路径映射规则

1. 精确匹配

@RequestMapping("/user/profile")  // 只匹配 /user/profile
public String profile() {
    return "user/profile";
}

2. 路径变量

@RequestMapping("/user/{id}")  // 匹配 /user/123, /user/abc等
public String getUserDetail(@PathVariable String id) {
    return "user/detail";
}

// 多个路径变量
@RequestMapping("/user/{userId}/post/{postId}")
public String getPost(@PathVariable Long userId, @PathVariable Long postId) {
    return "user/post";
}

3. 通配符匹配

@RequestMapping("/files/**")  // 匹配 /files/css/style.css
public String handleFiles(HttpServletRequest request) {
    return "files/index";
}

@RequestMapping("/user/*/profile")  // 匹配 /user/123/profile
public String userProfile() {
    return "user/profile";
}

4. 正则表达式

@RequestMapping("/user/{id:\\d+}")  // 只匹配数字ID
public String getUserById(@PathVariable Long id) {
    return "user/detail";
}

@RequestMapping("/user/{name:[a-zA-Z]+}")
public String getUserByName(@PathVariable String name) {
    return "user/detail";
}

属性完整配置

@Controller
public class AdvancedController {
    
    @RequestMapping(
        value = "/advanced/{id}",           // 路径映射
        method = RequestMethod.GET,         // HTTP方法
        params = {"type=sale", "status"},   // 必须包含的参数
        headers = {"Accept=application/json"}, // 必须包含的请求头
        consumes = "application/json",      // 接受的Content-Type
        produces = "application/json"       // 产生的Content-Type
    )
    public String advancedExample() {
        return "advanced/example";
    }
}

请求方法映射

HTTP方法快捷注解

Spring MVC提供了针对不同HTTP方法的快捷注解:

@Controller
public class UserController {
    
    // GET请求
    @GetMapping("/users")
    public String getUsers() {
        return "user/list";
    }
    
    // POST请求
    @PostMapping("/users")
    public String createUser() {
        return "redirect:/users";
    }
    
    // PUT请求
    @PutMapping("/users/{id}")
    public String updateUser(@PathVariable Long id) {
        return "user/edit";
    }
    
    // DELETE请求
    @DeleteMapping("/users/{id}")
    public String deleteUser(@PathVariable Long id) {
        return "redirect:/users";
    }
    
    // PATCH请求
    @PatchMapping("/users/{id}")
    public String patchUser(@PathVariable Long id) {
        return "user/patch";
    }
}

表单处理示例

显示表单页面

@GetMapping("/user/create")
public String showCreateForm(Model model) {
    model.addAttribute("user", new User());
    return "user/create-form";
}

@PostMapping("/user/create")
public String createUser(@ModelAttribute User user) {
    userService.save(user);
    return "redirect:/users";
}

PUT/DELETE请求处理

// HTML表单不支持PUT和DELETE方法,需要通过POST模拟
@PostMapping(value = "/user/{id}", params = "_method=PUT")
public String updateUser(@PathVariable Long id, @ModelAttribute User user) {
    user.setId(id);
    userService.update(user);
    return "redirect:/users";
}

@PostMapping(value = "/user/{id}", params = "_method=DELETE")
public String deleteUser(@PathVariable Long id) {
    userService.delete(id);
    return "redirect:/users";
}

自定义HTTP方法

@Controller
public class CustomMethodController {
    
    // 自定义请求头处理DELETE方法
    @RequestMapping(value = "/user/{id}", 
                   method = RequestMethod.POST,
                   headers = "X-HTTP-Method-Override=DELETE")
    public String customDelete(@PathVariable Long id) {
        userService.delete(id);
        return "redirect:/users";
    }
}

参数绑定机制

自动参数绑定

Spring MVC提供了强大的参数绑定功能,能够自动将HTTP请求参数绑定到控制器方法的参数上。

基本类型绑定

@GetMapping("/search")
public String search(@RequestParam String keyword) {
    // keyword参数自动绑定
    return "search/results";
}

@GetMapping("/user")
public String getUser(@RequestParam Long id) {
    // id参数自动转换为Long类型
    return "user/detail";
}

@RequestParam 注解详解

基础使用

@GetMapping("/categories")
public String getCategories(
    @RequestParam String type,      // 必需参数
    @RequestParam(required = false) String status, // 可选参数
    @RequestParam(defaultValue = "1") int page,    // 默认值
    @RequestParam(defaultValue = "10") int size    // 默认值
) {
    return "category/list";
}

数组和集合参数

// 处理数组参数
@GetMapping("/users")
public String getUsers(@RequestParam Long[] userIds) {
    // 对应URL: /users?userIds=1&userIds=2&userIds=3
    return "user/list";
}

// 处理List参数
@GetMapping("/tags")
public String getTags(@RequestParam List<String> tags) {
    // 对应URL: /tags?tags=java&tags=spring&tags=mvc
    return "tag/list";
}

// 处理Map参数
@GetMapping("/filters")
public String filter(@RequestParam Map<String, String> filters) {
    // filters会自动包含所有请求参数
    return "filter/results";
}

自定义参数名称

@GetMapping("/search")
public String search(@RequestParam("search-keyword") String keyword) {
    // 映射到参数名search-keyword
    return "search/results";
}

@PathVariable 注解详解

单个路径变量

@GetMapping("/user/{id}")
공blic String getUser(@PathVariable Long id) {
    return "user/detail";
}

@GetMapping("/user/{username}")
public String getUserByUsername(@PathVariable String username) {
    return "user/detail";
}

多个路径变量

@GetMapping("/user/{userId}/post/{postId}")
public String getUserPost(
    @PathVariable Long userId,
    @PathVariable Long postId
) {
    return "user/post/detail";
}

指定路径变量名称

@GetMapping("/user/{id}")
public String getUser(@PathVariable("id") Long userId) {
    // 明确指定路径变量名称
    return "user/detail";
}

限定路径变量格式

@GetMapping("/user/{id:\\d+}")  // 只匹配数字
public String getUserById(@PathVariable Long id) {
    return "user/detail";
}

@GetMapping("/user/{username:[a-zA-Z0-9_]+}")  // 只匹配字母、数字、下划线
public String getUserByUsername(@PathVariable String username) {
    return "user/detail";
}

@RequestHeader 注解

请求头绑定

@GetMapping("/api/users")
public String getUsers(@RequestHeader("Accept") String accept,
                       @RequestHeader(value = "Authorization", required = false) String auth) {
    return "user/list";
}

// 绑定所有请求头
@GetMapping("/debug")
public String debug(@RequestHeader Map<String, String> headers) {
    return "debug/headers";
}

@CookieValue 注解

Cookie绑定

@GetMapping("/profile")
public String getProfile(@CookieValue("sessionId") String sessionId) {
    return "user/profile";
}

// 指定Cookie名称
@GetMapping("/preferences")
public String getPreferences(@CookieValue(value = "theme", defaultValue = "light") String theme) {
    return "user/preferences";
}

路径变量处理

路径参数验证

使用约束注解

@GetMapping("/user/{id}")
public String getUser(@PathVariable @Min(1) Long id) {
    return "user/detail";
}

@GetMapping("/user/{username}")
public String getUserByUsername(@PathVariable @Size(min = 3, max = 20) String username) {
    return "user/detail";
}

自定义验证

@GetMapping("/user/{userId}")
public String getUser(@PathVariable("userId") @ValidUserId Long userId) {
    return "user/detail";
}

// 自定义验证注解
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UserIdValidator.class)
public @interface ValidUserId {
    String message() default "无效的用户ID";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

@Component
public class UserIdValidator implements ConstraintValidator<ValidUserId, Long> {
    @Override
    public boolean isValid(Long value, ConstraintValidatorContext context) {
        return value != null && value > 0 && userRepository.existsById(value);
    }
}

路径变量转换

自定义转换器

@Component
public class StringToUserConverter implements Converter<String, User> {
    @Autowired
    private UserService userService;
    
    @Override
    public User convert(String username) {
        return userService.findByUsername(username);
    }
}

// 使用自定义转换器
@GetMapping("/user/{username}")
public String getUser(@PathVariable User user) {
    // username会自动转换为User对象
    return "user/detail";
}

请求参数处理

复杂对象绑定

表单对象绑定

@PostMapping("/user/create")
public String createUser(@ModelAttribute User user) {
    userService.save(user);
    return "redirect:/users";
}

// 指定模型属性名称
@PostMapping("/admin/create")
public String createAdmin(@ModelAttribute("admin") User admin) {
    return "admin/create";
}

嵌套对象绑定

public class UserProfile {
    private User user;
    private Address address;
    private List<String> hobbies;
    
    // getters and setters
}

@PostMapping("/profile/save")
public String saveProfile(@ModelAttribute UserProfile profile) {
    return "profile/save";
}

JSON请求体处理

RESTful API中的JSON处理

@RestController
@RequestMapping("/api/users")
public class UserRestController {
    
    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody @Valid User user) {
        User savedUser = userService.save(user);
        return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);
    }
    
    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(@PathVariable Long id, 
                                         @RequestBody @Valid User user) {
        user.setId(id);
        User updatedUser = userService.update(user);
        return ResponseEntity.ok(updatedUser);
    }
}

文件上传处理

单文件上传

@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file) {
    if (!file.isEmpty()) {
        // 处理上传的文件
        String filename = file.getOriginalFilename();
        // 保存文件逻辑
    }
    return "upload/success";
}

多文件上传

@PostMapping("/upload-multiple")
public String uploadFiles(@RequestParam("files") MultipartFile[] files) {
    for (MultipartFile file : files) {
        if (!file.isEmpty()) {
            // 处理每个文件
        }
    }
    return "upload/success";
}

表单+文件上传

@PostMapping("/user/create")
public String createUserWithAvatar(@ModelAttribute User user,
                                 @RequestParam("avatar") MultipartFile avatar) {
    // 处理用户创建和头像上传
    return "redirect:/users";
}

请求体处理

@RequestBody 注解详解

处理JSON请求

@RestController
public class ApiController {
    
    @PostMapping("/api/login")
    public ResponseEntity<LoginResponse> login(@RequestBody LoginRequest request) {
        // 处理登录逻辑
        return ResponseEntity.ok(new LoginResponse());
    }
}

public class LoginRequest {
    private String username;
    private String password;
    
    // getters and setters
}

使用HttpMessageConverter

@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Override:

    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
                .indentOutput(true)
                .dateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
    }
}

XML请求处理

配置XML支持

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-xml</artifactId>
    <version>2.13.3</version>
</dependency>
@PostMapping(value = "/user", consumes = "application/xml")
public ResponseEntity<User> createUserFromXML(@RequestBody User user) {
    return ResponseEntity.ok(userService.save(user));
}

请求体验证

使用JSR-303验证

public class UserCreateRequest {
    @NotBlank(message = "用户名不能为空")
    @Size(min = 3, max = 20, message = "用户名长度必须在3-20个字符")
    private String username;
    
    @NotBlank(message = "邮箱不能为空")
    @Email(message = "邮箱格式不正确")
    private String email;
    
    @NotBlank(message = "密码不能为空")
    @Size(min = 6, message = "密码长度至少6位")
    private String password;
    
    // getters and setters
}

@PostMapping("/user/create")
public ResponseEntity<?> createUser(@RequestBody @Valid UserCreateRequest request,
                                   BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        // 返回验证错误信息
        return ResponseEntity.badRequest().body(bindingResult.getAllErrors());
    }
    
    // 创建用户逻辑
    return ResponseEntity.ok("用户创建成功");
}

返回值处理

视图名返回

基础视图返回

@GetMapping("/home")
public String home() {
    return "home";  // 返回逻辑视图名
}

@GetMapping("/user/{id}")
public String userDetail(@PathVariable Long id) {
    return "user/detail";  // 路径: /WEB-INF/views/user/detail.jsp
}

重定向

@PostMapping("/user/create")
public String createUser(@ModelAttribute User user) {
    userService.save(user);
    return "redirect:/users";  // 重定向到用户列表
}

// 带参数的重定向
@PostMapping("/user/create")
public String createUser(@ModelAttribute User user) {
    User savedUser = userService.save(user);
    return "redirect:/user/" + savedUser.getId();
}

转发

@GetMapping("/internal")
public String internalRedirect() {
    return "forward:/internal-target";
}

ModelAndView 返回

基础ModelAndView

@GetMapping("/dashboard")
public ModelAndView dashboard() {
    ModelAndView mav = new ModelAndView();
    mav.setViewName("dashboard");
    mav.addObject("userCount", userService.getTotalCount());
    mav.addObject("onlineUsers", userService.getOnlineUserCount());
    return mav;
}

构造函数方式

@GetMapping("/profile/{id}")
public ModelAndView getUserProfile(@PathVariable Long id) {
    User user = userService.findById(id);
    return new ModelAndView("user/profile", "user", user);
    // 等同于 setViewName("user/profile") 和 addObject("user", user)
}

@ResponseBody 注解

返回JSON数据

@GetMapping("/api/user/{id}")
@ResponseBody
public User getUserJson(@PathVariable Long id) {
    return userService.findById(id);
}

@RestController  // @RestController = @Controller + @ResponseBody
@RequestMapping("/api")
public class ApiController {
    
    @GetMapping("/users")
    public List<User> getAllUsers() {
        return userService.getAllUsers();
    }
}

ResponseEntity 返回

完整HTTP响应

@RestController
public class ApiController {
    
    @GetMapping("/api/user/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        try {
            User user = userService.findById(id);
            return ResponseEntity.ok(user);
        } catch (UserNotFoundException e) {
            return ResponseEntity.notFound().build();
        }
    }
    
    @PostMapping("/api/user")
    public ResponseEntity<User> createUser(@RequestBody @Valid User user) {
        User savedUser = userService.save(user);
        return ResponseEntity.status(HttpStatus.CREATED)
                           .body(savedUser);
    }
}

自定义响应头

@GetMapping("/api/download/{id}")
public ResponseEntity<Resource> downloadFile(@PathVariable Long id) {
    Resource file = fileService.getFile(id);
    
    return ResponseEntity.ok()
            .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + id + ".pdf\""
            .contentType(MediaType.APPLICATION_PDF)
            .body(file);
}

RESTful API 设计

REST 设计原则

资源识别

@RestController
@RequestMapping("/api/users")  // 资源集合
public class UserRestController {
    
    @GetMapping  // GET /api/users
    public List<User> getUsers() {
        return userService.getAllUsers();
    }
    
    @PostMapping  // POST /api/users
    public ResponseEntity<User> createUser(@RequestBody @Valid User user) {
        User savedUser = userService.save(user);
        return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);
    }
    
    @GetMapping("/{id}")  // GET /api/users/{id}
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        User user = userService.findById(id);
        return ResponseEntity.ok(user);
    }
    
    @PutMapping("/{id}")  // PUT /api/users/{id}
    public ResponseEntity<User> updateUser(@PathVariable Long id, 
                                          @RequestBody @Valid User user) {
        user.setId(id);
        User updatedUser = userService.update(user);
        return ResponseEntity.ok(updatedUser);
    }
    
    @DeleteMapping("/{id}")  // DELETE /api/users/{id}
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userService.delete(id);
        return ResponseEntity.noContent().build();
    }
}

分页和排序

分页参数处理

@GetMapping
public ResponseEntity<Page<User>> getUsers(
    @RequestParam(defaultValue = "0") int page,
    @RequestParam(defaultValue = "10") int size,
    @RequestParam(defaultValue = "id") String sortBy,
    @RequestParam(defaultValue = "asc") String sortDir) {
    
    Pageable pageable = PageRequest.of(page, size, 
        Sort.Direction.fromString(sortDir), sortBy);
    Page<User> users = userService.findAll(pageable);
    return ResponseEntity.ok(users);
}

搜索和过滤

搜索功能

@GetMapping("/search")
public ResponseEntity<List<User>> searchUsers(
    @RequestParam(required = false) String keyword,
    @RequestParam(required = false) String department,
    @RequestParam(required = false) String status) {
    
    List<User> users = userService.search(keyword, department, status);
    return ResponseEntity.ok(users);
}

API版本控制

URL版本控制

@RestController
@RequestMapping("/api/v1/users")
public class UserV1Controller {
    // v1版本的实现
}

@RestController
@RequestMapping("/api/v2/users")
public class UserV2Controller {
    // v2版本的实现
}

请求头版本控制

@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @GetMapping(produces = "application/vnd.api.v1+json")
    public ResponseEntity<List<UserV1>> getUsersV1() {
        // v1版本实现
    }
    
    @GetMapping(produces = "application/vnd.api.v2+json")
    public ResponseEntity<List<UserV2>> getUsersV2() {
        // v2版本实现
    }
}

控制器最佳实践

控制器的职责分离

1. 保持控制器的轻薄

@Controller
public class UserController {
    
    @Autowired
    private UserService userService;  // 只注入服务层
    
    @GetMapping("/user/{id}")
    public String getUserDetail(@PathVariable Long id, Model model) {
        User user = userService.findById(id);  // 只负责调用服务
        model.addAttribute("user", user);
        return "user/detail";  // 只负责返回视图
    }
    
    // 不要在控制器中写业务逻辑
}

2. 使用DTO进行数据传输

// 专门的DTO类用于API传输
public class UserApiDto {
    private Long id;
    private String username;
    private String email;
    // 不包含敏感信息如密码
    
    // getters and setters
}

@RestController
@RequestMapping("/api/users")
public class UserApiController {
    
    @GetMapping("/{id}")
    public ResponseEntity<UserApiDto> getUser(@PathVariable Long id) {
        User user = userService.findById(id);
        UserApiDto dto = convertToDto(user);
        return ResponseEntity.ok(dto);
    }
    
    private UserApiDto convertToDto(User user) {
        // 转换逻辑
    }
}

异常处理策略

1. 使用@ControllerAdvice

@ControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(UserNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ResponseEntity<ErrorResponse> handleUserNotFound(UserNotFoundException ex) {
        ErrorResponse error = new ErrorResponse("USER_NOT_FOUND", ex.getMessage());
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
    }
    
    @ExceptionHandler(ValidationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseEntity<ErrorResponse> handleValidation(ValidationException ex) {
        ErrorResponse error = new ErrorResponse("VALIDATION_ERROR", ex.getMessage());
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
    }
}

2. 业务异常自定义

public class UserNotFoundException extends RuntimeException {
    public UserNotFoundException(Long id) {
        super("User not found with id: " + id);
    }
}

public class ValidationException extends RuntimeException {
    public ValidationException(String message) {
        super(message);
    }
}

参数验证最佳实践

1. 使用Spring验证注解

@PostMapping("/user/create")
public ResponseEntity<?> createUser(@RequestBody @Valid UserCreateRequest request,
                                   BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        Map<String, String> errors = new HashMap<>();
        bindingResult.getFieldErrors().forEach(error -> {
            errors.put(error.getField(), error.getDefaultMessage());
        });
        return ResponseEntity.badRequest().body(errors);
    }
    
    // 处理逻辑
    return ResponseEntity.ok("用户创建成功");
}

2. 自定义验证注解

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UniqueUsernameValidator.class)
public @interface UniqueUsername {
    String message() default "用户名已存在";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

性能优化建议

1. 异步处理

@RestController
public class AsyncController {
    
    @GetMapping("/async/task/{id}")
    public ResponseEntity<CompletableFuture<String>> asyncTask(@PathVariable Long id) {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            // 执行耗时任务
            return processTask(id);
        });
        
        return ResponseEntity.ok(future);
    }
}

2. 缓存处理

@RestController
public class ApiController {
    
    @GetMapping("/api/user/{id}")
    @Cacheable(value = "users", key = "#id")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        User user = userService.findById(id);
        return ResponseEntity.ok(user);
    }
}

常见问题解决

1. 参数绑定失败

问题描述: @RequestParam绑定失败

// 错误示例
@GetMapping("/search")
public String search(@RequestParam String keyword) {  // keyword为null时会抛出异常
    return "search/results";
}

// 正确解决方案
@GetMapping("/search")
public String search(@RequestParam(required = false) String keyword,
                     Model model) {
    if (keyword != null && !keyword.trim().isEmpty()) {
        // 处理搜索逻辑
    }
    return "search/results";
}

2. 路径冲突问题

问题描述: 多个路径映射冲突

// 冲突的路径
@RequestMapping("/user/*") 
public String userWildcard() {
    return "user/wildcard";
}

@RequestMapping("/user/{id}")  // 两者可能冲突
public String userDetail(@PathVariable Long id) {
    return "user/detail";
}

// 解决方案: 调整映射顺序或使用更精确的模式
@RequestMapping("/user/{id:\\d+}")  // 明确数字ID
public String userDetail(@PathVariable Long id) {
    return "user/detail";
}

3. JSON反序列化问题

问题描述: JSON请求体无法正确绑定到对象

// 确保JSON字段名与Java属性名匹配
public class UserCreateRequest {
    private String username;  // 对应JSON中的"username"
    private String email;     // 对应JSON中的"email"
    
    // 可以使用@JsonProperty指定字段名
    @JsonProperty("user_name")
    private String userName;
    
    // getters and setters
}

4! @PathVariable类型转换问题

问题描述: String无法转换为Long

// 错误处理方式
@GetMapping("/user/{id}")
public String getUser(@PathVariable Long id) {
    // 如果路径是/user/abc,会转换失败
}

// 解决方案1: 使用String接收然后手动转换
@GetMapping("/user/{id}")
public String getUser(@PathVariable String id) {
    try {
        Long userId = Long.parseLong(id);
        // 处理逻辑
    } catch (NumberFormatException e) {
        return "error/400";  // 无效ID
    }
}

// 解决方案2: 使用正则表达式约束
@GetMapping("/user/{id:\\d+}")
public String getUser(@PathVariable Long id) {
    // 只能匹配数字ID
}

5. CORS跨域问题

常见问题: API接口跨域访问失败

// 解决方案: 配置CORS
@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOrigins("http://localhost:3000")
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                .allowedHeaders("*")
                .allowCredentials(true);
    }
}

// 或者使用注解
@CrossOrigin(origins = "http://localhost:3000")
@RestController
@RequestMapping("/api/users")
public class UserRestController {
    // 控制器方法
}

总结

Spring MVC控制器和请求处理模块是框架的核心部分,本教程全面介绍了:

核心技术要点

1. @RequestMapping注解

  • 灵活的路由映射配置
  • 支持多种路径模式
  • HTTP方法限定和属性配置

2. 参数绑定机制

  • @RequestParam、@PathVariable等注解使用
  • 复杂对象的自动绑定
  • 自定义转换器和验证

3. 请求处理流程

  • HTTP请求到控制器方法的映射
  • 参数提取和类型转换
  • 业务逻辑调用和响应生成

4. RESTful API设计

  • REST架构风格遵循
  • 资源URL设计规范
  • HTTP状态码正确使用

5. 高级特性

  • 文件上传处理
  • JSON/XML请求体处理
  • 异步处理和性能优化

最佳实践建议

  1. 职责分离: 控制器只负责请求处理和响应生成
  2. 异常处理: 统一全局异常处理机制
  3. 参数验证: 完善的输入参数验证
  4. DTO使用: 专门的传输对象避免敏感数据暴露
  5. 版本控制: API版本管理策略
  6. 性能优化: 异步处理和缓存机制

掌握了控制器和请求处理模块后,建议继续学习其他Spring MVC模块:

  • 视图技术和数据处理模块
  • 表单处理和验证模块
  • 高级特性模块(拦截器、异常处理等)
  • 测试和集成模块

这些模块的知识将使您能够构建更加健壮和生产级的Spring MVC应用程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小凯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值