주먀

5. piechart 그리기 본문

학원/Spring

5. piechart 그리기

주먀 2023. 6. 9. 11:34

* eclips js -> javaScript 에서 열때 경로 *

C:\eGovFrame-4.0.0\workspace.edu\SpringMVC02\src\main\webapp\resources

 

* 비동기통신 문법 *

$.ajax({

1. 어디로 요청을 보낼건지

url : 'controller url mapping',

2. 보내줄 데이터

data : 보내주고 데이터(객체),

3. 받아올 데이터 타입

dataType : 'json',

4. 성공했을 때 함수

success : function(res){

},

5. 실패했을 때 함수

error : function(){

})

 

* 복습 *

페이지를 되돌려주는 메소드가 아니라 결과값을 화면에 출력해주는 메소드

@ResponseBody -> retrun

Spring 내부적으로 결과값 반환 라이브러리 ---> jackson-databind

조회한 column명 != 객체 필드명

--> <resultMap type = "객체의 풀네임" id = "변수명">

            <result column = "colum명" property = "필드명 "/>

            <result column = colum명" property = "필드명 "/>

</resultMap>

--> <select resultMap = "test"> </select>

 

* 파이차트 그리기 실습 *

- 10대 ~ 60대이상 --> 평균 시청률 --> 소수점 셋째자리

- 프로그램명이 뮤직뱅크인 데이터의 10대 ~ 60대 이상까지의 평균 시청률을 조회 --> 파이차트 그리기

 

1. SQL 구문 작성 --> work bench에서 잘 실행되는 지 체크

SELECT
PROGRAM_NM,
ROUND(AVG(N10S_RT), 3) AS N10S_RT,
ROUND(AVG(N20S_RT), 3) AS N20S_RT,
ROUND(AVG(N30S_RT), 3) AS N30S_RT,
ROUND(AVG(N40S_RT), 3) AS N40S_RT,
ROUND(AVG(N50S_RT), 3) AS N50S_RT,
ROUND(AVG(N60S_ABOVE_RT), 3) AS N60S_ABOVE_RT
FROM COM.BROADCAST
WHERE PROGRAM_NM = '뮤직뱅크';

 

2. pie 차트를 그려주고 있는 js 코드를 찾아주기

( canvas 태그이면 js로 한다. / 그리는건 하단에 script태그 확인한다. )

7. js로 돌아와서 pie 차트 들어갈 데이터 제작 후

8. 차트 그리기

// 페이지가 로드 완료되면 비동기 통신 시작하도록 코드 작성
$(function () { // document.ready() --> jquery로 표현한 것
  $.ajax({
    url: 'getAgeData',
    dataType: 'json',
    success: function (res) {
      console.log(res);

      // daat 생성하기
      let my_labels = ['10대', '20대', '30대', '40대', '50대', '60대'];
      // label 생성하기
      let my_data = [];
      my_data.push(res.n10s_rt);
      my_data.push(res.n20s_rt);
      my_data.push(res.n30s_rt);
      my_data.push(res.n40s_rt);
      my_data.push(res.n50s_rt);
      my_data.push(res.n60s_above_rt);
      // makePieChart 사용하기
      makePieChart(my_labels, my_data);
    },
    error: function () {
      console.log('실패ㅠ')
    }
  })
});

// Set new default font family and font color to mimic Bootstrap's default styling
Chart.defaults.global.defaultFontFamily = 'Nunito', '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif';
Chart.defaults.global.defaultFontColor = '#858796';
function makePieChart(my_labels, my_data) {
  // Pie Chart Example
  var ctx = document.getElementById("myPieChart");
  var myPieChart = new Chart(ctx, {
    type: 'doughnut',
    data: {
      // labels DB에서 조회한 값 변경
      labels: my_data,
      datasets: [{
        // data에 DB에서 조회한 값 가져오기
        data: my_data,
        labels: [55, 30, 15],
        backgroundColor: ['#4e73df', '#1cc88a', '#36b9cc', '#4e73df', '#1cc88a', '#36b9cc'],
        hoverBackgroundColor: ['#2e59d9', '#17a673', '#2c9faf'],
        hoverBorderColor: "rgba(234, 236, 244, 1)",
      }],
    },
    options: {
      maintainAspectRatio: false,
      tooltips: {
        backgroundColor: "rgb(255,255,255)",
        bodyFontColor: "#858796",
        borderColor: '#dddfeb',
        borderWidth: 1,
        xPadding: 15,
        yPadding: 15,
        displayColors: false,
        caretPadding: 10,
        //data: my_data,
      },
      legend: {
        display: false
      },
      cutoutPercentage: 80,
    },
  });

}

 

3. js파일 수정 --> 비동기통신 데이터 조회 요청을 보내게끔 작성

3-1. 객체 가져올때 소문자로 가져오기

3-2. 함수 블록화 시킬때 함수명 겹치치 않게하기 ( makePieChart )

3-3. 함수명 순서 동일하게 주기 ( my_labels, my_data )

 

 

4. 요청을 처리하는 url mapping 잡아주기 ( 컨트롤러 )

5. mapper 들을 사용해서 DB에서 데이터 조회하기

6. 결과값 반환

BroadCastController.java

package kr.smhrd.controller;

import java.util.ArrayList;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import kr.smhrd.entity.BroadCast;
import kr.smhrd.mapper.BroadCastMapper;

@Controller // 1) 클래스파일이 Controller(POJO)임을 알려주기
public class BroadCastController {

	// Mapper 인터페이스 사용할 수 잇게끔 연결
	@Autowired
	private BroadCastMapper mapper;

	@RequestMapping("/") // 2) url mapping을 "/"로 들어왔을 떄 잡아주기
	public String index(Model model) {

		// db에서 데이터 조회하기
		BroadCast vo = mapper.getRating();
		model.addAttribute("vo", vo);
		return "index";
		// 3) /로 들어왔을 때 index.jsp 페이지를 forward방식으로 되돌려주기
	}

	// 월별 데이터 조회할 수 있는 url
	@GetMapping("/getMonthData")
	public @ResponseBody ArrayList<BroadCast> getMonthData() {
		// @ResponseBody --> 비동기 통신으로 요청이 들어왔을 때
		// --> 반환하는 결과값이 페이지 이름이 아니라,
		// --> 웹 화면에 출력해야하는 결과값임을 나타내는 annotation
		// ajax(비동기) 요청이 들어왔을 때, 결과값을 반환하려면 웹페이지 화면에 출력!
		System.out.println("요청이 들어오니?");
		// 1. db에서 월별 전체시청률 평균 조회해오기
		ArrayList<BroadCast> result = mapper.getMonthData();
		// 2. 조회한 결과값을 return 반환 시켜주기
		return result;
		// 만약에 객체, ArrayList 복잡한 형태를 화면에 출력하려면???
		// --> jsp/servlet --> Gson 라이브러리 사용
		// --> spring framework --> jackson-databind 라이브러리 사용(자동으로 결과값을 convert)
	}

	// 연령대별 데이터 조회
	@RequestMapping("/getAgeData")
	public @ResponseBody BroadCast getAgeData() {
		BroadCast result = mapper.getAgeData();
		System.out.println("들어오니?");
		return result;
	}

}

 

Mapper

package kr.smhrd.mapper;

import java.util.ArrayList;

import kr.smhrd.entity.BroadCast;

// @Mapper ---> 생략가능
public interface BroadCastMapper {

	// 남/여/전체 시청률 평균을 조회하는 기능
	// 조회한 결과 행이 하나이기 때문에 BroadCast로 받아오기!
	// session.selectOne();
	public BroadCast getRating();

	public ArrayList<BroadCast> getMonthData();

	public BroadCast getAgeData();
	
	

}

 

XML

- from : 앞에 com은 삭제해도 된다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="kr.smhrd.mapper.BroadCastMapper">

	<select id="getRating" resultType="kr.smhrd.entity.BroadCast">
		SELECT
		PROGRAM_NM,
		ROUND( AVG (
		MALE_RT ) , 3 ) AS MALE_RT,
		ROUND ( AVG( FEMALE_RT ) , 3 ) AS
		FEMALE_RT,
		ROUND ( AVG( WTCHNG_RT ) , 3 ) AS WTCHNG_RT
		FROM
		COM.BROADCAST
		WHERE PROGRAM_NM = '뮤직뱅크';
	</select>

	<!-- DB에서 조회해 온 결과값의 column과 객체의 필드명이 서로 달랐을 때 사용할 수 있는 resultMap -->
	<!-- id : resultMap의 이름(변수명) 정하는 attribute type : 내가 표현하고 싶은 객체(자료형) -->
	<resultMap type="kr.smhrd.entity.BroadCast" id="monthData">
		<!-- colunm : 조회해온 column 명칭 / property : 객체의 필드명 -->
		<result column="DE" property="brdcst_de" />
		<result column="RT" property="wtchng_rt" />
	</resultMap>


	<!-- 2) 월별 시청률 평균 조회하기 -->
	<select id="getMonthData" resultMap="monthData">
		SELECT MONTH(BRDCST_DE) AS
		DE,
		ROUND(AVG(WTCHNG_RT),3) AS RT
		FROM BROADCAST
		WHERE PROGRAM_NM = '뮤직뱅크'
		GROUP BY DE
	</select>

	<!-- 3) 연령대별 시청률 평균 조회하기 -->
	<select id="getAgeData" resultType="kr.smhrd.entity.BroadCast">
		SELECT
			PROGRAM_NM,
			ROUND(AVG(N10S_RT), 3) AS N10S_RT,
			ROUND(AVG(N20S_RT), 3) AS N20S_RT,
			ROUND(AVG(N30S_RT), 3) AS N30S_RT,
			ROUND(AVG(N40S_RT), 3) AS N40S_RT,
			ROUND(AVG(N50S_RT), 3) AS N50S_RT,
			ROUND(AVG(N60S_ABOVE_RT), 3) AS N60S_ABOVE_RT
		FROM BROADCAST
		WHERE PROGRAM_NM = '뮤직뱅크';
	</select>




</mapper>

 

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core"  prefix="c"%>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">
    <title>Dashboard</title>
    <!-- Custom fonts for this template-->
    <link href="resources/vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
    <link href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i"
        rel="stylesheet">
    <!-- Custom styles for this template-->
    <link href="resources/css/sb-admin-2.min.css" rel="stylesheet">

</head>

<body id="page-top">

    <!-- Page Wrapper -->
    <div id="wrapper">

        <!-- Sidebar -->
        <ul class="navbar-nav bg-gradient-primary sidebar sidebar-dark accordion" id="accordionSidebar">

            <!-- Sidebar - Brand -->
            <a class="sidebar-brand d-flex align-items-center justify-content-center" href="index.html">
                <div class="sidebar-brand-icon rotate-n-15">
                    <i class="fas fa-laugh-wink"></i>
                </div>
                <div class="sidebar-brand-text mx-3">SB Admin <sup>2</sup></div>
            </a>

            <!-- Divider -->
            <hr class="sidebar-divider">
            <!-- Heading -->
            <div class="sidebar-heading">
                Page
            </div>
            <!-- Nav Item - Charts -->
            <li class="nav-item">
                <a class="nav-link" href="register">
                    <i class="fas fa-fw fa-clipboard-list"></i>
                    <span>출연진 관리</span></a>
            </li>

            <!-- Divider -->
            <hr class="sidebar-divider d-none d-md-block">

            <!-- Sidebar Toggler (Sidebar) -->
            <div class="text-center d-none d-md-inline">
                <button class="rounded-circle border-0" id="sidebarToggle"></button>
            </div>
        </ul>
        <!-- End of Sidebar -->

        <!-- Content Wrapper -->
        <div id="content-wrapper" class="d-flex flex-column">

            <!-- Main Content -->
            <div id="content">

                <!-- Topbar -->
                <nav class="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow">

                    <!-- Sidebar Toggle (Topbar) -->
                    <button id="sidebarToggleTop" class="btn btn-link d-md-none rounded-circle mr-3">
                        <i class="fa fa-bars"></i>
                    </button>

                    <!-- Topbar Search -->
                    <form
                        class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
                        <div class="input-group">
                            <input type="text" class="form-control bg-light border-0 small" placeholder="Search for..."
                                aria-label="Search" aria-describedby="basic-addon2">
                            <div class="input-group-append">
                                <button class="btn btn-primary" type="button">
                                    <i class="fas fa-search fa-sm"></i>
                                </button>
                            </div>
                        </div>
                    </form>


                </nav>
                <!-- End of Topbar -->

                <!-- Begin Page Content -->
                <div class="container-fluid">

                    <!-- Page Heading -->
                    <div class="d-sm-flex align-items-center justify-content-between mb-4">
                        <h1 class="h3 mb-0 text-gray-800">Dashboard</h1>
                    </div>

                    <!-- Content Row -->
                    <div class="row">

                        <!-- Earnings (Monthly) Card Example -->
                        <div class="col-xl-3 col-md-6 mb-4">
                            <div class="card border-left-primary shadow h-100 py-2">
                                <div class="card-body">
                                    <div class="row no-gutters align-items-center">
                                        <div class="col mr-2">
                                            <div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
                                            ${vo.program_nm} 남성 시청율 평균
                                            </div>
                                            <div class="row no-gutters align-items-center">
                                                <div class="col-auto">
                                                    <div class="h5 mb-0 mr-3 font-weight-bold text-gray-800">${vo.male_rt}%</div>
                                                </div>
                                                <div class="col">
                                                    <div class="progress progress-sm mr-2">
                                                        <div class="progress-bar bg-primary" role="progressbar"
                                                            style="width:${vo.male_rt}%" aria-valuenow="${vo.male_rt}" aria-valuemin="0"
                                                            aria-valuemax="100"></div>
                                                    </div>
                                                </div>
                                            </div>
                                        </div>
                                        <div class="col-auto">
                                            <i class="fas fa-clipboard-list fa-2x text-gray-300"></i>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="col-xl-3 col-md-6 mb-4">
                            <div class="card border-left-danger shadow h-100 py-2">
                                <div class="card-body">
                                    <div class="row no-gutters align-items-center">
                                        <div class="col mr-2">
                                            <div class="text-xs font-weight-bold text-danger text-uppercase mb-1">
                                            ${vo.program_nm} 여성 시청률 평균
                                            </div>
                                            <div class="row no-gutters align-items-center">
                                                <div class="col-auto">
                                                    <div class="h5 mb-0 mr-3 font-weight-bold text-gray-800">${vo.female_rt}%</div>
                                                </div>
                                                <div class="col">
                                                    <div class="progress progress-sm mr-2">
                                                        <div class="progress-bar bg-danger" role="progressbar"
                                                            style="width: ${vo.female_rt}%" aria-valuenow="${vo.female_rt}" aria-valuemin="0"
                                                            aria-valuemax="100"></div>
                                                    </div>
                                                </div>
                                            </div>
                                        </div>
                                        <div class="col-auto">
                                            <i class="fas fa-clipboard-list fa-2x text-gray-300"></i>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="col-xl-3 col-md-6 mb-4">
                            <div class="card border-left-info shadow h-100 py-2">
                                <div class="card-body">
                                    <div class="row no-gutters align-items-center">
                                        <div class="col mr-2">
                                            <div class="text-xs font-weight-bold text-info text-uppercase mb-1">
                                            ${vo.program_nm} 전체 시청률 평균
                                            </div>
                                            <div class="row no-gutters align-items-center">
                                                <div class="col-auto">
                                                    <div class="h5 mb-0 mr-3 font-weight-bold text-gray-800">${vo.wtchng_rt}%</div>
                                                </div>
                                                <div class="col">
                                                    <div class="progress progress-sm mr-2">
                                                        <div class="progress-bar bg-info" role="progressbar"
                                                            style="width: ${vo.wtchng_rt}%" aria-valuenow="${vo.wtchng_rt}" aria-valuemin="0"
                                                            aria-valuemax="100"></div>
                                                    </div>
                                                </div>
                                            </div>
                                        </div>
                                        <div class="col-auto">
                                            <i class="fas fa-clipboard-list fa-2x text-gray-300"></i>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>

                    <!-- Content Row -->

                    <div class="row">

                        <!-- Area Chart -->
                        <div class="col-xl-8 col-lg-7">
                            <div class="card shadow mb-4">
                                <!-- Card Header - Dropdown -->
                                <div
                                    class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
                                    <h6 class="m-0 font-weight-bold text-primary">${vo.program_nm} 월별 시청률 </h6>
                                </div>
                                <!-- Card Body -->
                                <div class="card-body">
                                    <div class="chart-area">
                                        <canvas id="myAreaChart"></canvas>
                                        <!-- js파일은 head태그 안쪽(변수, 태그), body 끝나는 태그 위쪽에 로드(새로운태그, css속성변경할때) -->
                                    </div>
                                </div>
                            </div>
                        </div>

                        <!-- Pie Chart -->
                        <div class="col-xl-4 col-lg-5">
                            <div class="card shadow mb-4">
                                <!-- Card Header - Dropdown -->
                                <div
                                    class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
                                    <h6 class="m-0 font-weight-bold text-primary">${vo.program_nm} 연령대별 시청률 </h6>
                                </div>
                                <!-- Card Body -->
                                <div class="card-body">
                                    <div class="chart-pie pt-4 pb-2">
                                        <canvas id="myPieChart"></canvas>
                                    </div>
                                    <div class="mt-4 text-center small">
                                        <span class="mr-2">
                                            <i class="fas fa-circle text-primary"></i> 10대
                                        </span>
                                        <span class="mr-2">
                                            <i class="fas fa-circle text-success"></i> 20대
                                        </span>
                                        <span class="mr-2">
                                            <i class="fas fa-circle text-info"></i> 30대
                                        </span>
                                        <span class="mr-2">
                                            <i class="fas fa-circle text-info"></i> 40대
                                        </span>
                                        <span class="mr-2">
                                            <i class="fas fa-circle text-info"></i> 50대
                                        </span>
                                        <span class="mr-2">
                                            <i class="fas fa-circle text-info"></i> 60대이상
                                        </span>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>

                    <!-- Content Row -->
                    <div class="row">

                        <!-- Content Column -->
                        <div class="col-lg-6 mb-4">

                            <!-- Project Card Example -->
                            <div class="card shadow mb-4">
                                <div class="card-header py-3">
                                    <h6 class="m-0 font-weight-bold text-primary">출연진 TOP5</h6>
                                </div>
                                <div class="card-body">
                                    <h4 class="small font-weight-bold">
                                    NMIXX <span class="float-right">20%</span>
                                    </h4>
                                    <div class="progress mb-4">
                                        <div class="progress-bar bg-danger" role="progressbar" style="width: 20%"
                                            aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"></div>
                                    </div>
                                    <h4 class="small font-weight-bold">
                                    스테이씨 <span class="float-right">40%</span>
                                    </h4>
                                    <div class="progress mb-4">
                                        <div class="progress-bar bg-warning" role="progressbar" style="width: 40%"
                                            aria-valuenow="40" aria-valuemin="0" aria-valuemax="100"></div>
                                    </div>
                                    <h4 class="small font-weight-bold">
                                    르세라핌 <span class="float-right">60%</span>
                                    </h4>
                                    <div class="progress mb-4">
                                        <div class="progress-bar" role="progressbar" style="width: 60%"
                                            aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"></div>
                                    </div>
                                    <h4 class="small font-weight-bold">
                                    뉴진스<span class="float-right">80%</span>
                                    </h4>
                                    <div class="progress mb-4">
                                        <div class="progress-bar bg-info" role="progressbar" style="width: 80%"
                                            aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div>
                                    </div>
                                    <h4 class="small font-weight-bold">
                                    아이브<span class="float-right">100%</span>
                                    </h4>
                                    <div class="progress">
                                        <div class="progress-bar bg-success" role="progressbar" style="width: 100%"
                                            aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>

                </div>
                <!-- /.container-fluid -->

            </div>
            <!-- End of Main Content -->

            <!-- Footer -->
            <footer class="sticky-footer bg-white">
                <div class="container my-auto">
                    <div class="copyright text-center my-auto">
                        <span>Copyright &copy; Your Website 2023</span>
                    </div>
                </div>
            </footer>
            <!-- End of Footer -->

        </div>
        <!-- End of Content Wrapper -->

    </div>
    <!-- End of Page Wrapper -->

    <!-- Scroll to Top Button-->
    <a class="scroll-to-top rounded" href="#page-top">
        <i class="fas fa-angle-up"></i>
    </a>


    <!-- Bootstrap core JavaScript-->
    <script src="resources/vendor/jquery/jquery.min.js"></script>
    <script src="resources/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>

    <!-- Core plugin JavaScript-->
    <script src="resources/vendor/jquery-easing/jquery.easing.min.js"></script>

    <!-- Custom scripts for all pages-->
    <script src="resources/js/sb-admin-2.min.js"></script>

    <!-- Page level plugins -->
    <script src="resources/vendor/chart.js/Chart.min.js"></script>

    <!-- Page level custom scripts -->
    <script src="resources/js/demo/chart-area-demo.js"></script>
    <script src="resources/js/demo/chart-pie-demo.js"></script>

</body>

</html>