오늘이라도
[Spring] 11. 웹사이트 만들기 ⑩ : 파일 첨부, 업로드, 다운로드, 글 삭제 본문
취업성공패키지 SW 개발자 교육/Spring
[Spring] 11. 웹사이트 만들기 ⑩ : 파일 첨부, 업로드, 다운로드, 글 삭제
upcake_ 2020. 7. 14. 09:18반응형
https://github.com/upcake/Class_Examples
교육 중에 작성한 예제들은 깃허브에 올려두고 있습니다.
gif 파일은 클릭해서 보는 것이 정확합니다.
- 웹사이트 만들기 ⑩ : 파일 첨부, 업로드, 다운로드, 글 삭제 -
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="core" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>list JSP</title>
</head>
<body>
<h3>공지사항</h3>
<div id="list-top">
<div>
<ul>
<core:if test="${login_info.admin eq 'Y' }">
<li><a class="btn-fill" href="new.no">글쓰기</a></li>
</core:if>
</ul>
</div>
</div>
<table>
<tr>
<th class="w-px60">번호</th>
<th>제목</th>
<th class="w-px100">작성자</th>
<th class="w-px120">작성일자</th>
<th class="w-px60">첨부파일</th>
</tr>
<core:forEach items="${list }" var="vo">
<tr>
<td>${vo.no }</td>
<td class="left"><a href="detail.no?id=${vo.id }" >${vo.title }</a></td>
<td>${vo.name }</td>
<td>${vo.writedate }</td>
<td>${empty vo.filename ? '' : '<img class="file-img" src="img/attach.png" />' }</td>
</tr>
</core:forEach>
</table>
</body>
</html>
▲list.jsp
<?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="notice.mapper" >
<select id="list" resultType="notice.NoticeVO">
SELECT ROWNUM no, n.*
FROM (SELECT * FROM notice ORDER BY id) n
ORDER BY no desc
</select>
<insert id="insert">
INSERT INTO notice (title, content, writer, filename, filepath)
VALUES (#{title }, #{content }, #{writer }, #{filename, jdbcType=VARCHAR }, #{filepath, jdbcType=VARCHAR })
</insert>
<select id="detail" resultType="notice.NoticeVO">
SELECT n.*, (SELECT name FROM member m WHERE m.id = n.writer) name FROM notice n WHERE id=#{id }
</select>
<!-- jdbcType=VARCHAR 속성을 넣으면 null값이 허용된다. -->
<update id="read">
UPDATE notice SET readcnt = readcnt + 1 WHERE id=#{id}
</update>
<delete id="delete">
DELETE FROM notice WHERE id=#{id }
</delete>
</mapper>
▲notice-mapper.xml
package com.hanul.iot;
import java.io.File;
import java.util.HashMap;
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.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import common.CommonService;
import member.MemberServiceImpl;
import member.MemberVO;
import notice.NoticeServiceImpl;
import notice.NoticeVO;
@Controller
public class NoticeController {
@Autowired private NoticeServiceImpl service;
@Autowired private MemberServiceImpl member;
@Autowired private CommonService common;
//공지사항 목록화면 요청
@RequestMapping("/list.no")
public String list(Model model, HttpSession session) {
//공지사항 클릭 하면 admin으로 자동 로그인
HashMap<String, String> map = new HashMap<String, String>();
//HashMap : 데이터를 담을 자료 구조
map.put("id", "admin");
map.put("pw", "1234");
session.setAttribute("login_info", member.member_login(map));
session.setAttribute("category", "no");
//DB에서 공지 글 목록을 조회해와 목록 화면에 출력
model.addAttribute("list", service.notice_list());
return "notice/list";
}
//신규 공지 글 작성 화면 요청
@RequestMapping("/new.no")
public String notice() {
return "notice/new";
}
//신규 공지 글 저장 처리 요청
@RequestMapping("/insert.no")
public String insert(MultipartFile file, NoticeVO vo, HttpSession session) {
//첨부한 파일을 서버 시스템에 업로드하는 처리
if( !file.isEmpty() ) {
vo.setFilepath(common.upload("notice", file, session));
vo.setFilename(file.getOriginalFilename());
}
vo.setWriter( ((MemberVO) session.getAttribute("login_info")).getId() );
//화면에서 입력한 정보를 DB에 저장한 후
service.notice_insert(vo);
//목록 화면으로 연결
return "redirect:list.no";
}
//공지글 상세 화면 요청
@RequestMapping("/detail.no")
public String detail(int id, Model model) {
//선택한 공지글에 대한 조회수 증가 처리
service.notice_read(id);
//선택한 공지글 정보를 DB에서 조회해와 상세 화면에 출력
model.addAttribute("vo", service.notice_detail(id));
model.addAttribute("crlf", "\r\n");
return "notice/detail";
} //detail()
//첨부파일 다운로드 요청
@ResponseBody @RequestMapping("/download.no")
public void download(int id, HttpSession session, HttpServletResponse response) {
NoticeVO vo = service.notice_detail(id);
common.download(vo.getFilename(), vo.getFilepath(), session, response);
} //download()
//공지글 삭제 처리 요청
@RequestMapping("/delete.no")
public String delete(int id, HttpSession session) {
//선택한 공지글에 첨부된 파일이 있다면 서버의 물리적 영역에서 해당 파일도 삭제한다
NoticeVO vo = service.notice_detail(id);
if(vo.getFilepath() != null) {
File file = new File(session.getServletContext().getRealPath("resources") + vo.getFilepath());
if( file.exists() ) { file.delete(); }
}
//선택한 공지글을 DB에서 삭제한 후 목록 화면으로 연결
service.notice_delete(id);
return "redirect:list.no";
} //delete()
//공지글 수정 화면 요청
@RequestMapping("/modify.no")
public String modify(int id, Model model) {
//선택한 공지글 정보를 DB에서 조회해와 수정화면에 출력
model.addAttribute("vo", service.notice_detail(id));
return "notice/modify";
} //modify()
} //class
▲NoticeController.java
<%@ 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" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>detail JSP</title>
</head>
<body>
<h3>공지글 안내</h3>
<table>
<tr>
<th class="w-px160">제목</th>
<td colspan="5" class="left">${vo.title }</td>
</tr>
<tr>
<th>작성자</th>
<td>${vo.name }</td>
<th class="w-px120">작성일자</th>
<td class="w-px120">${vo.writedate }</td>
<th class="w-px80">조회수</th>
<td class="w-px80">${vo.readcnt }</td>
</tr>
<tr>
<th>내용</th>
<td colspan="5" class="left">${fn:replace(vo.content, crlf, '<br>') }</td>
</tr>
<tr>
<th>첨부 파일</th>
<td colspan="5" class="left">
${vo.filename }
<core:if test="${!empty vo.filename }">
<a href="download.no?id=${vo.id }" style='margin-left: 15px'><i class="fas fa-download font-img"></i></a>
</core:if>
</td>
</tr>
</table>
<div class="btnSet">
<a class="btn-fill" href="list.no">목록으로</a>
<core:if test="${login_info.admin eq 'Y' }">
<a class="btn-fill" href='modify.no?id=${vo.id }'>수정</a>
<a class="btn-fill" onclick="if(confirm('정말 삭제하시겠습니까?')) {href='delete.no?id=${vo.id }' }">삭제</a>
</core:if>
</div>
</body>
</html>
▲detail.jsp
package notice;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class NoticeServiceImpl implements NoticeService {
@Autowired private NoticeDAO dao;
@Override
public void notice_insert(NoticeVO vo) {
dao.notice_insert(vo);
}
@Override
public List<NoticeVO> notice_list() {
return dao.notice_list();
}
@Override
public NoticeVO notice_detail(int id) {
return dao.notice_detail(id);
}
@Override
public void notice_update(NoticeVO vo) {
// TODO Auto-generated method stub
}
@Override
public void notice_delete(int id) {
dao.notice_delete(id);
}
@Override
public void notice_read(int id) {
dao.notice_read(id);
}
}
▲NoticeServiceImpl.java
package notice;
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 NoticeDAO implements NoticeService {
@Autowired private SqlSession sql;
@Override
public void notice_insert(NoticeVO vo) {
sql.insert("notice.mapper.insert", vo);
}
@Override
public List<NoticeVO> notice_list() {
return sql.selectList("notice.mapper.list");
}
@Override
public NoticeVO notice_detail(int id) {
return sql.selectOne("notice.mapper.detail",id);
}
@Override
public void notice_update(NoticeVO vo) {
// TODO Auto-generated method stub
}
@Override
public void notice_delete(int id) {
sql.delete("notice.mapper.delete", id);
}
@Override
public void notice_read(int id) {
sql.update("notice.mapper.read", id);
}
}
▲NoticeDAO.java
package notice;
import java.sql.Date;
public class NoticeVO {
private int id, readcnt, no;
private String title, content, writer, filename, filepath, name;
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private Date writedate;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getReadcnt() {
return readcnt;
}
public void setReadcnt(int readcnt) {
this.readcnt = readcnt;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getWriter() {
return writer;
}
public void setWriter(String writer) {
this.writer = writer;
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public String getFilepath() {
return filepath;
}
public void setFilepath(String filepath) {
this.filepath = filepath;
}
public Date getWritedate() {
return writedate;
}
public void setWritedate(Date writedate) {
this.writedate = writedate;
}
}
▲NoticeVO.java
package notice;
import java.util.List;
public interface NoticeService {
//CRUD : Create, Read, Update, Delete
void notice_insert(NoticeVO vo); //공지글 저장
List<NoticeVO> notice_list(); //공지글 목록 조회
NoticeVO notice_detail(int id); //공지글 상세 조회
void notice_update(NoticeVO vo); //공지글 변경 저장
void notice_delete(int id); //공지글 삭제
void notice_read(int id); //조회수 증가 처리
}
▲NoticeService.java
package common;
import java.io.File;
import java.io.FileInputStream;
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);
};
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()
}
▲CommonService.java
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>modify JSP</title>
</head>
<body>
<h3>공지글 수정</h3>
<form>
<table>
<tr>
<th class="w-px160">제목</th>
<td><input type="text" name="title" /></td>
</tr>
<tr>
<th>내용</th>
<td><textarea name="content">${vo.content }</textarea></td>
</tr>
<tr>
<th>첨부 파일</th>
<td></td>
</tr>
</table>
</form>
</body>
</html>
▲modify.jsp
반응형
'취업성공패키지 SW 개발자 교육 > Spring' 카테고리의 다른 글
[Spring] 13. 웹사이트 만들기 ⑫ : 페이징, 답글 작성 (0) | 2020.07.16 |
---|---|
[Spring] 12. 웹사이트 만들기 ⑪ : 공지글 수정, 목록에서 첨부파일 다운로드, 페이징 밑작업 (0) | 2020.07.15 |
[Spring] 10. 웹사이트 만들기 ⑨ : 공지사항에 첨부 파일 기능 추가 (2) | 2020.07.13 |
[Spring] 9. 웹사이트 만들기 ⑧ : 첨부 파일 메일, HTML 메일 발송, 공지사항 목록 조회 (1) | 2020.07.10 |
[Spring] 8. 웹사이트 만들기 ⑦ : 회원가입 완성, 축하 메일 발송 (0) | 2020.07.09 |