Подтвердить что ты не робот

Spring MVC 3: вернуть страницу Spring -Data как JSON

У меня есть уровень доступа к данным, созданный с помощью Spring -Data. Теперь я создаю веб-приложение поверх него. Этот один метод контроллера должен вернуть Spring -Data страницу в формате JSON.

Такая страница представляет собой список с дополнительной информацией пейджинга, такой как общее количество записей и т.д.

Это возможно и если да, то как?

И напрямую связанный с этим я могу определить отображение имен свойств? Например. это означает, что мне нужно определить, как свойства информации пейджинга называются в JSON (иначе, чем на странице). Возможно ли это и как?

4b9b3361

Ответ 1

Поддерживается такой сценарий, как этот, предстоящий в Spring HATEOAS и Spring Data Commons. Spring HATEOAS поставляется с объектом PageMetadata, который по существу содержит те же данные, что и Page, но менее строгим образом, так что он может быть легче маршалирован и немаршален.

Другим аспектом, который мы реализуем в сочетании с Spring HATEOAS и Spring Data commons, является то, что мало что нужно для простого маршалинга страницы, ее содержимого и метаданных, а также для создания ссылок, возможно, существующих следующей или предыдущих страниц, так что клиенту не нужно создавать URI для перемещения по этим страницам.

Пример

Предположим, что класс домена Person:

class Person {

  Long id;
  String firstname, lastname;
}

а также соответствующий репозиторий:

interface PersonRepository extends PagingAndSortingRepository<Person, Long> { }

Теперь вы можете выставить контроллер Spring MVC следующим образом:

@Controller
class PersonController {

  @Autowired PersonRepository repository;

  @RequestMapping(value = "/persons", method = RequestMethod.GET)
  HttpEntity<PagedResources<Person>> persons(Pageable pageable, 
    PagedResourcesAssembler assembler) {

    Page<Person> persons = repository.findAll(pageable);
    return new ResponseEntity<>(assembler.toResources(persons), HttpStatus.OK);
  }
}

Вероятно, здесь немного объяснять. Позвольте сделать шаг за шагом:

  • У нас есть контроллер Spring MVC, который подключает репозиторий к нему. Для этого требуется Spring Настройка данных (через @Enable(Jpa|Mongo|Neo4j|Gemfire)Repositories или эквиваленты XML). Метод контроллера сопоставляется с /persons, что означает, что он примет все запросы GET к этому методу.
  • Тип ядра, возвращаемый из метода, представляет собой PagedResources - тип из Spring HATEOAS, который представляет некоторый контент, обогащенный Links плюс a PageMetadata.
  • При вызове метода Spring MVC придется создавать экземпляры для Pageable и PagedResourcesAssembler. Чтобы получить эту работу, вам необходимо включить веб-поддержку Spring Data, либо через аннотацию @EnableSpringDataWebSupport, которая должна быть представлена ​​в предстоящей вехе Spring Data Commons, либо через автономные определения bean (документально здесь).

    Pageable будет заполнена информацией из запроса. Конфигурация по умолчанию превратит ?page=0&size=10 в Pageable, запрашивая первую страницу, размером страницы 10.

    PageableResourcesAssembler позволяет вам легко превратить Page в экземпляры PagedResources. Он не только добавит метаданные страницы в ответ, но и добавит соответствующие ссылки к представлению на основе той страницы, на которую вы получаете доступ, и как настроено ваше разрешение Pageable.

Пример конфигурации JavaConfig для включения этого для JPA будет выглядеть следующим образом:

@Configuration
@EnableWebMvc
@EnableSpringDataWebSupport
@EnableJpaRepositories
class ApplicationConfig {

  // declare infrastructure components like EntityManagerFactory etc. here
}

Пример запроса и ответа

Предположим, что в базе данных 30 Persons. Теперь вы можете вызвать запрос GET http://localhost:8080/persons, и вы увидите что-то похожее на это:

{ "links" : [
    { "rel" : "next", "href" : "http://localhost:8080/persons?page=1&size=20 }
  ],
  "content" : [
    … // 20 Person instances rendered here
  ],
  "pageMetadata" : {
    "size" : 20,
    "totalElements" : 30,
    "totalPages" : 2,
    "number" : 0
  }
}

Обратите внимание, что ассемблер создал правильный URI, а также отображает конфигурацию по умолчанию, чтобы разрешить параметры в Pageable для предстоящего запроса. Это означает, что если вы измените эту конфигурацию, ссылки будут автоматически привязаны к изменению. По умолчанию ассемблер указывает на метод контроллера, к которому он был вызван, но который можно настроить, передав пользовательский Link, который будет использоваться в качестве базы для создания ссылок на страницы с перегрузками метода PagedResourcesAssembler.toResource(…).

Outlook

Биты PagedResourcesAssembler будут доступны в следующем выпуске релиза Spring Data Babbage . Он уже доступен в текущих моментальных снимках. Вы можете увидеть рабочий пример этого приложения Spring RESTBucks . Просто клонируйте его, запустите mvn jetty:run и закрутите http://localhost:8080/pages.

Ответ 2

Оливер, ваш ответ велик, и я отмечаю это как ответ. Здесь просто для полноты того, что я придумал для среднего времени, которое может быть полезно для кого-то другого.

Я использую JQuery Datatables в качестве виджета grid/table. Он отправляет очень специфический параметр на сервер и исключает очень специфический ответ: см. http://datatables.net/usage/server-side.

Для этого создается пользовательский вспомогательный объект, отражающий ожидаемые данные. Обратите внимание, что getter и setter должны быть названы так, как если бы они были произведены неправильно json (имена свойств и данных, чувствительные к регистру, используют эту "псевдо-венгерскую нотацию"...).

public class JQueryDatatablesPage<T> implements java.io.Serializable {

    private final int iTotalRecords;
    private final int iTotalDisplayRecords;
    private final String sEcho;
    private final List<T> aaData;

    public JQueryDatatablesPage(final List<T> pageContent,
            final int iTotalRecords,
            final int iTotalDisplayRecords,
            final String sEcho){

        this.aaData = pageContent;
        this.iTotalRecords = iTotalRecords;
        this.iTotalDisplayRecords = iTotalDisplayRecords;
        this.sEcho = sEcho;
    }

    public int getiTotalRecords(){
        return this.iTotalRecords;
    }

    public int getiTotalDisplayRecords(){
        return this.iTotalDisplayRecords;
    }

    public String getsEcho(){
        return this.sEcho;
    }

    public List<T> getaaData(){
        return this.aaData;
    }
}

Вторая часть - это метод в соответствующем контроллере:

@RequestMapping(value = "/search", method = RequestMethod.GET, produces = "application/json")
public @ResponseBody String search (
        @RequestParam int iDisplayStart,
        @RequestParam int iDisplayLength,
        @RequestParam int sEcho, // for datatables draw count
        @RequestParam String search) throws IOException {

    int pageNumber = (iDisplayStart + 1) / iDisplayLength;
    PageRequest pageable = new PageRequest(pageNumber, iDisplayLength);
    Page<SimpleCompound> page = compoundService.myCustomSearchMethod(search, pageable);
    int iTotalRecords = (int) (int) page.getTotalElements();
    int iTotalDisplayRecords = page.getTotalPages() * iDisplayLength;
    JQueryDatatablesPage<SimpleCompound> dtPage = new JQueryDatatablesPage<>(
            page.getContent(), iTotalRecords, iTotalDisplayRecords,
            Integer.toString(sEcho));

    String result = toJson(dtPage);
    return result;

}

private String toJson(JQueryDatatablesPage<?> dt) throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new Hibernate4Module());
    return mapper.writeValueAsString(dt);
}

compoundService поддерживается Spring -Data repository. Он управляет транзакциями и безопасностью уровня метода. toJSON() использует метод Jackson 2.0, и вам нужно зарегистрировать соответствующий модуль в mapper, в моем случае для спящего режима 4.

Если у вас двунаправленные отношения, вам необходимо аннотировать все классы сущностей с помощью

@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="jsonId")

Это позволяет Jackson 2.0 сериализовать круговые зависимости (в предыдущей версии этого не было возможно и требует, чтобы ваши сущности были аннотированы).

Вам нужно будет добавить следующие зависимости:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.2.1</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-hibernate4</artifactId>
    <version>2.2.1</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.2.1</version>
    <type>jar</type>
</dependency>