Eggs Sunny Side Up
본문 바로가기
프레임워크(Framework)/Spring

DB에 저장된 데이터값을 ajax로 그래프 그리기

by guswn100059 2023. 6. 8.

DB에 저장된 데이터값을 ajax로 그래프 그리기

JS

중괄호{} => 객체

대괄호[] => 배열

 

ajax 비동기 통신 => json구조로 변환 라이브러리

pom.xml

jackson-databind

https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind/2.14.2

 

 

BroadCastController

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.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 {
	// -> 동기통신 요청만 처리하는 controller
	
	// Mapper 인터페이스를 사용할 수 있게끔 연결
	@Autowired
	private BroadCastMapper mapper;

	@GetMapping("/") // 2) url mapping을 "/"로 들어왔을 때 잡아주기
	public String index(Model model) {
		
		BroadCast list = mapper.select();
		
		model.addAttribute("list", list);
		
		return "index"; // 3) "/"로 들어왔을 때 index.jsp 페이지를 forward 방식으로 되돌려주기
	
	}
	
	
//	// 월별 데이터 조회할 수 있는 url
//	// getMonthData ==> return null
//	@RequestMapping("/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("/getSData")
//	public @ResponseBody BroadCast getSData() {
//		
//		System.out.println("요청");
//		
//		BroadCast result = mapper.getSData();
//		
//		return result;
//	}
}

 

BroadCastRESTController

package kr.smhrd.controller;

import java.util.ArrayList;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

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

@RestController // @Controller + @ResponseBody
public class BroadCastRESTController {
	// -> 비동기통신 요청을 처리해주는 Controller
	// -> 웹페이지 화면에 데이터를 돌려주는 역할
	// -> 메소드를 선언할 때 @ResponseBody 생략이 가능
	
	@Autowired
	private BroadCastMapper mapper;

	// 월별 데이터 조회할 수 있는 url
	@RequestMapping("/getMonthData")
	public ArrayList<BroadCast> getMonthData() {
		System.out.println("요청이 들어오닝");
		ArrayList<BroadCast> result = mapper.getMonthData();
		return result;
		
	}

	// 연령대별 데이터 조회
	@RequestMapping("/getSData")
	public BroadCast getSData() {
		System.out.println("요청");
		BroadCast result = mapper.getSData();
		return result;
	}
	
	// 출연진 Top5 조회
	@RequestMapping("/getCastCount")
	public ArrayList<BroadCast> getCastCount() {
		// 1. DB에서 데이터 조회
		ArrayList<BroadCast> result = mapper.getCastCount();
		
		// 2. 조회한 결과값 화면에 출력될 수 있는 형태로 변환
		// 1개의 column안에 여러 명의 이름이 들어있음
		// 2-1) result의 0번 인덱스에 접근
		System.out.println(result.get(0));
		
		// 2-2) fixing_cast_nm 데이터에 접근
		System.out.println(result.get(0).getFixing_cast_nm());
		
		// 2-3) , 를 기준으로 데이터 쪼개기
		System.out.println(result.get(0).getFixing_cast_nm().split(",")[0]);
		
		
		return result;
	}

}

 

BroadCastMapper.java => DAO

package kr.smhrd.mapper;

import java.util.ArrayList;

import org.apache.ibatis.annotations.Select;

import kr.smhrd.entity.BroadCast;

// @Mapper => 버전 업그레이드로 생략 가능
public interface BroadCastMapper {
	
	// 남, 여, 전체 시청률 평균을 조회하는 기능
	// 조회한 결과 행이 하나이기 때문에 BroadCast로 받아오기
	// session.selectOne();
	public BroadCast select();

	public ArrayList<BroadCast> getMonthData();

	public BroadCast getSData();
	
	@Select("SELECT FIXING_CAST_NM, CAST_NM FROM BROADCAST WHERE PROGRAM_NM = '뮤직뱅크'")
	public ArrayList<BroadCast> getCastCount();
	
}

 

BroadCastMapper.xml => mybatis

<?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="select"  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">
		<!-- column : 조회해온 column 명칭 / property : 객체의 필드명 -->
		<result column="DE" property="brdcst_de"/>
		<result column="RT" property="wtchng_rt"/>
	</resultMap>
	
	<!-- 월별 전체시청률 평균 조회 -->
	<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>
	
	<!-- 10 ~ 60대 평균시청률 조회 -->
	<resultMap type="kr.smhrd.entity.BroadCast" id="sData">
		<result column="10대" property="n10s_rt"/>
		<result column="20대" property="n20s_rt"/>
		<result column="30대" property="n30s_rt"/>
		<result column="40대" property="n40s_rt"/>
		<result column="50대" property="n50s_rt"/>
		<result column="60대" property="n60s_above_rt"/>
	</resultMap>
	
	<select id="getSData" resultMap="sData">
		SELECT round(avg(N10S_RT), 3) AS 10대
			 , round(avg(N20S_RT), 3) AS 20대
		     , round(avg(N30S_RT), 3) AS 30대
		     , round(avg(N40S_RT), 3) AS 40대
		     , round(avg(N50S_RT), 3) AS 50대
		     , round(avg(N60S_ABOVE_RT), 3) AS 60대
		  FROM BROADCAST
		 WHERE PROGRAM_NM = '뮤직뱅크'
	</select>
	
	

</mapper>

 

index.jsp

 

 

char-area-demo.js

// VS코드에서 수정 후에 반드시 ctrl+s 저장하기!!
// eclipse로 돌아가서 해당하는 파일을 다시 한 번 열어주기! => 반영이 빨라짐.


// 링크 클릭, 버튼 클릭, 페이지 변환이 일어나면서 데이터 응답 => 동기통신
// 비동기통신 방식으로 DB에서 데이터를 조회해와서 차트를 그리기! 
// => $.ajax()
// 문법  
$(function () {
  $.ajax({
    // 1) 어디로 요청을 보내야하는지
    url: 'getMonthData',
    // 2) 보내줄 값이 있는지
    // data : '있을 때만 사용',
    // 3) 받아올 결과값의 자료형 지정
    dataType: 'json',
    // 4) 성공했을 때 실행할 함수
    success: function (res) {
      console.log(res);
      // res => 배열 => 객체들이 존재
      // res의 0번 인덱스에 있는 객체안에 wtchng_rt를 console에 출력하기
      console.log(res[0].wtchng_rt);

      // 1. labels에 들어갈 수 있는 배열을 하나 생성
      let monthData = [];

      // 3. data에 들어갈 수 있는 배열을 하나 생성
      let wtchngData = []

      for (let i = 0; i < res.length; i++) {
        // 2. 배열에 res 안에 들어있는 brdcst_de라는 데이터를 하나씩 추가
        monthData.push(res[i].brdcst_de);
        // 4. 배열에 res 안에 들어있는 wtchng_rt라는 데이터를 하나씩 추가
        wtchngData.push(res[i].wtchng_rt);
      }

      // 5. 차트 그리는 전체 코드를 함수로 만들고, 함수를 사용해서 배열 2개를 매개변수로 넘기기
      makeAreaChart(monthData, wtchngData);

    },
    // 5) 실패했을 때 실행할 함수
    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';

// Area Chart Example
function makeAreaChart(monthData, wtchngData) {
  var ctx = document.getElementById("myAreaChart");
  var myLineChart = new Chart(ctx, {
    type: 'line',
    data: {
      // x축 라벨(DB에서 조회한 값으로 수정)
      labels: monthData,
      datasets: [{
        label: "Earnings",
        lineTension: 0.3,
        backgroundColor: "rgba(78, 115, 223, 0.05)",
        borderColor: "rgba(78, 115, 223, 1)",
        pointRadius: 3,
        pointBackgroundColor: "rgba(78, 115, 223, 1)",
        pointBorderColor: "rgba(78, 115, 223, 1)",
        pointHoverRadius: 3,
        pointHoverBackgroundColor: "rgba(78, 115, 223, 1)",
        pointHoverBorderColor: "rgba(78, 115, 223, 1)",
        pointHitRadius: 10,
        pointBorderWidth: 2,
        // data에 DB에서 조회한 값 가져오기
        data: wtchngData,
      }],
    },
    options: {
      maintainAspectRatio: false,
      layout: {
        padding: {
          left: 10,
          right: 25,
          top: 25,
          bottom: 0
        }
      },
      scales: {
        xAxes: [{
          time: {
            unit: 'date'
          },
          gridLines: {
            display: false,
            drawBorder: false
          },
          ticks: {
            maxTicksLimit: 7
          }
        }],
        yAxes: [{
          ticks: {
            maxTicksLimit: 5,
            padding: 10,
          },
          gridLines: {
            color: "rgb(234, 236, 244)",
            zeroLineColor: "rgb(234, 236, 244)",
            drawBorder: false,
            borderDash: [2],
            zeroLineBorderDash: [2]
          }
        }],
      },
      legend: {
        display: false
      },
      tooltips: {
        backgroundColor: "rgb(255,255,255)",
        bodyFontColor: "#858796",
        titleMarginBottom: 10,
        titleFontColor: '#6e707e',
        titleFontSize: 14,
        borderColor: '#dddfeb',
        borderWidth: 1,
        xPadding: 15,
        yPadding: 15,
        displayColors: false,
        intersect: false,
        mode: 'index',
        caretPadding: 10,
      }
    }
  });
}

 

index.jsp

 

chart-pie-demo.js

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

      let age = ['10대', '20대', '30대', '40대', '50대', '60대 이상']
      // json으로 변환 시 필드는 무조건 소문자로 변경됨!
      // 따라서 대문자말고 소문자로 작성 기억!!
      let ageData = [res.n10s_rt, res.n20s_rt, res.n30s_rt, res.n40s_rt, res.n50s_rt, res.n60s_above_rt];

      console.log(res.n10s_rt);

      // 함수선언할 때 매개변수의 순서는 무조건 맞춰야함!
      makePieChart(age, ageData);
      

    },
    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';

// Pie Chart Example
// 함수명은 무조건 중복없이 선언해줘야 함!!
function makePieChart(age, ageData){
  var ctx = document.getElementById("myPieChart");
  var myPieChart = new Chart(ctx, {
    type: 'doughnut',
    data: {
      labels: age,
      datasets: [{
        //data에 DB에서 조회한 값 가져오기
        data: ageData,
        backgroundColor: ['#4e73df', '#1cc88a', '#36b9cc', '#4e73df', '#1cc88a', '#36b9cc'],
        hoverBackgroundColor: ['#2e59d9', '#17a673', '#2c9faf', '#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,
      },
      legend: {
        display: false
      },
      cutoutPercentage: 80,
    },
  });
}

댓글