본문 바로가기
SpringFramework | SpringBoot

SpringFramework + Oracle + Mybatis의 기본적인 CRUD에 대하여 알아보자_2

by Lcoding 2023. 12. 5.
반응형

SpringFramework + Oracle + Mybatis의 기본적인 CRUD에 대하여 알아보자_2 

 

1. 우선 결과 모습을 동영상으로 먼저 보겠습니다.

- 만들어볼 기능

- 회원 추가 [ create - insert ]

- 회원 전체 리스트 조회 [ read - select ]

- 회원 특정 리스트 조회 [ 검색 ]

- 회원 정보 변경 [ update ]

- 회원 삭제 [ delete ]

 

 

 

 

2.

- config 디렉토리내에 MyBatisConfig 파일은 어노테이션으로 컨피그레이션 선언이 되어있으며, MemberService와 MemberRepository에 빈을 주입해준다.

@Configuration
@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파일을 생성해준다.

@Data
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 인터페이스와

public interface 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가 있습니다.

@Data
public class MemberSearchCond {

private String userId;
private String userName;

public MemberSearchCond() {
}

public MemberSearchCond(String userId, String userName) {
this.userId = userId;
this.userName = userName;
}
}

 

@Data
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의 구현체와 

 

@Slf4j
@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 인터페이스 파일이 들어있습니다.

@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 인터페이스와 

public interface MemberService {

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파일이 위치합니다.

@Service
@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가 존재합니다.

@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파일이 존재합니다. 

<?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.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들이 존재합니다.

<!DOCTYPE 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해줍니다.

@Import(MyBatisConfig.class)
@SpringBootApplication(scanBasePackages = "com.prepot.web")
public class PrepotApplication {

public static void main(String[] args) {
SpringApplication.run(PrepotApplication.class, args);
}

}

 

 

 

반응형

loading