210427 TIL(D+74 μŠ€ν”„λ§ νˆ¬ν‘œ κ΅¬ν˜„, Crawling, μ»€μŠ€ν…€ μ–΄λ…Έν…Œμ΄μ…˜ ν™œμš©ν•œ AOP, μ›Ή μ†ŒμΌ“)

2021. 4. 27. 17:25Β·πŸ’» 개발/πŸ“– TIL (Today I Learned)

- Spring으둜 νˆ¬ν‘œ κΈ°λŠ₯ κ΅¬ν˜„ν•˜κΈ°

 

1. νˆ¬ν‘œ κΈ°λŠ₯에 ν•„μš”ν•œ DB ν…Œμ΄λΈ” μž‘μ„±

 

POLL ν…Œμ΄λΈ” : νˆ¬ν‘œ 글에 λŒ€ν•œ 번호(PK)와 μž‘μ„±μž, μž‘μ„±μ œλͺ©, νˆ¬ν‘œ μ‹œμž‘ λ‚ μ§œ, λλ‚˜λŠ” λ‚ μ§œ, νˆ¬ν‘œ ν•­λͺ© 개수, 총 νˆ¬ν‘œμˆ˜, κΈ€ 생성 μ‹œκ°„μ„ λ‹΄κ³  μžˆλ‹€.

POLLSUB ν…Œμ΄λΈ” : POLL ν…Œμ΄λΈ”μ˜ POLLID(νˆ¬ν‘œκΈ€ 번호)λ₯Ό 받아와 νˆ¬ν‘œ ν•­λͺ©λ“€ 각각의 이름과 νˆ¬ν‘œ 수λ₯Ό λ‹΄μ•„λ‘”λ‹€.

VOTER ν…Œμ΄λΈ” : IDκ°€ νˆ¬ν‘œν–ˆμ„ λ•Œ μ–΄λ–€ νˆ¬ν‘œκΈ€μ— μ–΄λ–€ ν•­λͺ©μ„ νˆ¬ν‘œν–ˆλŠ”μ§€μ™€ νˆ¬ν‘œν•œ μ‹œκ°„μ„ λ‹΄μ•„λ‘”λ‹€.

 

 

 

2. MyBatisλ₯Ό ν™œμš©ν•œ 쿼리문 μž‘μ„±

 

Poll.xml

<?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="Poll">

<!-- λͺ¨λ“  νˆ¬ν‘œ λͺ©λ‘ -->
<select id="getPollAllList" resultType="bit.com.a.poll.PollDto">
	SELECT POLLID, ID, QUESTION, SDATE, EDATE, ITEMCOUNT, POLLTOTAL, REGDATE
	FROM POLL
	ORDER BY SDATE DESC
</select>


<!-- νˆ¬ν‘œλ₯Ό ν–ˆλŠ”μ§€ μ—¬λΆ€ 확인 (1이면 νˆ¬ν‘œν•œ 것)-->
<select id="isVote" parameterType="bit.com.a.poll.Voter" resultType="int">
	SELECT NVL(COUNT(*), 0)
	FROM VOTER
	WHERE POLLID=#{pollId} AND ID=#{id}
</select>
	
	
	
<!-- νˆ¬ν‘œ λ§Œλ“€κΈ° -->
<insert id="makePoll" parameterType="bit.com.a.poll.PollDto">
	INSERT INTO POLL(POLLID, ID, QUESTION, SDATE, EDATE, ITEMCOUNT, POLLTOTAL, REGDATE)
	VALUES(POLL_SEQ.NEXTVAL, #{id}, #{question}, #{sDate}, #{eDate}, #{itemCount}, 0, SYSDATE)
</insert>	


<!-- νˆ¬ν‘œ ν•­λͺ©λ“€ -->
<insert id="makePollSub" parameterType="bit.com.a.poll.PollSubDto">
	INSERT INTO POLLSUB(POLLSUBID, POLLID, ANSWER, ACOUNT)
	VALUES(POLLSUB_SEQ.NEXTVAL, (SELECT NVL(MAX(POLLID),0) FROM POLL), #{answer}, 0)
</insert>


<!-- νˆ¬ν‘œ 정보 취득 -->
<select id="getPoll" parameterType="bit.com.a.poll.PollDto" resultType="bit.com.a.poll.PollDto">
	SELECT POLLID, ID, QUESTION, SDATE, EDATE, ITEMCOUNT, POLLTOTAL, REGDATE
	FROM POLL
	WHERE POLLID=#{pollId}
</select>
<!-- νˆ¬ν‘œ ν•­λͺ©λ“€ -->
<select id="getPollSubList" parameterType="bit.com.a.poll.PollDto" resultType="bit.com.a.poll.PollSubDto">
	SELECT POLLSUBID, POLLID, ANSWER, ACOUNT
	FROM POLLSUB
	WHERE POLLID=#{pollId}
</select>


<!--  νˆ¬ν‘œν–ˆμ„ λ•Œ  -->
<!-- λˆ„κ°€? -->
<insert id="pollingVoter" parameterType="bit.com.a.poll.Voter">
	INSERT INTO VOTER(VOTERID, POLLID, POLLSUBID, ID, REGDATE)
	VALUES(VOTER_SEQ.NEXTVAL, #{pollId}, #{pollSubId}, #{id}, SYSDATE)
</insert>
<!-- μ–΄λŠ νˆ¬ν‘œμ— -->
<update id="pollingPoll" parameterType="bit.com.a.poll.Voter">
	UPDATE POLL
	SET POLLTOTAL=POLLTOTAL+1
	WHERE POLLID=#{pollId}
</update>
<!-- μ–΄λŠ ν•­λͺ©μ„ -->
<update id="pollingSub" parameterType="bit.com.a.poll.Voter">
	UPDATE POLLSUB
	SET ACOUNT=ACOUNT+1
	WHERE POLLSUBID=#{pollSubId} AND POLLID=#{pollId}
</update>

</mapper>  

 

3. ServiceImplμ—μ„œ νŠΈλžœμž­μ…˜ 처리

 

PollServiceImpl.java

package bit.com.a.poll;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class PollServiceImpl implements PollService {

	@Autowired
	PollDao dao;
	
	
	@Override
	public List<PollDto> getPollAllList(String id) {
		
		//λͺ¨λ“  νˆ¬ν‘œ λͺ©λ‘μ„ κ°€μ§€κ³  μ˜¨λ‹€.
		List<PollDto> list = dao.getPollAllList();
		
		//νˆ¬ν‘œ μ°Έμ—¬ν–ˆλŠ”μ§€ 확인 ν›„ λ„˜κ²¨μ€„ λͺ©λ‘ (ν•œλ²ˆλ§Œ μ°Έμ—¬ κ°€λŠ₯ν•΄μ•Ό ν•˜λ―€λ‘œ)
		List<PollDto> pList = new ArrayList<PollDto>();
		
		
		/* Voter ν…Œμ΄λΈ”μ— 기둝이 μžˆλ‹€λ©΄ ν•΄λ‹Ή νˆ¬ν‘œμ— μ°Έμ—¬ν•œ 것 */
		for (PollDto poll : list) {
			int pollId = poll.getPollId();	// νˆ¬ν‘œκΈ€ 번호λ₯Ό κΊΌλ‚Έλ‹€.
			//νˆ¬ν‘œν–ˆμŒ : 1, νˆ¬ν‘œμ•ˆν–ˆμŒ : 2
			int count = dao.isVote(new Voter(pollId, 0, id));
			if (count == 1) {
				poll.setVote(true);
			} else {
				poll.setVote(false);
			}
			pList.add(poll);
		}
		
		return pList;
	}


	@Override
	public void makePoll(PollBean pBean) {
		
		// νˆ¬ν‘œ 주제
		PollDto poll = new PollDto(pBean.getId(), pBean.getQuestion(), pBean.getsDate(), pBean.geteDate(), pBean.getItemCount(), 0);
		dao.makePoll(poll);
		
		//νˆ¬ν‘œ ν•­λͺ©λ“€
		String answer[] = pBean.getPollNum();
		for (int i = 0; i < pBean.getItemCount(); i++) {
			PollSubDto pollSub = new PollSubDto();
			pollSub.setAnswer(answer[i]);
			dao.makePollSub(pollSub);
		}
	}


	@Override
	public PollDto getPoll(PollDto poll) {
		return dao.getPoll(poll);
	}


	@Override
	public List<PollSubDto> getPollSubList(PollDto poll) {
		return dao.getPollSubList(poll);
	}


	@Override
	public void polling(Voter voter) {
		
		dao.pollingVoter(voter);
		dao.pollingPoll(voter);
		dao.pollingSub(voter);
		
	}
	
	
}

 

4. Controller μž‘μ„±

 

PollController.java

package bit.com.a.poll;

import java.util.List;

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.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import bit.com.a.dto.MemberDto;

@Controller
public class PollController {

	@Autowired
	PollService service;
	
	
	@RequestMapping(value = "pollList.do", method = { RequestMethod.GET, RequestMethod.POST })
	public String pollList(Model model, HttpServletRequest req) {
		model.addAttribute("doc_title", "νˆ¬ν‘œ λͺ©λ‘");
		
		String id = ((MemberDto)req.getSession().getAttribute("login")).getId();
		
		List<PollDto> list = service.getPollAllList(id);
		model.addAttribute("pLists", list);
		
		return "pollList.tiles"; 
	}
	
	
	@RequestMapping(value = "pollMake.do", method = { RequestMethod.GET, RequestMethod.POST })
	public String pollMake(Model model) {
		model.addAttribute("doc_title", "νˆ¬ν‘œ λ§Œλ“€κΈ°");
		
		return "pollMake.tiles";
	}
	
	
	@RequestMapping(value = "pollMakeAf.do", method = { RequestMethod.GET, RequestMethod.POST })
	public String pollMakeAf(PollBean pBean) {
		
		service.makePoll(pBean);
		
		return "redirect:/pollList.do";
	}
	
	
	@RequestMapping(value = "pollDetail.do", method = { RequestMethod.GET, RequestMethod.POST })
	public String pollDetail(PollDto poll, Model model) {
		model.addAttribute("doc_title", "νˆ¬ν‘œ λ‚΄μš©");
		
		PollDto dto = service.getPoll(poll);
		List<PollSubDto> list = service.getPollSubList(poll);
		model.addAttribute("poll", dto);
		model.addAttribute("pollSubList", list);
		
		return "pollDetail.tiles";
	}
	
	
	@RequestMapping(value = "polling.do", method = { RequestMethod.GET, RequestMethod.POST })
	public String polling(Voter voter) {
		service.polling(voter);
		
		return "redirect:/pollList.do";
	}
	
	@RequestMapping(value = "pollResult.do", method = { RequestMethod.GET, RequestMethod.POST })
	public String pollResult(PollDto poll, Model model) {
		model.addAttribute("doc_title", "νˆ¬ν‘œ κ²°κ³Ό");
		
		//PollTotal
		PollDto dto = service.getPoll(poll);
		//νˆ¬ν‘œ ν•­λͺ©λ“€
		List<PollSubDto> list = service.getPollSubList(poll);
		model.addAttribute("poll", dto);
		model.addAttribute("pollSubList", list);
		
		return "pollResult.tiles";
	}
	
	
}

 

5. 뷰단 μž‘μ„±

pollList.jsp (리슀트 νŽ˜μ΄μ§€)

더보기
<%@page import="util.PollUtil"%>
<%@page import="bit.com.a.dto.MemberDto"%>
<%@page import="bit.com.a.poll.PollDto"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>


<%
	List<PollDto> pLists = (List<PollDto>)request.getAttribute("pLists");
	MemberDto mem = (MemberDto)session.getAttribute("login");
%>


<!-- κ΄€λ¦¬μž -->
<%
if(mem.getAuth() == 1) {
%>
	<table class="list_table" style="width: 95%;">
		<col width="50"><col width="50"><col width="300"><col width="100">
		<col width="100"><col width="50"><col width="50"><col width="100">	
		<tr>
			<th>번호</th>
			<th>아이디</th>
			<th>νˆ¬ν‘œμ œλͺ©</th>
			<th>μ‹œμž‘μΌ</th>
			<th>μ’…λ£ŒμΌ</th>
			<th>보기 개수</th>
			<th>νˆ¬ν‘œνšŸμˆ˜</th>
			<th>등둝일</th>
		</tr>
		<%
		for(int i = 0; i < pLists.size(); i++) {
			PollDto poll = pLists.get(i);
			%>
			<tr bgcolor="#aabbcc">
				<td><%=i+1 %></td>
				<td><%=poll.getId() %></td>
				<td><%=poll.getQuestion() %></td>
				<td><%=poll.getsDate() %></td>
				<td><%=poll.geteDate() %></td>
				<td><%=poll.getItemCount() %></td>
				<td><%=poll.getPollTotal() %></td>
				<td><%=poll.getRegDate() %></td>
			</tr>
		<%
		}
		%>
	</table>

<!-- μ‚¬μš©μž -->
<% 
} else { 
%>

	<table class="list_table" style="width: 95%;">
		<col width="50"><col width="50"><col width="300"><col width="100"><col width="100">
		<col width="100"><col width="50"><col width="50"><col width="100">	
		<tr>
			<th>번호</th>
			<th>아이디</th>
			<th>νˆ¬ν‘œμ œλͺ©</th>
			<th>κ²°κ³Ό</th>
			<th>μ‹œμž‘μΌ</th>
			<th>μ’…λ£ŒμΌ</th>
			<th>보기 개수</th>
			<th>νˆ¬ν‘œνšŸμˆ˜</th>
			<th>등둝일</th>
		</tr>
		<%
		for(int i = 0; i < pLists.size(); i++) {
			PollDto poll = pLists.get(i);
			%>
			<tr bgcolor="#aabbcc">
				<td><%=i+1 %></td>
				<td><%=poll.getId() %></td>
				<%	// νˆ¬ν‘œ 주제
				boolean isS = poll.isVote();
				
				//νˆ¬ν‘œν–ˆμŒ			κΈ°κ°„λ§Œλ£Œ
				if(isS || PollUtil.isEnd(poll.geteDate())) {
				%>
				<td>[마감]<%=poll.getQuestion() %></td>
				<%
				} else {	// νˆ¬ν‘œλ₯Ό μ•ˆν–ˆμœΌλ©°, 기간이 아직 λ§Œλ£Œλ˜μ§€ μ•ŠμŒ
				%>
				<td>
					<a href="pollDetail.do?pollId=<%=poll.getPollId() %>"><%=poll.getQuestion() %></a>
				</td>
				<%	
				}
				%>
				
				<td>
				<%
				if(isS || PollUtil.isEnd(poll.geteDate())) {
				%>
					<a href="pollResult.do?pollId=<%=poll.getPollId() %>">κ²°κ³Ό</a>
				<%	
				} else {
				%>
				<img alt="" src="image/pen.gif">
				<%	
				}
				%>
				</td>
				
				<td><%=poll.getsDate() %></td>
				<td><%=poll.geteDate() %></td>
				<td><%=poll.getItemCount() %></td>
				<td><%=poll.getPollTotal() %></td>
				<td><%=poll.getRegDate() %></td>
			</tr>
		<%
		}
		%>
	</table>

<% 
}
%>


<%
if(mem.getAuth() == 1) {
%>
<a href="pollMake.do">νˆ¬ν‘œ λ§Œλ“€κΈ°</a>
<%	
}
%>

 

pollMake.jsp (νˆ¬ν‘œκΈ€ μž‘μ„± νŽ˜μ΄μ§€)

더보기

 

 

<%@page import="java.util.Calendar"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<%
Calendar cal = Calendar.getInstance();
int tYear = cal.get(Calendar.YEAR);
int tMonth = cal.get(Calendar.MONTH)+1;
int tDay = cal.get(Calendar.DATE);
%>
    

<form action="pollMakeAf.do" method="post">
	<table class="list_table" style="width: 85%">
		<colgroup>
			 <col width="200px"><col width="200px">
		</colgroup>
		<tr>
			<th>아이디</th>
			<td style="text-align: left;">
				${login.id}<input type="hidden" name="id" value="${login.id }">
			</td>
		</tr>
		<tr>
			<th>νˆ¬ν‘œκΈ°ν•œ</th>
			<td style="text-align: left;">
				<select name="sYear">
					<%
					for(int i = tYear; i < tYear + 6; i++) {
					%>
					<option <%=(tYear+"").equals(i+"")?"selected='selected'":"" %> value="<%=i %>"><%=i %></option>	
					<%
					}
					%>
				</select>λ…„
				<select name="sMonth">
					<%
					for(int i = 1; i <= 12; i++) {
					%>
					<option <%=(tMonth+"").equals(i+"")?"selected='selected'":"" %> value="<%=i %>"><%=i %></option>	
					<%
					}
					%>
				</select>μ›”
				<select name="sDay">
					<%
					for(int i = 1; i <= cal.getActualMaximum(Calendar.DAY_OF_MONTH); i++) {
					%>
					<option <%=(tDay+"").equals(i+"")?"selected='selected'":"" %> value="<%=i %>"><%=i %></option>	
					<%
					}
					%>
				</select>일
				~
				<select name="eYear">
					<%
					for(int i = tYear; i < tYear + 6; i++) {
					%>
					<option <%=(tYear+"").equals(i+"")?"selected='selected'":"" %> value="<%=i %>"><%=i %></option>	
					<%
					}
					%>
				</select>λ…„
				<select name="eMonth">
					<%
					for(int i = 1; i <= 12; i++) {
					%>
					<option <%=(tMonth+"").equals(i+"")?"selected='selected'":"" %> value="<%=i %>"><%=i %></option>	
					<%
					}
					%>
				</select>μ›”
				<select name="eDay">
					<%
					for(int i = 1; i <= cal.getActualMaximum(Calendar.DAY_OF_MONTH); i++) {
					%>
					<option <%=(tDay+"").equals(i+"")?"selected='selected'":"" %> value="<%=i %>"><%=i %></option>	
					<%
					}
					%>
				</select>일
			</td>
		</tr>
		<tr>
			<th>νˆ¬ν‘œλ‚΄μš©</th>
			<td style="text-align: left;">
				<textarea rows="10" cols="50" name="question"></textarea>
			</td>
		</tr> 
		<tr>
			<th>νˆ¬ν‘œ λ¬Έν•­μˆ˜</th>
			<td style="text-align: left;">
				<select name="itemCount" onchange="pollChange(this)">
					<%
					for(int i = 2; i <= 20; i++) {
					%>
					<option <%= (4+"").equals(i+"")? "selected='selected'":"" %> value="<%=i %>" ><%=i %></option>
					<%	
					}
					%>
				</select>
			</td>
		</tr>
		<tr>
			<th>νˆ¬ν‘œ 상세 λ¬Έν•­</th>
			<td style="text-align: left;">
			<%
			for(int i = 1; i <=20; i++) {
			%>
			<div id='poll<%=i %>'>
				<%=(i+"") %>번:<input type="text" name="poll<%=i %>" size="60">
			</div>
			<%	
			}
			%>
			</td>
		</tr>
		<tr>
			<td colspan="2">
				<input type="submit" value="νˆ¬ν‘œλ§Œλ“€κΈ°">
			</td>
		</tr>		
	</table>
</form>


<script>
$(document).ready(function() {
	
	/* ν•­λͺ©λ“€ μ΄ˆκΈ°ν™” */
	for(i = 5; i <= 20; i++) {
		$('#poll'+i).hide();
	}
	
	
});


function pollChange(sel) {
	
	let val = sel.options[sel.selectedIndex].value;	// selected μ„ νƒν•œκ°’ λ°˜ν™˜
	console.log(val);
	
	for(i = 1; i <= 20; i++) {
		$('#poll'+i).val("");
		$('#poll'+i).hide();
	}
	
	//μ„€μ • κ°’λ§ŒνΌ 보여쀀닀.
	for(i = 1; i <= val; i++) {
		$('#poll'+i).show();
	}
	
}


</script>

 

pollDetail.jsp (νˆ¬ν‘œκΈ€ 상세 νŽ˜μ΄μ§€)

더보기

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<form action="polling.do" method="post">
	<table class="list_table" style="width: 95%">
		<colgroup>
			<col width="200px">
			<col width="500px">
		</colgroup>
		<tr>
			<th>νˆ¬ν‘œλ²ˆν˜Έ</th>
			<td style="text-align: left;">
				<input type="text" name="pollId" value="${poll.pollId }" size="50" readonly="readonly">
			</td>
		</tr>
		<tr>
			<th>아이디</th>
			<td style="text-align: left;">
				<input type="text" name="id" value="${login.id}" size="50" readonly="readonly">
			</td>
		</tr>
		<tr>
			<th>νˆ¬ν‘œκΈ°ν•œ</th>
			<td style="text-align: left;">
				${poll.sDate} ~ ${poll.eDate}
			</td>
		</tr>
		<tr>
			<th>νˆ¬ν‘œλ‚΄μš©</th>
			<td style="text-align: left;">
				<textarea rows="10" cols="50" name="question" readonly="readonly">${poll.question}</textarea>
			</td>
		</tr>
		<tr>
			<th>보기 개수</th>
			<td style="text-align: left;">
				${poll.itemCount }
			</td>
		</tr>
		<tr>
			<th>보기</th>
			<td style="text-align: left;">
				<c:forEach items="${pollSubList }" var="pSub" varStatus="i">
				${i.count }번
				<input type="radio" name="pollSubId" ${i.count==1?"checked='checked'":"" } value="${pSub.pollSubId }">
				<input type="text" name="answer" size="60" value="${pSub.answer }" readonly="readonly">
				<br>
				</c:forEach>
			</td>
		</tr>
		<tr align="center">
			<td colspan="2">
				<input type="submit" value="νˆ¬ν‘œν•˜κΈ°">
			</td>
		</tr>
	</table>
</form>

 

 

pollResult.jsp (νˆ¬ν‘œ κ²°κ³Ό νŽ˜μ΄μ§€)

 

β€» ν•˜μ΄μ°¨νŠΈ (www.highcharts.com/) 파이 κ·Έλž˜ν”„ μ‚¬μš©

 DBλ₯Ό JSON ν˜•μ‹μœΌλ‘œ λ§Œλ“€μ–΄ JS에 μ‚½μž…

<%@page import="bit.com.a.poll.PollSubDto"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!-- https://codepen.io/pen/ 'ν•˜μ΄μ°¨νŠΈ' -->
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<script src="https://code.highcharts.com/modules/export-data.js"></script>
<script src="https://code.highcharts.com/modules/accessibility.js"></script>

    
<%
	List<PollSubDto> list = (List<PollSubDto>)request.getAttribute("pollSubList");
	
	String jsonData = "[";
	for(PollSubDto p : list) {
		jsonData += "{name:'" +p.getAnswer()+ "', y:" +p.getaCount()+ "}, ";
	}
	jsonData = jsonData.substring(0, jsonData.length()-1);
	jsonData += "]";
	System.out.println(jsonData);
	
	request.setAttribute("jsonData", jsonData);

%>  


<table class="list_table" style="width: 95%">
	<colgroup>
		<col width="200px"><col width="500px">
	</colgroup>
	<tr>
		<th>νˆ¬ν‘œλ²ˆν˜Έ</th>
		<td style="text-align: left;">
			<input type="text" value="${poll.pollId }" size="50" readonly="readonly">
		</td>
	</tr>
	<tr>
		<th>아이디</th>
		<td style="text-align: left;">
			<input type="text" value="${login.id }" size="50" readonly="readonly">
		</td>
	</tr>
	<tr>
		<th>νˆ¬ν‘œκΈ°ν•œ</th>
		<td style="text-align: left;">
			${poll.sDate } ~ ${poll.eDate }
		</td>
	</tr>
	<tr>
		<th>νˆ¬ν‘œλ‚΄μš©</th>
		<td style="text-align: left;">
			<textarea rows="10" cols="50" readonly="readonly">${poll.question }</textarea>
		</td>
	</tr>
	<tr>
		<th>νˆ¬ν‘œκ²°κ³Ό</th>
		<td>
			<figure class="highcharts-figure">
			  <div id="container"></div>
			</figure>
		</td>
	</tr>



</table> 

<script type="text/javascript">

Highcharts.chart('container', {
	  chart: {
	    plotBackgroundColor: null,
	    plotBorderWidth: null,
	    plotShadow: false,
	    type: 'pie'
	  },
	  title: {
	    text: 'νˆ¬ν‘œ κ²°κ³Ό'
	  },
	  tooltip: {
	    pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
	  },
	  accessibility: {
	    point: {
	      valueSuffix: '%'
	    }
	  },
	  plotOptions: {
	    pie: {
	      allowPointSelect: true,
	      cursor: 'pointer',
	      dataLabels: {
	        enabled: true,
	        format: '<b>{point.name}</b>: {point.percentage:.1f} %'
	      }
	    }
	  },
	  series: [{
	    name: 'νˆ¬ν‘œμœ¨',
	    colorByPoint: true,
	    data: <%=jsonData %>
	  }]
	});
	
</script> 

 

 


- Crawling (크둀링)

- μ›ΉνŽ˜μ΄μ§€λ₯Ό κ·ΈλŒ€λ‘œ 가져와 ν•„μš”ν•œ 데이터λ₯Ό μΆ”μΆœν•΄ λ‚΄λŠ” ν–‰μœ„

 

 

 

Jsoup을 ν™œμš©ν•œ 크둀링

 

- κΈ°λ³Έ μ„ΈνŒ…

1. mvn λ ˆνŒŒμ§€ν† λ¦¬μ—μ„œ jsoup 검색

2. Jsoup Java HTML Parserμ—μ„œ jar파일 λ‹€μš΄λ‘œλ“œ

3. lib 폴더에 μ‚½μž…

 

 

- μ‚¬μš© μ˜ˆμ‹œ

CGV κ³΅μ‹μ‚¬μ΄νŠΈμ—μ„œ μ˜ν™”μ œλͺ©, 예맀율 κ°€μ Έμ˜€κΈ°

Document doc = Jsoup.connect("http://www.cgv.co.kr/movies/").get();

 

1. μ˜ν™” 제λͺ© κ°€μ Έμ˜€κΈ°

/*
<div class="box-contents">
	<a href="/movies/detail-view/?midx=84514">
		<strong class="title">λ‚΄μΌμ˜ κΈ°μ–΅</strong> 
*/
Elements titles = doc.select("div.box-contents strong.title");

for (int i = 0; i < 7; i++) {
	Element title = titles.get(i);
	String t = title.text();
	System.out.println(t);
}

2. 예맀율 κ°€μ Έμ˜€κΈ°

/* 예맀율 */
/*
	<div class="score">
			<strong class="percent">예맀율<span>7.8%</span></strong>
			<!-- 2020.05.07 κ°œλ΄‰μ „ 프리에그 λ…ΈμΆœ, κ°œλ΄‰ν›„ κ³¨λ“ μ—κ·Έμ§€μˆ˜ λ…ΈμΆœλ³€κ²½ (적용 λ²”μœ„1~ 3μœ„)-->
			<div class='egg-gage small'>
				<span class='egg great'></span>
				<span class='percent'>86%</span>
*/
Elements percents = doc.select("div.score strong.percent span");

for (int i = 0; i < 7; i++) {
	Element percent = percents.get(i);
	String p = percent.text();
	System.out.println(p);
}

 

MovieChart.java

package movie;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class MovieChart {
	public static List<MovieVo> getCGVData() throws IOException {
		
         	 /* CGV μ‚¬μ΄νŠΈ */
		Document doc = Jsoup.connect("http://www.cgv.co.kr/movies/").get();
        		
		/* μ˜ν™”μ œλͺ© */
		/*
		<div class="box-contents">
            <a href="/movies/detail-view/?midx=84514">
                <strong class="title">λ‚΄μΌμ˜ κΈ°μ–΅</strong> 
		 */
		Elements titles = doc.select("div.box-contents strong.title");
		/* 예맀율 */
		/*
		  <div class="score">
         	 <strong class="percent">예맀율<span>7.8%</span></strong>
          	<!-- 2020.05.07 κ°œλ΄‰μ „ 프리에그 λ…ΈμΆœ, κ°œλ΄‰ν›„ κ³¨λ“ μ—κ·Έμ§€μˆ˜ λ…ΈμΆœλ³€κ²½ (적용 λ²”μœ„1~ 3μœ„)-->
         	 <div class='egg-gage small'>
         		 <span class='egg great'></span>
         		 <span class='percent'>86%</span>
		 */
		Elements percents = doc.select("div.score strong.percent span");
		
		
		List<MovieVo> list = new ArrayList<MovieVo>();
		
		
		
		for (int i = 0; i < 7; i++) {
			Element title = titles.get(i);
			String t = title.text();
			Element percent = percents.get(i);
			String p = percent.text();
		//	System.out.println(t);
		//	System.out.println(p);
			
			MovieVo vo = new MovieVo();
			double pv = Double.parseDouble(p.replace("%", ""));
			
			vo.setTitle(t);
			vo.setPercent(pv);
			
			list.add(vo);
		}
		
		return list;
	}

}

JUM μ‹€μ‹œκ°„ 검색어 크둀링

/* JUM μ‹€μ‹œκ°„ 검색어 */
		Document doc = Jsoup.connect("https://zum.com/").get();
		Elements searchs = doc.select("div.issue_keyword_total span.d_keyword");
		
		System.out.println("쀌 μ‹€μ‹œκ°„ 검색어");
		for (int i = 0; i < 20; i+=2) {
			Element search = searchs.get(i);
			String s = search.text();
			System.out.println((i/2)+1 +" "+s);
		}

 


- μ»€μŠ€ν…€ μ–΄λ…Έν…Œμ΄μ…˜μ„ ν™œμš©ν•œ AOP κ΅¬ν˜„

 

ν•œ 예둜 aopλ₯Ό ν™œμš©ν•˜μ—¬ login session 이 μžˆλŠ”μ§€λ₯Ό 검사할 λ•Œ, λͺ¨λ“  컨트둀러 λ©”μ†Œλ“œμ— μ μš©ν•˜κ²Œ 되면 λ‘œκ·ΈμΈλ§ˆμ € λ˜μ§€ μ•ŠλŠ” λΆˆμƒμ‚¬κ°€ 생긴닀. μ΄λ ‡κ²Œ aopλ₯Ό μ μš©ν•˜κ³  μ‹Άμ§€ μ•Šμ€ λ©”μ†Œλ“œκ°€ μžˆλ‹€λ©΄ μ»€μŠ€ν…€ μ–΄λ…Έν…Œμ΄μ…˜μ„ ν™œμš©ν•˜λ©΄ λœλ‹€.

 

 

1. μ–΄λ…Έν…Œμ΄μ…˜ 생성

 

μž„μ˜μ˜ μ΄λ¦„μœΌλ‘œ μ»€μŠ€ν…€ μ–΄λ…Έν…Œμ΄μ…˜μ„ μƒμ„±ν•œλ‹€.

 

NoLogging.java

package bit.com.a.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NoLogging {

}

 

 

2. AOP ν¬μΈνŠΈμ»·μ— μ–΄λ…Έν…Œμ΄μ…˜ 쑰건 μΆ”κ°€

 

bit.com.a.controller ν•˜μœ„μ— μžˆλŠ” λ©”μ†Œλ“œμ΄λ©΄μ„œ NoLogging μ–΄λ…Έν…Œμ΄μ…˜μ΄ λΆ™μ§€ μ•Šμ€ κ²ƒλ§Œ AOPκ°€ μ‹€ν–‰λ˜κ²Œ 쑰건을 건닀.

 

LogAOP.java

@Around("within(bit.com.a.controller.*)" +
			"&& !@annotation(bit.com.a.annotation.NoLogging)")

 

 

3. AOPκ°€ λ°œλ™λ˜μ§€ μ•Šμ„ λ©”μ†Œλ“œ μœ„μ— @μ–΄λ…Έν…Œμ΄μ…˜ μΆ”κ°€

 

μ—¬κΈ°μ„  NoLoggingμ΄λΌλŠ” μ΄λ¦„μ˜ μ–΄λ…Έν…Œμ΄μ…˜μ„ λ§Œλ“€μ—ˆλ‹€. μ–΄λ…Έν…Œμ΄μ…˜μ„ μΆ”κ°€ν•˜λ©΄ ν•΄λ‹Ή λ©”μ†Œλ“œλŠ” AOPκ°€ λ°œλ™λ˜μ§€ μ•ŠλŠ”λ‹€.

@NoLogging
@RequestMapping(value = "login.do", method = RequestMethod.GET)
public String login() {
	return "login.tiles";
}

 

 

 


- Web Socket (μ›Ή μ†ŒμΌ“)

 - 두 ν”„λ‘œκ·Έλž¨κ°„μ˜ λ©”μ‹œμ§€λ₯Ό κ΅ν™˜ν•˜κΈ° μœ„ν•œ 톡신방법 쀑 ν•˜λ‚˜

 

νŠΉμ§•

 

1. 영ꡬ적 μ–‘λ°©ν–₯ 톡신

ν΄λΌμ΄μ–ΈνŠΈμ™€ μ„œλ²„κ°€ μ„œλ‘œ 원할 λ•Œ 데이터λ₯Ό μ£Όκ³  받을 수 있으며 연결이 λŠμ–΄μ§€μ§€ μ•Šκ³  μ§€μ†λœλ‹€.

 

2. μ‹€μ‹œκ°„ λ„€νŠΈμ›Œν‚Ή

λΉ λ₯΄κ²Œ 데이터λ₯Ό κ΅ν™˜ν•˜λŠ” μ‹€μ‹œκ°„ μ²˜λ¦¬κ°€ ν•„μš”ν•  λ•Œ μ‚¬μš©λœλ‹€.

 

 

κ΅¬ν˜„ 방법

 

1. pom.xml에 dependency μΆ”κ°€

  <!-- μ›Ή μ†ŒμΌ“ -->
   <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-websocket</artifactId>
       <version>5.3.3</version>
   </dependency>
   
   <dependency>
       <groupId>org.glassfish</groupId>
       <artifactId>javax.json</artifactId>
       <version>1.0.4</version>
   </dependency>   
   
   <dependency>
       <groupId>org.json</groupId>
       <artifactId>json</artifactId>
       <version>20190722</version>
   </dependency>
   
   <dependency>
       <groupId>com.googlecode.json-simple</groupId>
       <artifactId>json-simple</artifactId>
       <version>1.1.1</version>
   </dependency>

 

2. spring 폴더 μ•ˆ websocket-context.xml μƒμ„±

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:websocket="http://www.springframework.org/schema/websocket"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
		http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket-4.3.xsd">

	<websocket:handlers>
		<websocket:mapping handler="myHandler" path="/echo.do"/>
		<websocket:handshake-interceptors>
			<bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor"/>
		</websocket:handshake-interceptors>
		
	</websocket:handlers>
	
	<bean id="myHandler" class="bit.com.a.websocket.WebSocket"/>
	
</beans>

 

3. web-xml μˆ˜μ •

 <async-supported>true</async-supported> νƒœκ·Έλ„ μΆ”κ°€

<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>
	      /WEB-INF/spring/servlet-context.xml
	      /WEB-INF/spring/aop-context.xml
	      /WEB-INF/spring/file-context.xml
	      /WEB-INF/spring/websocket-context.xml <!-- μ—¬κΈ°μΆ”κ°€ -->
      </param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    <async-supported>true</async-supported> <!-- μ—¬κΈ°μΆ”κ°€ -->
  </servlet>

 

 

4. WebSocket.java 생성

 

- TextWebSocketHandlerλ₯Ό 상속

- 체크된 것듀 Override ν•΄μ€€λ‹€.

 

package bit.com.a.websocket;

import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

public class WebSocket extends TextWebSocketHandler{
	
	private Map<String, WebSocketSession> userMap = new ConcurrentHashMap<String, WebSocketSession>();

	public WebSocket() {
		System.out.println("EchoHandler 생성됨" + new Date());
	}

	
	/* ν΄λΌμ΄μ–ΈνŠΈμ™€ 접속이 μ„±κ³΅ν–ˆμ„ λ•Œ 호좜 */
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		System.out.println("연결됨" + session.getId() + " " + new Date());
		userMap.put(session.getId(), session);
	}

	/* ν΄λΌμ΄μ–ΈνŠΈμ™€ 접속이 λŠκ²Όμ„ λ•Œ */
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		System.out.println("μ—°κ²° μ’…λ£Œ" + session.getId() + " " + new Date());
		userMap.remove(session.getId());
	}

	/* λ©”μ‹œμ§€ μ†‘μˆ˜μ‹ (recv & send) */
	@Override
	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
		
		// μˆ˜μ‹ (recv)
		System.out.println("λ©”μ‹œμ§€ μˆ˜μ‹ :" +message.getPayload()+" "+ new Date());
		
		// 솑신(send) - λͺ¨λ“  client에 μ „μ†‘ν•œλ‹€.
		for (WebSocketSession s : userMap.values()) {
			s.sendMessage(message);
		}
		
	}

	/* μ˜ˆμ™Έ λ°œμƒ */
	@Override
	public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
		System.out.println(session.getId() + " μ˜ˆμ™Έ λ°œμƒ " + new Date());
	}
	
}

 

 

5. λ·° & μžλ°”μŠ€ν¬λ¦½νŠΈ 생성

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<table class="list_table" style="width: 85%">
	<colgroup>
		<col width="200px"><col width="500px">
	</colgroup>
	<tr>
		<th>μ±„νŒ…λͺ…</th>
		<td style="text-align: left;">
			<input type="text" id="name"> 
			<input type="button" id="enterBtn" value="μž…μž₯" onclick="connect()">
			<input type="button" id="exitBtn" value="λ‚˜κ°€κΈ°" onclick="disconnect()">
		</td>
	</tr>
	<tr>
		<th>아이디</th>
		<td style="text-align: left;">
			<input type="text" id="id" value="${login.id }" readonly="readonly">
		</td>
	</tr>
	<tr>
		<td colspan="2">
			<textarea rows="10" cols="70" id="messageArea"></textarea>
		</td>
	</tr>
	<tr>
		<td colspan="2">
			<input type="text" id="message" size="50">
			<input type="button" id="sendBtn" value="전솑" onclick="send()">
		</td>
	</tr>
</table>


<script>
	let wSocket;
	
	// 접속	
	function connect() {
		
		if(wSocket != undefined && wSocket.readyState != WebSocket.CLOSED) {
			alert('이미 μž…μž₯ν•˜μ…¨μŠ΅λ‹ˆλ‹€.');
			return;
		}
		
		//WebSocket 생성
		wSocket = new WebSocket("ws://192.168.0.231:8090/sample10/echo.do");

		
		wSocket.onopen = onOpen;
		wSocket.onmessage = onMessage;
		wSocket.close = onClose;
		
		
	}
	
	// 접속을 쀑단
	function disconnect() {
		wSocket.close();
		location.href = "chating.do";
	}
	
	// 연결이 λ˜μ—ˆμ„ λ•Œ
	function onOpen(evt) {
		appendMessage("μ—°κ²°λ˜μ—ˆμŠ΅λ‹ˆλ‹€.");
		
	}
	
	//μˆ˜μ‹ μ΄ λ˜μ—ˆμ„ λ•Œ
	function onMessage(evt) {
		let data = evt.data;
		if(data.substring(0, 4) == "msg:") {
			appendMessage(data.substring(4));
		}
	}
	
	// λŠκ²Όμ„ λ•Œ
	function onClose() {
		appendMessage("연결이 λŠκ²ΌμŠ΅λ‹ˆλ‹€.");
	}
	
	// λ©”μ‹œμ§€ 솑신
	function send() {
		let id = $('#id').val();
		let msg = $('#message').val();
		
		wSocket.send("msg:"+id+":"+msg);
		$("#message").val("");
	}
	
	// μΆ”κ°€ λ¬Έμžμ—΄μ„ κΈ°μž…
	function appendMessage(msg) {
		//λ©”μ‹œμ§€λ₯Ό μΆ”κ°€ ν•˜κ³  κ°œν–‰
		$("#messageArea").append(msg+"\n");
		
		// μŠ€ν¬λ‘€μ„ μœ„λ‘œ 이동 μ‹œν‚¨λ‹€
		const top = $('#messageArea').prop("scrollHeight");
		
		$("#messageArea").scrollTop(top);
		
	}

</script>

 

 

 

μ›Ήμ†ŒμΌ“ μ‹€μ‹œκ°„ μ±„νŒ… κ΅¬ν˜„ ν™”λ©΄

μ™Όμͺ½μ΄ Edge, 였λ₯Έμͺ½μ΄ Chrome으둜 μ ‘μ†ν•˜μ˜€λ‹€.

ν•˜λ‹¨ μ½˜μ†”μ— λ‹€λ₯Έ μ„Έμ…˜ID값이 좜λ ₯λ˜λŠ” 것을 확인할 수 μžˆλ‹€.

 

 

μ €μž‘μžν‘œμ‹œ (μƒˆμ°½μ—΄λ¦Ό)

'πŸ’» 개발 > πŸ“– TIL (Today I Learned)' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

210422 TIL (D+71 μŠ€ν”„λ§ File μ—…λ‘œλ“œ, λ‹€μš΄λ‘œλ“œ κ΅¬ν˜„)  (0) 2021.04.22
ajax ν™œμš© μΊ˜λ¦°λ” λ§Œλ“€κΈ°  (1) 2021.04.21
'πŸ’» 개발/πŸ“– TIL (Today I Learned)' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€
  • 210422 TIL (D+71 μŠ€ν”„λ§ File μ—…λ‘œλ“œ, λ‹€μš΄λ‘œλ“œ κ΅¬ν˜„)
  • ajax ν™œμš© μΊ˜λ¦°λ” λ§Œλ“€κΈ°
EastShine_
EastShine_
더 λ‚˜μ€ κ°œλ°œμžκ°€ 되기 μœ„ν•œ λ‚˜μ˜ 기둝 πŸ“
  • EastShine_
    개발.LOG πŸ’»
    EastShine_
  • 전체
    였늘
    μ–΄μ œ
  • 05-25 07:43
    • λΆ„λ₯˜ 전체보기 (27)
      • πŸ’» 개발 (21)
        • πŸ–₯️ 운영체제 (3)
        • 🌏 λ„€νŠΈμ›Œν¬ (0)
        • πŸ’Ύ Database (3)
        • πŸŽ› Java (0)
        • πŸ–² Javascript (0)
        • πŸ€ Spring (5)
        • 🎸 ETC (4)
        • πŸ“ˆ μ•Œκ³ λ¦¬μ¦˜ (3)
        • πŸ“– TIL (Today I Learned) (3)
      • 🏠 일상 (6)
        • πŸ““ 일상 일기 (6)
  • 인기 κΈ€

  • νƒœκ·Έ

    e-book pdf μΆ”μΆœ
    회고
    Whisper API
    transactionaleventlistener
    λ°±μ—”λ“œ
    λŒ€κΈ°μ—΄
    6κΈ°
    e-book pdf λ³€ν™˜
    spring
    νŠΈλžœμž­μ…˜ 뢄리
    ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€
    redis
    μ•Œκ³ λ¦¬μ¦˜
    낙관적락
    λ™μ‹œμ„±μ²˜λ¦¬
    μ½”λ”©ν…ŒμŠ€νŠΈ
    ν•­ν•΄ν”ŒλŸ¬μŠ€
    비관적락
    Python
    μ½˜μ„œνŠΈμ˜ˆμ•½μ„œλΉ„μŠ€
  • 졜근 λŒ“κΈ€

  • 졜근 κΈ€

  • hELLOΒ· Designed Byμ •μƒμš°.v4.10.1
EastShine_
210427 TIL(D+74 μŠ€ν”„λ§ νˆ¬ν‘œ κ΅¬ν˜„, Crawling, μ»€μŠ€ν…€ μ–΄λ…Έν…Œμ΄μ…˜ ν™œμš©ν•œ AOP, μ›Ή μ†ŒμΌ“)
μƒλ‹¨μœΌλ‘œ

ν‹°μŠ€ν† λ¦¬νˆ΄λ°”