8/21/2019

스프링 게시판 만들기 #5. 게시물 작성 구현

views → board 폴더를 우클릭한 뒤, New → Other를 선택합니다.

JSP File을 선택하고 다음(Next) 버튼을 클릭합니다.

경로를 확인하고, 파일명(File name)에 write.jsp를 입력한 뒤 완료(Finish) 버튼을 클릭합니다.

write.jsp 파일이 생성되었습니다. 이전 단계에서 템플릿을 설정하지 않았지만, 기본적으로 HTML5 템플릿으로 설정된걸 확인할 수 있습니다.

write.jsp의 코드를 수정합니다.

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>게시물 작성</title>
</head>
<body>

</body>
</html>

JSP파일을 만들었지만, 프로젝트를 실행하더라도 이 JSP파일에는 접속할 수 없습니다. 컨트롤러 작업을 해주어야만 접속할 수 있습니다.

컨트롤러에 write.jsp에 대한 get메서드를 추가합니다.

// 게시물 작성
@RequestMapping(value = "/write", method = RequestMethod.GET)
public void getWirte() throws Exception {
   
}

home.jsp에 게시물 작성 페이지(write.jsp)로 바로 이동할 수 있도록 링크를 추가합니다.

<a href="/board/write">게시물 작성</a>

프로젝트를 시작하고, 게시물 작성 링크를 클릭합니다.

게시물 작성 페이지(write.jsp)에 에러없이 접속했습니다. 다만 내부에 코드가 하나도 없기 때문에 아무것도 표시되지 않습니다.

게시물을 작성하고, DB에 입력할 수 있도록 <form> 태그를 추가합니다.

<form method="post">

<label>제목</label>
<input type="text" name="title" /><br />

<label>작성자</label>
<input type="text" name="writer" /><br />

<label>내용</label>
<textarea cols="50" rows="5" name="content"></textarea><br />

<button type="submit">작성</button>

</form>

여기서 주의해야할 부분은, 입력 엘리먼트인 <input><textarea>의 이름(name) 속성의 값이 BoardVO와 동일해야한다는것 입니다.

동일하지 않으면 전송을할 수 없는건 아니지만, 별도로 작업을 해주어야하기 때문에 VO(Value Object)를 만든 의미가 없습니다. 프론트단에서 전송하는 데이터 타입을 VO화 시키고, 백단인 컨트롤러에서도 같은 VO타입으로 받도록 해주면 알아서 데이터가 들어가기 때문에 편리합니다.

프로젝트를 시작하고, 게시물 작성 페이지에 접속해보면 위와같이 굉장히 두박해도 어떻게든 입력할 수 있게(...) 되었습니다.

시험삼아 내용을 입력하고 작성 버튼을 클릭해봅니다.

405에러가 발생했습니다. 405에러는, 페이지가 존재하지만 현재 메서드 형식을 받을 수 없다는 에러입니다.

위에서 컨트롤러에 게시물 작성용 get 메서드를 생성했었는데, get은 서버 → 사용자로 데이터가 이동하는것입니다. 게시물 작성처럼 사용자 → 서버로 데이터가 이동하려면 post 메서드가 필요로하는데, 현재 컨트롤러에는 post 메서드가 없기 때문에 이런 에러가 발생하는것 입니다.

그렇다고 컨트롤러에 post 메서드만 달랑 만들어두면 해결되는 문제가 아닙니다. 컨트롤러가 데이터를 받았으면 Service에 넘기고 이걸 다시 DAO에 넘기고 마지막으로 데이터 베이스에 옮기면서 데이터가 입력되어야하는데, 현재는 Service와 DAO는 물론 데이터 베이스에 데이터를 넣을 쿼리 또한 문제되지 않았습니다.

가장 먼저 데이터 베이스에 데이터를 넣을 쿼리문을 준비합니다. 데이터를 직업 넣어봐서 성공적으로 된 쿼리문을 사용하도록 합니다. 물론 쿼리문 작성에 능숙해지면 꼭 해야할 필요는 없습니다.

boardMapper.xml에 코드를 추가합니다.

<!-- 게시물 작성 -->
<insert id="write" parameterType="com.board.domain.BoardVO">
 insert into
  tbl_board(title, content, writer)
   values(#{title}, #{content}, #{writer})
</insert>

게시물 목록을 만들었을 땐 resutType였습니다. resultType는 데이터를 쿼리를 실행한 뒤 결과가 있을 경우에 사용하며, 반대로 데이터를 넣을 때는 parameterType를 사용합니다.

BoardDAO.java에 게시물 작성용 메서드를 추가합니다.

// 게시물 작성
public void write(BoardVO vo) throws Exception;

인터페이스인 BoardDAO에 메서드를 추가하면, 구현체인 BoardDAOImpl에 에러가 발생합니다. 왜냐하면, 구현체인 BoardDAOImpl에는 인터페이스인 BoardDAO와 동일한 메서드가 존재해야하기 때문입니다.

BoardDAOImple.java를 열면 클래스명에 빨간줄이 그어진걸 확인할 수 있습니다.

이렇게 문제가 있는곳에 마우스를 올려주고 잠시 기다리면..

이런식으로 문제를 해결할 방법을 알려줍니다. 지금의 문제는 인터페이스에 있는 메서드가 구현체에 없는것이므로 구현되지 않은 메서드 추가(Add unimplemented methods)를 클릭하면 메서드가 자동으로 추가됩니다.

또는 빨간줄이 그어진곳에 커서를 위치하고(한번 클릭하면 됩니다), 컨트롤(Ctrl) + 1 키를 누르면 이렇게 현재 사용할 수 있거나 조치할 수 있는 방법이 나타납니다.

이렇게 write 메서드가 생성되었습니다.

boardMapper에 있는 쿼리를 이용하여 데이터 베이스에 데이터를 넣을 수 있도록 코드를 추가합니다.

sql.insert(namespace + ".write", vo);

BoardDAO와 BoardDAOImple를 작업했던것과 마찬가지의 방법으로, BoardService와 BoardServiceImple에 게시물 작성용 메서드를 추가합니다.

컨트롤러에 게시물 작성의 post 메서드를 추가합니다.

// 게시물 작성
@RequestMapping(value = "/write", method = RequestMethod.POST)
Public String posttWirte(BoardVO vo) throws Exception {
  service.write(vo);
  
  return "redirect:/board/list";
}

리턴(return)에 "redirect:/board/list가 있습니다. 이건 모든 작업을 마치고 /board/list, 즉 게시물 목록 화면으로 이동하겠다는 의미로 보시면 됩니다.

이제 프로젝트를 시작한 뒤, 게시물 작성 페이지(write.jsp)에서 내용을 입력하고 작성 버튼을 클릭합니다.

작성 버튼을 누르면 게시물 목록 페이지로 이동되며, 가장 마지막에 새로 추가된걸 확인할 수 있습니다.

게시물 수정
  1. // 게시물 작성
    @RequestMapping(value = "/write", method = RequestMethod.POST)
    Public String posttWirte(BoardVO vo) throws Exception {
    service.write(vo);

    return "redirect:/board/list";
    }

    ㄴ public 대문자

    답글삭제
  2. Public String posttWirte(BoardVO vo)
    ==> postWrite

    답글삭제
  3. 익명5/13/2020

    안녕하세요 작성글 보며 열심히 독학중인 학생입니다.
    코딩하다 궁금한점이 있어서 질문 남겨요 DAOImpl에서는 작성 쿼리에 return값이 없는 이유가 DB에 데이터를 넣고 return 값을 필요 없기 때문이고 Controller에서 return값을 redirect로 가기때문에 String으로 하는거 맞나요?

    답글삭제

  4. insert into
    board.tbl_board(title, content, writer)
    values(#{title}, #{content}, #{writer})


    혹시라도 500 오류 나시는 분들은 board.tbl_board로 고쳐서 해보세요!

    답글삭제
  5. 스프링초보자입니다.4/16/2021

    안녕하세요 혹시 그 컨트롤러에서 @RequestMapping에 value값이 동일하게 사용됬는데 저같은경우 톰캣실행시 오류가뜨더라구요 그래서 검색을 해봤더니 동일한 value 값을 사용하면안된다고하는데 어떻게 동일한 value 값을 사용하신건가요?

    답글삭제
    답글
    1. 안녕하세요? 방문해주셔서 감사합니다.

      알고계신대로, @RequestMapping의 value값은 동일한게 아닌 프로젝트내에 고유한 값(URL)을 사용해야하는것이 맞습니다.

      하지만 본문에는 이상하게도 동일한 @RequestMapping값이 똑같은 write인 이유는...
      컨트롤러에서도 @RequestMapping을 받기 때문입니다.

      이 화면를 보시면, 컨트롤러에 @RequestMapping에 /border/* 라고 되어있는걸 볼 수 있습니다.

      이건 /border~ 로 시작되는 URL은 전부 이 컨트롤러에서 담당하겠다, 라고 하는것과 같습니다.
      그러므로 실제로는 컨트롤러와 메서드의 @RequestMapping을 합한 값(URL)으로 정해지기 때문에

      각각 다른 컨트롤러 하위 메서드의 @RequestMapping이 같다고하더라도 처리가 될 수 있습니다.

      삭제
  6. 한가지 궁금한 부분이 있습니다. namespace + .list 라던가 .writer 라든가.
    xml에서 id는 list이고 write 인데 impl에서는 왜 .이 들어가는지 궁금해요~~

    답글삭제
    답글
    1. 안녕하세요? 방문해주셔서 감사합니다.

      매퍼(mapper)는 각 매퍼를 구분하는 네임스페이스(namespace)와 매퍼 하위에 쿼리문을 묶은 아이디(id)로 구분됩니다.

      dao에서 매퍼에 접근할 때 네임스페이스와 아이디 모두 필요한데요, 이때 네임스페이스와 아이디를 구분하는게 .입니다.

      boardMapper.writer 는 boardMapper라는 네임스페이슬 가진 매퍼의 하위에 있는 writer라는 아이디를 선택하는것이 됩니다.

      삭제
  7. 처음부터 여기까지 다 잘따라왔는데 마지막에 실행해보니까 404에러뜨네요...ㅠㅠ 왜그럴까요 ㅠㅠ

    답글삭제
    답글
    1. 안녕하세요? 방문해주셔서 감사합니다.

      404에러가 발생한 경우, 경로(url)이 잘못되었거나 실제 파일이 없는 경우입니다.
      컨트롤러에 입력한 경로와 실제 경로가 맞는지 확인해보셔야 할 것 같습니다.

      삭제
  8. 안녕하세요 저는 데이터베이스 2개에 폼 값을 제출과 동시에 따로 저장하려고 하는데 어떻게 해야 할까요???

    답글삭제
    답글
    1. 안녕하세요? 방문해주셔서 감사합니다.

      2개의 db라면.. 접속 정보까지 아예 다르겠지요?
      그렇다면 root-context부터 시작하여 기존과 동일하게 db설정을 해주시고, mapper와 dao까지 각각 만들어두신뒤, service에서 기존dao와 새로운 dao를 호출하게 해주면 될 것 같습니다.

      삭제
  9. 익명9/09/2021

    postwrite는RequestMethod.POST라서 그렇게 정한건가요? 문법에 맞게

    답글삭제
    답글
    1. 안녕하세요? 방문해주셔서 감사합니다.

      postWrite는 문법과 관계 없이 메서드의 이름이지만, 역할과 동일한 이름으로 입력해둔것입니다.
      postWrite대신 a, b, c..처럼 작성해도 서로 매칭만 잘되었다면 정상적으로 동작합니다.

      삭제
  10. form 태그로 하면 한글이 깨지는데 db쿼리를 실행하기전에 이미깨진상태로 설정은 다한거같은데 spring 에서 더해야되는거있나요? web.xml jsp파일에서 인코딩 utf-8로 해봤는데

    답글삭제
    답글
    1. 안녕하세요? 방문해주셔서 감사합니다.

      인코딩 설정은 스프링 백/프론트, DB까지 전부 동일하게 설정해주셔야합니다.

      삭제
  11. 와.. 이거 하는 동안에 진짜
    되고 안되고
    설정을 이랬다 저랬다
    알트 F5 눌러서 메이븐 업데이트하면 자바버전 바뀌어있고...

    오늘도 지식이 늘었다

    답글삭제
  12. 오류는 안나는데 제목,작성자,내용이 안 들어갑니다.. 어디를 봐야할까요

    답글삭제
    답글
    1. 조회화면에서 조회해보면 제목, 작성자, 내용은 비어있고 데이터와 조회수는 나옵니다..

      삭제
    2. 안녕하세요? 방문해주셔서 감사합니다.

      특정 컬럼의 데이터가 안들어갈 경우.. 즉 null이 된다는것은, 프론트에서 넘겨준 데이터가 백을 통해 DB로까지 전달되지 않은것 입니다.

      프론트의 input태그에 있는 name 요소가 VO또는 DB의 컬럼명과 다르게 되어있거나, VO에서 getter/setter가 없을 경우 이런 문제가 발생할겁니다.

      삭제
  13. 500 – 내부 서버 오류가 계속 나네요ㅠㅠ 하루종일 봤는데 오류사항을 모르겠습니다.

    답글삭제
  14. public void getWirte() 메소드가 실제로는 write.jsp 파일을 리턴하는 메소드인것같은데 리턴없이 어떻게 메소드콜이되는건지 원리가 궁금합니다

    답글삭제
  15. 익명8/21/2023

    선생님 감사합니다~ 만수무강 하세요~~!!

    답글삭제