게시판에 들어갔을 때에 게시판을 구분해주기 위해서 board_info_idx를 사용한다.
그 화면에서 글쓰기를 눌렀을 때에 board/write 만 나오게되는데 나중에 글쓰기 기능을 할 때에 이 글쓰기가 어떤 게시판에서 작성된 게시글인지 알아야 하기 때문에 write까지 parameter가 전달될 수 있도록 세팅을 하려한다.
boardcontroller /main 에서 requestparam 으로 들고와서 모델에 넣어준다.
그리고 board 폴더의 main.jsp 에서 write로 보내주면서 board_info_idx 값을 뒤에 덧붙여서 보내준다.
이제 write에서도 requestparam 으로 받고 빈에 세팅해주고 board/write.jsp 호출한다.
다음과 같이 form 태그로 바꿔주고 write_pro를 호출
contetnBean에는 notblank 를 걸어주었고 우측은 에러메세지 프로퍼티 파일이다.
그런데 저렇게만 form 태그를 구성을하면 file 데이터는 서버로 전달되지 않고 문자열 데이터만 전달이 된다. 이것을 전달하게끔 하려면
enctype을 기입해야만 사용자가 입력한 문자열 데이터와 선택한 파일 데이터를 모두 서버에 전달할 수 있게된다.
하지만 이것을 선택하면 유효성 검사가 무조건 실패하게끔 된다. 이 이유는 다른 방식으로 데이터를 전달하기 때문에 bean에 제대로 주입하지 못하여서 유효성 검사에 걸리게 된다.
그래서 ServletAppContext.java에 이것을 선언해준다. 이것만 해주면 되는게 아니라 multipart 세팅에 관련된 것도 적어줘야 한다. 이것은 SpringConfigClass.java에 적어준다.
MultiPartConfigElement의 매개변수는 순서대로
1. 클라이언트가 보낸 파일 데이터를 저장해놓는 임시 파일의 경로를 지정, null 값이면 apache tomcat에서 정한 임시폴더로 지정이 된다.
2. 업로드 하는 파일의 최대 용량 세팅
3. 파일 데이터를 포함한 전체 요청 정보의 최대 용량 세팅
4. 파일의 임계값. 0으로 두면 알아서 데이터를 받아서 저장한다.
서버에서 MultiPartFile 형식으로 주입을 하려고 계속 시도하기 때문에 bean에 MultiPartFile 형식이 있어야 한다.
그래서 ContentBean 안에 private MultipartFile upload_File; 를 넣어주어야 한다.
이제 글 작성을 위해 BoardService를 만들고 BoardController에서 주입을 받는다.
getUploadFile 를 print 로 찍어보면 이름이 나오게되는데, 이게 null이어도 다른 이름이 나오게된다. 따라서 첨부했는지 안했는지 여부는 파일 크기의 값으로 판단을 해야한다. getUpload_File().getSize() 를 통해서 말이다.
이미지가 올라갈 때에 어디다가 저장이 될지를 정해놔야한다. 서버쪽에 운영을 하면 서버 경로를 정해주면 되는데 eclipse에서 테스를 할 때에는 조금 다르다. 실제 실행되는 곳은
request.getServletContext().getRealPath("/") 를 print 해봐서 나오는 곳으로 알 수가 있다.
이제 이 경로를 option.properties를 만들어서 path.upload= 경로 로 해두자. 역슬러시는 / 로 다 바꿔두자. 아니면 역슬러시를 2번 쓰자.
이제 업로드하는 메서드를 작성한다.
@PropertySource를 통해 option.properties를 들고오고 그곳에 있는 path.upload 를 @Value를 통해 가지고 온다.
중복된 파일이 올라오면 덮어 씌여지기 때문에 System.currentTimeMillis()를 통해 현재시간을 구한 다음에
_ upload_File.getOriginalFilename() 을 쓰면 업로드 되는 파일의 이름을 구할 수가 있다.
그리고 upload_File.transferTo 를 해주면 파일로 저장이 된다. 이제 저곳에 경로를 세팅해준다. path_upload(경로) 슬래시 file_name 해주면 이제 저장이 된다. File 은 java.io 를 import
이제 이것을 addContentInfo에 추가해준다.
빈에서 파일을 들고와 이게 size가 0보다 크다면 (null이 아닌 파일이 있다면) saveUploadFile 를 통해 file_name을 들고와서 setContent_file에 set 해준다. content_file은 string 이어서 파일 명값이고 upload_File은 multipart file 형식으로 진짜 말그대로 파일을 저장하는 변수이다.
write 에서 빈에 requestparam으로 받아온 board_info_idx를 넣어주고
form 안에 히든으로 넣어주게되면
write_pro 에서 빈에 idx값이 담기게 된다.
이걸 담기게 하는 이유는
이 content_table에서 게시판의 제목과 내용들 컬럼들과 함께 어떤 게시판에 올라온 것인지 content_board_idx를 필요로 하기 때문이다.
이제 mapper를 만들어 주었다. 마지막은 sysdate으로 날짜를 집어넣어준 것이다.
맨 위가 dao 밑에가 service 이다.
jsp에서 빈에 넣을 때에 제목,내용,그리고 파일만 담기기 때문에(hidden으로 wr_idx도) 나머지 값들을 채워주어야 하는데,
content_idx는 시퀀스로 넣고, subject, text는 빈에 있고 content_file은 wrtieContentBean.setContent_file(file_name)으로 담아주고, writer_idx는 loginUserBean을 Resource로 가져와서 저렇게 담아준다. board_idx 또한 hidden으로 jsp에 있기 때문에 담겨져있고 content_date 은 mapper에서 sysdate을 통해 담아주었다.
write_success 만들었다.
사실 이거를 원래 했으면 오류가 뜨게된다. mybatis 오류인데, 이게 무슨 문제냐면
mapper의 #{content_file} 이 부분이다. 캡처에서는 뒤에 덧붙여져있긴 한데 보통 이렇게 할 것이다.
만약 첨부를 하고 작성을 하면 db에 제대로 들어갈 것이다. 하지만 만약 첨부를 안하면 오류가 뜨게된다.
boardService를 보면 getSize()>0이면 빈에 file_name을 넣게되는데 만약 없다면 null값이 들어가게 된다.
db에서 content_file 속성을 보면 null을 허용하는 컬럼이다. 그런데 널 값을 넣으면 mybatis에서 오류가 나게 된다.
참 이상하다... 이것을 방지하기 위해서 ${content_file, jdbcType=VARCHAR} 을 하게되면 널을 허용하는 컬럼에 널을 집어넣게 되면 오류가 나지않고 집어넣을 수 있게된다. mybatis를 이용할 때에 널을 허용하는 컬럼에는 꼭 jdbcType=VARCHAR를 덧붙여서 오류를 방지를 해야한다.
이제 게시판을 보았을 때에 글을 보게끔 한다.
먼저, 게시판을 들어갔을 때에 게시판 이름이 board_info_idx에 맞게끔 뜨게 한다.
mapper dao service jsp controller 순이다.
따로 설명은 필요없을 것 같다. 이제 페이지 구성 부분을 보자.
content_table에는 content_writer_idx 만 있지 name 정보는 없기 때문에 user_table 과 조인을해서 name 가져오고 content_writer_name 으로 정하고 date또한 to_char 를 이용해 string 형으로 바꾼다음에 content_date 으로 이름을 부여하였다. 이 content_writer_name 과 content_date은 ContentBean에 변수를 추가해서 자동 주입되게끔 하였다.
정보가 하나가 아닐 수 있기 때문에 List로 선언하였다.
list 받아와서 모델에 추가
c태그를 이용해 포문 돌려서 출력되게끔 하였다.
이제 이것을 통해서 read 할 수 있게끔 한다.
여기 main.jsp의 제목 부분에
다음과 같이 ? 를 통해 파라미터를 보내면서 board/read로 보낸다.
BoardController의 read 부분 get 에서 requestParam 을 통해 main 에서 달아준 info_idx 와 content_idx를 가져온다.
board_info_idx는 모델을 통해 넣어주고(ContentBean에 없으니깐), content_idx를 통해 read 에 필요한 빈 내용들을 가져온다.
getContentInfo의 쿼리는 다음과 같다. idx를 통해 이름, 날짜, 제목, 내용, 파일명을 가져온다.
read.jsp 이다. 따로 태그 설정안해주고 저렇게 변수들을 넣어주었다.
만약 파일명이 널이아니라면 이미지를 들고오고 아니라면 보여주지 않는다.
이제 write 을 성공하고나서 board/write_success 부분을 처리하겠다.
보기위해서는 main에서 read를 할 때처럼 board_info_idx와 content_idx를 알아야 한다.
이게 write_success 이다. read로 필요한 값을 파라미터 붙여서 보내는데
content_board_idx 야 빈에 들어오니깐 알겠는데, content_idx는 어떻게 들고오는 걸까 ??
이건 시퀀스로 처리되는데 말이다. #{} 형식이 아니고.
답은 @SelectKey 를 통해 before=true(먼저 시행) 시퀀스를 먼저 돌려서 keyProperty content_idx 해둔 것을 토대로 insert문에서 #{content_idx} 에 넣어주는데에 있다. 이것은 빈안에 들어가고 컨트롤러에서 사용이 가능하다.
이제 이것을 wrtie_success로 보내주었기 때문에 성공적으로 글을 쓰고 내가 쓴 글을 확인할 수가 있다.
이제 수정과 삭제 기능을 추가할 것이다. 수정과 삭제 버튼은 로그인한 사람과 작성한 사람이 같을 경우에만 노출을 하고, 직접 주소를 입력하고 요청할 경우를 대비해 Interceptor로 처리해 준다.
글 작성자의 idx를 알기 위해서 mapper를 좀 수정한다.
글의 정보를 가져오는 쿼리문인데, ctnt.content_writer_idx 를 추가해서 글 작성자의 idx를 가져왔다.
이제 현재 접속중인 유저의 idx 를 알아야 하는데 이를 위해 BoardController에 Resource를 통해 loginUserBean을 주입받아서
model에 넘겨주게 된다.
그리고 c:if 태그를 달아서 idx 값이 서로 일치하면 수정과 삭제 버튼이 보이게끔 하였다.
이제 주소를 치고 들어오는 것을 방지하기 위해 interceptor에서 처리하게끔 한다.
인터셉터 자바 파일을 새로 만들어 준다. 자바 형식에서 인터셉터는 주입을 받을 수 없으므로 생성자를 만들어 준다. 저것들은 ServletAppContext.java에서 등록을 해주면서 주입해준다. content_idx를 통해 그 글의 정보를 가진 빈을 들고와서 loginUserBean의 idx 와 비교해서 틀리다면 /board/not_writer 로 보내준다.
BoardController에 다음과 같이 not_write GetMapping을 만들어주고,
인터셉터에 등록해준다. BoardService는 기존에 없었으므로 Autowired를 통해 받아와줬다.
/board/modify 와 /board/delete 일 때에만 거치도록 설정을 해주었고 생성자를 통해 loginUserBean 과 boardService 둘 다 받아온 것을 볼 수가 있다.
이제 본인의 글이 아닌 상태에서 주소창에 modify 나 delete를 통한 접근을 막을 수 있게 되었다.
'공부 기록들' 카테고리의 다른 글
2020.05.02 미니 프로젝트(完) (페이지 구현하기, 메인화면 처리하기) (0) | 2020.05.03 |
---|---|
2020.05.01 미니 프로젝트(7) (글 수정하기, 글 삭제하기) (0) | 2020.05.02 |
2020.04.29 미니 프로젝트(5) (정보수정) (0) | 2020.04.29 |
2020.04.28 미니 프로젝트(4) (로그인 처리, 로그인 확인 처리, 상단 메뉴 처리) (0) | 2020.04.28 |
2020.04.27 미니 프로젝트(3) (유효성 검사, 아이디 중복 확인 처리, 저장처리) (0) | 2020.04.27 |