[spring] 화면 처리 - 2
업데이트:
등록 입력 페이지와 등록 처리
게시물의 등록 잡업은 POST 방식으로 처리하지만, 화면에서 입력을 받아야 하므로 GET 방식으로 입력 페이지를 볼 수 있도록 BoardController.java에 메서드를 추가한다.
// BoardController.java
@GetMapping("/register")
public void register() {
}
register()는 입력 페이지를 보여주는 역할만 하기 때문에 별도의 처리가 필요하지 않다.
register.jsp 파일을 생성한다.
<!-- register.jsp -->
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<%@include file="../includes/header.jsp"%>
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">Board Register</h1>
</div>
<!-- /.col-lg-12 -->
</div>
<!-- /.row -->
<div class="row">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">Board Register</div>
<!-- /.panel-heading -->
<div class="panel-body">
<form role="form" action="/board/register" method="post">
<div class="form-group">
<label>Title</label> <input class="form-control" name="title">
</div>
<div class="form-group">
<label>Text area</label>
<textarea rows="3" class="form-control" name="content"></textarea>
</div>
<div class="form-group">
<label>Writer</label> <input class="form-control" name="writer">
</div>
<button type="submit" class="btn btn-default">Submit
Button</button>
<button type="reset" class="btn btn-default">Reset Button</button>
</form>
</div>
<!-- end panel-body -->
</div>
<!-- end panel-body -->
</div>
<!-- end panel -->
</div>
<!-- end row -->
<%@ include file="../includes/footer.jsp"%>
input이나 textarea 태그의 name
속성은 BoardVO 클래스의 변수와 일치시켜준다.
BoardController의 POST 방식으로 동작하는 register()는 redirect
시키는 방식을 이용하므로, 게시글 등록 후에는 다시 ‘/board/list’로 이동하게 된다.
등록은 정상적으로 이루어지지만 한글이 깨진다.
한글 문제와 UTF-8 필터 처리
한글 입력에 문제가 있다면 브라우저에서 한글이 깨져서 전송되는지 확인 후 문제가 없다면 스프링 MVC쪽에서 한글을 처리하는 필터를 등록해야한다.
브라우저에서 전송되는 데이터는 개발자 도구를 통해서 확인할 수 있다. Network 탭을 열고 다시 게시물을 등록하면 한글이 깨졌는지 확인할 수 있다.
브라우저에서 한글이 깨지지 않았다. 즉, Controller 혹은 데이터베이스 쪽에서 문제가 발생함을 알 수 있다.
BoardController와 BoardServiceImpl에서 로그를 확인한다.
BoardController에 전달될 때 이미 한글이 깨진 상태로 처리된 것을 확인할 수 있다.
문제 해결
<!-- web.xml -->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
web.xml 적용 후 다시 게시물을 작성하면 한글이 정상적으로 출력된다.
재전송(redirect) 처리
등록, 수정, 삭제 작업은 처리가 완료된 후 다시 동일한 내용을 전송할 수 없도록 아예 브라우저의 URL을 이동하는 방식을 사용한다. 이러한 과정에서 하나 더 신경 써야 하는 것은 브라우저에 등록, 수정, 삭제 결과를 바로 알 수 있게 피드백을 줘야한다.
BoardController에서 redirect 처리를 할 때 addFlashAttribute()
가 적합하다. 그 이유는 일회성으로만 데이터를 전달하기 때문이다.
list.jsp에 script를 작성한다.
<script type="text/javascript">
$(document).ready(function() {
var result = '<c:out value="${result}"/>';
})
</script>
새로운 게시물의 번호는 addFlashAttribute()로 저장되었기 때문에 한 번도 사용된 적이 없다면 위와 같이 값을 만들어 내지만 사용자가 ‘/board/list’를 호출하거나, 새로고침을 통해 호출하는 경우는 아래와 같이 아무런 내용이 없게 된다.
모달(Model)창 보여주기
모달 코드는 SB Admin2의 page 폴더 내 notifications.html 파일에서 찾아서 복사하고, list.jsp 파일 table 태그 밑에 붙여넣기 하면 된다고 써져있었는데 계속 모달창이 안떠서 그냥 스트립트 태그 위에 붙여넣었다.
<!-- list.jsp -->
<!-- Model 추가 -->
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog"
aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Modal title</h4>
</div>
<div class="modal-body">처리가 완료되었습니다.</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
<!-- /.modal -->
<script type="text/javascript">
$(document).ready(
function() {
var result = '<c:out value="${result}"/>';
checkModal(result);
function checkModal(result) {
if (result === '') {
return;
}
if (parseInt(result) > 0) {
$(".modal-body").html(
"게시글 " + parseInt(result) + "번이 등록되었습니다.");
}
$("#myModal").modal("show");
}
});
</script>
모달창이 안 뜨는 문제 빼고 또 다른 문제가 있었는데, bno가 1씩 증가되는게 아니라 2씩 증가되는 문제도 있었다. 그래서 울면서 다시..쳤다는….슬픈 얘기. 혹시 나처럼 1씩 증가가되는게 아니라 마음대로 증가된다면 아래의 코드로 복붙을 추천한다. 코드는 맨 아래에 있다. 이동
모달이 안뜨면 제일 먼저 $("#myModal").modal("show")
이 부분의 아이디와 모달 제일 처음 div 태그 id가 같은지 확인하고, 같다면 헤더나 푸터에 있는 부트스트랩 경로를 확인하면 될 것이다..아마..
목록에서 버튼으로 이동하기
<!-- list.jsp 수정 -->
<div class="panel panel-default">
<div class="panel-heading">Board List Page
<button id='regBtn' type="button"
class="btn btn-xs pull-right">Register New Board</button>
</div>
<!-- /.panel-heading -->
지금 상태에서 누르면 아무 동작도 안한다.
list.jsp 하단에 jQuery를 이용해 동작시킨다.
<!-- list.jsp 스크립트 추가 -->
$("#regBtn").on("click", function(){
self.location ="/board/register";
});
위의 코드 작성 후 버튼을 누르면 /board/register 경로로 이동한다.
코드 모음
모달 적용 전인 코드
- BoardController.java
package org.zerock.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.zerock.domain.BoardVO;
import org.zerock.service.BoardService;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;
@Controller
@Log4j
@RequestMapping("/board/*") // 보드로 시작하는 모든 처리를 BoardController가 하도록 처리
@AllArgsConstructor // 생성자에 의존성 주입
public class BoardController {
private BoardService service;
@GetMapping("/list")
public void list(Model model) {
log.info("list");
model.addAttribute("list", service.getList());
}
@PostMapping("/register")
public String register(BoardVO board, RedirectAttributes rttr) {
log.info("register: "+board);
service.register(board);
rttr.addFlashAttribute("result", board.getBno());
return "redirect:/board/list";
}
@GetMapping("/get")
public void get(@RequestParam("bno") Long bno, Model model) {
log.info("/get");
model.addAttribute("board", service.get(bno));
}
@PostMapping("/modify")
public String modify(BoardVO board, RedirectAttributes rttr) {
log.info("modify: "+board);
if(service.modify(board)) {
rttr.addFlashAttribute("result", "success");
}
return "redirect:/board/list";
}
@PostMapping("/remove")
public String remove(@RequestParam("bno") Long bno, RedirectAttributes rttr) {
log.info("remove....."+bno);
if (service.remove(bno)) {
rttr.addFlashAttribute("result", "success");
}
return "redirect:/board/list";
}
@GetMapping("/register")
public void register() {
}
}
- src/main/java/org.zerock.mapper.BoardMapper.java
package org.zerock.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Select;
import org.zerock.domain.BoardVO;
public interface BoardMapper {
//@Select("SELECT * FROM tbl_board WHERE bno > 0")
public List<BoardVO> getList();
public void insert(BoardVO board);
public void insertSelectKey(BoardVO board);
public BoardVO read(Long bno);
public int delete(Long bno);
public int update(BoardVO board);
}
- BoardService.java
package org.zerock.service;
import java.util.List;
import org.zerock.domain.BoardVO;
public interface BoardService {
public void register(BoardVO board);
public BoardVO get(Long bno);
public boolean remove(Long bno);
public List<BoardVO> getList();
public boolean modify(BoardVO board);
}
- BoardServiceImpl.java
package org.zerock.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.zerock.domain.BoardVO;
import org.zerock.mapper.BoardMapper;
import lombok.AllArgsConstructor;
import lombok.Setter;
import lombok.extern.log4j.Log4j;
@Log4j
@Service
@AllArgsConstructor
public class BoardServiceImpl implements BoardService{
@Setter(onMethod_ = @Autowired)
private BoardMapper mapper;
@Override
public void register(BoardVO board) {
log.info("register....."+board);
mapper.insertSelectKey(board);
}
@Override
public BoardVO get(Long bno) {
log.info("get......."+bno);
return mapper.read(bno);
}
@Override
public boolean remove(Long bno) {
log.info("remove....."+bno);
return mapper.delete(bno) == 1;
}
@Override
public List<BoardVO> getList() {
log.info("getList......");
return mapper.getList();
}
@Override
public boolean modify(BoardVO board) {
log.info("modify....."+board);
return mapper.update(board)==1;
}
}
- src/main/resources/org/zerock/mapper/BoardMapper.xml (아마 제일 유력한 용의자..)
<?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="org.zerock.mapper.BoardMapper">
<select id="getList" resultType="org.zerock.domain.BoardVO">
<![CDATA[select * from tbl_board where bno>0]]>
</select>
<insert id= "insert" >
insert into tbl_board(bno, title, content, writer)
values (seq_board.nextval, #{title}, #{content}, #{writer})
</insert>
<insert id="insertSelectKey">
<selectKey keyProperty="bno" order="BEFORE" resultType="long">
select seq_board.nextval from dual
</selectKey>
insert into tbl_board (bno, title, content, writer)
values (#{bno}, #{title}, #{content}, #{writer})
</insert>
<select id="read" resultType="org.zerock.domain.BoardVO">
select * from tbl_board where bno=#{bno}
</select>
<delete id="delete" >
delete from tbl_board where bno = #{bno}
</delete>
<update id="update">
update tbl_board
set title=#{title},
content = #{content},
writer = #{writer},
updateDate = sysdate
where bno = #{bno}
</update>
</mapper>
- 참고 : 코드로 배우는 스프링 웹 프로젝트
댓글남기기