当前位置: 首页 > article >正文

SpringMVC请求映射:@RequestMapping的高级用法

在这里插入图片描述

文章目录

    • 引言
    • 一、路径模式与变量提取
    • 二、请求条件组合与精确控制
    • 三、请求映射注解变体与语义化
    • 四、URI模板与矩阵变量支持
    • 五、自定义请求映射与注解组合
    • 六、请求映射最佳实践与性能优化
    • 总结

引言

在SpringMVC框架中,请求映射是连接客户端请求与服务器处理逻辑的桥梁。@RequestMapping注解作为SpringMVC最核心的注解之一,为开发者提供了强大而灵活的URL映射机制。随着Web应用复杂度的提高,简单的URL匹配已不能满足现代应用开发的需求。深入理解@RequestMapping的高级特性和用法,对于构建健壮、灵活的Web应用至关重要。本文将深入探讨@RequestMapping的高级用法,包括复杂路径匹配、多维度请求条件组合、注解变体的应用场景以及RESTful API的最佳实践,帮助开发者更加高效地使用这一强大工具,构建出更加优雅的Web应用。

一、路径模式与变量提取

@RequestMapping支持多种路径匹配模式,从简单的精确匹配到复杂的通配符和路径变量。路径变量使用{varName}语法定义,可以通过@PathVariable注解将其绑定到方法参数。SpringMVC还支持正则表达式路径变量{varName:regex},用于更精确的匹配控制。对于层次化的资源路径,可以使用**通配符捕获多级路径。这些高级匹配特性使得URL设计更加灵活,能够优雅地表达资源之间的层次关系,同时通过路径变量直观地传递参数,符合RESTful设计理念。

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 演示@RequestMapping的高级路径匹配
 */
@Controller
@RequestMapping("/api")
public class AdvancedPathMappingController {
    
    /**
     * 基本路径变量
     * URL示例: /api/users/123
     */
    @RequestMapping("/users/{userId}")
    @ResponseBody
    public String getUserById(@PathVariable("userId") Long userId) {
        return "User ID: " + userId;
    }
    
    /**
     * 多个路径变量
     * URL示例: /api/users/123/orders/456
     */
    @RequestMapping("/users/{userId}/orders/{orderId}")
    @ResponseBody
    public String getUserOrder(
            @PathVariable("userId") Long userId,
            @PathVariable("orderId") Long orderId) {
        return "User ID: " + userId + ", Order ID: " + orderId;
    }
    
    /**
     * 使用正则表达式限制路径变量
     * 仅匹配5位数字的产品代码
     * URL示例: /api/products/12345
     */
    @RequestMapping("/products/{productCode:[0-9]{5}}")
    @ResponseBody
    public String getProductByCode(@PathVariable("productCode") String productCode) {
        return "Product code: " + productCode;
    }
    
    /**
     * 通配符路径匹配
     * 匹配如:/api/files/documents/report.pdf
     */
    @RequestMapping("/files/**")
    @ResponseBody
    public String getFile() {
        return "File path: " + request.getRequestURI();
    }
    
    /**
     * 路径变量与通配符结合
     * 匹配如:/api/repos/myorg/myrepo/tree/master/src/main
     */
    @RequestMapping("/repos/{org}/{repo}/tree/{branch}/**")
    @ResponseBody
    public String getRepositoryContent(
            @PathVariable("org") String organization,
            @PathVariable("repo") String repository,
            @PathVariable("branch") String branch) {
        String fullPath = request.getRequestURI();
        String relativePath = fullPath.substring(fullPath.indexOf("/tree/" + branch) + 
                ("/tree/" + branch).length());
        
        return "Organization: " + organization + 
               ", Repository: " + repository + 
               ", Branch: " + branch + 
               ", Path: " + relativePath;
    }
    
    /**
     * 可选路径变量(通过正则表达式实现)
     * 匹配:/api/search 和 /api/search/query
     */
    @RequestMapping("/search{/query:.*}")
    @ResponseBody
    public String search(@PathVariable(value = "query", required = false) String query) {
        if (query == null || query.isEmpty()) {
            return "Search home page";
        }
        return "Search results for: " + query.substring(1); // 去除开头的斜杠
    }
}

二、请求条件组合与精确控制

@RequestMapping不仅可以基于URL路径进行匹配,还支持多种请求条件的组合,包括HTTP方法(method)、请求参数(params)、请求头(headers)、媒体类型(consumes/produces)等。通过组合这些条件,可以实现对请求的精确筛选和控制。对于复杂的Web应用,不同的客户端(如浏览器、移动应用、API客户端)可能需要不同的处理逻辑,通过请求条件组合可以优雅地解决这一问题。此外,基于Content-Type的映射对于构建支持多种数据格式的API尤为重要,可以根据客户端期望的数据格式提供相应的处理逻辑。

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 演示@RequestMapping的请求条件组合
 */
@Controller
@RequestMapping("/products")
public class RequestConditionController {
    
    /**
     * 基于HTTP方法的映射(不使用便捷注解)
     * 仅处理GET请求
     */
    @RequestMapping(value = "", method = RequestMethod.GET)
    @ResponseBody
    public String listProducts() {
        return "Product list";
    }
    
    /**
     * 基于请求参数的映射
     * 仅当请求包含'category'参数且值为'books'时匹配
     * URL示例: /products/filter?category=books
     */
    @RequestMapping(value = "/filter", params = "category=books")
    @ResponseBody
    public String filterBookProducts() {
        return "Filtered book products";
    }
    
    /**
     * 带有多个请求参数条件
     * 要求有sort参数,但没有order参数
     * URL示例: /products/filter?category=electronics&sort=price
     */
    @RequestMapping(
        value = "/filter", 
        params = {"category=electronics", "sort", "!order"}
    )
    @ResponseBody
    public String filterElectronicsProductsSorted() {
        return "Filtered electronics products, sorted";
    }
    
    /**
     * 基于请求头的映射
     * 仅匹配来自移动设备的请求(通过User-Agent判断)
     */
    @RequestMapping(
        value = "/view", 
        headers = "User-Agent=Mozilla/5.0.*Android.*"
    )
    @ResponseBody
    public String viewProductOnMobile() {
        return "Mobile view of product";
    }
    
    /**
     * 处理来自特定客户端的请求
     * 基于自定义请求头进行匹配
     */
    @RequestMapping(
        value = "/view",
        headers = "X-API-VERSION=1"
    )
    @ResponseBody
    public String viewProductV1API() {
        return "Product view API v1";
    }
    
    /**
     * 基于Accept头的映射(produces属性)
     * 客户端期望接收HTML响应
     */
    @RequestMapping(
        value = "/details/{id}",
        produces = "text/html"
    )
    public String getProductDetailsHtml() {
        return "product/details"; // 返回视图名称
    }
    
    /**
     * 基于Accept头的映射(produces属性)
     * 客户端期望接收JSON响应
     */
    @RequestMapping(
        value = "/details/{id}",
        produces = "application/json"
    )
    @ResponseBody
    public Product getProductDetailsJson(@PathVariable Long id) {
        Product product = productService.findById(id);
        return product; // 返回JSON数据
    }
    
    /**
     * 基于Content-Type头的映射(consumes属性)
     * 处理JSON格式的请求体
     */
    @RequestMapping(
        value = "",
        method = RequestMethod.POST,
        consumes = "application/json"
    )
    @ResponseBody
    public String createProductFromJson(@RequestBody Product product) {
        productService.save(product);
        return "Product created from JSON";
    }
    
    /**
     * 基于Content-Type头的映射(consumes属性)
     * 处理XML格式的请求体
     */
    @RequestMapping(
        value = "",
        method = RequestMethod.POST,
        consumes = "application/xml"
    )
    @ResponseBody
    public String createProductFromXml(@RequestBody Product product) {
        productService.save(product);
        return "Product created from XML";
    }
    
    /**
     * 复杂条件组合示例
     * 同时指定HTTP方法、请求参数、请求头、Content-Type和Accept
     */
    @RequestMapping(
        value = "/process",
        method = RequestMethod.PUT,
        params = "action=update",
        headers = "X-API-TOKEN",
        consumes = "application/json",
        produces = "application/json"
    )
    @ResponseBody
    public Product processProductUpdate(@RequestBody Product product) {
        return productService.update(product);
    }
}

三、请求映射注解变体与语义化

从Spring 4.3开始,框架引入了一系列@RequestMapping的变体注解,包括@GetMapping、@PostMapping、@PutMapping、@DeleteMapping和@PatchMapping,用于简化特定HTTP方法的映射定义。这些变体注解不仅简化了代码,还提高了代码的语义化,使API意图更加明确。在RESTful API开发中,选择合适的HTTP方法对于表达资源操作的语义至关重要。@GetMapping用于资源获取,@PostMapping用于资源创建,@PutMapping用于资源完整更新,@PatchMapping用于资源部分更新,@DeleteMapping用于资源删除。通过使用这些语义化注解,可以构建出符合REST原则的API。

import org.springframework.web.bind.annotation.*;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;

/**
 * 使用@RequestMapping变体注解构建RESTful API
 */
@RestController
@RequestMapping("/api/articles")
public class ArticleApiController {
    
    private final ArticleService articleService;
    
    public ArticleApiController(ArticleService articleService) {
        this.articleService = articleService;
    }
    
    /**
     * 获取文章列表
     * 使用@GetMapping替代@RequestMapping(method = RequestMethod.GET)
     */
    @GetMapping
    public List<Article> getAllArticles() {
        return articleService.findAll();
    }
    
    /**
     * 获取特定文章
     * @PathVariable直接注解在路径参数上
     */
    @GetMapping("/{id}")
    public ResponseEntity<Article> getArticleById(@PathVariable Long id) {
        return articleService.findById(id)
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }
    
    /**
     * 创建新文章
     * 使用@PostMapping替代@RequestMapping(method = RequestMethod.POST)
     */
    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public Article createArticle(@Valid @RequestBody Article article) {
        return articleService.create(article);
    }
    
    /**
     * 完全更新文章
     * 使用@PutMapping替代@RequestMapping(method = RequestMethod.PUT)
     */
    @PutMapping("/{id}")
    public ResponseEntity<Article> updateArticle(
            @PathVariable Long id, 
            @Valid @RequestBody Article article) {
        
        return articleService.update(id, article)
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }
    
    /**
     * 部分更新文章
     * 使用@PatchMapping替代@RequestMapping(method = RequestMethod.PATCH)
     */
    @PatchMapping("/{id}")
    public ResponseEntity<Article> partialUpdateArticle(
            @PathVariable Long id,
            @RequestBody Map<String, Object> updates) {
        
        return articleService.partialUpdate(id, updates)
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }
    
    /**
     * 删除文章
     * 使用@DeleteMapping替代@RequestMapping(method = RequestMethod.DELETE)
     */
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteArticle(@PathVariable Long id) {
        boolean deleted = articleService.delete(id);
        
        if (deleted) {
            return ResponseEntity.noContent().build();
        } else {
            return ResponseEntity.notFound().build();
        }
    }
    
    /**
     * 嵌套资源:获取文章评论
     * 展示如何处理资源之间的关系
     */
    @GetMapping("/{articleId}/comments")
    public List<Comment> getArticleComments(@PathVariable Long articleId) {
        return commentService.findByArticleId(articleId);
    }
    
    /**
     * 嵌套资源:添加文章评论
     */
    @PostMapping("/{articleId}/comments")
    @ResponseStatus(HttpStatus.CREATED)
    public Comment addArticleComment(
            @PathVariable Long articleId,
            @Valid @RequestBody Comment comment) {
        
        comment.setArticleId(articleId);
        return commentService.create(comment);
    }
    
    /**
     * 使用请求参数过滤资源
     * 展示如何与@RequestParam结合使用
     */
    @GetMapping("/search")
    public List<Article> searchArticles(
            @RequestParam(required = false) String title,
            @RequestParam(required = false) String author,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size) {
        
        return articleService.search(title, author, page, size);
    }
}

四、URI模板与矩阵变量支持

SpringMVC支持更高级的URI模板特性,如矩阵变量(Matrix Variables)。矩阵变量是URI路径中的键值对,使用分号(;)分隔,形如/path;param1=value1;param2=value2。这一特性在RESTful API中很有用,尤其是需要在路径中传递多个可选参数时。与查询参数不同,矩阵变量是路径的一部分,更符合REST资源的层次结构。要启用矩阵变量支持,需要配置UrlPathHelper的removeSemicolonContent属性为false。通过@MatrixVariable注解,可以将矩阵变量绑定到控制器方法参数上,灵活处理复杂的URL路径参数。

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.util.UrlPathHelper;
import org.springframework.context.annotation.Configuration;

/**
 * 配置类,启用矩阵变量支持
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        UrlPathHelper urlPathHelper = new UrlPathHelper();
        // 不移除分号内容,从而支持矩阵变量
        urlPathHelper.setRemoveSemicolonContent(false);
        configurer.setUrlPathHelper(urlPathHelper);
    }
}

/**
 * 演示矩阵变量的使用
 */
@Controller
@RequestMapping("/catalog")
public class MatrixVariableController {
    
    /**
     * 基本矩阵变量用法
     * URL示例: /catalog/products;category=books;price=50
     */
    @GetMapping("/products")
    @ResponseBody
    public String findProducts(
            @MatrixVariable(name = "category", required = false) String category,
            @MatrixVariable(name = "price", required = false) Integer price) {
        
        StringBuilder result = new StringBuilder("Products with ");
        if (category != null) {
            result.append("category: ").append(category).append(" ");
        }
        if (price != null) {
            result.append("price: ").append(price);
        }
        
        return result.toString();
    }
    
    /**
     * 在多路径段中使用矩阵变量
     * URL示例: /catalog/brands;country=germany/products;category=electronics
     */
    @GetMapping("/brands/{brandId}/products")
    @ResponseBody
    public String findProductsByBrand(
            @PathVariable String brandId,
            @MatrixVariable(name = "country", pathVar = "brands") String country,
            @MatrixVariable(name = "category", pathVar = "products") String category) {
        
        return "Brand: " + brandId + 
               ", Country: " + country + 
               ", Category: " + category;
    }
    
    /**
     * 处理多值矩阵变量
     * URL示例: /catalog/filter;colors=red,green,blue;sizes=S,M,L
     */
    @GetMapping("/filter")
    @ResponseBody
    public String filterProducts(
            @MatrixVariable(name = "colors") List<String> colors,
            @MatrixVariable(name = "sizes") List<String> sizes) {
        
        return "Filtering products by colors: " + colors + 
               " and sizes: " + sizes;
    }
    
    /**
     * 处理全部矩阵变量
     * URL示例: /catalog/search;minPrice=100;maxPrice=500;brand=apple;inStock=true
     */
    @GetMapping("/search")
    @ResponseBody
    public String searchProducts(
            @MatrixVariable Map<String, Object> matrixVars) {
        
        return "Search criteria: " + matrixVars;
    }
    
    /**
     * 结合路径变量和矩阵变量
     * URL示例: /catalog/categories/electronics;featured=true/products
     */
    @GetMapping("/categories/{category}/products")
    @ResponseBody
    public String getProductsByCategory(
            @PathVariable String category,
            @MatrixVariable(name = "featured", required = false) Boolean featured) {
        
        return "Category: " + category + 
               (featured != null ? ", Featured: " + featured : "");
    }
    
    /**
     * 处理URI模板变量
     * URL示例: /catalog/items/123-456-789
     */
    @GetMapping("/items/{itemCode}")
    @ResponseBody
    public String getItemByCode(@PathVariable String itemCode) {
        // 手动解析复合ID
        String[] parts = itemCode.split("-");
        return "Item type: " + parts[0] + 
               ", Vendor: " + parts[1] + 
               ", Product: " + parts[2];
    }
    
    /**
     * 结合正则表达式、路径变量和矩阵变量
     * URL示例: /catalog/2023/spring;region=europe/collection
     */
    @GetMapping("/{year:\\d{4}}/{season};region={region}/collection")
    @ResponseBody
    public String getSeasonalCollection(
            @PathVariable Integer year,
            @PathVariable String season,
            @MatrixVariable String region) {
        
        return year + " " + season + " collection for " + region;
    }
}

五、自定义请求映射与注解组合

SpringMVC的注解系统支持元注解(meta-annotations)机制,允许开发者创建自定义注解,组合和扩展现有注解功能。通过创建自定义注解,可以封装常用的请求映射模式,使代码更加简洁和标准化。自定义注解通常包含@RequestMapping或其变体,以及其他相关注解如@ResponseBody、@ResponseStatus等。这种方式特别适合定义API版本控制、统一响应格式、权限检查等横切关注点。通过自定义注解,可以在团队中建立标准化的API开发规范,提高代码一致性和可维护性。

import org.springframework.web.bind.annotation.*;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;

import java.lang.annotation.*;

/**
 * 自定义API版本化注解
 * 组合了@RequestMapping,并添加了版本前缀
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping("/v1")
public @interface ApiV1 {
    /**
     * 指定路径
     */
    String[] value() default {};
}

/**
 * 自定义GET请求注解
 * 组合了@GetMapping和@ResponseBody
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@GetMapping
@ResponseBody
public @interface ApiGet {
    /**
     * 指定路径
     */
    String[] value() default {};
    
    /**
     * 指定生产的媒体类型
     */
    String[] produces() default {MediaType.APPLICATION_JSON_VALUE};
}

/**
 * 自定义POST请求注解
 * 组合了@PostMapping、@ResponseBody和@ResponseStatus
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@PostMapping
@ResponseBody
@ResponseStatus(HttpStatus.CREATED)
public @interface ApiPost {
    /**
     * 指定路径
     */
    String[] value() default {};
    
    /**
     * 指定消费的媒体类型
     */
    String[] consumes() default {MediaType.APPLICATION_JSON_VALUE};
    
    /**
     * 指定生产的媒体类型
     */
    String[] produces() default {MediaType.APPLICATION_JSON_VALUE};
}

/**
 * 使用自定义注解的控制器
 */
@RestController
@ApiV1
@RequestMapping("/custom")
public class CustomAnnotationController {
    
    private final ItemService itemService;
    
    public CustomAnnotationController(ItemService itemService) {
        this.itemService = itemService;
    }
    
    /**
     * 使用自定义@ApiGet注解
     * 等同于@GetMapping + @ResponseBody
     * URL: /v1/custom/items
     */
    @ApiGet("/items")
    public List<Item> getAllItems() {
        return itemService.findAll();
    }
    
    /**
     * 使用自定义@ApiPost注解
     * 等同于@PostMapping + @ResponseBody + @ResponseStatus(CREATED)
     * URL: /v1/custom/items
     */
    @ApiPost("/items")
    public Item createItem(@Valid @RequestBody Item item) {
        return itemService.create(item);
    }
    
    /**
     * 自定义注解与标准注解组合使用
     * URL: /v1/custom/items/{id}
     */
    @ApiGet("/items/{id}")
    public ResponseEntity<Item> getItemById(@PathVariable Long id) {
        return itemService.findById(id)
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }
}

/**
 * 自定义安全检查注解
 * 组合了权限检查逻辑
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@PreAuthorize("hasRole('ADMIN')")  // Spring Security注解
public @interface AdminOnly {
}

/**
 * 更复杂的自定义注解示例
 * 组合了多个横切关注点
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@PutMapping
@ResponseBody
@AdminOnly
@Transactional
public @interface AdminUpdate {
    /**
     * 指定路径
     */
    String[] value() default {};
}

/**
 * 使用安全相关自定义注解
 */
@RestController
@RequestMapping("/admin")
public class AdminController {
    
    /**
     * 使用组合了多个关注点的自定义注解
     */
    @AdminUpdate("/settings/{id}")
    public Setting updateSetting(
            @PathVariable Long id,
            @Valid @RequestBody Setting setting) {
        
        return settingService.update(id, setting);
    }
}

六、请求映射最佳实践与性能优化

在实际项目中,合理设计和配置请求映射对于提高应用性能和可维护性至关重要。首先,应避免过于复杂的URL模式和模糊的映射条件,精确指定HTTP方法和路径,减少不必要的条件判断。其次,对于大型应用,应基于功能模块或资源类型组织控制器,并利用类级别的@RequestMapping设置基础路径,保持URL结构清晰。对于频繁访问的API,可以配置HandlerMapping的缓存设置,提高请求分发效率。此外,还应注意避免映射冲突,使用AntPathMatcher配置更精细的路径匹配策略,并定期检查不必要的请求映射,减少内存占用和请求处理开销。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.util.pattern.PathPatternParser;

/**
 * RequestMapping配置最佳实践示例
 */
@Configuration
public class RequestMappingConfig implements WebMvcConfigurer {
    
    /**
     * 配置高性能的路径匹配器(Spring 5.3+)
     * 使用PathPatternParser替代传统的AntPathMatcher
     */
    @Bean
    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
        RequestMappingHandlerMapping handlerMapping = new RequestMappingHandlerMapping();
        handlerMapping.setPatternParser(new PathPatternParser());
        // 设置请求映射的缓存大小
        handlerMapping.setCacheSize(1024);
        // 设置映射注册顺序敏感
        handlerMapping.setUseSuffixPatternMatch(false);
        handlerMapping.setUseTrailingSlashMatch(false);
        return handlerMapping;
    }
}

/**
 * 控制器层次结构示例 - 基础控制器接口
 * 定义共享的请求映射和行为
 */
@RequestMapping("/api/v1")
public interface BaseApi<T, ID> {
    
    @GetMapping
    List<T> findAll();
    
    @GetMapping("/{id}")
    ResponseEntity<T> findById(@PathVariable ID id);
    
    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    T create(@Valid @RequestBody T entity);
    
    @PutMapping("/{id}")
    ResponseEntity<T> update(@PathVariable ID id, @Valid @RequestBody T entity);
    
    @DeleteMapping("/{id}")
    ResponseEntity<Void> delete(@PathVariable ID id);
}

/**
 * 用户API控制器 - 继承基础API接口
 * 遵循REST最佳实践
 */
@RestController
@RequestMapping("/users")
public class UserApiController implements BaseApi<User, Long> {
    
    private final UserService userService;
    
    public UserApiController(UserService userService) {
        this.userService = userService;
    }
    
    // 实现基础接口方法
    @Override
    public List<User> findAll() {
        return userService.findAll();
    }
    
    @Override
    public ResponseEntity<User> findById(@PathVariable Long id) {
        return userService.findById(id)
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }
    
    @Override
    public User create(@Valid @RequestBody User user) {
        return userService.create(user);
    }
    
    @Override
    public ResponseEntity<User> update(@PathVariable Long id, @Valid @RequestBody User user) {
        return userService.update(id, user)
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }
    
    @Override
    public ResponseEntity<Void> delete(@PathVariable Long id) {
        boolean deleted = userService.delete(id);
        return deleted ? 
                ResponseEntity.noContent().build() : 
                ResponseEntity.notFound().build();
    }
    
    /**
     * 扩展基础API - 用户特定端点
     * 展示如何在保持API一致性的同时添加特定功能
     */
    @GetMapping("/search")
    public List<User> searchUsers(
            @RequestParam(required = false) String name,
            @RequestParam(required = false) String email) {
        return userService.search(name, email);
    }
    
    /**
     * 嵌套资源示例 - 用户角色
     */
    @GetMapping("/{userId}/roles")
    public List<Role> getUserRoles(@PathVariable Long userId) {
        return userService.findRolesByUserId(userId);
    }
}

/**
 * 高性能控制器示例
 * 应用请求映射最佳实践
 */
@RestController
@RequestMapping("/api/v1/reports")
public class ReportController {
    
    private final ReportService reportService;
    
    public ReportController(ReportService reportService) {
        this.reportService = reportService;
    }
    
    /**
     * 使用良好定义的路径变量和请求参数
     * 避免模糊匹配,提高分发效率
     */
    @GetMapping("/{year}/{month}")
    public Report getMonthlyReport(
            @PathVariable int year,
            @PathVariable int month,
            @RequestParam(defaultValue = "summary") String type) {
        
        validateYearMonth(year, month);
        return reportService.generateReport(year, month, type);
    }
    
    /**
     * 限定请求参数类型,减少运行时类型转换
     */
    @GetMapping("/sales")
    public SalesReport getSalesReport(
            @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate from,
            @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate to,
            @RequestParam(defaultValue = "DAILY") ReportGranularity granularity) {
        
        validateDateRange(from, to);
        return reportService.generateSalesReport(from, to, granularity);
    }
    
    /**
     * 高效处理大文件下载
     * 使用produces属性精确控制内容类型
     */
    @GetMapping(value = "/export", produces = "application/vnd.ms-excel")
    public ResponseEntity<Resource> exportReport(
            @RequestParam int year,
            @RequestParam(required = false) Integer month) {
        
        Resource file = reportService.generateExcelReport(year, month);
        
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, 
                        "attachment; filename=\"report.xlsx\"")
                .body(file);
    }
    
    /**
     * 参数验证方法
     */
    private void validateYearMonth(int year, int month) {
        if (year < 2000 || year > LocalDate.now().getYear()) {
            throw new IllegalArgumentException("Invalid year: " + year);
        }
        if (month < 1 || month > 12) {
            throw new IllegalArgumentException("Invalid month: " + month);
        }
    }
    
    private void validateDateRange(LocalDate from, LocalDate to) {
        if (from.isAfter(to)) {
            throw new IllegalArgumentException("Start date must be before end date");
        }
        if (from.isBefore(LocalDate.now().minusYears(5))) {
            throw new IllegalArgumentException("Reports only available for the last 5 years");
        }
    }
}

总结

@RequestMapping是SpringMVC框架中最为核心和强大的注解之一,通过本文对其高级用法的探讨,我们深入了解了路径模式与变量提取、请求条件组合、注解变体的语义化应用、URI模板与矩阵变量支持以及自定义注解组合等高级特性。这些功能为构建灵活、高效的Web应用提供了坚实基础。在实际应用中,开发者应遵循最佳实践,合理设计URL结构,精确指定请求条件,避免过于复杂的映射规则,并根据应用特点优化性能配置。通过合理运用@RequestMapping的高级特性,可以构建出更加语义化、易于维护的API,提高开发效率和代码质量。对于大型应用,建议结合Spring的AOP机制和自定义注解,进一步抽象和简化请求映射逻辑,实现更加优雅的解决方案。随着微服务架构的普及,掌握@RequestMapping的高级用法对于构建标准化、高性能的RESTful API变得尤为重要。


http://www.kler.cn/a/574512.html

相关文章:

  • js 全局的 isNaN和Number.isNaN的区别
  • 深度学习模型组件-RevNorm-可逆归一化(Reversible Normalization)
  • 批量修改或设置 Word 标题、主题、标记、作者、总编辑时间等元数据
  • 蓝桥杯C组真题——巧克力
  • 【3.2-3.8学习周报】
  • MacOS Big Sur 11 新机安装brew wget python3.12 exo
  • Dockerfile概述及编辑
  • 【Oracle学习笔记】2.数据表
  • 2025-03-06 学习记录--C/C++-PTA 习题6-6 使用函数输出一个整数的逆序数
  • 深度解码!清华大学第六弹《AIGC发展研究3.0版》
  • 网络协议:HTTP协议
  • 23中设计模式之观察者模式
  • 计算机基础:二进制基础05,八进制简介
  • 如何在WPS中接入DeepSeek并使用OfficeAI助手(超细!成功版本)
  • 【硬件IIC与软件IIC在程序实现上的核心区别】结合STM32F103C8T6标准库代码进行对比分析
  • EasyDSS视频推拉流/直播点播平台:Mysql数据库接口报错502处理方法
  • Python 高级图表绘制秘籍: Matplotlib 与 Seaborn 热力图、箱线图实战
  • 初探 Mercury:首个商业级扩散大语言模型的初步观察与体验
  • 绝美焦糖暖色调复古风景画面Lr调色教程,手机滤镜PS+Lightroom预设下载!
  • 微服务拆分-拆分商品服务