Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags more
Archives
Today
Total
관리 메뉴

말하는 햄zzi

Skeleton 프로젝트 본문

Java/Spring

Skeleton 프로젝트

대양파 2023. 7. 13. 16:51
728x90

Skeleton

Spring Boot 애플리케이션 기본적 구조 제공하는 골격 같은 프로젝트 

 

1.JPA Entity 설정 

: JPA Entitu = 데이터베이스 테이블과 자바 객체 관계 정의

 

ex)

Student Entity

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Data;

@Data
@Entity
public class StudentEntity {
    @Id // 해당 멤버 변수가 엔티티의 기본키임을 표시
    @GeneratedValue(strategy = GenerationType.IDENTITY) //기본 키의 값을 자동으로 생성
		//엔티티의 속성들
	  private Long id;
    private String name;
    private Integer age;
    private String phone;
    private String email;
}

 

2.Repository interface 생성

: Repository 데이터베이스와 상호작용하기 위한 메서드 정의

 

ex)

StudentRepository

import com.example.student.entity.StudentEntity;
import org.springframework.data.jpa.repository.JpaRepository;

public interface StudentRepository extends JpaRepository<StudentEntity, Long> {
    
}

 

3.Service 클래스에 Repository Interface 의존성 주입

: Service 클래스가 데이터베이스와 상호작용하기 위해 Repository 사용할수 있도록 하는 역할 

Repository는 테이터베이스와의 데이터 접근을 추상화한 인터페이스

Service 클래스는 비즈니스 로직 처리하기 위한 클래스 

 

ex)

StudentService

import com.example.student.repository.StudentRepository;
import org.springframework.stereotype.Service;


@Service // Spring Framework에게 해당 클래스가 서비스 구성 요소임을 알려줌
public class StudentService {

    private final StudentRepository repository; 
			//repository 멤버 변수에 StudentRepository의 구현체가 주입됨으로써
			//클래스는 StudentRepository를 사용하여 데이터베이스와 상호작용할 수 있게 됨

    public StudentService(StudentRepository repository) {
        this.repository = repository;
    }

}

 

 

4.Controller클래스에 Service 클래스 의존성 주입

: Controller클래스는 비즈니스 로직을 처리하기 위해 Service 클래스의 기능을 활용 할수 있음

 

ex)

StudentController

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller //Spring Framework에게 컨트롤러 역할을 수행하고 있음을 알림
@RequestMapping("/students") //"localhost:8080/students"경로에 맵핑
public class StudentController {

    private final StudentService service; 


    public StudentController(StudentService service) {
        this.service = service;
		  /*service 멤버 변수에 studentService의 인스턴스 주입 
		 > StudentController 클래스가 StudentService를 활용하여 비즈니스 로직 처리 가능 */
    }

}

 

@RequestMapping

: 특정 url요청을 어떤 메서드에 매핑할지 결정하는 어노테이션 

<Get.Post.Put.Delete>Mapping = RequestMapping Method 정의한 것

ex)

@RequestMapping(method = REquestMethod.Get)

= @GetMapping

 

위 어노테이션 애시는 동일하게 사용 가능 

차이점은 RequestMapping의 경우 클래스 , 메서드 사용 할수 0 

(Get,Post,Put,Delete,...)Mapping의 경우 메서드에서만 사용 가능 

@Controller
@RequestMapping("/students") // -> "localhost:8080/students"
public class StudentController {

    @GetMapping("/home") // -> "localhost:8080/students/home"
    public String home(Model model) {
        return "home";
    }
...

 

5.StudentDto클래스 생성 

: 데이터 전송과 변환을 위한 수단

 

ex)

StudentDto

import com.example.student.entity.StudentEntity;
import lombok.Data;

@Data
public class StudentDto {

    private Long id;
    private String name;
    private Integer age;
    private String phone;
    private String email;

    // static factory method pattern
    public static StudentDto fromEntity(StudentEntity entity) {
        StudentDto dto = new StudentDto();
        dto.setId(entity.getId());
        dto.setName(entity.getName());
        dto.setAge(entity.getAge());
        dto.setPhone(entity.getPhone());
        dto.setEmail(entity.getEmail());
        return dto;
    }
    
}

 

※Dto 사용하는 이유?

 

데이터 전송 명확성 :

DTO는 데이터 전송에 필요한 필드와 해당 필드에 대한 getter와 setter메서드를 포함

데이터 전송에 필요한 필드와 메서드가 명확하게 정의되어 다른 개발자들이 데이터를 쉽게 이해하고 사용할 수 0

 

데이터 보호 :

데이터를 읽기 전용으로 만들 수 0

데이터를 변경할 수 있는 세터 메서드를 제공하지 않거나, 필드를 직접적으로 접근할 수 없도록 접근 제어자를 설정함으로써 데이터의 무결성과 보안을 보호할 수0

 

효율적 데이터 전송 :

관련된 데이터 필드를 하나의 객체로 그룹화하므로, 데이터 전송 시에 필요한 필드만 전송할 수 0

네트워크 트래픽을 줄이고 전송 시간을 단축시키는 데 도움.

DTO는 다양한 데이터 형식(예: JSON, XML)으로의 변환을 지원하여 다른 시스템 간에 데이터를 쉽게 전달할 수0

 

느슨한 결합 : 

시스템의 다른 계층 간에 데이터를 전달

 ex) 데이터베이스 계층에서 DTO를 사용하여 데이터를 검색, 비즈니스 로직 계층에서는 해당 DTO를 사용하여 데이터를 가공

 각 계층은 독립적으로 변경될 수 있으며, 서로에게 영향을 미치지 않고 동작할 수 0

 

6.CRUD:"/students" 요청 응답 

 

ex)

StudentController

@GetMapping("")
public String home(Model model) {
    model.addAttribute("studentList", service.readStudentAll());
    return "home";
}

StudentService

// READ ALL
public List<StudentDto> readStudentAll() {
    // TODO entity 조회 repository method
    List<StudentDto> studentDtoList = new ArrayList<>();
    List<StudentEntity> studentEntityList = this.repository.findAll();
    // 1. foreach loop
    for (StudentEntity entity : studentEntityList) {
            studentDtoList.add(StudentDto.fromEntity(entity));
    }

		// 두 가지 다른 방법
    // 2. foreach method
    studentEntityList.forEach(
            entity -> studentDtoList.add(
                    StudentDto.fromEntity(entity)
            )
    );    
		// 3. stream
    studentDtoList = repository.findAll().stream().map(StudentDto::fromEntity).toList();
       
    return studentDtoList;
}

 

7.CRUD:"/students/create-view 요청 응답

 

ex)

StudentController

// create.html 응답
@GetMapping("/create-view")
public String createView() {
    return "create";
}

// 새로운 StudentEntity 생성 후 상세보기 페이지
@PostMapping("/create")
public String create(StudentDto dto) {
    StudentDto newDto = service.createStudent(dto);
    return "redirect:/students/" + newDto.getId(); // PRG 패턴
}

StudentService

// CREATE
public StudentDto createStudent(StudentDto dto) {
    StudentEntity newStudent = new StudentEntity();
    newStudent.setName(dto.getName());
    newStudent.setAge(dto.getAge());
    newStudent.setPhone(dto.getPhone());
    newStudent.setEmail(dto.getEmail());
    return StudentDto.fromEntity(repository.save(newStudent));
}

 

8.CRUD:"/students/{id}"요청 응답

 

ex)

StudentController

// id에 해당하는 StudentEntity의 read.html 응답
@GetMapping("/{id}")
public String read(@PathVariable("id") Long id, Model model) {
    model.addAttribute("student", service.readStudent(id));
    return "read";
}

StudentService

// READ
public StudentDto readStudent(Long id) {
    Optional<StudentEntity> optionalEntity = repository.findById(id);
    if (optionalEntity.isPresent()) return StudentDto.fromEntity(optionalEntity.get());
    else throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}

 

9.CRUD:"/students/{id}/update-view요청 응답

 

ex)

StudentController

// id에 해당하는 StudentEntity의 update.html 응답
@GetMapping("/{id}/update-view")
public String updateView(@PathVariable("id") Long id, Model model){
    model.addAttribute("student", service.readStudent(id));
    return "update";
}

// id에 해당하는 StudentEntity 수정 후 상세보기 페이지로
    @PostMapping("/{id}/update")
    public String update(
            @PathVariable("id") Long id,
            StudentDto dto
    ) {
        StudentDto updateDto = service.updateStudent(id, dto);
        return "redirect:/students/" + updateDto.getId();
}

StudentService

// UPDATE
public StudentDto updateStudent(Long id, StudentDto dto) {
        Optional<StudentEntity> optionalEntity = repository.findById(id);
					
        if (optionalEntity.isPresent()) { // 조회된 StudentEntity를 가져옴
            StudentEntity targetEntity = optionalEntity.get();

						// dto의 필드 값으로 targetEntity의 필드 값을 업데이트
            targetEntity.setName(dto.getName());
            targetEntity.setAge(dto.getAge());
            targetEntity.setPhone(dto.getPhone());
            targetEntity.setEmail(dto.getEmail());

            return StudentDto.fromEntity(repository.save(targetEntity));

					// 조회된 StudentEntity가 없는 경우
        } else throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}

 

10.CRUD:"/students/delete-view"요청응답

 

ex)

StudentController

// id에 해당하는 StudentEntity delete.html
@GetMapping("/{id}/delete-view")
public String deleteView(@PathVariable Long id, Model model) {
    model.addAttribute("student", service.readStudent(id));
    return "delete";
}

// id에 해당하는 StudentEntity 삭제 후 홈페이지로
@PostMapping("/{id}/delete")
public String delete(@PathVariable("id") Long id) {
    service.deleteStudent(id);
    return "redirect:/students";
}

 

StudentService

// DELETE
public void deleteStudent(Long id) {
    if (repository.existsById(id)) repository.deleteById(id); // delete할 게 있는지 확인하고 있으면 지우기
    else throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
728x90
반응형

'Java > Spring' 카테고리의 다른 글

HTTP  (0) 2023.07.23
Optional<T> / JPA  (0) 2023.07.13
IOC(Inversion of Control)-(2)  (0) 2023.07.13
IOC(Inversion of Control)-(1)  (0) 2023.07.12
MyBatis  (0) 2023.07.11