-2

Spring Boot Rest 如何提供一个端点,该端点具有一个路径变量,该变量采用不同类型的值

@Autowired
private UserRepository userRepository;

@RequestMapping(value="/user/{idOrName}", method=RequestMethod.GET)
public User findUser(@PathVariable String idOrName) {
  this.userRepository.findByIdOrName(idOrName, idOrName);
}

public interface UserRepository extends MongoRepository<User, Long> {
  User findByIdOrName(Long id, String name);
}

@Data
@Document(collection="user")
public class User {
  private Long Id;
  private String name;
}

问题陈述: 从 User 模型中可以看出,Id 是 typeofLong并且 Name 是 typeof String。现在我需要实现单端点,它提供了通过 id 或 name 搜索用户的功能。

如何实现具有一个路径变量的休息端点,该路径变量接受不同类型的 id 或名称?

我的问题是不确定如何定义@PathVariable用户何时发送StringLong。甚至有可能做到吗?还是我应该做@PathVariableasString和 parse Long

4

2 回答 2

1

简短的回答。正如 Spring 在他们的文档中所说,您不能将不同的类型混合到单个 @PathVariable 中。

根据Spring IO文档关于@PathVariable

@PathVariable 参数可以是任何简单类型,例如 int、long、Date 等。Spring 会自动转换为适当的类型,如果不能这样做,则抛出 TypeMismatchException。

请注意,文档将 @PathVariable 参数概述为不可互换为不同类型的单一对象类型。

此外,在另一个 stackoverflow 问题中回答异常处理是完全正常的,即尝试从 String 中确定 Longtry/catch甚至不值得工作并且会降低性能。

您可以使用单个@PathVariable并且有try/catch块来捕获NumberFormatException或简单地使用正则表达式。

方法一:异常处理

@RequestMapping(value="/user/{identifier}", method=RequestMethod.GET)
public User findUser(@PathVariable("identifier") String identifier) {
    try {
        Long long_identifier = Long.parseLong(identifier);
        this.userRepository.findByIdOrName(long_identifier);
    } catch(NumberFormatException nfe) {
        //We know it's a plain string by now.
        this.userRepository.findByIdOrName(identifier);
    }
}

方法二:正则表达式

注意:如果未找到值,则查询应仅返回空结果。

@RequestMapping(value="/user/{identifier}", method=RequestMethod.GET)
public User findUser(@PathVariable("identifier") String identifier) {
    //Check for digits only
    String regexpr = "\\d+";
    this.userRepository.findByIdOrName(
        identifier.matches(regexpr)
        ? Long.parseLong(identifier)
        : identifier
    );
}

方法3:使用正则表达式请求映射

@RequestMapping(value="/user/{identifier:[A-Za-z]+}", method=RequestMethod.GET)
public User findUserByString(@PathVariable("identifier") String identifier) {
    this.userRepository.findByIdOrName(identifier);
}

@RequestMapping(value="/user/{identifier:[0-9]+}", method=RequestMethod.GET)
public User findUserByLong(@PathVariable("identifier") Long identifier) {
    this.userRepository.findByIdOrName(identifier);
}
于 2018-09-10T15:11:10.197 回答
0

鉴于这是一个搜索,另一种合理的方法是使用查询参数:

/users?name=jdoe

或者

/users?id=123

并使用多个@QueryParameter 而不是@PathParameter。

并考虑创建使用 @PathParamter 的别名,例如:

/users/name/{name}
/users/id/{id}

客户端可以使用查询参数方法或别名,以更容易为准。findUser()可以简单地委托给findById()findByName()取决于提供的查询参数。

于 2018-09-10T15:40:28.800 回答