1

Тема: Rest Api with Spring - дефолтне сортування за полем класу

Привіт.
Роблю перші кроки.
програма з контролю витрат-поля date (дата витрат), amount - сума витрат, currency - валюта і product - на що витрачено.
Ентітя нижче.

package com.spring.entities;


import java.time.LocalDate;
import java.util.Objects;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Expense {

    @Id
    @Column(nullable = false, updatable = false)
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long id;
    private LocalDate date;
    private Double amount;
    private String currency;
    private String product;
    
    
    

    public LocalDate getDate() {
        return date;
    }

    public void setDate(LocalDate date) {
        this.date = date;
    }

    public Double getAmount() {
        return amount;
    }

    public void setAmount(Double amount) {
        this.amount = amount;
    }

    public String getCurrency() {
        return currency;
    }

    public void setCurrency(String currency) {
        this.currency = currency;
    }

    public String getProduct() {
        return product;
    }

    public void setProduct(String product) {
        this.product = product;
    }

    
    
    @Override
    public boolean equals(Object obj) {
        
        return Objects.equals(id, ((Expense)obj).id);
    }
    
    @Override
    public int hashCode() {
        
        return Objects.hashCode(id);
    }

}

Потрібно, що за замовчуванням на endpoint 'expenses' відповідь була по даті, при чому відсортованій, тобто json повинен бути як нижче:


GET http://localhost:8080/expenses

{
“2021-04-22”: [
{
“id”: 2,
“date”: “2021-04-22”,
“amount”: 12,
“currency”: “USD”,
“product”: “Salmon”
}
],
“2021-04-27”: [
{
“id”: 4,
“date”: “2021-04-27”,
“amount”: 4.75,
“currency”: “EUR”,
“product”: “Beer”
},
{
“id”: 5,
“date”: “2021-04-27”,
“amount”: 25.5,
“currency”: “UAH”,
“product”: “Sweets”
}
]
}

Буду вдячний за допомогу

2 Востаннє редагувалося fed_lviv (22.03.2021 12:46:13)

Re: Rest Api with Spring - дефолтне сортування за полем класу

taras2409 написав:

...дефолтне сортування за полем класу

Не дуже зрозумів, що саме Ви маєте на увазі під дефолтним сортуванням. Проте, схиляюсь до того варіанту, що Вам потрібно буде його, все ж таки задати, в запиті до БД (ORDER BY..., Sort,...)

taras2409 написав:

...тобто json повинен бути як нижче:

Звісно можна спробувати написати відповідний SQL запит (тобто використати native query) ну й при цьому глянути чи СУБД, яку Ви використовуєте, щось таке підтримує (JSON_ARRAYAGG(), JSON_OBJECTAGG(), json_build_object(), json_agg(), ...).
Інший варіант - використати відповідний клас (DTO) в якому й будуть такі дані (тобто згрупувати та відсортувати поточні дані й відобразити їх в певному об'єкті).

P.S. Про всяк випадок:
Щодо:

taras2409 написав:

...amount - сума витрат,

Як працювати з цінами?
Щодо equals та hashCode:
The best way to implement equals, hashCode, and toString with JPA and Hibernate

3

Re: Rest Api with Spring - дефолтне сортування за полем класу

Вдячний за відповідь. Мабуть, я невірно виразився.
Зараз при виклику http://localhost:8080/expenses

{
                "date": "2021-10-02",
                "amount": 14.75,
                "currency": "Eu",
                "product": "bread",
                "_links": {
                    "self": {
                        "href": "http://localhost:8080/expenses/3"
                    },
                    "expense": {
                        "href": "http://localhost:8080/expenses/3"
                    }
                }
            },
            {
                "date": "2020-09-15",
                "amount": 14.75,
                "currency": "Eu",
                "product": "bread",
                "_links": {
                    "self": {
                        "href": "http://localhost:8080/expenses/5"
                    },
                    "expense": {
                        "href": "http://localhost:8080/expenses/5"
                    }
                }
            }

А потрібно, щоб саме за цим Endpoint  (expenses ), тобто, при введенні Uri http://localhost:8080/expenses була саме така відповідь, тобто згруповано по даті, ще й соровано:

{
“2021-04-22”: [
{
“id”: 2,
“date”: “2021-04-22”,
“amount”: 12,
“currency”: “USD”,
“product”: “Salmon”
}
],
“2021-04-27”: [
{
“id”: 4,
“date”: “2021-04-27”,
“amount”: 4.75,
“currency”: “EUR”,
“product”: “Beer”
}

Можливо, є варіант якось це через RestController зробити чи іншим способом безпосередньо у коді?

4

Re: Rest Api with Spring - дефолтне сортування за полем класу

taras2409 написав:

Можливо, є варіант якось це через RestController зробити чи іншим способом безпосередньо у коді?

Варіант №1:

fed_lviv написав:

...спробувати написати відповідний SQL запит (тобто використати native query)...

Тобто написати SQL запит, який буде повертати вже готовий JSON (хоч в даному випадку я б таке, напевно не робив би, а ось в інших ситуаціях - допомагає) й в контролері/сервісі виконати даний запит.

Варіант №2:

fed_lviv написав:

...використати відповідний клас (DTO) в якому й будуть такі дані..

Опишіть клас, який буде мати відповідні поля, тобто певну мапу (щось типу - Map<LocalDate, SomeObject[]>) й туди покладіть відповідні дані з об'єктів Expense (звісно для цього потрібно згрупувати потрібні дані). На крайній випадок можна обійтися без створення спеціального DTO, тобто напряму закидати все в мапу й вже її повертати з методу Вашого контролера.

Подякували: taras24091

5

Re: Rest Api with Spring - дефолтне сортування за полем класу

Дякую, буду пробувати через запит MySql  - Map не підійде для даного випадку, оскільки ключ LocalDate не унікальний, хіба що навпаки, обєкт Expenses зробити ключем (він завжди відрізняється через різні id), а LocalDate  значенням. Дасться чути)

6

Re: Rest Api with Spring - дефолтне сортування за полем класу

taras2409 написав:

...Map не підійде для даного випадку, оскільки ключ LocalDate не унікальний...

??? Переглядаючи JSON, який Ви надали, в мене не виникає сумнівів в унікальності:

taras2409 написав:

...
“2021-04-27”: [
{
“id”: 4,
“date”: “2021-04-27”,
“amount”: 4.75,
“currency”: “EUR”,
“product”: “Beer”
},
{
“id”: 5,
“date”: “2021-04-27”,
“amount”: 25.5,
“currency”: “UAH”,
“product”: “Sweets”
}
]
...

Тобто на рівні JSON ця унікальність присутня, оскільки відбувається групування (створення масивів) по даті. Тобто те про що я й писав:

fed_lviv написав:

...покладіть відповідні дані з об'єктів Expense (звісно для цього потрібно згрупувати потрібні дані)...

taras2409 написав:

...через запит MySql ...

Якщо версія MySQL >= 5.7.22 то можна використати JSON_OBJECTAGG(), JSON_ARRAYAGG().
Для прикладу маємо такі дані:

id     date                 product
1    2021-03-22    Хліб
2    2021-03-24    Пиво
3    2021-03-11    Сало
4    2021-03-22    Борошно

Ось такий запит поверне готовий JSON:

SELECT
    JSON_OBJECTAGG( date, grp ) AS json 
FROM
    ( SELECT date, JSON_ARRAYAGG( JSON_OBJECT( "product", product, "id", id ) ) AS grp FROM expense GROUP BY date ) AS tmp 
ORDER BY
    date;

Результат:
{"2021-03-11": [{"id": 3, "product": "Сало"}], "2021-03-22": [{"id": 1, "product": "Хліб"}, {"id": 4, "product": "Борошно"}], "2021-03-24": [{"id": 2, "product": "Пиво"}]}

Подякували: taras24091

7

Re: Rest Api with Spring - дефолтне сортування за полем класу

Дякую, як і пишу, роблю тільки перші кроки)