14일차 특이사항
1. Spring 게시판 복습 중. 페이지 전환 없이 게시판 수정하기 기능을 map방식으로 만들고 있는데 계속 실패한다.
2. 오류 내용 - Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.type.TypeException: Could not set parameters for mapping: ParameterMapping{property='boardSubject', mode=IN, javaType=class java.lang.Object, jdbcType=null, numericScale=null, resultMapId='null', jdbcTypeName='null', expression='null'}. Cause: org.apache.ibatis.type.TypeException: Error setting null for parameter #1 with JdbcType OTHER . Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. Cause: java.sql.SQLException: 부적합한 열 유형: 1111
부적합한 열 유형: 1111 은 데이터가 제대로 넘어가지 않아서 발생하는 오류다. null이 발생하는데 원인을 모르겠다. 난 분명히 model에 데이터를 저장해서 post방식으로 form을 넘겨줬는데.... 문제가 뭔지 모르겠다.
// 수정하기
@RequestMapping("/update")
public String update(@RequestParam Map<String, Object> map, HttpServletRequest request) {
int updt = service.update(map);
return "redirect:list";
}
컨트롤러 코드다. 뭐가 이상하지? 맞는 것 같은데
3. 결국 Dto를 사용하기로 했다. map 방식은 물어보고 다시 해봐야겠다.
문제 해결
1. Dto를 사용하여 해결했다.
2. 소스코드
- 컨트롤러
@Controller
public class BoardController {
@Inject
public BoardService service;
@Inject
public SqlSessionTemplate sqlSession;
// 게시글 목록
@RequestMapping("/list")
public String list(Map<String, Object> paramMap, Model model) {
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
list = service.list(paramMap);
model.addAttribute("list", list);
return "list";
}
// 글쓰기 페이지 이동
@RequestMapping("/write")
public String write() {
return "write";
}
// 글쓰기
@RequestMapping("/insert")
public String insert(@RequestParam Map<String, Object> map
,HttpServletRequest request) {
System.out.println("map 변수 내용: " + map);
int insert = service.insert(map);
return "redirect:list";
}
// 상세 페이지 이동
@RequestMapping("/detail")
public String detail(int seq, Model model, @ModelAttribute BoardDto dto) {
Map<String, Object> detail = sqlSession.selectOne("mapper.detail", seq);
model.addAttribute("detail", detail);
return "write";
}
//수정하기
@RequestMapping("/update")
public String update(@ModelAttribute BoardDto boardDto, HttpServletRequest request) {
System.out.println("detail 변수 내용: " + boardDto);
int updt = service.update(boardDto);
return "redirect:list";
}
// 삭제하기
@RequestMapping("/delete")
public String delete(Integer[] chk) {
int delete = sqlSession.delete("mapper.delete",chk);
return "redirect:list";
}
}
- 매퍼
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper">
<resultMap type="map" id="rsMap">
<result column="seq" property="seq"/>
<result column="mem_name" property="memName"/>
<result column="mem_id" property="memId"/>
<result column="board_subject" property="boardSubject"/>
<result column="board_content" property="boardContent"/>
</resultMap>
<!-- 게시판 리스트 가져오기 -->
<select id="list" resultMap="rsMap">
select
seq
, mem_name
, mem_id
, board_subject
, board_content
, reg_date
, upt_date
,view_cnt
, useyn
from board_study
order by seq desc
</select>
<!-- 글 등록하기 -->
<insert id = "insert" parameterType="map">
insert into board_study
(
seq
,mem_name
,mem_id
,board_subject
,board_content
,reg_date
,view_cnt
,useyn
)values(
( select nvl(max(seq), 0)+1 from board_study)
,#{name}
,#{id}
,#{subject}
,#{content}
,sysdate
,0
,'y'
)
</insert>
<!-- 글 상세보기 -->
<select id="detail" resultMap="rsMap" parameterType="int">
select
seq
, mem_name
, mem_id
, board_subject
, board_content
, reg_date
, upt_date
,view_cnt
, useyn
from board_study
where seq = #{seq}
</select>
<!-- 글 수정하기 -->
<update id="update" parameterType="com.com.board.BoardDto">
UPDATE
board_study
SET
MEM_NAME = #{name},
MEM_ID = #{id},
BOARD_SUBJECT = #{subject},
BOARD_CONTENT = #{content},
UPT_DATE = sysdate
WHERE SEQ = #{seq}
</update>
<!-- 글 삭제하기 -->
<delete id="delete" parameterType="int">
delete from board_study
where seq in (
<foreach collection="array" separator="," item="aa">
#{aa}
</foreach>
)
</delete>
</mapper>
- list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri = "http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<title>게시판 리스트</title>
</head>
<script>
$(document).ready(function() {
// 삭제 버튼 누를 시
$(function(){
$("#delBtn").click(function(){
$("#listFrm").attr("action","delete").attr("method","post").submit();
})
})
});
</script>
<body>
<div>
<input type = "button" name = "writeBtn" id = "writeBtn" value = "글쓰기" onclick = "location.href='write'">
<input type = "button" name = "delBtn" id = "delBtn" value = "삭제">
</div>
<form name = "listFrm" id = "listFrm">
<table border = "1">
<thead>
<tr>
<th><input type = "checkbox" name = "all"></th>
<th>글번호</th>
<th>작성자(ID)</th>
<th>제목</th>
<th>작성일</th>
<th>수정일</th>
<th>조회수</th>
</tr>
</thead>
<tbody id = "tableBody">
<c:forEach items="${list }" var = "boardList" varStatus="loop" begin="0" end="9">
<tr id = "trList">
<td><input type = "checkbox" name = "chk" value = "${boardList.seq}"></td>
<td>${boardList.seq }</td>
<td>${boardList.memName }(${boardList.memId })</td>
<td><a href = "detail?seq=${boardList.seq }">${boardList.boardSubject }</a></td>
<td><fmt:formatDate value="${boardList.REG_DATE }" pattern="yyyy-MM-dd"/> </td>
<td><fmt:formatDate value="${boardList.UPT_DATE }" pattern="yyyy-MM-dd"/></td>
<td>${boardList.VIEW_CNT }</td>
</tr>
</c:forEach>
</tbody>
</table>
</form>
</body>
</html>
- write.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri = "http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<title>게시판 리스트</title>
</head>
<script>
$(document).ready(function() {
// 삭제 버튼 누를 시
$(function(){
$("#delBtn").click(function(){
$("#listFrm").attr("action","delete").attr("method","post").submit();
})
})
});
</script>
<body>
<div>
<input type = "button" name = "writeBtn" id = "writeBtn" value = "글쓰기" onclick = "location.href='write'">
<input type = "button" name = "delBtn" id = "delBtn" value = "삭제">
</div>
<form name = "listFrm" id = "listFrm">
<table border = "1">
<thead>
<tr>
<th><input type = "checkbox" name = "all"></th>
<th>글번호</th>
<th>작성자(ID)</th>
<th>제목</th>
<th>작성일</th>
<th>수정일</th>
<th>조회수</th>
</tr>
</thead>
<tbody id = "tableBody">
<c:forEach items="${list }" var = "boardList" varStatus="loop" begin="0" end="9">
<tr id = "trList">
<td><input type = "checkbox" name = "chk" value = "${boardList.seq}"></td>
<td>${boardList.seq }</td>
<td>${boardList.memName }(${boardList.memId })</td>
<td><a href = "detail?seq=${boardList.seq }">${boardList.boardSubject }</a></td>
<td><fmt:formatDate value="${boardList.REG_DATE }" pattern="yyyy-MM-dd"/> </td>
<td><fmt:formatDate value="${boardList.UPT_DATE }" pattern="yyyy-MM-dd"/></td>
<td>${boardList.VIEW_CNT }</td>
</tr>
</c:forEach>
</tbody>
</table>
</form>
</body>
</html>
느낀 점
1. 해결해서 기분은 좋은데 더 좋은 방법이 있지 않을까 집착이 생긴다. 끝이 없다. 그냥 마무리하고 다른 사람이 만든 코드를 연구해봐야겠다. 많이 관찰하다 보면 좋은 길이 보일 것이다. 일단 추상적으로 CRUD가 무엇인지 기능을 만들어 본 것이다. 만들고, 읽고, 수정하고, 삭제했다. 세세하게 설계하는 것은 계속 해보면 된다.
2. 체크박스 전체 체크가 되지 않는다. 아직 원인이 뭔지 못찾음.
3. MyBatis에서 DTO (데이터 전송 객체) 클래스의 멤버 변수 이름과 SQL Mapper의 결과 매핑이 일치해야 한다. 그렇지 않으면 MyBatis는 자동으로 매핑을 수행하지 못하고 작동하지 않는다. 이는 MyBatis의 기본 동작 방식이다. Dto이름을 바꿔주던가 아니면 ResultMap을 사용하는 방법이 있다.
예시
예를 들어, DTO 클래스의 멤버 변수 이름이 "userName" 이고 SQL Mapper의 결과 열 이름이 "user_name" 인 경우, 다음과 같이 ResultMap을 사용하여 매핑을 정의할 수 있다.
<resultMap type="com.example.UserDTO" id="userResultMap">
<result column="user_name" property="userName" />
</resultMap>
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
<select id="getUser" resultMap="userResultMap">
SELECT user_name FROM users WHERE user_id = #{userId}
</select>
MyBatis가 "user_name" 컬럼값을 "userName" 멤버 변수에 매핑합니다. 매핑한다는 것은 입력한다고 보면 된다. 이름 뭐시기를 Dto에 넣어버림.
'일경험' 카테고리의 다른 글
[국민취업지원제도 일경험프로그램 16일차] 게시판 페이징 기능, 게시판 검색 기능 (0) | 2023.08.23 |
---|---|
[국민취업지원제도 일경험프로그램 15일차] 게시판 페이징 처리... (0) | 2023.08.22 |
[국민취업지원제도 일경험프로그램 13일차] SQL 문제 풀이 및 함수 정리 (2) | 2023.08.18 |
[국민취업지원제도 일경험프로그램 12일차] SQL 문제 풀이(JOIN) (0) | 2023.08.17 |
[국민취업지원제도 일경험프로그램 11일차] SQL문제, 게시판 상세조회 페이지 (0) | 2023.08.16 |