오늘이라도

[Spring] 19. 방명록 만들기 ⑤ : 덧글 수정, 삭제 / 공공 데이터 API 가져오기 본문

취업성공패키지 SW 개발자 교육/Spring

[Spring] 19. 방명록 만들기 ⑤ : 덧글 수정, 삭제 / 공공 데이터 API 가져오기

upcake_ 2020. 7. 27. 14:23
반응형

https://github.com/upcake/Class_Examples

교육 중에 작성한 예제들은 깃허브에 올려두고 있습니다. 

gif 파일은 클릭해서 보는 것이 정확합니다.


 - 방명록 만들기 ⑤ : 덧글 수정, 삭제 / 공공 데이터 API 가져오기 -

 

▲덧글 수정/삭제 작동 화면

 

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="core" %>
<%@ taglib  uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<core:forEach items="${list }" var="vo" varStatus="status"> 
	<!-- varStatus 인덱스값 찾아갈때 사용하는 속성 -->
	${status.index eq 0 ? '<hr>' : '' }
	<div data-id="${vo.id }"> <!-- data-* 속성 : 특별한 조작 없이 HTML 요소에 추가 정보를 저장할 수 있게 해주는 속성 -->
		${vo.name } [${vo.writedate }]
		<core:if test="${login_info.id eq vo.writer }"><!-- 로그인한 사용자가 작성한 댓글 수정/삭제 기능 -->
			<span style="float:right;">
				<a class="btn-fill-s btn-modify-save">수정</a>
				<a class="btn-fill-s btn-delete-cancel">삭제</a>
			</span>
		</core:if>
		<div class="original">${fn:replace(fn:replace(vo.content, lf, '<br>' ), crlf, '<br>') }</div>
		<div class="modify" style="display:none; margin-top:6px;"></div>
	</div>
	<hr>
</core:forEach>
<script>
/* closest()
 현재 element 에서 탐색 출발
 DOM 트리에서 selector 에 매칭되는 하나의 element 를 찾을 때까지 위로 탐색
 반환된 jQuery 객체는 0개 또는 1개의 element 를 포함한다.
*/

/*
$('.original').each(function(){
	$(this).text(
		$(this).text().replace(/</g, '$lt;').replace(/>/g, '$gt;')
			.replace(/&lt;br&gt;/g, '<br>')
	);
});
*/

//수정 / 저장 버튼 클릭
$('.btn-modify-save').on('click', function(){
	var $div = $(this).closest('div');

	if( $(this).text() == '수정' ) {
		//수정 텍스트 창 크기 고정
		$div.children('.modify').css('height', $div.children('.original').height()-6); 

		//줄바꿈 태그 변환
		var tag = "<textarea style='width:99%; height:90%; resize:none'>" + $div.children('.original').html().replace(/<br>/g, '\n') + "</textarea>";
		$div.children('.modify').html(tag);
		display($div, 'm');
	} else {
		var comment = {id:$div.data('id'),
						 content:$div.children('.modify').find('textarea').val() };
		//alert(JSON.stringify(comment)); JSON형태로 잘 출력되는지 확인
		
		$.ajax({
			url: 'board/comment/update',
			data: JSON.stringify(comment),
			contentType: 'application/json',
			type: 'post',
			success: function(data) {
				alert(data);
				comment_list();
			}, error: function(req, text) {
				alert(text + ':' + req.status);
			}
		});
	}
});

//삭제 / 취소 버튼 클릭
$('.btn-delete-cancel').on('click', function(){
	var $div = $(this).closest('div');

	if( $(this).text() == '취소' ) {
		display($div, 'd');
	} else {
		if( confirm('정말 삭제하시겠습니까?') ) {
			$.ajax({
				url: 'board/comment/delete/' + $div.data('id'),
				success: function() {
					comment_list();
				}, error: function(req, text) {
					alert(text + ':' + req.status);
				},
			});
		}
	}
})

function display(div, mode) {
	//수정 상태(m) : 저장/취소, 원글 안 보이고, 수정 글은 보이고 
	//보기 상태(d) : 수정/삭제, 원글 보이고, 수정 글은 안 보이고
	div.find('.btn-modify-save').text(mode=='m' ? '저장' : '수정');
	div.find('.btn-delete-cancel').text(mode=='m' ? '취소' : '삭제');
	div.children('.original').css('display', mode=='m' ? 'none' : 'block');
	div.children('.modify').css('display', mode=='m' ? 'block' : 'none');
}
</script>

▲list.jsp

 

package com.hanul.iot;

import java.io.File;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import board.BoardCommentVO;
import board.BoardPage;
import board.BoardServiceImpl;
import board.BoardVO;
import common.CommonService;
import member.MemberVO;

@Controller
public class BoardController {
	@Autowired private BoardServiceImpl service;
	@Autowired private BoardPage page;
	@Autowired private CommonService common;
	
	//방명록 목록 화면 요청================================================================
	@RequestMapping("/list.bo")
	public String list(HttpSession session, Model model, @RequestParam(defaultValue = "1") int curPage,
			String search, String keyword, @RequestParam(defaultValue = "10") int pageList, 
			@RequestParam(defaultValue = "list") String viewType) {
		//DB에서 방명록 정보를 조회해와 목록 화면에 출력
		session.setAttribute("category", "bo");
		page.setCurPage(curPage);
		page.setSearch(search);
		page.setKeyword(keyword);
		page.setPageList(pageList);
		page.setViewType(viewType);
		
		model.addAttribute("page", service.board_list(page));
		
		return "board/list";
	} //list()
	
	//방명록 신규 화면 요청================================================================
	@RequestMapping("/new.bo")
	public String board() {
		//방명록 글쓰기 화면으로 연결
		return "board/new";
	} // board()
	
	//신규 방명록 저장 처리 요청================================================================
	@RequestMapping("/insert.bo")
	public String insert(BoardVO vo, MultipartFile file, HttpSession session) {
		//화면에서 입력한 정보를 DB에 저장한 후 목록 화면으로 연결
		if( !file.isEmpty() ) {
			vo.setFilename( file.getOriginalFilename() );
			vo.setFilepath(common.upload("board", file, session));
		}
		vo.setWriter( ((MemberVO) session.getAttribute("login_info")).getId() );
		service.board_insert(vo);
		return "redirect:list.bo";
	} //insert()
	
	//방명록 상세 화면 요청====================================================================
	@RequestMapping("/detail.bo")
	public String detail(int id, Model model) {
		//선택한 방명록 글을 DB에서 조회해와 상세 화면에 출력
		service.board_read(id);
		model.addAttribute("vo", service.board_detail(id));
		model.addAttribute("page", page);
		model.addAttribute("crlf", "\r\n");
		
		return "board/detail";
	} //detail()
	
	//방명록 상세 화면 요청====================================================================
	@ResponseBody @RequestMapping("/download.bo")
	public void download(int id, HttpSession session, HttpServletResponse response) {
		//해당 글의 첨부 파일 정보를 조회해와 다운로드한다.
		BoardVO vo = service.board_detail(id);
		common.download(vo.getFilename(), vo.getFilepath(), session, response);
	} //download()
	
	//방명록 수정 화면 요청====================================================================
	@RequestMapping("/modify.bo")
	public String modify(int id, Model model) {
		//선택한 방명록 글의 정보를 DB에서 조회해와 수정 화면에 출력
		model.addAttribute("vo", service.board_detail(id));
		return "board/modify";
	} //modify()
	
	//방명록 수정 화면 요청====================================================================
	@RequestMapping("/update.bo")
	public String update(BoardVO vo, MultipartFile file, HttpSession session, String attach, Model model) {
		//화면에서 입력한 정보를 DB에 변경, 저장한 후 상세 화면으로 연결
		BoardVO board = service.board_detail(vo.getId());
		String uuid = session.getServletContext().getRealPath("resources") + board.getFilepath();
		
		//파일을 첨부한 경우 - 없었는데 새로 첨부, 있었는데 바꿔 첨부
		if( !file.isEmpty() ) {
			vo.setFilename(file.getOriginalFilename());
			vo.setFilepath(common.upload("board", file, session));
			
			if( board.getFilename() != null ) {
				File f = new File(uuid);
				if( (f.exists()) ) { f.delete(); }
			}
		} else {
			//파일 첨부가 없는 경우 - if 없었고, else 있었는데 그대로 사용하는 경우
			if( attach.isEmpty() ) {  
				File f = new File(uuid);
				if( (f.exists()) ) { f.delete(); }
			} else {
				vo.setFilename(board.getFilename());
				vo.setFilepath(board.getFilepath());
			}
		}
		service.board_update(vo);
		
		//기존 방법
		//return "redirect:detail.bo?id=" + vo.getId();
		
		//다른 방법
		model.addAttribute("url", "detail.bo");
		model.addAttribute("id", vo.getId());
		return "board/redirect";
	} //update()
	
	//방명록 수정 화면 요청====================================================================
	@RequestMapping("/delete.bo")
	public String delete(int id, Model model) {
		//선택한 글을 DB에서 삭제한 후 목록 화면으로 연결
		service.board_delete(id);
		model.addAttribute("url", "list.bo");
		model.addAttribute("id", id);
		model.addAttribute("page", page);
		
		return "board/redirect";
	} //delete()
	
	//댓글 저장 처리 요청====================================================================
	@ResponseBody @RequestMapping ("/board/comment/insert")
	public boolean comment_insert(BoardCommentVO vo, HttpSession session) {
		//화면에서 입력한 정보를 DB에 저장한다.
		vo.setWriter( ((MemberVO) session.getAttribute("login_info")).getId());
		return service.board_comment_insert(vo) > 0 ? true : false;
	} //comment_insert()
	
	//댓글 목록 조회 요청====================================================================
	@RequestMapping("/board/comment/{pid}")
	public String comment_list(@PathVariable int pid, Model model) {
		//DB에서 댓글 목록을 조회해와 댓글 목록 화면에 출력
		model.addAttribute("list", service.board_comment_list(pid));
		model.addAttribute("crlf", "\r\n");
		model.addAttribute("lf", "\n");		// lf의 형태로 라인피드가 저장될 수도 있어서 윗라인이 적용이 안될경우 이 코드도 작성한다.
		
		return "board/comment/list";
	} //comment_list()
	
	//댓글 변경 저장 처리 요청
	@ResponseBody @RequestMapping(value="/board/comment/update", produces="application/text; charset=utf-8")
	public String comment_update(@RequestBody BoardCommentVO vo) {
		return service.board_comment_update(vo) > 0 ? "성공" : "실패";
	} //comment_update()
	
	//댓글 삭제 처리 요청
	//ResponseBody : 화면(jsp)으로 연결이 아니라 호출한쪽으로 돌아갈때 사용하는 어노테이션
	@ResponseBody @RequestMapping("/board/comment/delete/{id}")
	public void comment_delete(@PathVariable int id) {
		service.board_comment_delete(id);	
	} //comment_delete()
} //class

▲BoardController.java

 

package board;

import java.util.List;

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

@Service
public class BoardServiceImpl implements BoardService {
	@Autowired private BoardDAO dao;

	@Override
	public int board_insert(BoardVO vo) {
		return dao.board_insert(vo);
	}

	@Override
	public BoardPage board_list(BoardPage page) {
		return dao.board_list(page);
	}

	@Override
	public BoardVO board_detail(int id) {
		return dao.board_detail(id);
	}

	@Override
	public void board_read(int id) {
		dao.board_read(id);
	}

	@Override
	public int board_update(BoardVO vo) {
		return dao.board_update(vo);
	}

	@Override
	public int board_delete(int id) {
		return dao.board_delete(id);
	}

	@Override
	public int board_comment_insert(BoardCommentVO vo) {
		return dao.board_comment_insert(vo);
	}

	@Override
	public List<BoardCommentVO> board_comment_list(int pid) {
		return dao.board_comment_list(pid);
	}

	@Override
	public int board_comment_update(BoardCommentVO vo) {
		return dao.board_comment_update(vo);
	}

	@Override
	public int board_comment_delete(int id) {
		return dao.board_comment_delete(id);
	}

}

▲BoardServiceImpl.java

 

package board;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class BoardDAO implements BoardService {
	@Autowired private SqlSession sql;
	
	@Override
	public int board_insert(BoardVO vo) {
		return sql.insert("board.mapper.insert", vo);
	}

	@Override
	public BoardPage board_list(BoardPage page) {
		page.setTotalList((Integer) sql.selectOne("board.mapper.total", page));
		page.setList(sql.selectList("board.mapper.list", page));
		return page;
	}

	@Override
	public BoardVO board_detail(int id) {
		return sql.selectOne("board.mapper.detail", id);
	}

	@Override
	public void board_read(int id) {
		sql.update("board.mapper.read", id);
	}

	@Override
	public int board_update(BoardVO vo) {
		return sql.update("board.mapper.update", vo);
	}

	@Override
	public int board_delete(int id) {
		return sql.delete("board.mapper.delete", id);
	}

	@Override
	public int board_comment_insert(BoardCommentVO vo) {
		return sql.insert("board.mapper.comment_insert", vo);
	}

	@Override
	public List<BoardCommentVO> board_comment_list(int pid) {
		return sql.selectList("board.mapper.comment_list", pid);
	}

	@Override
	public int board_comment_update(BoardCommentVO vo) {
		return sql.update("board.mapper.comment_update", vo);
	}

	@Override
	public int board_comment_delete(int id) {
		return sql.delete("board.mapper.comment_delete", id);
	}
}

▲BoardDAO.java

 

<?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="board.mapper">
	<select id="total" resultType="integer">
		SELECT COUNT(*) FROM board <include refid="search"/>
	</select>
	
	<select id="list" resultType="board.BoardVO">
		SELECT n.*, (SELECT name FROM member WHERE member.id=writer) name
		FROM (SELECT b.*, ROWNUM no
	   	 	  FROM (SELECT * FROM board <include refid="search"/> ORDER by id) b
			  ORDER BY no DESC) n
		WHERE no BETWEEN #{beginList } AND #{endList }
					
	</select>
	
	<sql id="search">
		<if test="search == 'title' or search == 'content'" >
			WHERE ${search } LIKE '%' || #{keyword } || '%'
		</if>
		<if test="search == 'writer'" >
			WHERE <include refid="writer" />
		</if>
		<if test="search == 'all'">
			WHERE TITLE LIKE '%' || #{keyword } || '%'
			OR content LIKE '%' || #{keyword } || '%'
			OR <include refid="writer" />
		</if>
	</sql>
	
	<sql id="writer">
		writer IN (SELECT id FROM member WHERE name LIKE '%' || #{keyword } || '%')
	</sql>
	
	<insert id="insert">
		INSERT INTO board(title, content, writer, filename, filepath)
		VALUES (#{title }, #{content}, #{writer}, #{filename, jdbcType=VARCHAR}, #{filepath, jdbcType=VARCHAR} )
	</insert>
	
	<update id="read">
		UPDATE BOARD SET readcnt= readcnt + 1 WHERE id= #{id }
	</update>
	
	<select id="detail" resultType="board.BoardVO">
		SELECT b.*, (SELECT name FROM member m WHERE m.id= b.writer) name
		FROM board b 
		WHERE id=#{id }
	</select>
	
	<update id="update">
		UPDATE board SET title=#{title }, content=#{content }, filename=#{filename, jdbcType=VARCHAR}, filepath=#{filepath, jdbcType=VARCHAR}
		WHERE id=#{id }
	</update>
	
	<delete id="delete">
		DELETE FROM board WHERE id=#{id}
	</delete>
	
	<insert id="comment_insert">
		INSERT INTO board_comment(content, pid, writer)
		VALUES (#{content}, #{pid}, #{writer})
	</insert>
	
	<select id="comment_list" resultType="board.BoardCommentVO">
		SELECT c.*, (SELECT name FROM member m WHERE m.id=writer) name,
				TO_CHAR(writedate, 'yyyy-mm-dd hh24:mi:ss') writedate
		FROM board_comment c
		WHERE pid=#{pid}
		ORDER BY id DESC
	</select>
	
	<update id="comment_update">
		UPDATE board_comment SET content=#{content} WHERE id=#{id}
	</update>
	
	<delete id="comment_delete">
		DELETE FROM board_comment WHERE id=#{id}
	</delete>
</mapper>

▲board-mapper.xml

 

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><response><header><resultCode>00</resultCode><resultMsg>NORMAL SERVICE.</resultMsg></header><body><items><item><addr>서울특별시 강남구 영동대로112길 15 103호 (삼성동, 풍림아파트상가)</addr><clCd>81</clCd><clCdNm>약국</clCdNm><estbDd>19790209</estbDd><postNo>06082</postNo><sgguCd>110001</sgguCd><sgguCdNm>강남구</sgguCdNm><sidoCd>110000</sidoCd><sidoCdNm>서울</sidoCdNm><telno>545-0164</telno><XPos>127.0615148</XPos><YPos>37.5155186</YPos><yadmNm>부활약국</yadmNm><ykiho>JDQ4MTg4MSM1MSMkMSMkMCMkMDMkMzgxMzUxIzExIyQxIyQzIyQ3OSQyNjEwMDIjNDEjJDEjJDgjJDgz</ykiho></item><item><addr>서울특별시 강남구 봉은사로 465 (삼성동)</addr><clCd>81</clCd><clCdNm>약국</clCdNm><emdongNm>삼성동</emdongNm><estbDd>19741211</estbDd><postNo>06096</postNo><sgguCd>110001</sgguCd><sgguCdNm>강남구</sgguCdNm><sidoCd>110000</sidoCd><sidoCdNm>서울</sidoCdNm><telno>02-545-2467</telno><XPos>127.0504907</XPos><YPos>37.5124855</YPos><yadmNm>신삼성약국</yadmNm><ykiho>JDQ4MTg4MSM1MSMkMSMkMCMkMDMkMzgxMzUxIzExIyQxIyQzIyQ3OSQyNjE4MzIjODEjJDEjJDIjJDgz</ykiho></item><item><addr>서울특별시 강남구 봉은사로114길 42 (삼성동)</addr><clCd>81</clCd><clCdNm>약국</clCdNm><emdongNm>삼성동</emdongNm><estbDd>20000630</estbDd><postNo>06172</postNo><sgguCd>110001</sgguCd><sgguCdNm>강남구</sgguCdNm><sidoCd>110000</sidoCd><sidoCdNm>서울</sidoCdNm><telno>02-556-8357</telno><XPos>127.0653425</XPos><YPos>37.5121721</YPos><yadmNm>강남소화약국</yadmNm><ykiho>JDQ4MTg4MSM1MSMkMSMkMCMkMDMkMzgxMzUxIzExIyQxIyQzIyQ3OSQzNjE4MzIjNDEjJDEjJDgjJDgz</ykiho></item><item><addr>서울특별시 강남구 삼성로 549 (삼성동, 정화빌딩)</addr><clCd>81</clCd><clCdNm>약국</clCdNm><estbDd>19860906</estbDd><postNo>06155</postNo><sgguCd>110001</sgguCd><sgguCdNm>강남구</sgguCdNm><sidoCd>110000</sidoCd><sidoCdNm>서울</sidoCdNm><telno>557-7676</telno><XPos>127.0542916</XPos><YPos>37.5106027</YPos><yadmNm>은약국</yadmNm><ykiho>JDQ4MTg4MSM1MSMkMSMkMCMkMDMkMzgxMzUxIzExIyQxIyQzIyQ4OSQzNjE4MzIjODEjJDEjJDIjJDgz</ykiho></item><item><addr>서울특별시 서초구 서초대로74길 23 102호 (서초동)</addr><clCd>81</clCd><clCdNm>약국</clCdNm><emdongNm>서초동</emdongNm><estbDd>20070222</estbDd><postNo>06621</postNo><sgguCd>110021</sgguCd><sgguCdNm>서초구</sgguCdNm><sidoCd>110000</sidoCd><sidoCdNm>서울</sidoCdNm><telno>02-3474-0617</telno><XPos>127.0271068</XPos><YPos>37.4956227</YPos><yadmNm>서초삼성약국</yadmNm><ykiho>JDQ4MTg4MSM1MSMkMSMkMCMkMDMkMzgxMzUxIzExIyQxIyQzIyQ5OSQyNjE0ODEjODEjJDEjJDIjJDgz</ykiho></item><item><addr>서울특별시 강동구 천호대로 1195 지앤지타워 1층 101호 (길동)</addr><clCd>81</clCd><clCdNm>약국</clCdNm><estbDd>20200309</estbDd><postNo>05350</postNo><sgguCd>110002</sgguCd><sgguCdNm>강동구</sgguCdNm><sidoCd>110000</sidoCd><sidoCdNm>서울</sidoCdNm><telno>02-472-3311</telno><XPos>127.1439027</XPos><YPos>37.5350031</YPos><yadmNm>강동엠약국</yadmNm><ykiho>JDQ4MTg4MSM1MSMkMSMkMCMkMDMkMzgxMzUxIzExIyQxIyQzIyQ5OSQzNjE0ODEjNDEjJDEjJDgjJDgz</ykiho></item><item><addr>서울특별시 강남구 논현로 88 3층 (개포동, 노엘빌딩)</addr><clCd>81</clCd><clCdNm>약국</clCdNm><emdongNm>개포동</emdongNm><estbDd>20100810</estbDd><postNo>06307</postNo><sgguCd>110001</sgguCd><sgguCdNm>강남구</sgguCdNm><sidoCd>110000</sidoCd><sidoCdNm>서울</sidoCdNm><telno>02-571-0043</telno><XPos>127.0451614</XPos><YPos>37.4778221</YPos><yadmNm>다나약국</yadmNm><ykiho>JDQ4MTg4MSM1MSMkMSMkMCMkMDMkMzgxMzUxIzExIyQxIyQzIyQ5OSQ0NjE0ODEjNTEjJDEjJDYjJDgz</ykiho></item><item><addr>서울특별시 성북구 돌곶이로41길 10 (장위동)</addr><clCd>81</clCd><clCdNm>약국</clCdNm><emdongNm>장위동</emdongNm><estbDd>20050303</estbDd><postNo>02754</postNo><sgguCd>110012</sgguCd><sgguCdNm>성북구</sgguCdNm><sidoCd>110000</sidoCd><sidoCdNm>서울</sidoCdNm><telno>02-942-4553</telno><XPos>127.0457034</XPos><YPos>37.6184653</YPos><yadmNm>선약국</yadmNm><ykiho>JDQ4MTg4MSM1MSMkMSMkMCMkMDMkMzgxMzUxIzExIyQyIyQzIyQwMCQzNjE0ODEjODEjJDEjJDIjJDgz</ykiho></item><item><addr>서울특별시 동작구 시흥대로 662 (신대방동)</addr><clCd>81</clCd><clCdNm>약국</clCdNm><estbDd>20101220</estbDd><postNo>07068</postNo><sgguCd>110008</sgguCd><sgguCdNm>동작구</sgguCdNm><sidoCd>110000</sidoCd><sidoCdNm>서울</sidoCdNm><telno>02-6104-1234</telno><XPos>126.9082173</XPos><YPos>37.4906353</YPos><yadmNm>대림온누리약국</yadmNm><ykiho>JDQ4MTg4MSM1MSMkMSMkMCMkMDMkMzgxMzUxIzExIyQyIyQzIyQwMCQzNjEwMDIjNjEjJDEjJDgjJDgz</ykiho></item><item><addr>서울특별시 강남구 도산대로 113 1층 (신사동)</addr><clCd>81</clCd><clCdNm>약국</clCdNm><estbDd>20170721</estbDd><postNo>06035</postNo><sgguCd>110001</sgguCd><sgguCdNm>강남구</sgguCdNm><sidoCd>110000</sidoCd><sidoCdNm>서울</sidoCdNm><telno>02-549-8774</telno><XPos>127.0208674</XPos><YPos>37.5170222</YPos><yadmNm>가나안약국</yadmNm><ykiho>JDQ4MTg4MSM1MSMkMSMkMCMkMDMkMzgxMzUxIzExIyQxIyQzIyQ2MiQyNjEyMjIjODEjJDEjJDYjJDgz</ykiho></item></items><numOfRows>10</numOfRows><pageNo>1</pageNo><totalCount>23138</totalCount></body></response>

▲가져온 약국 API 데이터

 

 

package com.hanul.iot;

import javax.servlet.http.HttpSession;

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

import common.CommonService;

@Controller
public class DataController {
	private String key = "API 키"; 
	@Autowired private CommonService common;
	
	@RequestMapping("/list.da")
	public String data(HttpSession session) {
		session.setAttribute("category", "da");
		
		return "data/list";
	}
	
	//약국 정보 조회 요청
		@ResponseBody @RequestMapping("/data/pharmacy")
		public String pharmarcy_list() {
			StringBuilder url 
				= new StringBuilder("http://apis.data.go.kr/B551182/pharmacyInfoService/getParmacyBasisList");
			url.append("?ServiceKey=" + key);
			return common.xml_list(url);
		}
}

▲DataController.java

 

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>data list jsp</title>
</head>
<body>
<h3>공공 데이터</h3>
<div class="btnSet">
	<a class="btn-fill">약국 조회</a>
	<a class="btn-fill">유기 동물 조회</a>
</div>

<div id="data-list" style="margin:20px 0 auto"></div>

<script type="text/javascript">
$('.dataOption a').click(function() {
	//이미 선택된 내용에 대해서는 적용하지 않으려면
	if( $(this).hasClass('btn-empty') ) {
		alert('누름')
		$('.dataOption a').removeClass();
		$(this).addClass('btn-fill');
		var idx = $(this).index();
		$('.dataOption a:not(:eq(' + idx + '))').addClass('btn-empty');
	
		if( idx == 0) { pharmacy_list(); }
		else { animal_list(); }
	}
});

pharmacy_list();
function pharmacy_list() {
	$.ajax({
		url:'data/pharmacy',
		success: function(){
			
		}, error: function(text, req) {
			alert(text + " : " + req.status)
		}
	});
}

function animal_list() {

}
</script>
</body>
</html>

▲list.jsp

 

package common;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.mail.EmailAttachment;
import org.apache.commons.mail.HtmlEmail;
import org.apache.commons.mail.MultiPartEmail;
import org.apache.commons.mail.SimpleEmail;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;

@Service
public class CommonService {
	public void sendEmail(String email, String name, HttpSession session) {
		//1. 기본 이메일 전송 처리
		//sendSimple(email, name);
		
		//2. 첨부 파일 있는 이메일 전송 처리
		//session이 있어야 파일 첨부가 가능
		//sendAttach(email, name, session);
		
		//3. HTML 태그 이메일 전송 처리
		sendHtml(email, name, session);
		
		//4. 공공 데이터 REST API 요청 처리
	};
	
	private void sendSimple(String email, String name) {
		SimpleEmail mail = new SimpleEmail();
		
		mail.setHostName("smtp.naver.com");	//메일 전송 서버 지정, 네이버 메일 - 환경설정 - pop3 설정
		mail.setCharset("utf-8"); //인코딩 설정
		mail.setDebug(true); //메일 전송 과정 추적해서 콘솔에 띄워줌
		
		mail.setAuthentication("아이디", "비밀번호"); //로그인하기 위해 정보 입력
		mail.setSSLOnConnect(true); //입력한 정보로 로그인 요청
		
		try {
			mail.setFrom("보내는 메일", "관리자");	//보내는 사람 메일 / 이름 설정
			mail.addTo(email, name); //받는 사람 메일 / 이름, 회원가입 페이지에에서 가져온다.
			mail.addTo("받을 메일", "수신자"); //복수의 사람 지정 가능
			
			mail.setSubject("회원가입 축하"); //메일 제목
			mail.setMsg(name + "님! 가입을 축하드립니다!"); //메일 내용
			
			mail.send(); //메일 발송 
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
	}
	
	private void sendAttach(String email, String name, HttpSession session) {
		MultiPartEmail mail = new MultiPartEmail();
		
		mail.setHostName("smtp.naver.com");	//메일 전송 서버 지정, 네이버 메일 - 환경설정 - pop3 설정
		mail.setCharset("utf-8"); //인코딩 설정
		mail.setDebug(true); //메일 전송 과정 추적해서 콘솔에 띄워줌
		
		mail.setAuthentication("아이디", "비밀번호"); //로그인하기 위해 정보 입력
		mail.setSSLOnConnect(true); //입력한 정보로 로그인 요청
		
		try {
			mail.setFrom("보내는 메일", "관리자");	//보내는 사람 메일 / 이름 설정
			mail.addTo(email, name); //받는 사람 메일 / 이름, 회원가입 페이지에에서 가져온다.
			mail.addTo("받을 메일", "수신자"); //복수의 사람 지정 가능
			
			mail.setSubject("첨부 파일 테스트"); //메일 제목
			mail.setMsg(name + "님! 가입을 축하드립니다!\n 첨부 파일 테스트"); //메일 내용
			
			//파일 첨부하기
			EmailAttachment file = new EmailAttachment();
			
			//① 물리적 디스크내 파일 첨부
			file.setPath("D:\\이력서-자소서-양식.hwp");
			mail.attach(file);
			
			//② 프로젝트 내의 파일 첨부
			file = new EmailAttachment();
			file.setPath(session.getServletContext().getRealPath("resources/images/logo.png"));
			mail.attach(file);
			
			//③ URL을 통해 파일 첨부
			file = new EmailAttachment();
			file.setURL(new URL("https://mvnrepository.com/assets/images/392dffac024b9632664e6f2c0cac6fe5-logo.png"));
			mail.attach(file);
			
			mail.send(); //메일 발송 
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
	}
	
	private void sendHtml(String email, String name, HttpSession session) {
		HtmlEmail mail = new HtmlEmail();
		
		mail.setHostName("smtp.naver.com");	//메일 전송 서버 지정, 네이버 메일 - 환경설정 - pop3 설정
		mail.setCharset("utf-8"); //인코딩 설정
		mail.setDebug(true); //메일 전송 과정 추적해서 콘솔에 띄워줌
		
		mail.setAuthentication("아이디", "비밀번호"); //로그인하기 위해 정보 입력
		mail.setSSLOnConnect(true); //입력한 정보로 로그인 요청
		
		try {
			mail.setFrom("보내는 메일", "관리자");	//보내는 사람 메일 / 이름 설정
			mail.addTo(email, name); //받는 사람 메일 / 이름, 회원가입 페이지에에서 가져온다.
			mail.addTo("받을 메일", "수신자"); //복수의 사람 지정 가능
			
			mail.setSubject("HTML 메일 테스트");
			
			StringBuffer msg = new StringBuffer();
			msg.append("<html>");
			msg.append("<body>");
			msg.append("<a href='https://mvnrepository.com'><img src='https://mvnrepository.com/assets/images/392dffac024b9632664e6f2c0cac6fe5-logo.png' /></a>");
			msg.append("<hr>");
			msg.append("<h3>HTML 메일 테스트</h3>");
			msg.append("<p>가입을 축하드립니다.</p>");
			msg.append("<p>HTML 메일 테스트</p>");
			msg.append("</body>");
			msg.append("</html>");
			mail.setHtmlMsg(msg.toString());
			
			EmailAttachment file = new EmailAttachment();
			file.setPath(session.getServletContext().getRealPath("resources/css/common.css"));
			mail.attach(file);
			
			file = new EmailAttachment();
			file.setURL(new URL("https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"));
			mail.attach(file);
			
			mail.send();
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
	}
	
	
	//첨부 파일 업로드 처리////////////////////////////////////////////////////////
	public String upload(String category, MultipartFile file, HttpSession session) {
		//서버의 업로드할 물리적 위치
		// workspace/.metadata/....../wtpwebapps/iot/resources
		String resources = session.getServletContext().getRealPath("resources");
		String upload = resources + "/upload";
		
		//업로드할 파일의 형태 : .../upload/notice/2020/07/13/abc.txt
		//String folder = upload + "/upload/2020/07/13";
		String folder = upload + "/" + category + "/" + new SimpleDateFormat("yyyy/MM/dd").format(new Date());
		
		//폴더가 없다면 폴더를 생성
		File f = new File(folder);
		if(!f.exists()) { f.mkdirs(); } //폴더가 존재하지 않으면 경로 생성
		
		//동시 다발적 동일명의 파일 업로드를 위한 고유 ID 부여: afd324adfa_abc.txt
		String uuid = UUID.randomUUID().toString() + "_" + file.getOriginalFilename();
		try {
			file.transferTo( new File(folder, uuid) );
		} catch (Exception e) {
			System.out.println(e.getMessage());		
		}
		
		// /upload/.../asdfadsfsa_abc.txt ▶ 업로드한 파일의 경로를 반환
		// ① folder.replace(resources, "")
		// ② folder.substring(resources.length()) + "/" + uuid;
		return folder.substring(resources.length()) + "/" + uuid;
	} //upload()
	
	//첨부 파일 다운로드 처리///////////////////////////////////////////////////////
	public File download(String filename, String filepath, HttpSession session, HttpServletResponse response) {
		File file = new File(session.getServletContext().getRealPath("resources") + filepath);
		//filepath에 resources/ << 슬래쉬부터의 경로가 저장되어 있다
		String mime = session.getServletContext().getMimeType(filename);
		
		response.setContentType(mime);
		
		try {
			filename = URLEncoder.encode(filename, "utf-8").replaceAll("\\+", "%20");
			// + 는 기호라 \ 필요, \ 또한 기호라 \ 필요
			// %20 = 스페이스바
			
			response.setHeader("content-disposition", "attachment; filename=" + filename);
			
			ServletOutputStream out = response.getOutputStream();
			FileCopyUtils.copy(new FileInputStream(file), out);
			out.flush();
			
		} catch(Exception e) {
			System.out.println(e.getMessage());
		}
		return file;
	} //download()
	
	// 공공 데이터 REST API 요청 처리=========================================================================
	public String xml_list(StringBuilder url) {
		String result = url.toString();
		
		try {
			HttpURLConnection conn
			 = (HttpURLConnection)new URL( result ).openConnection();
			conn.setRequestMethod("GET");
			conn.setRequestProperty("Content-type", "application/json");
			BufferedReader rd;
	        if(conn.getResponseCode() >= 200 && conn.getResponseCode() <= 300) {
	            rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
	        } else {
	            rd = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
	        }
	        StringBuilder sb = new StringBuilder();
	        String line;
	        while ((line = rd.readLine()) != null) {
	            sb.append(line);
	        }
	        rd.close();
	        conn.disconnect();
			result = sb.toString();
			System.out.println(result);
			
		}catch(Exception e) {
			System.out.println(e.getMessage());
		}
		return result;
	}
}	

▲CommonService.java

 

 

 

반응형