웹개발의 봄, Spring 2주차 - 2
2022년 3월 29일(화) ~ 30일(수)
[스파르타코딩클럽] 웹개발의 봄, Spring 2주차 과정 - 2
◎ 스프링의 구조 3가지
- Controller : 가장 바깥 부분, 요청/응답을 처리함.
→ API와 통신함 - Service : 중간 부분, 실제 중요한 작동이 많이 일어나는 부분
→ Update를 담당
// domain.Course.java Method에 추가
public void update(Course course) {
this.title = course.title;
this.tutor = course.tutor;
}
// service.CourseService.java
@RequiredArgsConstructor
@Service // 스프링에게 이 클래스는 서비스임을 명시
public class CourseService {
// final: 서비스에게 꼭 필요한 녀석임을 명시 / 한번 값이 부여되면 변경될 수 없다.
private final CourseRepository courseRepository;
// @RequiredArgsConstructor로 대체
// // 생성자를 통해, Service 클래스를 만들 때 꼭 Repository를 넣어주도록
// // 스프링에게 알려줌
// public CourseService(CourseRepository courseRepository) {
// this.courseRepository = courseRepository;
// }
// 위의 두 과정을 통해 CourseRepository 가 내가 언제든 쓸 수 있게 스프링이 생성해서 넘겨줌
//업데이트 부분
@Transactional // SQL 쿼리가 일어나야 함을 스프링에게 알려줌 // 업데이트 시 반영하게 함
// 업데이트 시 필요한 것 : id, 업데이트 할 정보를 가져올 녀석 (title, tutor 정보가 들어있음)
public Long update(Long id, CourseRequestDto requestDto) {
Course course1 = courseRepository.findById(id).orElseThrow(
() -> new IllegalArgumentException("해당 아이디가 존재하지 않습니다.")
);
course1.update(requestDto);
return course1.getId();
}
}
- Repo : 가장 안쪽 부분, DB와 맞닿아 있음.
→ Repository, Entity
◎ JPA 심화
- CRUD? : Create, Read, Update, Delete
- Create & Read
@Bean
public CommandLineRunner demo(CourseRepository repository) {
return (args) -> {
// 데이터 저장하기
repository.save(new Course("프론트엔드의 꽃, 리액트", "임민영"));
// 데이터 전부 조회하기
List<Course> courseList = repository.findAll();
for (int i = 0; i < courseList.size(); i++) {
Course course = courseList.get(i);
System.out.println(course.getId());
System.out.println(course.getTitle());
System.out.println(course.getTutor());
}
// 데이터 하나 조회하기
// findById 아이디로 찾기
// orElseThrow 없을 때 할꺼 작성
// NullPointerException 가리킬게 없을 때 대처방법
Course course = repository.findById(2L).orElseThrow(
() -> new NullPointerException("아이디가 존재하지 않습니다.")
);
};
}
- Update
@Bean
public CommandLineRunner demo(CourseRepository courseRepository, CourseService courseService) {
return (args) -> {
courseRepository.save(new Course("프론트엔드의 꽃, 리액트", "임민영"));
System.out.println("데이터 인쇄");
List<Course> courseList = courseRepository.findAll();
for (int i=0; i<courseList.size(); i++) {
Course course = courseList.get(i);
System.out.println(course.getId());
System.out.println(course.getTitle());
System.out.println(course.getTutor());
}
CourseRequestDto requestDto = new CourseRequestDto("웹개발의 봄, Spring", "임민영");
courseService.update(1L, requestDto);
courseList = courseRepository.findAll();
for (int i=0; i<courseList.size(); i++) {
Course course = courseList.get(i);
System.out.println(course.getId());
System.out.println(course.getTitle());
System.out.println(course.getTutor());
}
};
}
- Delete
courseRepository.deleteAll(); // 삭제하는 부분
◎ Lombok
-
자바 프로젝트를 진행하는데 거의 필수적으로 필요한 메소드/생성자 등을 자동생성해줌으로써 코드를 절약할 수 있도록 도와주는 라이브러리
-
설치 : project 생성시 진행했음
-
환경설정
- Setting > "Annotation Processors" 입력 > 우측 "Enable annotation processing" 체크하고 OK 클릭
- Shift 두 번 누르고 plugins 입력 후 엔터 > lombok 설치 후 재시작
-
사용
- @Getter : getter 부분 삭제하고 사용
- @Setter : setter 부분 삭제하고 사용
- @NoArgsConstructor : 기본생성자를 대신 생성해줌
- @RequiredArgsConstructor : private final로 선언된 문자를 자동으로 Class에서 넣어줌
◎ DTO(Data Transfer Object)
- 문제점 : 기존에 있는 Course class를 이용해 업데이트 하는 내용을 전달받음.
- 내가 아닌 다른 사람이 Course class를 변경을 하면 오류 날 가능성이 높아짐
- DB가 변경될 가능성이 커짐
-> DB에 연결된 class는 그대로 두고, 물고다니는 class는 따로 만들 가능성이 부각됨
- 생성하기
// domain.CourseRequestDto.java
@NoArgsConstructor
@Getter
public class CourseRequestDto {
private String title;
private String tutor;
public CourseRequestDto(String title, String tutor) {
this.title = title;
this.tutor = tutor;
}
}
- 적용하기
// service.CourseService
@RequiredArgsConstructor
@Service // 스프링에게 이 클래스는 서비스임을 명시
public class CourseService {
// final: 서비스에게 꼭 필요한 녀석임을 명시 / 한번 값이 부여되면 변경될 수 없다.
private final CourseRepository courseRepository;
// @RequiredArgsConstructor로 대체
// // 생성자를 통해, Service 클래스를 만들 때 꼭 Repository를 넣어주도록
// // 스프링에게 알려줌
// public CourseService(CourseRepository courseRepository) {
// this.courseRepository = courseRepository;
// }
// 위의 두 과정을 통해 CourseRepository 가 내가 언제든 쓸 수 있게 스프링이 생성해서 넘겨줌
//업데이트 부분
@Transactional // SQL 쿼리가 일어나야 함을 스프링에게 알려줌 // 업데이트 시 반영하게 함
// 업데이트 시 필요한 것 : id, 업데이트 할 정보를 가져올 녀석 (title, tutor 정보가 들어있음)
public Long update(Long id, CourseRequestDto requestDto) {
Course course1 = courseRepository.findById(id).orElseThrow(
() -> new IllegalArgumentException("해당 아이디가 존재하지 않습니다.")
);
course1.update(requestDto);
return course1.getId();
}
}
// domain.Course.java
@Getter // Getter 코드를 대체
@NoArgsConstructor // 기본생성자를 대신 생성해줍니다.
@Entity // 테이블임을 나타냅니다.
public class Course extends Timestamped{
@Id // ID 값, Primary Key로 사용하겠다는 뜻입니다.
@GeneratedValue(strategy = GenerationType.AUTO) // 자동 증가 명령입니다.
private Long id;
@Column(nullable = false) // 컬럼 값이고 반드시 값이 존재해야 함을 나타냅니다.
private String title;
@Column(nullable = false)
private String tutor;
public Course(CourseRequestDto requestDto) {
this.title = requestDto.getTitle();
this.tutor = requestDto.getTutor();
}
//생성자
public Course(String title, String tutor) {
this.title = title;
this.tutor = tutor;
}
// 업데이트트
public void update(CourseRequestDto requestDto) {
this.title = requestDto.getTitle();
this.tutor = requestDto.getTutor();
}
}
// Application
@EnableJpaAuditing // 생성, 수정 일자에따라 날짜가 자동으로 업데이트
@SpringBootApplication
public class Week02Application {
public static void main(String[] args) {
SpringApplication.run(Week02Application.class, args);
}
@Bean
public CommandLineRunner demo(CourseRepository courseRepository, CourseService courseService) {
return (args) -> {
courseRepository.save(new Course("프론트엔드의 꽃, 리액트", "임민영"));
System.out.println("데이터 인쇄");
List<Course> courseList = courseRepository.findAll();
for (int i=0; i<courseList.size(); i++) {
Course course = courseList.get(i);
System.out.println(course.getId());
System.out.println(course.getTitle());
System.out.println(course.getTutor());
}
CourseRequestDto requestDto = new CourseRequestDto("웹개발의 봄, Spring", "임민영");
courseService.update(1L, requestDto);
courseList = courseRepository.findAll();
for (int i=0; i<courseList.size(); i++) {
Course course = courseList.get(i);
System.out.println(course.getId());
System.out.println(course.getTitle());
System.out.println(course.getTutor());
}
courseRepository.deleteAll();
};
}
}
◎ API
-
API: 클라이언트 - 서버 간의 약속
클라이언트가 정한대로 서버에게 요청(Request)을 보내면,
서버가 요구사항을 처리하여 응답(Response)을 반환합니다. -
REST: 주소에 명사, 요청 방식에 동사를 사용함으로써 의도를 명확히 드러냄을 의미함
-
주소 요청시 주의 사항
- 주소에 들어가는 명사들은 복수형을 사용
- 주소에 동사는 가급적 사용하지 않음
-
ARC(Advanced REST Client) : API 만들고 나서 테스트를 돕는 tool
- get / delete : 주소를 바로 입력해서 실행.
- post / put
- HEADERS에 HTTP request 추가
- BODY에 json 형식으로 내용 추가하여 실행
- HEADERS에 HTTP request 추가
-
Controller 코드
// controller.CoursesController.java
@RequiredArgsConstructor
@RestController // json으로 응답하기
public class CourseController {
private final CourseRepository courseRepository;
private final CourseService courseService;
// 어노테이션(Annotation)을 통해해같은 소라도 방식이 다름을 구분합니다.
// Get 방식
@GetMapping("/api/courses")
public List<Course> getCourses() {
return courseRepository.findAll();
}
// Post 방식
@PostMapping("/api/courses")
public Course createCourse(@RequestBody CourseRequestDto requestDto) {
// @RequestBody: POST, PUT 방식에서 API에서 넘어오는 데이터를 잘 받으려면 RequestBody의 형태로 받아야함
// requestDto 는, 생성 요청을 의미합니다.
// 강의 정보를 만들기 위해서는 강의 제목과 튜터 이름이 필요하잖아요?
// 그 정보를 가져오는 녀석입니다.
// 저장하는 것은 Dto가 아니라 Course이니, Dto의 정보를 course에 담아야 합니다.
// 잠시 뒤 새로운 생성자를 만듭니다.
Course course = new Course(requestDto);
// JPA를 이용하여 DB에 저장하고, 그 결과를 반환합니다.
return courseRepository.save(course);
}
// Put 방식
@PutMapping("/api/courses/{id}")
public Long updateCourse(@PathVariable Long id, @RequestBody CourseRequestDto requestDto) {
return courseService.update(id, requestDto);
}
// Delete 방식
@DeleteMapping("/api/courses/{id}")
public Long deleteCourse(@PathVariable Long id) {
courseRepository.deleteById(id);
return id;
}
Author And Source
이 문제에 관하여(웹개발의 봄, Spring 2주차 - 2), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@gwichanlee/웹개발의-봄-Spring-2주차-과정-2저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)