본문 바로가기
Vue.js

2024_09_04_수~09_04_목

by 알케니브 2024. 9. 4.

오늘의 코딩순서

(폴더: 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

 


오늘의 코딩 포인트

(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로 자원을 직접 지정하여 가져오는 방식

postman

 


(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;
		
	}

}

postman 정상작동 화면
Docker 정상작동 화면


  • 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