Использование пользовательского идентификатора в репозитории Spring Data REST, поддерживаемом MongoDB

#spring #mongodb #spring-boot

#spring #mongodb #spring-boot

Вопрос:

Я работаю над новым проектом с использованием Spring и MongoDB. Я новичок в обоих из них, так что потерпите, я не смог найти окончательного ответа на этот вопрос.

Я использую spring-boot-starter-data-rest и имею такой репозиторий:

 @RepositoryRestResource(collectionResourceRel = "widget", path = "widget")
interface WidgetRepository : MongoRepository<Widget, ObjectId> {
    fun findByType(@Param("type") type: String): List<Widget>
}
  

Для такого объекта, как этот:

 data class Widget @JsonCreator constructor(@JsonProperty val type: String) {
    @Id
    lateinit var id: ObjectId
}
  

Это автоматически дает вам CRUD API с использованием идентификатора документа Mongo:

 GET /widget/{mongo doc id}
GET /widget/search/findByType?type=
POST /widget
PUT /widget
PATCH /widget
  

Но я не хочу использовать идентификатор документа Mongo. Я хочу ввести дополнительный идентификатор и использовать его везде в API. Это связано с тем, что «виджеты» — это элементы в физическом мире, которые имеют штрих-код, и мы не хотим печатать идентификатор документа Mongo в штрих-коде.

Очевидно, что мы можем реализовать это с помощью инструментов Spring REST API, например

     @GetMapping("/widget/{barcode}/")
    fun getByBarcode(@PathVariable barcode: String): Widget {
        return widgetRepository.findByBarcode(barcode)
    }

  

и т. Д. Но есть ли какой-нибудь умный способ @RepositoryRestResource создать для нас свой automagic API с пользовательским идентификатором? Может быть, путем реализации CrudRepository<Widget, Barcode> таким образом, что мы должны обернуть MongoRepository<Widget, ObjectId> ? Я недостаточно знаком с тем, как Spring работает под капотом, чтобы знать, возможно ли что-то подобное.

Заранее спасибо

Комментарии:

1. Если ваш штрих-код является уникальным значением для каждого документа, то вместо ObjectId вы можете использовать Barcode в качестве _id . Значение _id документа может иметь любой тип BSON (кроме массива).

Ответ №1:

Я думаю, вы ищете EntityLookup :

SPI для настройки того, какое свойство объекта используется в качестве уникального идентификатора и как экземпляр объекта просматривается из серверной части.

Во-первых — извините, если я допустил какую-либо ошибку, я не использую для программирования в Kotlin — вам необходимо включить barcode свойство в свой объект:

 data class Widget @JsonCreator constructor(@JsonProperty val type: String, @JsonProperty val barcode: String) {
    @Id
    lateinit var id: ObjectId
}
  

Затем измените свой репозиторий и определите новый метод, который предоставит Widget данный его штрих-код:

 @RepositoryRestResource(collectionResourceRel = "widget", path = "widget")
interface WidgetRepository : MongoRepository<Widget, ObjectId> {
    fun findByBarcode(@Param("barcode") barcode: String): Optional<Widget>
    fun findByType(@Param("type") type: String): List<Widget>
}
  

Наконец, настройте RestRepositoryConfigurer и зарегистрируйте EntityLookup EntityLookupRegistrar :

 @Component
class RestRepositoryConfigurator : RepositoryRestConfigurer {
   override fun configureRepositoryRestConfiguration(config: RepositoryRestConfiguration) {
       config.withEntityLookup()
          .forRepository(WidgetRepository::class.java)
          .withIdMapping(Widget::barcode)
          .withLookup(WidgetRepository::findByBarcode)
   }
}
  

Пожалуйста, ознакомьтесь с разделом 15.1 документации Spring Data Rest, если вам нужна дополнительная информация.

Комментарии:

1. @michiakig У вас была возможность протестировать предложенное решение?

2. привет, спасибо за вашу помощь, это работает. нам пришлось изменить data class Widget на open class Widget , поскольку была ошибка о Widget::barcode том, что он является окончательным (классы kotlin являются окончательными по умолчанию)

3. Добро пожаловать @michiakig. Я рад узнать, что ответ был полезным. И, пожалуйста, извините за ошибку в классе Kotlin, как я уже говорил, я понимаю код, когда вижу его, но я не использую для программирования в Kotlin

4. да, нет проблем, я включил эту деталь только для будущих читателей 🙂 еще раз спасибо