Spring学习笔记_39——@PathVariable

时间:2024-11-21 18:58:11

@PathVariable

@RequestParam学习笔记

1. 介绍

@PathVariable 是一个在Spring MVC 框架中用于处理 URI 模板变量(URI Template Variables)的一个注解,它用于将Web请求中的URL路径参数映射到控制器(Controller)的方法参数上,从而使得方法的参数可以根据客户端请求的 URI 动态变化。这个注解通常与@RequestMapping@GetMapping@PostMapping等注解一起使用,以处理基于REST的URL。

2. 场景

当你的URL包含动态部分时,可以使用@PathVariable来获取这些动态部分的值。例如,如果你有一个URL /users/{userId},其中{userId}是一个动态参数,你可以使用@PathVariable来获取这个userId的值。

3. 源码

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PathVariable {
  	// String类型的属性,用于指定URL中占位符的名称
    @AliasFor("name")
    String value() default "";

  	// Spring从4.3.3版本开始提供
  	// String类型的属性,作用与value属性相同
    @AliasFor("value")
    String name() default "";
  
		// Spring从4.3.3版本开始提供的String类型的属性
  	// 用于指定URL中是否必须存在当前占位符的参数,默认值为true
    boolean required() default true;
}

4. Demo

假设我们有一个在线书店的 Web 应用,用户可以通过访问不同的 URL 来获取书籍的详细信息、作者的详细信息以及根据书籍分类浏览书籍。我们可以使用 @PathVariable 来处理这些 URL 中的动态部分。

@RestController
@RequestMapping("/api")
public class BookstoreController {

    // 假设我们有一个服务层来提供书籍、作者和分类的数据
    private final BookService bookService;
    private final AuthorService authorService;
    private final CategoryService categoryService;

    // 构造函数注入服务层
    public BookstoreController(BookService bookService, AuthorService authorService, CategoryService categoryService) {
        this.bookService = bookService;
        this.authorService = authorService;
        this.categoryService = categoryService;
    }

    // 获取书籍详细信息
    @GetMapping("/books/{bookId}")
    public ResponseEntity<Book> getBookById(@PathVariable Long bookId) {
        Book book = bookService.findById(bookId);
        if (book == null) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(book);
    }

    // 获取作者详细信息
    @GetMapping("/authors/{authorId}")
    public ResponseEntity<Author> getAuthorById(@PathVariable Long authorId) {
        Author author = authorService.findById(authorId);
        if (author == null) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(author);
    }

    // 浏览特定分类下的所有书籍
    @GetMapping("/categories/{categoryId}/books")
    public ResponseEntity<List<Book>> getBooksByCategoryId(@PathVariable Long categoryId) {
        List<Book> books = bookService.findByCategoryId(categoryId);
        if (books.isEmpty()) {
            return ResponseEntity.notFound().build(); // 或者返回一个空列表,取决于业务逻辑
        }
        return ResponseEntity.ok(books);
    }
}

服务层

public interface BookService {
    Book findById(Long bookId);
    List<Book> findByCategoryId(Long categoryId);
    // 其他方法...
}

public interface AuthorService {
    Author findById(Long authorId);
    // 其他方法...
}

public interface CategoryService {
    // 可能包含分类的查找、创建等方法,但在这个示例中未使用
}

实体类

public class Book {
    private Long id;
    private String title;
    private Author author;
    private Category category;
    // 其他字段、getter和setter方法...
}

public class Author {
    private Long id;
    private String name;
    // 其他字段、getter和setter方法...
}

public class Category {
    private Long id;
    private String name;
    // 其他字段、getter和setter方法...
}

5. @PathVariable和@RequestParam注解对比

5.1 使用场景
  1. @PathVariable
    • 使用框架:Spring MVC(Web框架)。
    • 用途:从请求的URL中获取路径变量的值。
    • 场景:在RESTful API中,用于提取URL路径中的参数。例如,/users/{userId}中的{userId}就是一个路径变量,可以通过@PathVariable来获取其值。
  2. @RequestParam
    • 使用框架:Spring MVC(Web框架)。
    • 用途:从请求的URL、表单数据或查询参数中获取请求参数的值。
    • 场景:用于处理普通的表单提交或查询字符串参数。例如,/search?keyword=spring中的keyword=spring就是一个查询参数,可以通过@RequestParam来获取其值。
5.2 参数来源
  1. @PathVariable
    • 参数来源于URL的路径部分。例如,在/users/{userId}中,{userId}的值就是从URL的路径中提取出来的。
  2. @RequestParam
    • 参数可以来源于URL的查询字符串部分(如/search?keyword=spring中的keyword),也可以来源于表单数据(如POST请求中提交的表单字段)。
5.3 注意
  1. @PathVariable
    • 通常与@RequestMapping@GetMapping@PostMapping等注解一起使用,这些注解定义了请求映射的URI模式。
    • 可以使用{variable}作为占位符来引用路径变量。
    • 可以接收多个路径变量,只需在方法参数中多次使用@PathVariable注解即可。
    • 由于路径变量通常用于表示资源标识符(如用户ID、书籍ID等),因此在使用时应确保它们的唯一性和有效性。
    • 错误处理:如果路径变量不存在或无法转换,Spring 会抛出 NoSuchRequestHandlingMethodException
  2. @RequestParam
    • 可以指定namevalue属性来明确指定要接收的请求参数名称。
    • 可以使用required属性来指定参数是否是必传的。如果不指定,默认为true。如果参数不是必传的,应将其设置为false,并考虑提供一个defaultValue作为默认值。
    • 当处理基本数据类型(如intlong等)作为请求参数时,如果参数不是必传的且未提供默认值,则可能会引发异常。为了避免这种情况,可以将参数类型更改为相应的包装类型(如IntegerLong等),或者提供一个默认值。
    • 如果请求参数与后端方法参数名不一致,可以通过@RequestParamvalue属性来映射它们之间的关系。
    • 错误处理:如果查询参数不存在且 required = true,Spring 会抛出 MissingServletRequestParameterException

6. 注意事项

  • 确保路径变量的名字与控制器方法参数的名字匹配,或者在 @PathVariable 注解中明确指定变量名。
  • 当处理多个路径变量时,保持 URL 设计的一致性和简洁性。
  • 对于可选的路径变量,考虑使用默认值或进行适当的错误处理。