2021. 12. 20. 17:12ㆍ스프링부트
매출관리 페이지를 추가합니다
admin -> sales.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/view/include/link.jsp" %>
<link rel="stylesheet" href="/css/admin/sales.css" >
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js" integrity="sha512-qTXRIMyZIFb8iQcfjXWCO8+M5Tbc38Qi5WzdPOYZHIlZpzBHG3L3by84BBBOiRGiEb7KKtAOAs5qYdUiZiQNNQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<%@ include file="/WEB-INF/view/include/header.jsp" %>
<main>
<section>
<div class="today">
<span>
<span>오늘 매출</span>
<span id="today"></span>
</span>
<button>상세보기</button>
</div>
</section>
<section class="detail today_detail">
<div>
<h3 class="sales_today_detail_title">
<span>매출 상세</span>
<span>
<button class="sort_name reverse">이름순</button>
<button class="sort_price reverse">가격순</button>
</span>
</h3>
<div class="sales_today_detail">
<div>메뉴</div>
<div>수량</div>
<div>가격</div>
</div>
</div>
</section>
<section class="graph_section" onselectstart="return false;" >
<div class="box">
<button class="year_btn">연 매출</button>
<button class="month_btn">이번 달 매출</button>
<button class="week_btn">이번 주 매출</button>
<input type="month"name="date" id="date">
<button class="other_month_search">검색</button>
<h1>1월 총 합계</h1>
<div>(단위 : 만원)</div>
<div class="graph_box">
<ul>
<!--
<li>
<span class="sales"></span>
<div class="graph"></div>
<span class="graph_date"></span>
</li>
-->
</ul>
<div class="graph_background">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
</div>
</section>
<section class="detail other_detail">
<div>
<h3 class="sales_today_detail_title">
<span id="other_detail_date"></span>
<span>
<button class="sort_name reverse">이름순</button>
<button class="sort_price reverse">가격순</button>
</span>
</h3>
<div class="sales_today_detail">
<!-- <div>메뉴</div>
<div>수량</div>
<div>가격</div> -->
</div>
</div>
</section>
</main>
<script src="/js/util/util.js"></script>
<script src="/js/admin/sales.js"></script>
</body>
</html>
admin -> sales.css
@charset "utf-8";
body {
background: #F3F5F7;
}
main {
width: 90%;
max-width: 1200px;
margin: 20px auto 100px;
}
section {
background: #fff;
padding: 10px 5px;
border: 1px solid #E0E5EE;
margin-bottom: 20px;
}
section.detail {
display: none;
max-height: 400px;
overflow-y: auto;
}
.today {
display: flex;
justify-content: space-between;
align-items: center;
}
.today #today {
font-weight: bold;
margin-left: 10px;
}
.sales_today_detail_title {
margin-bottom: 5px;
font-weight: 500;
display: flex;
justify-content: space-between;
}
.sales_today_detail {
display: grid;
grid-template-columns: 3fr 1fr 1fr;
grid-template-rows: 40px;
}
.sales_today_detail > div {
border: 1px solid #ddd;
line-height: 40px;
padding-left: 10px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
section.graph_section {
overflow-x: auto;
}
section.graph_section::-webkit-scrollbar {
display: none;
}
.box {
min-width: 650px;
}
main button {
padding: 5px 10px;
border-radius: 5px;
background: #fff;
border: 1px solid #ccc;
font-size: 1.2rem;
}
main #date {
padding: 5px 10px;
border-radius: 5px;
font-weight: bold;
border: 1px solid #ccc;
font-size: 1.2rem;
}
main h1 {
margin: 20px 0;
}
main .graph_box {
position: relative;
height: 55vh;
}
main .graph_box .graph_background {
position: absolute;
top: 0;
width: 100%;
height: 100%;
display: none;
}
main .graph_box .graph_background div {
height: 20%;
width: 100%;
border: 1px solid #ddd;
border-top: none;
}
main .graph_box ul {
display: flex;
height: 100%;
}
main .graph_box ul li {
flex: 1;
margin-right: 5px;
display: flex;
align-items: center;
justify-content: end;
flex-direction: column;
}
main .graph_box .graph {
width: 30%;
min-height: 3px;
background: green;
z-index: 1;
border-radius: 5px 5px 0 0;
position: relative;
transition: 0.1s;
cursor: pointer;
}
main .graph_box .graph:hover {
transform: scaleX(1.2);
background: red;
}
main .graph_box .sales {
font-size: 1.15rem;
}
main .graph_box .graph_date {
font-size: 1.15rem;
}
@media ( max-width :1250px) {
#tab {
width: 100%;
}
}
@media ( max-width :1024px) {
section.tab {
margin-top: 0px;
display: none;
}
.tab .box {
display: block;
}
header .admin_page_btn {
display: none;
}
header .menu_tab {
display: block;
}
}
@media ( max-width :767px) {
main {
width: 95%;
}
section.tab ul li {
font-size: 16px;
height: 50px;
}
section.tab ul li a {
line-height: 50px;
}
}
@media ( max-width :480px) {
main {
width: 100%;
}
}
admin -> sales.js
$(document).ready(function(){
const pathArr = location.pathname.split("/");
const storeId = pathArr[pathArr.length-1];
const dateInput = document.getElementById("date");
dateInput.valueAsDate = new Date();
// getDetail이 true일때 상세보기 가능
let getDetail = true;
function graphDraw(data, format, title){
let html = "";
for(i=0;i<data.length-1;i++) {
html +=
`<li>
<span class="sales"></span>
<div class="graph" data-date="${data[i].orderDate}"></div>
<span class="graph_date">${moment(data[i].orderDate).format(format) }</span>
</li>`
}
$(".graph_box ul").html(html);
if(!data[data.length-1]) {
$("main h1").text(title +"0원");
return;
}
const total = data[data.length-1].total;
$("main h1").text(title + total.toLocaleString() + "원");
for(i=0;i<data.length-1;i++) {
const sum = data[i].total;
const avg = sum / total * 100;
$(".graph_box li").eq(i).find(".graph").css("height", avg +"%");
if(sum != 0){
$(".graph_box li").eq(i).find(".sales").text((sum/10000).toFixed(1));
}
}
}
function sales(term){
const date = moment(new Date()).format("YYYY-MM");
let title = "";
let format = "";
const data = {
date : date,
storeId : storeId
};
switch(term) {
case "week": {
format = "MM월 DD일";
data.term = "week";
title = "이번 주 총 합계 ";
break;
}
case "thisMonth": {
format = "D";
data.term = "month";
title = moment(date).format("M") + "월 총 합계 ";
break;
}
case "month": {
format = "D";
data.date = $("#date").val();
data.term = "month";
title = moment(data.date).format("M") + "월 총 합계 ";
break;
}
case "year": {
format = "MM월"
data.term = "year";
title = moment(date).format("YYYY") + "년 총 합계 ";
break;
}
}
$.ajax({
url: "/admin/management/sales",
type: "GET",
data: data
})
.done(function(result) {
console.log(result);
graphDraw(result, format, title);
})
.fail(function(data){
alert("에러");
})
}
// 그래프 가로 스크롤
(function(){
let x;
let left;
let down;
const target = $(".graph_section");
target.mousedown(function(e){
down = true;
x = e.pageX;
left = $(this).scrollLeft();
});
$(window).mousemove(function(e){
if(down){
var newX = e.pageX;
target.scrollLeft(left - newX + x);
}
});
$(window).mouseup(function(e){
down = false;
});
})();
// 그래프 막대 그리기
function detailHtml(result){
let html = `<div>메뉴</div>
<div>수량</div>
<div>가격</div>`;
for(i=0;i<result.menuList.length;i++) {
const menu = result.menuList[i];
const option = menu.optionName == null ? "" : "[" + menu.optionName + "]";
html +=
`<div>${menu.foodName}${option }</div>
<div>${menu.amount}</div>
<div>${menu.totalPrice.toLocaleString()}</div>`;
}
return html;
}
// 하루 매출 상세보기
function salesDetail(data, fnc){
$.ajax({
url: "/admin/management/salesDetail",
type: "GET",
data: data
})
.done(function(result){
fnc(result);
})
.fail(function(){
alert("에러");
})
}
// 기본페이지 주 매출
sales("week");
// 월 매출
$(".month_btn").click(function(){
sales("thisMonth");
getDetail = true;
})
// 다른 달 일 매출
$(".other_month_search").click(function(){
sales("month");
getDetail = true;
})
// 이번주 매출
$(".week_btn").click(function(){
sales("week");
getDetail = true;
})
// 올해 매출
$(".year_btn").click(function(){
sales("year");
getDetail = false;
})
// 오늘 매출 실행함수
const todayDetail = function(result){
$("#today").text(result.total.toLocaleString() +"원");
const html = detailHtml(result);
$(".today_detail .sales_today_detail").html(html);
}
// 오늘 매출 보기
salesDetail({storeId : storeId}, todayDetail);
// 오늘 매출 상세 표시
$(".today button").click(function(){
$(".today_detail").fadeToggle(200);
});
// 이름순 정렬
$(".today_detail .sort_name").click(function(){
const data ={
storeId : storeId,
};
if($(this).hasClass("reverse")) {
$(this).removeClass("reverse");
data.sort = "nameR";
} else {
$(this).addClass("reverse");
data.sort = "name";
}
salesDetail(data, todayDetail);
})
// 가격순 정렬
$(".today_detail .sort_price").click(function(){
const data ={
storeId : storeId,
};
if($(this).hasClass("reverse")) {
$(this).removeClass("reverse");
data.sort = "priceR";
} else {
$(this).addClass("reverse");
data.sort = "price";
}
salesDetail(data, todayDetail);
})
const detail = function(result) {
const html = detailHtml(result);
$(".other_detail .sales_today_detail").html(html);
}
// 그래프 막대 클릭
$(document).on("click", ".graph", function(){
if(getDetail) {
const date = $(this).data("date");
const data ={storeId : storeId, date : date};
salesDetail(data, function(result) {
$(".other_detail").show();
const offset = $(".other_detail").offset().top /2;
$("html").animate({ scrollTop: offset }, 400);
const html = detailHtml(result);
$(".other_detail .sales_today_detail").html(html);
$("#other_detail_date").text(date);
});
}
})
// 다른날 상세보기 이름순 정렬 (그래프클릭)
$(".other_detail .sort_name").click(function(){
const data ={
storeId : storeId,
};
if($(this).hasClass("reverse")) {
$(this).removeClass("reverse");
data.sort = "nameR";
} else {
$(this).addClass("reverse");
data.sort = "name";
}
salesDetail(data, detail);
})
// 다른날 상세보기 가격순 정렬 (그래프클릭)
$(".other_detail .sort_price").click(function(){
const data ={
storeId : storeId,
};
if($(this).hasClass("reverse")) {
$(this).removeClass("reverse");
data.sort = "priceR";
} else {
$(this).addClass("reverse");
data.sort = "price";
}
salesDetail(data, detail);
})
})
매출 관리페이지 메서드를 추가합니다
@IsMyStore
@GetMapping("/admin/management/sales/{id}")
public String sales(@PathVariable long id) {
return "admin/sales";
}
데이터를 불러오는 메서드가 없어서 에러가 나니 sales.js의 아래 부분을 주석처리 해놓습니다
오늘 매출 데이터를 불러올 메서드를 추가합니다
@IsMyStore
@GetMapping("/admin/management/salesDetail")
public ResponseEntity<Map<String, Object>> salesDetail(long storeId, String date){
System.out.println("매출 상세");
System.out.printf("가게 번호 : %d, 날짜 : %s ", storeId, date);
Map<String, Object> salseToday = adminService.salesDetail(storeId, date);
return new ResponseEntity<Map<String, Object>>(salseToday, HttpStatus.OK);
}
date는 2021-12-1 형태로 넘어오게 되는데 date가 null이라면 오늘 매출, date가 null이 아니라면 해당 날짜의 매출데이터를 가져옵니다
Service와 DAO를 추가합니다
AdminServiceImp
@Override
public Map<String, Object> salesDetail(long storeId, String date) {
List<SalesDetail> salesToday = adminDAO.salesDetail(storeId, date);
long total = 0;
List<Cart> menuList = new ArrayList<>();
for(int i=0;i<salesToday.size();i++) {
List<Cart> cartList = FoodInfoFromJson.foodInfoFromJson(salesToday.get(i).getFoodInfo());
for(int j=0;j<cartList.size();j++) {
Cart cart = cartList.get(j);
if(menuList.contains(cart)) {
int index = menuList.indexOf(cart);
int amount = cart.getAmount();
int price = cart.getTotalPrice();
menuList.get(index).setAmount(amount + menuList.get(index).getAmount());
menuList.get(index).setTotalPrice(price + menuList.get(index).getTotalPrice());
} else {
menuList.add(cartList.get(j));
}
}
total += salesToday.get(i).getTotalPrice();
}
Map<String, Object> map = new HashMap<>();
map.put("menuList", menuList);
map.put("total", total);
return map;
}
salesDetail 메서드를 실행해 메뉴 목록과 메뉴가격의 합을 가져옵니다
DB에서 JSON_VALUE를 사용해 처리하고 싶었지만 optionName이 아래와 같이 []로 감싸져있어 값을 가져오는데 실패했습니다
{"optionName":["치즈크러스트로 변경","파스타 추가","베이컨 토핑 추가","치즈 토핑 추가"]}
메뉴 목록을 가져와 장바구니추가 메서드를 구현할 때 처럼 같은 메뉴끼리 분류해 LIST에 담고 메뉴의 총합과 함께 반환합니다
AdminDAOImp
@Override
public List<SalesDetail> salesDetail(long storeId, String date) {
Map<String, Object> map = new HashMap<>();
map.put("storeId", storeId);
map.put("date", date);
return sql.selectList("admin.salesDetail", map);
}
AdminMapper
<select id="salesDetail" resultType="SalesDetail">
WITH T_ORDER AS (
SELECT * FROM (
SELECT ORDER_NUM, STORE_ID, ORDER_DATE, TOTAL_PRICE, DELEVERY_STATUS FROM BM_ORDER_USER
UNION ALL
SELECT ORDER_NUM, STORE_ID, ORDER_DATE, TOTAL_PRICE, DELEVERY_STATUS FROM BM_ORDER_NON_USER
)
WHERE STORE_ID = #{storeId }
AND DELEVERY_STATUS = '배달 완료'
<if test="date == null">
AND TO_CHAR(ORDER_DATE, 'YYYYMMDD') = TO_CHAR(SYSDATE, 'YYYYMMDD')
</if>
<if test="date != null">
AND TO_CHAR(ORDER_DATE, 'YYYY-MM-DD') = #{date }
</if>
),
T_DETAIL AS (
SELECT ORDER_NUM,
LISTAGG(FOOD_INFO, '/') FOOD_INFO
FROM BM_ORDER_DETAIL_USER N
GROUP BY ORDER_NUM
UNION ALL
SELECT ORDER_NUM,
LISTAGG(FOOD_INFO, '/') FOOD_INFO
FROM BM_ORDER_DETAIL_NON_USER N
GROUP BY ORDER_NUM
)
SELECT TOTAL_PRICE
,FOOD_INFO
FROM T_ORDER O
LEFT JOIN T_DETAIL D
ON O.ORDER_NUM = D.ORDER_NUM
</select>
이름순 가격순 정렬을 기능을 추가하기위해 기존 salesDetail 클래스에 sort를 추가로 받을 수 있게합니다
sort의 값으로는 name, nameR, price, prcieR이 넘어옵니다(오름차순, 내림차순)
@IsMyStore
@GetMapping("/admin/management/salesDetail")
public ResponseEntity<Map<String, Object>> salesDetail(long storeId, String date, String sort){
System.out.println("매출 상세");
System.out.printf("가게 번호 : %d, 날짜 : %s, 정렬 : %s%n ", storeId, date, sort);
Map<String, Object> salseToday = adminService.salesDetail(storeId, date, sort);
return new ResponseEntity<Map<String, Object>>(salseToday, HttpStatus.OK);
}
util 패키지에 메뉴목록 정렬 클래스를 추가합니다
SalesSort
package com.baemin.util;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import com.baemin.dto.Cart;
public class SalesSort {
public SalesSort(List<Cart> menuList, String sort) {
sort(menuList, sort);
}
public void sort(List<Cart> menuList, String sort) {
Collections.sort(menuList, new Comparator<Cart>() {
@Override
public int compare(Cart o1, Cart o2) {
// 가격 오름차순
if("price".equals(sort)) {
return o1.getTotalPrice() - o2.getTotalPrice();
}
// 가격 내림차순
else if("priceR".equals(sort)) {
return o2.getTotalPrice() - o1.getTotalPrice();
}
// 기본 정렬 이름 오름차순
else {
String name1= o1.getFoodName();
String name2= o2.getFoodName();
if(name1.compareTo(name2) == 0) {
String[] option1 = o1.getOptionName();
String[] option2 = o2.getOptionName();
if(option1 == null) {
return 1;
}
if(option2 == null) {
return -1;
}
return option1[0].compareTo(option2[0]);
}
if("nameR".equals(sort)) {
return o2.getFoodName().compareTo(o1.getFoodName());
} else {
return o1.getFoodName().compareTo(o2.getFoodName());
}
}
}
});
}
}
생성자를 통해 객체 생성시 sort메서드를 실행하게 했습니다
Collections.sort()메서드에 Comparator의 compare 메서드를 오버라이딩 해서 정렬 기준을 정해줍니다
// 가격 오름차순
if("price".equals(sort)) {
return o1.getTotalPrice() - o2.getTotalPrice();
}
// 가격 내림차순
else if("priceR".equals(sort)) {
return o2.getTotalPrice() - o1.getTotalPrice();
}
두 객체의 totalPrice를 - 했을때 값이 음수냐 양수냐에 따라 오름차순 내림차순이 결정됩니다
// 기본 정렬 이름 오름차순
else {
String name1= o1.getFoodName();
String name2= o2.getFoodName();
if(name1.compareTo(name2) == 0) {
String[] option1 = o1.getOptionName();
String[] option2 = o2.getOptionName();
if(option1 == null) {
return 1;
}
if(option2 == null) {
return -1;
}
return option1[0].compareTo(option2[0]);
}
if("nameR".equals(sort)) {
return o2.getFoodName().compareTo(o1.getFoodName());
} else {
return o1.getFoodName().compareTo(o2.getFoodName());
}
}
두 객체의 이름을 비교하고 이름이 같다면 옵션의 이름을 기준으로 정렬을 합니다
AdminServiceImp의 salesDetail메서드에 추가한 정렬 클래스를 실행합니다
가격순,이름순 버튼 클릭시 정렬이 되고 한번 더 클릭시 역정렬이 됩니다
매출 그래프
주석 처리했던 sales.js의 아래 부분 주석을 해제합니다
매출 그래프 데이터를 불러올 메서드를 추가합니다
@IsMyStore
@GetMapping("/admin/management/sales")
public ResponseEntity<List<Sales>> sales(long storeId, String date, String term) {
// term =
// week, month, year
List<Sales> sales = adminService.sales(storeId,date, term);
return new ResponseEntity<List<Sales>>(sales, HttpStatus.OK);
}
date는 달력 선택 후 검색하기를 눌렀을 때 2021-12 형태로 년-달 까지만 받습니다
term은 이번주,이번달,연 매출 클릭 시 각각 week, month, year 값으로 넘어옵니다
Service와 DAO에 추가합니다
AdminServiceImp
@Override
public List<Sales> sales(long storeId, String date, String term) {
date = date + "-01";
Map<String, Object> map = new HashMap<>();
map.put("storeId", storeId);
map.put("date", date);
map.put("term", term);
return adminDAO.sales(map);
}
date의 형태가 2021-12 처럼 달까지만 표시되기 때문에 -01을 붙여 2021-12-01처럼 만들어줍니다
AdminDAOImp
@Override
public List<Sales> sales(Map<String, Object> map) {
return sql.selectList("admin.sales", map);
}
AdminMapper
<select id="sales" resultType="Sales">
WITH T_ORDER AS (
SELECT STORE_ID
,TO_DATE(ORDER_DATE) ORDER_DATE
,TOTAL_PRICE
FROM (
SELECT TO_CHAR(ORDER_DATE, 'YYYY/MM/DD') ORDER_DATE, STORE_ID, TOTAL_PRICE, DELEVERY_STATUS FROM BM_ORDER_USER
UNION ALL
SELECT TO_CHAR(ORDER_DATE, 'YYYY/MM/DD') ORDER_DATE, STORE_ID, TOTAL_PRICE, DELEVERY_STATUS FROM BM_ORDER_NON_USER
)
WHERE STORE_ID = #{storeId }
AND DELEVERY_STATUS = '배달 완료'
<choose>
<when test="term == 'year'">
AND ORDER_DATE BETWEEN TRUNC(TO_DATE(#{date }), 'YYYY') AND LAST_DAY(#{date })
</when>
<otherwise>
AND ORDER_DATE BETWEEN TRUNC(TO_DATE(#{date }), 'MM') AND LAST_DAY(#{date })
</otherwise>
</choose>
)
<if test="term == 'month'">
SELECT CAL.ORDER_DATE
,SUM(O.TOTAL_PRICE) TOTAL
FROM (
SELECT FIRST_DAY + LEVEL -1 ORDER_DATE
FROM (
SELECT TRUNC(TO_DATE(#{date }), 'MM') FIRST_DAY FROM DUAL
)
CONNECT BY FIRST_DAY + LEVEL -1 <![CDATA[ <= ]]> LAST_DAY(#{date })
) CAL
LEFT JOIN T_ORDER O
ON CAL.ORDER_DATE = O.ORDER_DATE
GROUP BY ROLLUP(CAL.ORDER_DATE)
ORDER BY ORDER_DATE
</if>
<if test="term == 'week'">
SELECT CAL.ORDER_DATE
,SUM(O.TOTAL_PRICE) TOTAL
FROM (
SELECT FIRST_DAY + LEVEL -1 ORDER_DATE
FROM (
SELECT TRUNC(SYSDATE, 'IW') FIRST_DAY FROM DUAL
)
CONNECT BY FIRST_DAY + LEVEL <![CDATA[ <= ]]> FIRST_DAY + 7
) CAL
LEFT JOIN T_ORDER O
ON CAL.ORDER_DATE = O.ORDER_DATE
GROUP BY ROLLUP(CAL.ORDER_DATE)
ORDER BY ORDER_DATE
</if>
<if test="term == 'year'">
SELECT TRUNC(CAL.ORDER_DATE, 'MM') ORDER_DATE
,SUM(O.TOTAL_PRICE) TOTAL
FROM (
SELECT ADD_MONTHS(FIRST_DAY, LEVEL -1) ORDER_DATE
FROM (
SELECT TRUNC(SYSDATE, 'YYYY') FIRST_DAY FROM DUAL
)
CONNECT BY LEVEL <![CDATA[ <= ]]> 12
) CAL
LEFT JOIN T_ORDER O
ON CAL.ORDER_DATE = TRUNC(O.ORDER_DATE, 'MM')
GROUP BY ROLLUP(TRUNC(CAL.ORDER_DATE, 'MM'))
ORDER BY ORDER_DATE
</if>
</select>
여러가지 날짜 함수들과 형변환을 해야해서 까다로웠습니다
WITH T_ORDER AS (
SELECT STORE_ID
,TO_DATE(ORDER_DATE) ORDER_DATE
,TOTAL_PRICE
FROM (
SELECT TO_CHAR(ORDER_DATE, 'YYYY/MM/DD') ORDER_DATE, STORE_ID, TOTAL_PRICE, DELEVERY_STATUS FROM BM_ORDER_USER
UNION ALL
SELECT TO_CHAR(ORDER_DATE, 'YYYY/MM/DD') ORDER_DATE, STORE_ID, TOTAL_PRICE, DELEVERY_STATUS FROM BM_ORDER_NON_USER
)
WHERE STORE_ID = #{storeId }
AND DELEVERY_STATUS = '배달 완료'
<choose>
<when test="term == 'year'">
AND ORDER_DATE BETWEEN TRUNC(TO_DATE(#{date }), 'YYYY') AND LAST_DAY(#{date })
</when>
<otherwise>
AND ORDER_DATE BETWEEN TRUNC(TO_DATE(#{date }), 'MM') AND LAST_DAY(#{date })
</otherwise>
</choose>
- 주문 테이블을 UNION ALL 합니다
- TRUNC 함수의 두번째 인자에 넣어준 패턴에 따라 #{date}를 달까지만 표시할지 해까지만 표시할지 정해줄수있습니다
- LAST_DAY 함수를 사용하면 해당 달의 마지막 날짜를 구할 수 있습니다
- term이 year라면 #{date}를 해까지 표시하고 2021-12-22 => 2021-01-01, #{date}달의 마지막 날짜까지 검색합니다 2021-12-22 => 2021-12-31
- term이 year가 아니라면 #{date}를 2021-12-22 => 2021-12-01 변환 후 마지막 달까지 검색합니다
<if test="term == 'month'">
SELECT CAL.ORDER_DATE
,SUM(O.TOTAL_PRICE) TOTAL
FROM (
SELECT FIRST_DAY + LEVEL -1 ORDER_DATE
FROM (
SELECT TRUNC(TO_DATE(#{date }), 'MM') FIRST_DAY FROM DUAL
)
CONNECT BY FIRST_DAY + LEVEL -1 <![CDATA[ <= ]]> LAST_DAY(#{date })
) CAL
LEFT JOIN T_ORDER O
ON CAL.ORDER_DATE = O.ORDER_DATE
GROUP BY ROLLUP(CAL.ORDER_DATE)
ORDER BY ORDER_DATE
</if>
mybatis에서 부등호를 사용하려면 <![CDATA[]]로 감싸서 사용해야합니다
- term이 month일 경우 해당 달의 FIRST_DAY를 구하고 LAST_DAY함수로 마지막 날짜를 구합니다
- LEVEL, CONNECT BY를 사용해 첫날 ~ 마지막날까지 달력을 만듭니다
- 이 달력과 T_ORDER 테이블을 LEFT JOIN합니다
- ROLLUP을 사용해 ORDER_DATE를 기준으로 합계를 구합니다
term이 week와 year때돼 마찬가지로 일주일, 1년 달력을 만들고 달력과 T_ORDER를 조인했습니다
'스프링부트' 카테고리의 다른 글
스프링부트+jsp로 배달사이트 만들기-34 구글아이디로 로그인 (1) | 2021.12.22 |
---|---|
스프링부트+jsp로 배달사이트 만들기-33 내 포인트, 리뷰 확인 (0) | 2021.12.22 |
스프링부트+jsp로 배달사이트 만들기-31 웹소켓으로 실시간 주문받기 (0) | 2021.12.17 |
스프링부트+jsp로 배달사이트 만들기-30 주문접수 (2) | 2021.12.17 |
스프링부트+jsp로 배달사이트 만들기-29 관리자페이지(메뉴 삭제,수정, 답장하기) (0) | 2021.12.17 |