Home > Mobile >  Stats in entity response DTO pageable
Stats in entity response DTO pageable

Time:12-24

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:

{
    "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;
    }

}

CodePudding user response:

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));
    }
}
  • Related