회원 한 줄을 DB 에서 꺼내 화면으로
v0.5 에서 우리가 만든 GreetService:
public String getGreeting(String name) {
return "안녕하세요, " + name + "님!"; // ← 하드코딩
}
이름은 폼에서 받지만, 진짜 회원 정보는 어디서? 결국 DB 가 필요합니다.
URL /member/view?id=hong 접속 → DB 에서 id=hong 회원 정보 조회 → 화면에 표시.
package com.smhrd.domain;
import lombok.Data;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@Data @AllArgsConstructor @NoArgsConstructor
public class Member {
private String id;
private String pwd;
}
👉 DB mymember 의 한 행이 자바 객체로 담길 그릇. 처음에는 두 칸이 전부.
package com.smhrd.mapper;
import com.smhrd.domain.Member;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface MemberMapper {
Member selectOne(String id);
}
👉 메서드 시그니처만 선언. 실제 SQL 은 다음 슬라이드의 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="com.smhrd.mapper.MemberMapper">
<select id="selectOne"
parameterType="string"
resultType="com.smhrd.domain.Member">
SELECT id, pwd
FROM mymember
WHERE id = #{id}
</select>
</mapper>
namespace="com.smhrd.mapper.MemberMapper" → 인터페이스의 풀 클래스명과 정확히 일치id="selectOne" → 인터페이스 메서드 이름과 정확히 일치resultType="com.smhrd.domain.Member" → 결과를 매핑할 자바 클래스#{id} → 메서드 매개변수 값을 안전하게 바인딩 (PreparedStatement)"Invalid bound statement" 또는 "BindingException" 오류. 인터페이스와 XML 의 namespace·id 매칭은 100% 정확해야 합니다.
package com.smhrd.service;
import com.smhrd.domain.Member;
import com.smhrd.mapper.MemberMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MemberService {
@Autowired
private MemberMapper mapper;
public Member find(String id) {
Member m = mapper.selectOne(id);
if (m == null) {
throw new IllegalArgumentException("회원이 없습니다: " + id);
}
return m;
}
}
package com.smhrd.controller;
import com.smhrd.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class MemberController {
@Autowired
private MemberService service;
@GetMapping("/member/view")
public String view(@RequestParam String id, Model model) {
model.addAttribute("member", service.find(id));
return "member/view";
}
}
<!-- /WEB-INF/views/member/view.jsp -->
<%@ page contentType="text/html; charset=UTF-8" %>
<html>
<head><title>회원 정보</title></head>
<body>
<h1>${member.id}</h1>
<table>
<tr><th>아이디</th><td>${member.id}</td></tr>
<tr><th>비밀번호</th><td>${member.pwd}</td></tr>
</table>
</body>
</html>
👉 ${member.id} = 모델의 member 객체의 id 필드 (getId() 호출).
@Service
public class GreetService {
public String getGreeting(String name) {
return "안녕하세요, " + name + "!";
}
}
@Service
public class MemberService {
@Autowired
private MemberMapper mapper;
public Member find(String id) {
return mapper.selectOne(id);
}
}
Service 가 인자를 가공해 반환하는 골격은 같음. 「가공」이 「DB 조회」로 바뀐 것뿐.
| 단계 | v0.5 | v1 |
|---|---|---|
| ① 입력 | 폼 입력 | URL ?id=1 |
| ② Controller | 받음 | 받음 |
| ③ Service | 하드코딩 | Mapper 호출 |
| ④ Mapper | (없음) | SQL 실행 |
| ⑤ DB | (없음) | 데이터 응답 |
| ⑥ Service 받기 | (없음) | Member 객체 |
| ⑦ Controller | 모델에 담기 | 모델에 담기 |
| ⑧ JSP | ${msg} | ${member.id} |
👉 새 박스 2 개(Mapper, DB) + 데이터 형태 변환 1 회.
INSERT INTO mymember(id, pwd)
VALUES('hong', 'temp1234');http://localhost:8080/.../member/view?id=hong| 증상 | 의심할 곳 |
|---|---|
| "Cannot create connection" | ① pom.xml ② DB URL/사용자/비밀번호 ③ MySQL 가동 |
| "BindingException Invalid bound statement" | ④ Mapper 인터페이스 namespace ↔ XML namespace |
| "BindingException ... method not found" | ⑤ Mapper 메서드명 ↔ XML id |
| 필드값이 모두 null | ⑥ 컬럼명 ↔ VO 필드명 (카멜/스네이크) |
👉 본 과정의 「DB 5 단계 지도」 차시가 이 6 곳을 모두 다룹니다.
<!-- log4j2.xml -->
<Logger name="jdbc.sqlonly" level="INFO" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
켜두면 Tomcat 콘솔에 매 요청의 실제 SQL 이 출력됨:
SELECT id, pwd
FROM mymember WHERE id = 'hong'
👉 「내가 짠 SQL 이 진짜 이거 맞나?」를 확인할 수 있는 디버깅의 핵심 도구.
오늘이 우리 프로젝트의 세 번째 마일스톤입니다.
v1 부터는 「DB 가 항상 곁에」 있습니다. 다음 차시들은 모두 이 종단간 구조 위에 기능을 추가합니다.
DB·MyBatis 의 의미는 안다.
한 번도 종단간으로 연결해본 적 없음.
DB → Mapper → Service → Controller → JSP 가 한 번에 연결된다.
SQL 로그가 디버깅의 첫 도구.
다음 Part: 회원과 게시판 — v1 위에 기능을 단계적으로 쌓습니다.