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

동적 쿼리 + JS 변수로 ajax 데이터 보내기

by guswn100059 2023. 6. 13.

Entity

BroadCast.java

package kr.smhrd.entity;

import java.util.Date;

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

@NoArgsConstructor
@AllArgsConstructor
@Data
public class BroadCast {
	// table에 존재하는 컬럼을 전부 필드로 만들기
	
	private int brdcst_num;
	private String brdcst_de;
	private String program_nm;
	private float nyo_rt;
	private float n10s_rt;
	private float n20s_rt;
	private float n30s_rt;
	private float n40s_rt;
	private float n50s_rt;
	private float n60s_above_rt;
	private float male_rt;
	private float female_rt;
	private float wtchng_rt;
	private String fixing_cast_nm;
	private String cast_nm;
}

 

CastCount.java

package kr.smhrd.entity;

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

@Data
@AllArgsConstructor
@NoArgsConstructor
public class CastCount {
	
	// 이름 - 횟수 나만의 자료형
	private String name;
	private int count;

}

 

SearchCriteria.java

package kr.smhrd.entity;

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

@Data
@AllArgsConstructor
@NoArgsConstructor
public class SearchCriteria {
	// Croteroa => 기준을 정해주는 자료형
	// --> 단순한 필드만 존재하기보다는 알고리즘 메소드를 가지고 있음!
	// --> PageCriteria -> 페이징기법
	
	// 검색 기준을 잡아주는 자료형
	private String type;
	private String content;

}

BroadCastController

package kr.smhrd.controller;

import java.util.ArrayList;

import javax.servlet.http.HttpServletRequest;

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.entity.SearchCriteria;
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(SearchCriteria cri , Model model) {
		
		System.out.println("기준 >> "+cri);
		BroadCast list = mapper.select(cri);
		// 서로 다른 클래스 파일 간에 값을 주고받을 수 있는 방법
		// --> 메소드의 매개변수
		// --> 메소드의 리턴
		
		model.addAttribute("list", list);
		
		
		return "index"; // 3) "/"로 들어왔을 때 index.jsp 페이지를 forward 방식으로 되돌려주기
	
	}
   }

 

BroadCastRESTController

package kr.smhrd.controller;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashSet;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
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.entity.CastCount;
import kr.smhrd.entity.SearchCriteria;
import kr.smhrd.mapper.BroadCastMapper;

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

	@Autowired
	private BroadCastMapper mapper;

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

	}

	// 연령대별 데이터 조회
	@RequestMapping("/getSData")
	public BroadCast getSData(String program_nm) {
		System.out.println("요청");
		BroadCast result = mapper.getSData(program_nm);
		return result;
	}

	// 출연진 Top5 조회
	@RequestMapping("/getCastCount")
	public ArrayList<CastCount> getCastCount(String program_nm) {
		
		// 1. DB에서 데이터 조회
		ArrayList<BroadCast> result = mapper.getCastCount(program_nm);

		// 2. 조회한 결과값 화면에 출력될 수 있는 형태로 변환
		// 1개의 column안에 여러 명의 이름이 들어있음
		// 연예인 이름을 전부 담을 수 있는 ArrayList<String>
		ArrayList<String> cast_nm = new ArrayList<String>();

		for (BroadCast b : result) {

			// 2-1) result안에 들어있는 MC이름을 가져와서 ','를 기준으로 쪼개기
			String[] temp1 = b.getFixing_cast_nm().split(",");
			// 2-2) result안에 들어있는 cast_nm을 가져와서 ,를 기준으로 쪼개기
			String[] temp2 = b.getCast_nm().split(",");
			// 2-3) 쪼갠 데이터들을 하나의 공간에 보관하기
			for (String s : temp1) {
				cast_nm.add(s);
			}
			for (String s : temp2) {
				cast_nm.add(s);
			}

		}
		System.out.println(cast_nm);
		
		// 2-4) 전체 연예인 명단에서 중복을 제거
		// Collection => 객체 자료구조들 (ArrayList, List, HashMap ...)
		// HashSet => 중복값을 허용하지 않는 자료구조 => 데이터를 꺼내려면 iterator 사용해야함
		// LinkedHashSet => 순서가 있는 중복값을 허용하지 않는 자료구조
		LinkedHashSet<String> castingHashSet = new LinkedHashSet<String>(cast_nm);
		System.out.println("중복제거한 결과값 >> "+castingHashSet);
		
		// 2-5) 최종적으로 리턴해줄 자료형
		// CastCount => 이름 : 횟수
		ArrayList<CastCount> resultList = new ArrayList<CastCount>();
		
		for(String c:castingHashSet) {
			
			if(!c.equals("")) {
			// 2-6) 연예인 이름 당 몇 번 등장했는지 횟수를 카운트
			// Collections.frequency(객체를 담고있는 컬렉션, 개수를 세고 싶은 객체)
			int count = Collections.frequency(cast_nm, c);
			// 2-7) 결과값은 resultList에 담아주기
			resultList.add(new CastCount(c, count));
			
			}
		}
		
		// 2-8) resultList
		// => 객체를 정렬 => count 기준으로 정렬
		// 객체를 정렬하는 방법
		// (1) 정렬하고 싶은 객체가 Comparable 인터페이스를 상속
		// (2) Comparator라는 인터페이스를 구현 ★사용★
		
		// 익명함수 방법 1. 
//		Collections.sort(resultList, new Comparator<CastCount>() {
//
//			// compare => 비교하는 함수
//			@Override
//			public int compare(CastCount o1, CastCount o2) {
//				return o2.getCount() - o1.getCount();
//				// 양수 => 내림차순 정렬
//				// 음수 => 오름차순 정렬
//			}
//		});
		
		// 익명함수 방법 2. 람다식 표현
		// => 익명함수를 호출할 때 많이 사용하는 방식(한줄로 간단히 표현할 수 있는 경우만 사용가능)
		// 사용법 : (매개변수) -> 리턴해줘야하는 결과값
		Collections.sort(resultList, (o1, o2)->o2.getCount()-o1.getCount());
		
		System.out.println("최종결과 >> "+ resultList);
		

		return resultList;
	}

}

BroadCastMapper.java => DAO

package kr.smhrd.mapper;

import java.util.ArrayList;

import org.apache.ibatis.annotations.Select;

import kr.smhrd.entity.BroadCast;
import kr.smhrd.entity.SearchCriteria;

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

	// 월별 데이터 조회
	public ArrayList<BroadCast> getMonthData(String program_nm);

	// 연령대별 데이터 조회
	public BroadCast getSData(String program_nm);
	
	// 출연진 TOP5 조회
	@Select("SELECT FIXING_CAST_NM, CAST_NM FROM BROADCAST WHERE PROGRAM_NM = #{program_nm}")
	public ArrayList<BroadCast> getCastCount(String program_nm);
	
}

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"
		parameterType="kr.smhrd.entity.SearchCriteria"
		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
		<include refid="searchOption" />
		GROUP BY PROGRAM_NM
	</select>
	<!-- 동적 쿼리문 -->
	<!-- 매개변수 : SearchCriteria(type, content) type이 프로그램명인지, MC이름인지, null인지 
		SQL구문이 동적으로 변경 -->
	<sql id="searchOption">
		<if test="type == null">
			WHERE PROGRAM_NM = '뮤직뱅크'
		</if>
		<if test="type == '방송제목'">
			WHERE PROGRAM_NM LIKE CONCAT('%', #{content}, '%')
		</if>
		<if test="type == 'MC이름'">
			WHERE FIXING_CAST_NM LIKE CONCAT('%', #{content}, '%')
		</if>

	</sql>



	<!-- 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 = #{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 = #{program_nm}
	</select>


</mapper>

자바스크립트 코드가 해석되는 순서

`\${EL}` 로 표현하면 .java에서 스킵하고 .html에서 해석이 되기 때문에

대개 html코드를 ajax로 추가할 때 쓰는 방식(백틱+역슬래쉬+EL식)


index.jsp

일부분임.

<!-- Topbar Search -->
                    <form action="${cpath}/"
                        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">
                        	<select name="type" class="form-control bg-light border-0">
                        		<option value="방송제목">방송제목</option>
                        		<option value="MC이름">MC이름</option>
                        	</select>
                        	&nbsp&nbsp&nbsp
                            <input name="content" 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="submit">
                                    <i class="fas fa-search fa-sm"></i>
                                </button>
                            </div>
                        </div>
                    </form>
    <!-- Page level custom scripts -->
    <script>
    	// 분리된 js 파일에서 java의 변수를 사용하고 싶다면
    	// js 파일이 로드되기 전에 script 태그를 열어서 변수를 하나 선언하면 된다.
    	var program_nm = '${list.program_nm}';
    </script>
    <script src="resources/js/demo/chart-area-demo.js"></script>
    <script src="resources/js/demo/chart-pie-demo.js"></script>
    
    <script >
    	// 프로그램명이니까 프로그램명을 어디서 받아올 수 있지? 
    	// --> list에서 꺼내올 수 있군!
    	// list --> java, javascript, html ,css 중에서 java에 있구나
    	// 현재 내가 코드를 작성하고 있는 파일의 확장자가 뭐지? --> .jsp --> java server page
    	// 오! 다행이다! java 변수에 접근할 수 있겠다!
    	// 1) ★EL★ 
    	// 2) 표현식 => 꺽새%
    	// ${EL} => js 변수가 있는지 찾는 경우라서 이렇게 표현하면 안됨!
    	// '${EL}'처럼 따옴표가 존재해야함!!
    	// `\${EL}` => .java에서 건너뛰고 .html에서 해석됨.
    	var program_nm = '${list.program_nm}'; 
    	
    	$(function(){
    		$.ajax({
    			url : 'getCastCount', // 전송방식? get방식 => 쿼리스트링 문법 ?key=value
    			data : {
    				program_nm : program_nm
    			},
    			dataType : 'json',
    			success : function(res){
    				console.log(res);    				
    				console.log(res[0].name); 
    				console.log(program_nm); // 내가 데이터를 가져왔으면 잘 가져왔는지 꼭 출력하기!!
    				
    				// DOM -> Document Object Model
    				// 1. id값이 top5인 태그를 가져오기
    				// document.getElementByID('top5')
    				// == document.querySelector('#top5')
    				// == $('#top5')
    				// jquery, 순수js => 요소(태그)를 조작하는 메소드들 공부!!
    				
    				// 2. 태그에 추가하기
    				
    					
    				for(let i = 0; i<5; i++){
    					$('#top5').append(
    						`<h4 class="small font-weight-bold">
                            \${res[i].name} <span class="float-right">\${res[i].count}번</span>
                            </h4>
                            <div class="progress mb-4">
                                <div class="progress-bar bg-danger" role="progressbar" style="width: \${res[i].count}%"
                                    aria-valuenow="\${res[i].count}" aria-valuemin="0" aria-valuemax="100"></div>
                            </div>`)
                     }
    				
    			},
    			error : function(){
    				console.log('실패!');
    			}
    		})
    	})
    
    
    
    </script>

 

chart-area-demo.js

ajax 부분만 가져옴.

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


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

      console.log(program_nm);

      // 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('실패!');
    }

  })
})

 

chart-pie-demo.js

ajax 부분만 가져옴.

// 페이지가 로드 완료되면 비동기통신 시작하도록 코드 작성
// var program_nm = "<c:out value='${list.program_nm}'/>";
$(function(){ // document.ready() => jquery로 표현한 것
  $.ajax({
    url : 'getSData',
    data : {
      program_nm : program_nm
    },
    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('실패!');
    }
  })
});

댓글