Spring

[Spring] CRUD란?

dalooong 2023. 7. 9. 02:43

✅ CRUD

💡 CRUD란 ? 일반적인 컴퓨터 소프트웨어가 가지는 기본적인 데이터 처리 기능을 묶어서 말합니다.

기본적으로 어떤 웹 프레임워크를 접할 때, CRUD작업을 구현해보는 것을 목표로 접근하는 것이 좋습니다.

  • Create : 생성 (insert)
  • Read : 읽기 (selelct)
  • Update : 갱신 (update)
  • Delete : 삭제 (delete)

→ CRUD에 맞게 순서대로 만들어보자

 

1️⃣ CRUD - Create

  1. StudentDto 만들기

💡 Dto란? data transfer object의 약자 해당 객체가 통신을 통해 오가는 데이터를 나타내는 객체라는 걸 명시

  • Create.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Create Student</title>
</head>
<body>
<h1>Create Student</h1>
<form action="/create">
    <!--  사용자가 제공할 데이터에 알맞은 input과 label을 만든다.  -->
    <label for="name-input">Name: <input id="name-input" name="name"></label>
    <br>
    <label for="email-input">Email: <input id="email-input" name="email"></label>
    <br>
    <!--  데이터 제출 버튼  -->
    <input type="submit">
</form>
</body>
</html>
  • StudentController
package com.example.crud;

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

@Controller
public class StudentController {
    //create-view getmapping
    @GetMapping("/create-view")
    public String createView() {
        return "create";

    }
}
  • StudentDto → Constructor, getter&setter 생성
package com.example.crud.model;

public class StudentDto {
    private Long id;
    private String name;
    private String email;

    public StudentDto(){}

    //constructor
    public StudentDto(Long id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }

    //getter,setter
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

💡 Post 재요청 방지 redirect 사용

어떤 주소로 POST 요청을 보낸 후, 새로고침을 하면 동일한 요청을 다시 보내는 문제가 발생한다.

이때 redirect를 이용하면 기존 POST 요청을 정리하고 재요청을 방지할 수 있다.

return "redirect:/create-view"; //새로운 "create-view"로 redirect함

2️⃣ CRUD - Read All

1. StudentService 메소드 추가

@Service
public class StudentService {

    private Long nextId = 1L;
    private final List<StudentDto> studentList = new ArrayList<>();

    public StudentDto createStudent(String name, String email) {
        StudentDto newStudent = new StudentDto(nextId, name, email);
        nextId++;
        studentList.add(newStudent);
        return newStudent;
    }

    public List<StudentDto> readStudentAll() {
        return studentList;
    }
}

2. home.html 생성

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Students Home</title>
</head>
<body>
  <h1>Student List</h1>
  <div th:if="${studentList.isEmpty()}">
    <p>No students here...</p>
  </div>
  <div th:unless="${studentList.isEmpty()}" th:each="student: ${studentList}">
    <p>번호: [[${student.id}]]</p>
    <p>이름: [[${student.name}]]</p>
    <p>이메일: [[${student.email}]]</p>
  </div>
  <a th:href="@{/create-view}">Create</a>
</body>
</html>

3. StudentController 수정

@Controller
public class StudentController {
    private final StudentService studentService;

    public StudentController(StudentService studentService) {
        this.studentService = studentService;
    }

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

    @PostMapping("/create")
    public String create(
            @RequestParam("name") String name,
            @RequestParam("email") String email) {
        System.out.println(name);
        System.out.println(email);
        StudentDto newStudent = studentService.createStudent(name, email);
        System.out.println(newStudent);
        return "redirect:/create-view";
				//제출한 뒤 /home으로 보내려면 다음과 같이 작성
        //return "redirect:/home";
        //
        //return "home";으로 할 경우, 리다이렉트하는 게 아니라 "home"이라는 view를 보여줌.
        //단, 이때 현재 코드는 view에 필요한 속성값을 넘겨주지 않기에, 에러가 발생하거나 
				//view가 제대로 표시되지 않을 수 있음.
        //실제로 view의 studentList.isEmpty() 부분에서 null 에러가 발생함.
    }

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

3️⃣ CRUD - Read One

타임리프 적용전에는 read.html 에서 id와 name이 문제없이 잘 확인이 되었지만,

타임리프 문법을 적용하니까 id가 null 값으로 에러가 발생했다

 

- getmapping url에 중괄호 추가 

 

 

 

4️⃣  CRUD - Update

  1. 상세보기→업데이트 페이지
  2. 업데이트 form

<aside> 💡 @PathVariable과 @RequestParam의 차이? @PathVariable은 URL 상에 표현된 변수를 활용하기 위해 사용됩니다. http://localhost:8080/foo/bar/baz 라는 URL이 있으면 해당 URL에 일부분(bar 같은 부분)을 값으로 활용하기 위해 사용하는 것이죠. -> 즉 이 데이터가 어디있는지를 표현할 때 사용되는게 @PathVariable 입니다.

@RequestParam 은 사용자가 요청과 함께 데이터를 보내주었을 때 그 데이터를 활용하는 용도로 사용됩니다

</aside>

  • Update.html 생성
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Update</title>
</head>
<body>
  <h1>Update Student</h1>
  <form th:action = "@{/{id}/update (id=${student.id})}" method="post">
  <!--  사용자가 제공할 데이터에 알맞은 input과 label을 만든1다.  -->
  <label for="name-input">
    Name: <input id="name-input" name="name" th:value="${student.name}">
  </label>
  <br>
  <label for="email-input">
    Email: <input id="email-input" name="email" th:value="${student.email}">
  </label>
  <br>
  <!--  데이터 제출 버튼  -->
  <input type="submit">
</form>
<!--  <a href="/home">Back</a>-->
<a th:href="@{/{id} (id=${student.id})}">Back</a>
</body>
</html>
  • StudentController.java에 update.html을 보여줄 메소드 생성
@GetMapping("/{id}/update-view")
    public String updateView(
        @PathVariable("id")
        Long id,
        Model model
    ){
        model.addAttribute("student", studentService.readStudent(id));
        return "update";
    }
  • read.html 수정 - update로 이동할 수 있는 링크 생성
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Read</title>
</head>
<body>
  <h1>[[${student.id}]]. [[${student.name}]]</h1>
  <p>이메일: [[${student.email}]]</p>
  <a href="/home">Back</a>
<!--  /id/update-view로 가야한다. -->
  <a th:href="@{/{id}/update-view (id=${student.id})}">Update</a>
  <a th:href="@{/{id}/delete-view (id=${student.id})}">Delete</a>
</body>
</html>

→ 학생의 인덱스를 찾아 list에서 값을 변경하기 위한 메소드를 추가한다.

    //어떤 학생 데이터를 갱신할 것인지
    // 그 학생의 갱신될 데이터
    public StudentDto updateStudent(Long id, String name, String email) {
        // 하나의 StudentDto를 찾아서
        int target = 1;
        //studentList의 크기 만큼 반복
        for (int i = 0; i < studentList.size(); i++) {
            if (studentList.get(i).getId().equals(id)) {
                //인덱스 기록
                target = i;
                //반복 종료
                break;
            }
        }
        if (target != 1) {
            //name과 email을 바꿔주자
            studentList.get(target).setName(name);
            studentList.get(target).setEmail(email);
            return studentList.get(target);
        }
        //대상을 못찾았다면
        else return null;
    }
  • StudentController에서 update부분 @getmapping /update추가
@GetMapping("/{id}/update")
    public String update(
            @PathVariable("id")
            Long id,
            @RequestParam("name")
            String name,
            @RequestParam("email")
            String email
    ){
        studentService.updateStudent(id, name, email);
        return String.format("redirect:/%s", id);
    }
  • 실행 결과