SpringFramework + Oracle + Mybatis의 기본적인 CRUD에 대하여 알아보자_2
1. 우선 결과 모습을 동영상으로 먼저 보겠습니다.
- 만들어볼 기능
- 회원 추가 [ create - insert ]
- 회원 전체 리스트 조회 [ read - select ]
- 회원 특정 리스트 조회 [ 검색 ]
- 회원 정보 변경 [ update ]
- 회원 삭제 [ delete ]
2.
- config 디렉토리내에 MyBatisConfig 파일은 어노테이션으로 컨피그레이션 선언이 되어있으며, MemberService와 MemberRepository에 빈을 주입해준다.
@RequiredArgsConstructor
public class MyBatisConfig {
private final MemberMapper memberMapper;
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MyBatisMemberRepository(memberMapper);
}
}
3.
- domain 디렉토리는 Vo 역할이며 Member.java라는 회원 Vo파일을 생성해준다.
public class Member {
private String userId;
private String passWord;
private String userName;
private String addr;
public Member() {
}
public Member(String userId, String passWord, String userName, String addr) {
this.userId = userId;
this.passWord = passWord;
this.userName = userName;
this.addr = addr;
}
}
4.
- repository 디렉토리 안에는 MemberRepository 인터페이스와
Member save(Member member);
List<Member> findAll(MemberSearchCond memberSearchCond);
void update(String userId, MemberUpdateDto updateParam);
Optional<Member> findById(String userId);
void deleteMember(String userId);
}
검색기능과 업데이트 기능에 사용할 dto가 있습니다.
public class MemberSearchCond {
private String userId;
private String userName;
public MemberSearchCond() {
}
public MemberSearchCond(String userId, String userName) {
this.userId = userId;
this.userName = userName;
}
}
public class MemberUpdateDto {
private String passWord;
private String userName;
private String addr;
public MemberUpdateDto() {
}
public MemberUpdateDto(String passWord, String userName, String addr) {
this.passWord = passWord;
this.userName = userName;
this.addr = addr;
}
}
5.
- repository - Mybatis 디렉토리 안에는 MemberRepository의 구현체와
@Repository
@RequiredArgsConstructor
public class MyBatisMemberRepository implements MemberRepository {
private final MemberMapper memberMapper;
@Override
public Member save(Member member) {
log.info("m class={}", memberMapper.getClass());
memberMapper.save(member);
return member;
}
@Override
public List<Member> findAll(MemberSearchCond memberSearchCond) {
return memberMapper.findAll(memberSearchCond);
}
@Override
public void update(String userId, MemberUpdateDto updateParam) {
memberMapper.update(userId,updateParam);
}
@Override
public Optional<Member> findById(String userId) {
return memberMapper.findById(userId);
}
@Override
public void deleteMember(String userId) {
memberMapper.deleteMember(userId);
}
}
Mapper.xml과 직접 연결되는 Mapper 인터페이스 파일이 들어있습니다.
public interface MemberMapper {
void save(Member member);
List<Member> findAll(MemberSearchCond memberSearchCond);
void update(@Param("userId") String userId, @Param("updateParam") MemberUpdateDto updateParam);
Optional<Member> findById(String userId);
void deleteMember(String userId);
}
6.
- service 디렉토리는 Service 인터페이스와
Member save(Member member);
List<Member> findMembers(MemberSearchCond memberSearchCond);
void update(String userId, MemberUpdateDto updateParam);
Optional<Member> findById(String userId);
void deleteMember(String userId);
}
그 구현체인 ServiceImpl파일이 위치합니다.
@RequiredArgsConstructor
public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository;
@Override
public Member save(Member member) {
return memberRepository.save(member);
}
@Override
public List<Member> findMembers(MemberSearchCond memberSearchCond) {
return memberRepository.findAll(memberSearchCond);
}
@Override
public void update(String userId, MemberUpdateDto updateParam) {
memberRepository.update(userId,updateParam);
}
@Override
public Optional<Member> findById(String userId) {
return memberRepository.findById(userId);
}
@Override
public void deleteMember(String userId) {
memberRepository.deleteMember(userId);
}
}
7.
- web 디렉토리는 Controller가 존재합니다.
@RequestMapping("/members")
@RequiredArgsConstructor
public class MemberController {
private final MemberService memberService;
@GetMapping
public String items(@ModelAttribute("memberSearch") MemberSearchCond memberSearch, Model model) {
List<Member> members = memberService.findMembers(memberSearch);
model.addAttribute("members", members);
return "main";
}
@GetMapping("/{userId}")
public String member(@PathVariable String userId, Model model) {
Member member = memberService.findById(userId).get();
model.addAttribute("member", member);
return "member";
}
@GetMapping("/add")
public String addForm() {
return "addMemberForm";
}
@PostMapping("/add")
public String memberAdd(Member member){
Member save = memberService.save(member);
System.out.println(save.getUserName());
return "redirect:/members";
}
@GetMapping("/{userId}/edit")
public String editForm(@PathVariable String userId, Model model) {
Member member = memberService.findById(userId).get();
model.addAttribute("member", member);
return "editForm";
}
@GetMapping("/{userId}/delete")
public String deleteMember(@PathVariable String userId, Model model) {
memberService.deleteMember(userId);
return "redirect:/members";
}
@PostMapping("/{userId}/edit")
public String edit(@PathVariable String userId, @ModelAttribute MemberUpdateDto updateParam) {
memberService.update(userId, updateParam);
return "redirect:/members/{userId}";
}
}
@GetMapping / @PostMapping / @ModelAttribute / @PathVariable 등은 따로 검색해서 의미를 익혀주시면 도움이 됩니다.
8.
- resources - mappers 디렉토리에는 xml파일이 존재합니다.
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.prepot.repository.mybatis.MemberMapper">
<insert id="save" >
insert into member (MEMBER_SEQ,USER_ID,PASS_WORD,USER_NAME,ADDR)
values (USER_SEQ.NEXTVAL,#{userId}, #{passWord}, #{userName},#{addr})
</insert>
<select id="findAll" resultType="Member">
select USER_ID,PASS_WORD,USER_NAME,ADDR
from member
<where>
<if test="userId != null and userId != ''">
and USER_ID like ('%'|| #{userId}||'%')
</if>
<if test="userName != null and userName != ''">
and USER_NAME like ('%'||#{userName}||'%')
</if>
</where>
</select>
<update id="update">
update member
set PASS_WORD=#{updateParam.passWord},
USER_NAME=#{updateParam.userName},
ADDR=#{updateParam.addr}
where USER_ID = #{userId}
</update>
<select id="findById" resultType="Member">
select USER_ID,PASS_WORD,USER_NAME,ADDR
from member
where user_ID = #{userId}
</select>
<delete id="deleteMember">
delete from member where USER_ID = #{userId}
</delete>
</mapper>
member관련 쿼리들이 존재하며, namespace 부분에 인터페이스인 Mapper의 경로가 입력되어야합니다.
9.
- resources - templates 디렉토리에는 동적인 html들이 존재합니다.
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<link th:href="@{/css/bootstrap.min.css}"
href="css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container" style="max-width: 600px">
<div class="py-5 text-center">
<h2>회원 목록</h2>
</div>
<form th:object="${memberSearch}" method="get" class="form-inline">
<div class="row">
<div class="col">
<input type="text" th:field="*{userId}" class="form-control" placeholder="아이디"/>
</div>
<div class="col">
<input type="text" th:field="*{userName}" class="form-control" placeholder="이름"/>
</div>
<div class="col">
<button type="submit" class="btn btn-secondary mb-2">검색</button>
</div>
<div class="col">
</div>
<div class="col">
<div class="col">
<button class="btn btn-primary float-end"
onclick="location.href='addMemberForm.html'"
th:onclick="|location.href='@{/members/add}'|"
type="button">회원 등록
</button>
</div>
</div>
</div>
</form>
<hr class="my-4">
<div>
<table class="table">
<thead>
<tr>
<th>아이디</th>
<th>패스워드</th>
<th>이름</th>
<th>주소</th>
</tr>
</thead>
<tbody>
<tr th:each="member : ${members}">
<td><a href="member.html" th:href="@{/members/{userId}(userId=${member.userId})}" th:text="${member.userId}">아이디</a></td>
<td th:text="${member.passWord}">패스워드</td>
<td th:text="${member.userName}">이름</td>
<td th:text="${member.addr}">주소</td>
</tr>
</tbody>
</table>
</div>
<hr class="my-4">
</div> <!-- /container -->
</body>
</html>
타임리프의 each문 참고용으로 위의 Html을 첨부합니다.
10.
메인메서드의 경우 아래와 같이 Config파일을 Import해줍니다.
@SpringBootApplication(scanBasePackages = "com.prepot.web")
public class PrepotApplication {
public static void main(String[] args) {
SpringApplication.run(PrepotApplication.class, args);
}
}
'SpringFramework | SpringBoot' 카테고리의 다른 글
Spring 서버에서 예외발생시의 흐름과 뷰 선택 우선순위 (0) | 2023.12.11 |
---|---|
템플릿 메소드 패턴과 팩토리 메소드 패턴의 차이점 (2) | 2023.12.06 |
SpringFramework + Oracle + Mybatis의 기본적인 CRUD에 대하여 알아보자_1 (1) | 2023.12.03 |
스프링 부트에서 index.html 위치 (0) | 2023.11.27 |
클라이언트에서 서버로 데이터를 전송하는 방법 (1) | 2023.11.24 |