Spring boot rest одиночная переменная пути, которая принимает разные типы значений - PullRequest
0 голосов
/ 10 сентября 2018

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 - это typeof Long, а Name - это typeof String. Теперь мне нужно реализовать одну конечную точку, которая предоставляет возможность поиска пользователя по идентификатору или имени.

Как я могу реализовать конечную точку покоя, имеющую одну переменную пути, которая принимает идентификатор или имя другого типа?

Моя проблема: Не уверен, как определить @PathVariable, когда пользователь отправляет либо String, либо Long. Это вообще возможно сделать? или я должен сделать @PathVariable как String и разобрать Long?

Ответы [ 2 ]

0 голосов
/ 10 сентября 2018

Учитывая, что это поиск, другой разумный подход - использовать параметры запроса:

/users?name=jdoe

или

/users?id=123

И используйте несколько @QueryParameter вместо @ PathParameter.

И рассмотрите возможность создания псевдонимов, использующих @PathParamter, таких как:

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

Клиенты могут использовать подход параметров запроса или псевдоним, в зависимости от того, что проще. findUser() может просто делегировать findById() или findByName() в зависимости от того, какой параметр запроса был предоставлен.

0 голосов
/ 10 сентября 2018

Краткий ответ. Вы не можете смешивать разные типы в одном @PathVariable, как говорит Spring в своей документации.

Согласно документации Spring IO о @PathVariable:

Аргумент @PathVariable может иметь любой простой тип, например int, long, Date и т. Д. Spring автоматически преобразуется в соответствующий тип или выдает исключение TypeMismatchException, если это не удается сделать.

Обратите внимание на то, что документация обрисовывает в общих чертах Аргумент @PathVariable как тип единственного объекта, который не взаимозаменяем с различными типами.

Кроме того, совершенно нормально иметь обработку исключений, как было дано в ответе на другой вопрос о стекопереработке , что попытка определить Long из String без try/catch даже не стоит работы и снижает производительность.

Вы можете использовать один @PathVariable и иметь блок try/catch для захвата NumberFormatException или просто регулярное выражение.

Метод 1: Обработка исключений

@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);
    }
}

Метод 2: регулярное выражение

Примечание: если значение не найдено, запрос должен просто вернуть пустой результат.

@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);
}
...