Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Stats in entity response DTO pageable

I need to return a DTO response with the entity’s statistics pageable.

Current response:

[
    {
        "id": 1,
        "name": "Customer 1",
        "customerStats": {
            "totalAmount": 950.0,
            "countOrders": 3,
            "countOrdersPending": 1,
            "countOrdersCompleted": 2
        }
    },
    {
        "id": 2,
        "name": "Customer 2",
        "customerStats": {
            "totalAmount": 1867.5,
            "countOrders": 5,
            "countOrdersPending": 2,
            "countOrdersCompleted": 3
        }
    }
]

Expected response:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

{
    "content": [
        {
            "id": 1,
            "name": "Customer 1",
            "customerStats": {
            "totalAmount": 950.0,
            "countOrders": 3,
            "countOrdersPending": 1,
            "countOrdersCompleted": 2
        }
        },
        {
            "id": 2,
            "name": "Customer 2",
            "customerStats": {
            "totalAmount": 1867.5,
            "countOrders": 5,
            "countOrdersPending": 2,
            "countOrdersCompleted": 3
        }
        }
    ],
    "pageable": {
        "sort": {
            "empty": true,
            "sorted": false,
            "unsorted": true
        },
        "offset": 0,
        "pageSize": 20,
        "pageNumber": 0,
        "paged": true,
        "unpaged": false
    },
    "last": true,
    "totalElements": 2,
    "totalPages": 1,
    "size": 20,
    "number": 0,
    "sort": {
        "empty": true,
        "sorted": false,
        "unsorted": true
    },
    "first": true,
    "numberOfElements": 2,
    "empty": false
}

I still need to do the conversion in the controller, how do I do the conversion in the CustomerController?

My classes:

MODEL

Customer

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "customers")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

}

Order

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import javax.persistence.*;
    
    @Entity
    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    @Table(name = "orders")
    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
    public class Order {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "customer_id", nullable = false, foreignKey = @ForeignKey(name = "fk_order_customer1"))
        private Customer customer;
        private Double amount;
    
        @Enumerated(value = EnumType.STRING)
        private OrderStatusType orderStatus;
    
    }

Enum

public enum OrderStatusType {
    PENDING,
    COMPLETED
}

DTO

CustomerStatsDto

import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
public class CustomerStatsDto {
    private Double totalAmount;
    private Long countOrders;
    private Long countOrdersPending;
    private Long countOrdersCompleted;

    public CustomerStatsDto(Double totalAmount, Long countOrders, Long countOrdersPending, Long countOrdersCompleted) {
        this.totalAmount = totalAmount;
        this.countOrders = countOrders;
        this.countOrdersPending = countOrdersPending;
        this.countOrdersCompleted = countOrdersCompleted;
    }
}

CustomerStatsResponse

public interface CustomerStatsResponse {
    Long getId();
    String getName();
    Double getTotalAmount();
    Long getCountOrders();
    Long getCountOrdersPending();
    Long getCountOrdersCompleted();
}

CustomerStatsResponseDto

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class CustomerStatsResponseDto {

    private Long id;
    private String name;
    private CustomerStatsDto customerStats;

    public CustomerStatsResponseDto(CustomerStatsResponse customerStatsResponse) {
        this.id = customerStatsResponse.getId();
        this.name = customerStatsResponse.getName();
        this.customerStats = new CustomerStatsDto(customerStatsResponse.getTotalAmount(), customerStatsResponse.getCountOrders(),
                customerStatsResponse.getCountOrdersPending(), customerStatsResponse.getCountOrdersCompleted());
    }
}

REPOSITORY

OrderRep

import com.example.demo.model.Order;
import org.springframework.data.jpa.repository.JpaRepository;

public interface OrderRep extends JpaRepository<Order, Long> {
}

CustomerRep

import com.example.demo.dto.CustomerStatsResponse;
import com.example.demo.model.Customer;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;

public interface CustomerRep extends JpaRepository<Customer, Long> {

    @Query(value = "SELECT c.id, c.name, " +
            "SUM(o.amount) AS totalAmount, " +
            "COUNT(o.id) AS countOrders, " +
            "(SELECT COUNT(ord.id) FROM orders ord " +
            "WHERE ord.customer_id = c.id AND ord.order_status = 'PENDING') as countOrdersPending, " +
            "(SELECT COUNT(ord.id) FROM orders ord " +
            "WHERE ord.customer_id = c.id AND ord.order_status = 'COMPLETED') as countOrdersCompleted " +
            "FROM customers c " +
            "INNER JOIN orders o ON c.id = o.customer_id " +
            "GROUP BY c.id, c.name"
            , nativeQuery = true)
    List<CustomerStatsResponse> customerStats();

    @Query(value = "SELECT c.id, c.name, " +
            "SUM(o.amount) AS totalAmount, " +
            "COUNT(o.id) AS countOrders, " +
            "(SELECT COUNT(ord.id) FROM orders ord " +
            "WHERE ord.customer_id = c.id AND ord.order_status = 'PENDING') as countOrdersPending, " +
            "(SELECT COUNT(ord.id) FROM orders ord " +
            "WHERE ord.customer_id = c.id AND ord.order_status = 'COMPLETED') as countOrdersCompleted " +
            "FROM customers c " +
            "INNER JOIN orders o ON c.id = o.customer_id " +
            "GROUP BY c.id, c.name"
            , nativeQuery = true)
    Page<CustomerStatsResponse> customerStatsPageable(Pageable pageable);

}

SERVICE

CustomerService

import com.example.demo.dto.CustomerStatsResponse;
import com.example.demo.model.Customer;
import com.example.demo.repository.CustomerRep;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@RequiredArgsConstructor
public class CustomerService {

    private final CustomerRep customerRep;

    public List<Customer> findAll() {
        return customerRep.findAll();
    }

    public List<CustomerStatsResponse> customerStats() {
        return customerRep.customerStats();
    }

    public Page<CustomerStatsResponse> customerStatsPageable(Pageable pageable) {
        return customerRep.customerStatsPageable(pageable);
    }

}

CONTROLLER

CustomerController

import com.example.demo.dto.CustomerStatsResponseDto;
import com.example.demo.model.Customer;
import com.example.demo.service.CustomerService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequestMapping("api/v1/customers")
@RequiredArgsConstructor
public class CustomerController {

    private final CustomerService customerService;

    @GetMapping
    public ResponseEntity<List<Customer>> findAll() {
        return ResponseEntity.ok(customerService.findAll());
    }

    @GetMapping("/stats")
    public ResponseEntity<List<CustomerStatsResponseDto>> customerStats() {
        return ResponseEntity.ok(customerService.customerStats().stream()
                .map(customerStatsResponse -> new CustomerStatsResponseDto(customerStatsResponse))
                .collect(Collectors.toList()));
    }

    @GetMapping("/stats/pageable")
    public ResponseEntity<Page<CustomerStatsResponseDto>> customerStatsPageable(Pageable pageable) {
        //Return Customer Stats pageable
        return null;
    }

}

>Solution :

You can do it easily with Page.map() method (reference documentation):

@RestController
@RequestMapping("api/v1/customers")
@RequiredArgsConstructor
public class CustomerController {

    private final CustomerService customerService;

    @GetMapping
    public ResponseEntity<List<Customer>> findAll() {
        return ResponseEntity.ok(customerService.findAll());
    }

    @GetMapping("/stats")
    public ResponseEntity<List<CustomerStatsResponseDto>> customerStats() {
        return ResponseEntity.ok(customerService.customerStats().stream()
                .map(CustomerStatsResponseDto::new)
                .collect(Collectors.toList()));
    }

    @GetMapping("/stats/pageable")
    public ResponseEntity<Page<CustomerStatsResponseDto>> customerStatsPageable(Pageable pageable) {
        return ResponseEntity.ok(customerService.customerStatsPageable()
                .map(CustomerStatsResponseDto::new));
    }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading