오늘의 코딩순서
(폴더: vue3Member01)
(0904 일지)
- 목록 생성: MemberListView + index.js + MemberDetailView.vue + member.js
(0905 일지)
- 목록 수정: MemberDetailView.vue + index.js + MemberEditView.vue + member.js
- 목록 삭제
- (Spring) WebConfig + JpaRestApiController
(현장HW) memberRepository에서 deleteById(id);만들기+ EntityManager를 이용하여 삭제로직 짜기+ postman에서 화면나오게 하기 + postman에 나오면 docker 새로 만들기
: MemberService + MemberRepository + JpaMemberRepository - (Vue) MemberDetailView.vue
(현장 HW): MemberDetailView.vue + member.js
- (Spring) WebConfig + JpaRestApiController
오늘의 코딩 포인트
(0904 일지)
1. 목록 생성
- MemberListView
<template>
<div>
<h2>회원 목록</h2>
<hr />
<div class="row g-3">
<!-- g-다음의 숫자만큼 카드의 간격을 조절할 수 있음 -->
<div v-for="member in members" :key="member.id" class="col-3">
<!-- 위의 members를 아래에 전달 -->
<!-- col-다음의 숫자를 6으로 나눈 수만큼 가로에 보여줌 -->
<MemberItem
:id="member.id"
:name="member.name"
:sal="member.sal"
@click="goMemberDetail(member.id)"
>
</MemberItem>
</div>
</div>
<AppCard>
<MemberDetailView :id="1"></MemberDetailView>
</AppCard>
</div>
</template>
<script setup>
// script setup은 무조건 한 번은 실행되지만,
// 여기서는 fetchMembers가 실행됨
import { getMembers } from '@/api/members'
import AppCard from '@/components/AppCard.vue'
import MemberDetailView from './MemberDetailView.vue'
import MemberItem from '@/components/members/MemberItem.vue'
import router from '@/router'
import { ref } from 'vue'
// import { useRouter } from 'vue-router'
// const router = useRouter()
const members = ref([])
const fetchMembers = async () => {
// async: 비동기
try {
const { data } = await getMembers()
// members.js와 연결
members.value = data
// totalCount.value = headers['x-total-count'];
console.log('members.value2->', members.value)
} catch (error) {
console.error(error)
}
}
fetchMembers()
// 한번은 실행하도록 하기
const goMemberDetail = (id) => {
// router.push('/posts/'+id);
console.log('MemberListView goPage MemberDetail id->', id)
console.log('MemberDetail typeof id->', typeof id)
// router.push({name: 'MemberDetail'});
router.push({
name: 'MemberDetail',
params: {
//원래는 id: id같이 써야하하지만, 이름이 같으면 :부터는 생략가능
id
}
})
}
</script>
<style lang="scss" scoped></style>
- index.js
import AboutView from '@/views/AboutView.vue'
import HomeView from '@/views/HomeView.vue'
import MemberCreateView from '@/views/members/MemberCreateView.vue'
import MemberDetailView from '@/views/members/MemberDetailView.vue'
import MemberListView from '@/views/members/MemberListView.vue'
import NestedHomeView from '@/views/nested/NestedHomeView.vue'
import NestedOneView from '@/views/nested/NestedOneView.vue'
import NestedTwoView from '@/views/nested/NestedTwoView.vue'
import NestedView from '@/views/nested/NestedView.vue'
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{
path: '/',
name: 'Home',
component: HomeView
},
{
path: '/about',
name: 'About',
component: AboutView
},
{
path: '/members',
name: 'MemberList',
component: MemberListView
},
{
path: '/members/create',
name: 'MemberCreate',
component: MemberCreateView
},
{
path: '/members/detail/:id',
name: 'MemberDetail',
component: MemberDetailView,
props: true
},
{
path: '/nested',
name: 'Nested',
component: NestedView,
children: [
{
path: '',
name: 'NestedHome',
component: NestedHomeView
},
{
path: 'one',
name: 'NestedOne',
component: NestedOneView
},
{
path: 'two',
name: 'NestedTwo',
component: NestedTwoView
}
]
}
]
const router = createRouter({
history: createWebHistory('/'),
routes: routes
})
export default router
- MemberDetailView.vue
<template>
<div>
<h1>MemberDetailView</h1>
<h2>{{ member.name }}</h2>
<p>{{ member.sal }}</p>
<hr class="my-4" />
<!-- <p>params: {{ $route.param }}</p>
<p>Query: {{ $route.query }}</p>
<p>hash: {{ $route.hash }}</p> -->
</div>
</template>
<script setup>
import { getMemberById } from '@/api/members'
import { ref } from 'vue'
const props = defineProps({
id: String
})
const member = ref({
name: null,
sal: null
})
const fetchMember = async () => {
console.log('1.memberPostValue props.id->', props.id)
// 오류발생지점
const { data } = await getMemberById(props.id)
console.log('2.memberDetailValue props.id->', props.id)
console.log('3.memberDetailValue data->', data)
SetMember(data)
}
const SetMember = ({ name, sal }) => {
member.value.name = name
member.value.sal = sal
}
fetchMember()
// const goListPage = () => routerKey.push({ name: 'MemberList' })
</script>
<style lang="scss" scoped></style>
- member.js
import axios from 'axios'
export function getMembers() {
//MemberListView.vue의 getMembers와 연결됨
console.log('getMembers Start...')
return axios.get('http://localhost:8388/restApi/v1/members') // Risk API // get방식
}
// 신규 members 등록
export function createMember(data) {
console.log('신규 members 등록(createrMember)..')
console.log('신규 members 등록 data->' + data)
return axios.post('http://localhost:8388/restApi/v2/memberSave', data)
}
// 단일 member 조회
export function getMemberById(id) {
console.log('getMemberById typeof id->', typeof id)
console.log('getMemberById id->', id)
return axios.get('http://localhost:8388/restApi/v15/members/' + id)
}
uri로 자원을 직접 지정하여 가져오는 방식
(0905 일지)
2. 목록 수정
- MemberDetailView.vue
<template>
<div>
<h1>MemberDetailView</h1>
<h2>{{ member.name }}</h2>
<p>{{ member.sal }}</p>
<hr class="my-4" />
<div class="row g-2">
<div class="col-auto">
<button class="btn btn-outline-dark">이전글</button>
</div>
<div class="col-auto">
<button class="btn btn-outline-dark">다음글</button>
</div>
<div class="col-auto me-auto"></div>
<div class="col-auto">
<button class="btn btn-outline-dark" @click="goListPage">목록</button>
</div>
<div class="col-auto">
<button class="btn btn-outline-primary" @click="goMemberUpdatePage">수정</button>
</div>
</div>
</div>
</template>
<script setup>
import { getMemberById } from '@/api/members'
import router from '@/router'
import { ref } from 'vue'
const props = defineProps({
id: String
})
const member = ref({
name: null,
sal: null
})
const fetchMember = async () => {
console.log('1.memberPostValue props.id->', props.id)
// 오류발생지점
const { data } = await getMemberById(props.id)
console.log('2.memberDetailValue props.id->', props.id)
console.log('3.memberDetailValue data->', data)
SetMember(data)
}
const SetMember = ({ name, sal }) => {
member.value.name = name
member.value.sal = sal
}
fetchMember()
const goListPage = () => router.push({ name: 'MemberList' })
const goMemberUpdatePage = () =>
router.push({
name: 'MemberEdit',
params: { id: props.id }
})
</script>
<style lang="scss" scoped></style>
- index.js
aimport AboutView from '@/views/AboutView.vue'
import HomeView from '@/views/HomeView.vue'
import MemberCreateView from '@/views/members/MemberCreateView.vue'
import MemberDetailView from '@/views/members/MemberDetailView.vue'
import MemberEditView from '@/views/members/MemberEditView.vue'
import MemberListView from '@/views/members/MemberListView.vue'
import NestedHomeView from '@/views/nested/NestedHomeView.vue'
import NestedOneView from '@/views/nested/NestedOneView.vue'
import NestedTwoView from '@/views/nested/NestedTwoView.vue'
import NestedView from '@/views/nested/NestedView.vue'
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{
path: '/',
name: 'Home',
component: HomeView
},
{
path: '/about',
name: 'About',
component: AboutView
},
{
path: '/members',
name: 'MemberList',
component: MemberListView
},
{
path: '/members/create',
name: 'MemberCreate',
component: MemberCreateView
},
{
path: '/members/detail/:id',
name: 'MemberDetail',
component: MemberDetailView,
props: true
},
{
path: '/members/:id/edit',
name: 'MemberEdit',
component: MemberEditView,
props: true
},
{
path: '/nested',
name: 'Nested',
component: NestedView,
children: [
{
path: '',
name: 'NestedHome',
component: NestedHomeView
},
{
path: 'one',
name: 'NestedOne',
component: NestedOneView
},
{
path: 'two',
name: 'NestedTwo',
component: NestedTwoView
}
]
}
]
const router = createRouter({
history: createWebHistory('/'),
routes: routes
})
export default router
import AboutView from '@/views/AboutView.vue'
import HomeView from '@/views/HomeView.vue'
import MemberCreateView from '@/views/members/MemberCreateView.vue'
import MemberDetailView from '@/views/members/MemberDetailView.vue'
import MemberListView from '@/views/members/MemberListView.vue'
import NestedHomeView from '@/views/nested/NestedHomeView.vue'
import NestedOneView from '@/views/nested/NestedOneView.vue'
import NestedTwoView from '@/views/nested/NestedTwoView.vue'
import NestedView from '@/views/nested/NestedView.vue'
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{
path: '/',
name: 'Home',
component: HomeView
},
{
path: '/about',
name: 'About',
component: AboutView
},
{
path: '/members',
name: 'MemberList',
component: MemberListView
},
{
path: '/members/create',
name: 'MemberCreate',
component: MemberCreateView
},
{
path: '/members/detail/:id',
name: 'MemberDetail',
component: MemberDetailView,
props: true
},
{
path: '/members/:id/edit',
name: 'MemberEdit',
component: MemberEditView,
props: true
},
{
path: '/nested',
name: 'Nested',
component: NestedView,
children: [
{
path: '',
name: 'NestedHome',
component: NestedHomeView
},
{
path: 'one',
name: 'NestedOne',
component: NestedOneView
},
{
path: 'two',
name: 'NestedTwo',
component: NestedTwoView
}
]
}
]
const router = createRouter({
history: createWebHistory('/'),
routes: routes
})
export default router
- MemberEditView.vue
<template>
<div>
<h2>회원(Member) 수정</h2>
<hr class="my-4" />
<MemberForm v-model:sal="form.sal" v-model:name="form.name" @submit.prevent="memberUpdate">
<template #actions>
<button type="button" class="btn btn-outline-danger" @click="goDetailPage">취소</button>
<button class="btn btn-primary">수정</button>
</template>
</MemberForm>
</div>
</template>
<script setup>
import { getMemberById, updateMember } from '@/api/members'
import MemberForm from '@/components/members/MemberForm.vue'
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()
const id = parseInt(route.params.id)
// String로 넘겨준 것이기 때문에 parseInt로 형변환
const form = ref({
sal: null,
name: null
})
const fetchMember = async () => {
const { data } = await getMemberById(id)
console.log('MemberEditValue id->', id)
console.log('MemberEditValue data->', data)
setForm(data)
}
const setForm = ({ sal, name }) => {
form.value.sal = parseInt(sal)
form.value.name = name
}
fetchMember()
const memberUpdate = async () => {
try {
console.log('MemberEditValue memberUpdate form.value->', form.value)
const { data } = await updateMember(id, { ...form.value })
console.log('await ... updateMember data->', data)
router.push({ name: 'MemberDetail', params: { id } })
} catch (error) {
console.error(error)
}
}
const goDetailPage = () => router.push({ name: 'MemberDetail', params: { id } })
</script>
<style lang="scss" scoped></style>
- member.js
import axios from 'axios'
export function getMembers() {
//MemberListView.vue의 getMembers와 연결됨
console.log('getMembers Start...')
return axios.get('http://localhost:8388/restApi/v1/members') // Risk API // get방식
}
// 신규 members 등록
export function createMember(data) {
console.log('신규 members 등록(createrMember)..')
console.log('신규 members 등록 data->' + data)
return axios.post('http://localhost:8388/restApi/v2/memberSave', data)
}
// 단일 member 조회
export function getMemberById(id) {
console.log('getMemberById typeof id->', typeof id)
console.log('getMemberById id->', id)
return axios.get('http://localhost:8388/restApi/v15/members/' + id)
}
export function updateMember(id, data) {
console.log('updateMember typeof id->', typeof id)
console.log('updateMember id->', id)
return axios.put('http://localhost:8388/restApi/v21/members/' + id, data)
// 수정을 위해 put을 사용함
}
3. 목록 삭제
(Spring)
- WebConfig
package com.oracle.oBootJpaApi01;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
// CORS는 한 도메인이 도메인 간의 요청을 가진 다른 도메인의 리소스에
//액세스할 수 있게 해주는 보안 메커니즘으로
//최신 브라우저에서 구현된 동일 출처 정책 때문에 등장
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
// WebMvcConfigurer.super.addCorsMapping(registry);
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST" ,"PUT","DELETE")
.maxAge(3000);
}
}
- JpaRestApiController
package com.oracle.oBootJpaApi01.controller;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.oracle.oBootJpaApi01.domain.Member;
import com.oracle.oBootJpaApi01.service.MemberService;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@RestController
//@controller에 @ResponseBody를 추가한 어노테이션
@Slf4j
//private static final Logger logger
// = LoggerFactory.getLogger(MemberController.class); 와 같은 역할
@RequiredArgsConstructor
public class JpaRestApiController {
private final MemberService memberService;
// 1. API 생성 방법
// 1. Test 용
@RequestMapping("/helloText")
public String helloText() {
System.out.println("JpaRestApiController start...");
String hello = "안녕";
// StringConverter
return hello;
}
// 2. Bad API 예시
// ∵ 외부정보(고객용 정보)뿐 아니라, 내부정보(민감한 보안)까지 보여주는 API이기 때문에
@GetMapping("/restApi/v1/members")
public List<Member> membersVer1() {
System.out.println("JpaRestApiController /restApi/v1/members start...");
List<Member> listMember = memberService.getListAllMember();
System.out.println("JpaRestApiController /restApi/v1/members listMember.size()->"+listMember.size());
return listMember;
}
// 3. Good API 예시: Easy Version
// 목표: 이름과 급여를 뺀 정보 전송
@GetMapping("/restApi/v21/members")
public Result membersVer21() {
List<Member> findMembers = memberService.getListAllMember();
System.out.println("JpaRestApiController /restApi/v21/members findMembers.size()->"+findMembers.size());
List<MemberRtnDto> resultList = new ArrayList<MemberRtnDto>();
// 작성이유: 이전목적=> 반드시 필요한 Data만 보여준다(외부 노출 최대한 금지)
for(Member member : findMembers) {
MemberRtnDto memberRtnDto = new MemberRtnDto(member.getName(), member.getSal());
System.out.println("/restApi/v21/members getName->"+memberRtnDto.getName());
System.out.println("/restApi/v21/members getSal->"+memberRtnDto.getSal());
resultList.add(memberRtnDto);
}
System.out.println("restApi/v21/members resultList.size()->"+resultList.size());
return new Result(resultList.size(),resultList);
}
// 4. Good API 예시: 람다(화살표 표시) Version
// 목표: 이름과 급여만 전송
@GetMapping("/restApi/v22/members")
public Result membersVer22() {
List<Member> findMembers = memberService.getListAllMember();
System.out.println("JpaRestApiController restApi/v22/members findmembers.size()->"+findMembers.size());
// Java 8에서 추가한 스트림(Streams)은 람다를 활용할 수 있는 기술 중 하나
List<MemberRtnDto> memberCollect =
findMembers.stream()
.map(m->new MemberRtnDto(m.getName(), m.getSal()))
// ->표시를 람다라고 함
.collect(Collectors.toList())
;
System.out.println("restApi/v22/members memberCollect.size()->"+memberCollect.size());
return new Result(memberCollect.size(), memberCollect);
}
// Controller에서만 쓴다면 inner 클래스로 만들어 사용한다
@Data
@AllArgsConstructor
class Result<T> {
// T: 내가 원하는 데이터가 어떤 형태이든 다 받아줌
// 즉 유연성 ↑
private final int totCount; // 총 인원수 추가
private final T data;
}
@Data
@AllArgsConstructor
// 이 어노테이션을 사용하면 생성자를 만드는 것과 같은 효과를 봄
class MemberRtnDto{
// DTO의 역할을 함
// 사용자에게만 보여줄 Data이며, Controller에서만 사용하고 Service 등등에서 사용하지 않음
// ∴내장 DTO로 만든다
private String name;
private Long sal;
}
// (0808 일지)
// 5. Bad API 예시 2 ==> 원치않는 항목까지 들어갈 수 있음
@PostMapping("/restApi/v1/memberSave")
// @RequestBody : Json(member)으로 온것을 --> Member member Setting
public CreateMemberResponse savememberV1(@RequestBody @Valid Member member) {
System.out.println("JpaRestApiController /api/v1/memberSave member.getId()->"+member.getId());
log.info("member.getName()-> {}.", member.getName());
log.info("member.getSal()-> {}.", member.getSal());
Long id = memberService.saveMember(member);
return new CreateMemberResponse(id);
}
// 6. 5번의 Bad API를 개선하는 방법
// 목적 : Entity Member member --> 화면이나 API를 직접 setting하는 것은 금지
// 예시 : domain의 Member.class의 @NotEmpty --> @Column(name = "userName")
@PostMapping("/restApi/v2/memberSave")
// @RequestBody : Json(member)으로 온것을 --> Member member Setting
public CreateMemberResponse savememberV2(@RequestBody @Valid CreateMemberRequest cMember) {
System.out.println("JpaRestApiController /api/v2/memberSave cMember.getId()->"+cMember);
log.info("member.getName()-> {}.", cMember.getName());
log.info("member.getSal()-> {}.", cMember.getSal());
Member member = new Member();
member.setName(cMember.getName());
member.setSal(cMember.getSal());
// 선언 후 cMember를 member로 사용하기
Long id = memberService.saveMember(member);
return new CreateMemberResponse(id);
}
@Data
static class CreateMemberRequest {
@NotEmpty
private String name;
private Long sal;
}
@Data
@RequiredArgsConstructor
// 이 어노테이션을 걸면 아래 주석 세 줄을 생략해도 됨
class CreateMemberResponse {
private final Long id;
// public CreateMemberResponse(Long id) {
// this.id = id;
// }
}
// 2. API 조회 방법
// 단일 Id 조회 API
// URI 상에서 '{ }' 로 감싸여있는 부분과 동일한 변수명을 사용하는 방법
// 해당 데이터가 있으면 업데이트를 하기에
// PUT요청이 여러번 실행되어도 해당 데이터는 같은 상태이기에 멱등
@GetMapping("/restApi/v15/members/{id}")
public Member membersVer15(@PathVariable("id") Long id) {
// {id}를 id라고 선언하고 사용하겠다
System.out.println("JpaRestApiController restApi/v15/members id->"+id);
Member findMember = memberService.findByMember(id);
System.out.println("JpaRestApiController restApi/v15/members findMember->"+findMember);
return findMember;
}
// 3. API 수정 방법
@PutMapping("/restApi/v21/members/{id}")
public UpdateMemberResponse updateMemberV21(@PathVariable("id") Long id,
// PK 입력
@RequestBody @Valid UpdateMemberRequest uMember) {
System.out.println("JpaRestApiController updateMemberV21 id->"+id);
System.out.println("JpaRestApiController updateMemberV21 uMember->"+uMember);
memberService.updateMember(id, uMember.getName(), uMember.getSal());
Member findMember = memberService.findByMember(id);
return new UpdateMemberResponse (findMember.getId(),findMember.getName(), findMember.getSal() );
}
// 4. API 삭제 방법
@DeleteMapping("/restApi/v21/deleteMember/{id}")
public CreateMemberResponse deleteMemberV21(@PathVariable("id") Long id) {
System.out.println("JpaRestApiController deleteMemberV21 id->"+id);
memberService.deleteMember(id);
return new CreateMemberResponse(id);
}
@Data
static class UpdateMemberRequest {
// 수정할 항목들
private String name;
private Long sal;
}
@Data
@AllArgsConstructor
class UpdateMemberResponse {
private Long id;
private String name;
private Long sal;
}
}
(현장HW)
- MemberService
package com.oracle.oBootJpaApi01.service;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.oracle.oBootJpaApi01.domain.Member;
import com.oracle.oBootJpaApi01.repository.MemberRepository;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
@Service
@Transactional
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
// 1. 전체회원 조회 API
public List<Member> getListAllMember() {
List<Member> listMember = memberRepository.findAll();
System.out.println("memberService getListAllMember listMember.size()->"+listMember.size());
return listMember;
}
public Long saveMember(@Valid Member member) {
System.out.println("MemberService join member.getName()->"+member.getName());
Long id = memberRepository.save(member);
return id;
}
// 2. 단일 Id 조회 API
public Member findByMember(Long memberId) {
Member member = memberRepository.findByMember(memberId);
System.out.println("MemberService findByMember member->"+member);
return member;
}
// 3. API 수정 방법
public void updateMember(Long id, String name, Long sal) {
Member member = new Member();
member.setId(id);
member.setName(name);
member.setSal(sal);
System.out.println("MemberService updateMember member->"+member);
memberRepository.updateByMember(member);
return;
}
// (0905)(현장 HW)4. API 삭제 방법
public void deleteMember(Long id) {
System.out.println("MemberService deleteMember id->"+id);
memberRepository.deleteById(id);
System.out.println("MemberService deleteMember deleteById id->"+id);
return;
}
}
- MemberRepository
package com.oracle.oBootJpaApi01.repository;
import java.util.List;
import com.oracle.oBootJpaApi01.domain.Member;
public interface MemberRepository {
Long save(Member member);
List<Member> findAll();
Member findByMember(Long memberId);
int updateByMember(Member member);
// (0905)(현장 HW)4. API 삭제 방법
void deleteById(Long id);
}
- JpaMemberRepositor
package com.oracle.oBootJpaApi01.repository;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.oracle.oBootJpaApi01.domain.Member;
import jakarta.persistence.EntityManager;
import lombok.RequiredArgsConstructor;
@Repository
@RequiredArgsConstructor
//
public class JpaMemberRepository implements MemberRepository {
private final EntityManager em;
// @RequiredArgsConstructor가 아래 세 줄의 기능을 함
// @Autowired
// public JpaMemberRepository(EntityManager em) {
// this.em = em;
// }
// 1. 새로운 데이터 입력
@Override
public Long save(Member member) {
System.out.println("JpaMemberRepository save before...");
em.persist(member);
return member.getId();
}
// 2. 데이터 조회
@Override
public List<Member> findAll() {
// 객체 Member
List<Member> memberList = em.createQuery("select m from Member m", Member.class)
.getResultList();
System.out.println("JpaMemberRepository findAll memberList.size()->"+memberList.size());
return memberList;
}
// 3. 단일 Id 조회 API
@Override
public Member findByMember(Long memberId) {
Member member = em.find(Member.class, memberId);
return member;
}
// 4. API 수정 방법
@Override
public int updateByMember(Member member) {
int result = 0;
Member member3 = em.find(Member.class, member.getId());
if (member3 != null) {
// member3의 값이 존재할 경우 회원 저장
member3.setName(member.getName());
member3.setSal(member.getSal());
result = 1;
System.out.println("JpaMemberRepository updateByMember Update...");
} else {
// member3의 값이 존재하지 않을 경우 회원 저장X
result = 0;
System.out.println("JpaMemberRepository updateByMember No Exist...");
}
return result;
}
// (0905)(현장 HW)4. API 삭제 방법
@Override
public void deleteById(Long id) {
System.out.println("JpaMemberRepository deleteById before...");
Member member3 = em.find(Member.class, id);
em.remove(member3);
System.out.println("JpaMemberRepository deleteById member3->"+member3);
return;
}
}
- MemberDetailView.vue
<template>
<div>
<h1>MemberDetailView</h1>
<h2>{{ member.name }}</h2>
<p>{{ member.sal }}</p>
<hr class="my-4" />
<div class="row g-2">
<div class="col-auto">
<button class="btn btn-outline-dark">이전글</button>
</div>
<div class="col-auto">
<button class="btn btn-outline-dark">다음글</button>
</div>
<div class="col-auto me-auto"></div>
<div class="col-auto">
<button class="btn btn-outline-dark" @click="goListPage">목록</button>
</div>
<div class="col-auto">
<button class="btn btn-outline-primary" @click="goMemberUpdatePage">수정</button>
</div>
<div class="col-auto">
<button class="btn btn-outline-danger" @click="remove">삭제</button>
</div>
</div>
</div>
</template>
<script setup>
import { getMemberById } from '@/api/members'
import router from '@/router'
import { ref } from 'vue'
const props = defineProps({
id: String
})
const member = ref({
name: null,
sal: null
})
const fetchMember = async () => {
console.log('1.memberPostValue props.id->', props.id)
// 오류발생지점
const { data } = await getMemberById(props.id)
console.log('2.memberDetailValue props.id->', props.id)
console.log('3.memberDetailValue data->', data)
SetMember(data)
}
const SetMember = ({ name, sal }) => {
member.value.name = name
member.value.sal = sal
}
fetchMember()
const goListPage = () => router.push({ name: 'MemberList' })
const goMemberUpdatePage = () =>
router.push({
name: 'MemberEdit',
params: { id: props.id }
})
</script>
<style lang="scss" scoped></style>
- member.js
import axios from 'axios'
export function getMembers() {
//MemberListView.vue의 getMembers와 연결됨
console.log('getMembers Start...')
return axios.get('http://localhost:8388/restApi/v1/members') // Risk API // get방식
}
// 신규 members 등록
export function createMember(data) {
console.log('신규 members 등록(createrMember)..')
console.log('신규 members 등록 data->' + data)
return axios.post('http://localhost:8388/restApi/v2/memberSave', data)
}
// 단일 member 조회
export function getMemberById(id) {
console.log('getMemberById typeof id->', typeof id)
console.log('getMemberById id->', id)
return axios.get('http://localhost:8388/restApi/v15/members/' + id)
}
// member 수정
// member의 DTO가 여기로 넘어온셈
// 즉 PK에 들어갈 데이터가 data에 다 들어감
export function updateMember(id, data) {
console.log('updateMember typeof id->', typeof id)
console.log('updateMember id->', id)
return axios.put('http://localhost:8388/restApi/v21/members/' + id, data)
// 수정을 위해 put을 사용함
}
// member 삭제
export function deleteMember(id) {
console.log('deleteMember id->', id)
return axios.delete('http://localhost:8388/restApi/v21/deleteMember/' + id)
}
질문목록
수업교재
오늘의 숙제
'Vue.js' 카테고리의 다른 글
2024_09_03_화 (0) | 2024.09.03 |
---|---|
2024_08_30_금~09_02_월 (0) | 2024.08.30 |
2024_08_29_목 (0) | 2024.08.28 |
2024_08_28_수 (0) | 2024.08.28 |
2024_08_27_화 (0) | 2024.08.27 |