JAVA 웹개발 과정 국비 63일차 정리
63일차
※ 배우는 과정이므로 정확하지 않을 수 있습니다.
잘못된 점은 알려주시면 수정하도록 하겠습니다!
내일부터는 세미 프로젝트가 시작된다. 사실 오늘부터였지만 이것저것 셋팅하고 하다보니 오늘이 지나가버렸다.
세미 프로젝트가 끝나고 한꺼번에 정리해서 올릴 예정이다.
1. 게시판 만들기 이어서..
수업에서 배운 것을 토대로 아래 기능들을 구현할 수 있다.
- 검색 기능 구현
- 파일 업로드 후 글쓰기, 게시글에 업로드 된 파일 보이기
- 업로드 된 파일 다운받기
- 댓글 기능 구현
이제 바로 세미 프로젝트 시작이라서 기능들을 따로 git에 정리하지는 않으려고 한다.
좋은 방법으로 구현했는지도 모르겠고, ajax와 js 그리고 HTML 등등 모든게 짬뽕되어있는 수준이라서 차라리 세미 프로젝트로 게시판을 만든 후에 정리가 되면 한꺼번에 정리하는 것이 좋겠다는 생각이 들었다.
댓글 기능 빼고는 일단 구현은 다 성공했는데, 몇 가지 어려웠던 점만 간단하게 정리해둔다.
- 게시판에 글을 작성할 때, 파일 첨부와 글의 제목, 내용이 한꺼번에 insert가 되야하는데 어느 컨트롤러로 가야하는 것일까?
- 나는 파일 첨부는 파일컨트롤러로, 제목과 내용은 보드컨트롤러로 보냈는데 그렇게 하니까 보드DB에 게시글seq를 넣는 것이 어려웠다.
- 그래서 게시글이 insert되었을 때 마지막 seq를 게시판DB에서 받아와서 파일DB로 옮겼는데, 코드 실행 중간에 다른 사용자가 글을 올리게 되면 꼬일 수도 있어서 좋지 않은 방법이라고 하셨다.
- 결론은 게시글 insert이므로 보드컨트롤러로 가는 것이 맞다.
- 그렇다면 보드컨트롤러에서 파일dao를 쓰는 것은 괜찮은 것일까?
- 보드컨트롤러에서는 보드 dao만 써야되는 것 같아서 1번의 고민을 하게되었다.
- 그러나 다른 컨트롤러에서 다른 dao를 쓰는 것은 전혀 상관 없다.
- 따라서 글쓰기 요청은 보드컨트롤러로 진행되어 내부적으로 보드 dao와 파일 dao에 각각 넣어야 한다.
- 파일DB에 게시글 seq는 어떻게 넣는 걸까?
- 위의 언급했듯이 나의 방법은 좋지 않은 방법이였다.
- 다른 동기는 그 글을 검색해서 그 글의 seq를 저장하는 방법을 이용했다고 했다. 그러나 같은 작성자, 내용, 시간이라면?
- 위 두 방법보다 간단한 방법은 DB에서 seq.nextval을 따로 뽑아내서 메소드로 만드는 것이다.
- seq를 만들어내는 함수를 따로 만들어서 그 함수로 만든 seq를 보드와 파일 양쪽에 인자로 전달해서 사용하는 방법이다.
- 세미 프로젝트 때 사용해보아야겠다.
- 수정, 삭제 후 기존 페이지로 이동하기
- 나는 모든 페이지 주소값에 현재페이지와 현재 글번호를 다 가지고 다녔다.
- 그래서 sendRedirect와 setAttribute가 남발되었는데, 좋지 않은 코드라고 생각해 강사님께 여쭤봤더니 세션을 이용하거나 ajax를 이용하는 방법도 있다고 하셨다.
- 이것도 마찬가지로 세미 프로젝트때 사용해보며 효율적인 방법을 찾을 예정이다.
- 검색 기능 구현
- ajax를 사용했기 때문에 기존 게시글 목록 페이지에서 해결할 수 있을 줄 알았는데, 의외로 다 별개로 만들어줘야했다. 검색한 페이지 목록, select 메소드, navi 메소드…
- 이것도 마찬가지로 강사님께 여쭤보니 검색한 단어를 가지고 있기 때문에 if문으로 기존 페이지에 넣는 것 보다는 새로 만드는 것이 낫다고 하셨다.
- 이것때문에 mybatis를 쓴다고 하셨는데 아직 뭔지 잘 모르겠어서 패스!
1) 소스 코드
2. File 다운로드
세미 프로젝트 전 마지막 수업으로 파일 다운로드를 간단하게 배웠다.
1) 클라이언트 코드
수업에서는 ajax로 서버에서 파일 리스트를 전달 받았다.
내가 실습할 때는 setAttribute
로 fileDTO
를 넘겼는데, 어떻게 하든 상관 없는 것 같다.
oriName
과 sysName
을 서버로 넘겨준다.
<button id="fileList">파일 명단 보기</button>
<br>
<fieldset>
<legend>파일 목록</legend>
</fieldset>
<script>
$("#fileList").on("click",function(){
$.ajax({
url:"/list.file",
dataType:"json"
}).done(function(resp){
for(let i=0;i<resp.length;i++){
let div = $("<div>");
let anker = $("<a>");
anker.attr("href","/download.file?sysName="+resp[i].sysName+"&oriName="+resp[i].oriName);
anker.text(resp[i].oriName);
div.append(anker);
$("legend").after(div);
}
})
})
</script>
2) 서버 코드
다운로드를 하기 위해서 서버에서 필요한 정보로 방법을 나누면 아래와 같다.
- 게시글 seq를 받는 방법
- 파일의 sysName과 oriName을 받는 방법
1번 방법은 DB를 한번 더 거쳐서 sysName을 얻어와야 한다. 가령 다른 정보(파일 크기, 날짜)등을 받아오려면 이 방법이 더 유용하다.
2번 방법은 다운로드 기능만 구현할 때 사용하기 좋은 방법이다.
수업은 2번 방법으로 진행했다.
① 경로와 이름 받아오기
파일의 경로와 클라이언트로부터 받은 oriName
과 sysName
을 변수에 받는다.
String path = request.getServletContext().getRealPath("files");
String targetFileName = request.getParameter("sysName");
String targetOriName = request.getParameter("oriName");
② 파일 객체 생성
파일 이름과 경로를 합쳐 파일 객체를 생성해준다.
중간에 /
를 빠뜨리면 안된다.
File targetFile = new File(path + "/" + targetFileName);
③ 첨부파일임을 알리기
서버에서 데이터를 클라이언트에게 전달할 때, 지금 보내는 것은 첨부파일이니 렌더링 하지 말라고 미리 언질을 줘야한다.
그래서 response
를 reset
으로 비우고, setHeader
로 header부분을 다시 써준다고 생각하면 된다.
이때, 크롬 브라우저는 attachment
로 파일 이름을 받으면 ISO-8859-1
로 처리하기 때문에 인코딩 코드를 아래와 같이 꼭 넣어주자.
브라우저별로 코드는 다를 수 있다.
targetOriName = new String(targetOriName.getBytes("utf8"), "ISO-8859-1");
response.reset();
response.setHeader("Content-Disposition", "attachment; filename=\""+ targetOriName +"\"");
④ 파일 전송
기존에 네트워크 수업 때 한번 훑고 지나간 코드들이다.
하드디스크에 있는 파일을 복사해서 저장할 수 있는 배열 공간을 확보한다.
사이즈는 파일의 크기만큼이다.
파일 InputStream
을 개방한 후 readFully
로 파일의 모든 내용을 가져오고, flush
로 전송한다.
byte[] fileContents = new byte[(int)targetFile.length()];
try(ServletOutputStream sos = response.getOutputStream();
DataInputStream dis = new DataInputStream(new FileInputStream(targetFile));
){
dis.readFully(fileContents);
sos.write(fileContents);
sos.flush();
}
}
댓글남기기