스프링수업 6일차

한 일

  • 업데이트, 삭제, 유효성 검사 기능 추가
  • REST란?
  • 포스트맨 사용하기

업데이트, 삭제 기능 추가

기능을 추가할때 허가가 걸려있으면 불편하므로 관리자에게만 허가하는 부분 주석처리.

업데이트

이대로도 새로 저장은 되지만 그대로 두면 참여중인 프로젝트까지 모두 초기화되어 새로저장되는 문제가 생긴다.
예 - 직원 '강감찬'의 정보를 수정 > 강감찬이 참여하고있던 프로젝트가 0개가 되어버림

- EmployeeController -

@GetMapping("/new")
public String newEmployeeForm(Model model) {
	Employee e = new Employee();
	model.addAttribute("employee", e);
	return "employees/new-employee";
}
@PostMapping("/save")
public String createEmployee(Employee employee) {
	Long id = employee.getEmployeeId();
	if (id != null) {
		employeeService.update(employee);
	} else {
		employeeService.save(employee);
	}
	return "redirect:/employees/"; 	//post-redirect-get 패턴
}

- new-employee.html -
form태그 내부에 hidden type의 input태그로 id값을 넘겨줌

<input type="hidden" th:field="*{employeeId}" />

- EmployeeService -
클래스 내부에 업데이트 기능의 새 메서드 생성

public void update(Employee employee) {
	// 실제 DB에서 업데이트할 직원객체를 불러옴
	Employee emp = employeeRepository.findByEmployeeId(employee.getEmployeeId());
	// 필요한 내용만 업데이트
	emp.setFirstName(employee.getFirstName());
	emp.setLastName(employee.getLastName());
	emp.setEmail(employee.getEmail());		
	employeeRepository.save(emp);
}

=> input태그로 받아온 id값을 /save에서 검사,
id가 있으면 employeeService.update(employee)를 통해 업데이트 작업을,
id가 null이면 employeeService.save(employee)을 통해 새 직원을 입력하는 작업을 한다.

update(Employee employee)에서는 직원객체를 불러온 후 특정 내용만 업데이트하므로 다른 값을 가져온 그대로 유지된다.

id객체를 선언할 때 사용한 Long타입은 int, long타입과는 달리 클래스타입이므로 null값이 들어갈 수 있음.




수정 이후에도 참여중인 프로젝트까지 유지됨.

Validation 설정과 검사

새 직원 or 직원 업데이트시 입력한 이름, 이메일 등의 유효성을 스프링에서 검사하도록 어노테이션을 통해 설정함.


pom.xml에 validation 추가

- Employee -

@Id  //기본키를 명시
@GeneratedValue(strategy = GenerationType.IDENTITY)	// Id를 자동생성
private Long employeeId;

@NotBlank(message="이름을 입력해주세요")
@Size(min=1, max=20, message="이름은 1에서 20자 사이입니다.")
private String firstName;

@NotBlank(message="성을 입력해주세요")
@Size(min=1, max=2, message="성은 1에서 2자 사이입니다.")
private String lastName;

@NotBlank(message="이메일을 입력해주세요")
private String email;

@NotBlank : null 또는 ""인지 체크
@Size : 최소 최대사이즈 체크
@Email : 유효한 이메일 형식인지 체크
(여기서는 input type을 eamil로 지정했기때문에 빈칸만 체크하도록 처리.)

- EmployeeController -

@PostMapping("/save")
public String createEmployee(@Valid Employee employee, Errors errors) {
	if (errors.hasErrors()) return "employees/new-employee";	// 유효성 에러 발생시
	
	Long id = employee.getEmployeeId();
	if (id != null) {		// id가 있을 경우 업데이트
		employeeService.update(employee);
	} else {				// id가 없을 경우 새로 생성
		employeeService.save(employee);
	}
	return "redirect:/employees/"; 	//post-redirect-get 패턴
}

매개변수를 받아올때 @Valid 를 붙여 유효성검사를 한 객체를 매개변수로 받음을 알림.
잘못되었을 경우 Employee객체대신 Error객체가 넘어오게 됨.(이부분 대신 넘어오는건지 같이 넘어오는건지 헷갈림..)
errors.hasErrors()가 true일 경우 new-employee.html페이지로 이동

=> 매개변수를 받아올 때는 Project와 Error객체를 모두 가져옴.
유효성검사에 통과하지 못하면 error객체에 메시자가 담겨오고, 통과했을 경우 내용이 빈 상태로 객체가 넘어온다는 차이가 있음.
즉 객체는 무조건 2개를 모두 받되, 객체 내에 내용(메시지)이 있는가의 차이라고 생각하면 됨.

- new-employee.html -

<div class="row my-2">
  <input class="form-control" th:field="*{lastName}" type="text" placeholder="" />
  <span style="color:red" th:if="${#fields.hasErrors('lastName')}" th:errors="*{lastName}">            
</div>
<div class="row my-2">
  <input class="form-control" th:field="*{firstName}" type="text" placeholder="이름" />
  <span style="color:red" th:if="${#fields.hasErrors('firstName')}" th:errors="*{firstName}">  
</div>
<div class="row my-2">
  <input type="email" class="form-control" th:field="*{email}" placeholder="이메일" />
  <span style="color:red" th:if="${#fields.hasErrors('email')}" th:errors="*{email}">  
</div>

에러메시지를 띄워주기 위한 span태그 추가.

th:if="${#fields.hasErrors('email')}"
=> email에 대한 error가 있을 경우 Employee클래스에 설정해둔 에러메시지가 나타남.


유효성검사를 통과하지 못하면 해당 속성입력칸 아래에 에러메시지를 띄움.

스프링 부트 유효성검사 참고

삭제

- EmployeeController -

@GetMapping("/delete")
public String deleteEmployee(@RequestParam("id") long id) {
	employeeService.deleteEmployeeById(id);
	return "redirect:/employees";
}

- EmployeeService -

public void deleteEmployeeById(long id) {
	// 선태한 직원을 삭제하는 메서드
	employeeRepository.deleteById(id);
}

employeeRepository에서 id로 직원을 찾아 삭제.


삭제 버튼 클릭 시 해당 employeeId로 직원을 찾아 삭제함. > 삭제된 후 직원리스트 페이지로 이동하여 삭제여부를 바로 확인가능.

프로젝트에 수정 삭제기능 추가

앞의 직원과 동일한 방식으로 수정 삭제 유효성 검사기능 추가.

1) 수정 기능 추가1
new-project.html에 수정, 삭제 버튼 추가
수정 버튼을 눌렀을 때 new-project.html페이지로 선택한 프로젝트의 id로 DB를 검색해 가져온 값을 input창에 채워서 출력하도록

- new-project.html -

<div class="row my-2">
  <select class="form-select" th:field="*{stage}">
    <option th:value="시작전">시작전</option>
    <option th:value="진행중">진행중</option>
    <option th:value="완료">완료</option>
  </select>
</div>
<div class="row my-2">
  <textarea class="form-control" th:field="*{description}" placeholder="프로젝트 설명"></textarea>
  <span style="color:red" th:if="${#fields.hasErrors('description')}" th:errors="*{description}">
</div>
<!-- 직원 선택 태그 추가 -->
<div class="row my-2">
  <p>직원들을 선택</p>
  <!-- 선택태그의 매핑은 employee임. ${project.employees} = *{employees} -->
  <select class="form-select" th:field="*{employees}" multiple>
    <!-- 직원 전체를 옵션으로 출력 -->
    <option th:each="employee : ${empList}" th:value="${employee.employeeId}" th:text="${employee.firstName}"></option>
  </select>
</div>

2) 수정 기능 추가2
new-project.html페이지에 input hidden속성으로 projectId값을 ProjectController의 /save로 이동.

- new-project.html -
form 태그 내부에 추가

<input type="hidden" th:field="*{projectId}" />

3) 수정 기능 추가3
ProjectController의 /save에서 id를 검사해 null이 아닐 경우 update를, null일 경우 save를 진행.

- ProjectController -

@PostMapping("/save")
public String createProject(@Valid Project project, Errors errors, Model model) {
	if (errors.hasErrors()) {
		List<Employee> empList = employeeService.findAll();
		model.addAttribute("empList", empList);		// 프로젝트에 할당된 직원정보도 필요하므로 가져옴 
		return "projects/new-project";
	}
	
	Long id = project.getProjectId();
	System.out.println("받아온 projectId= " + id);
	
	if (id != null) {
		projectService.update(project);
	} else {
		projectService.save(project);
	}
	return "redirect:/projects";	// post-redirect-get 패턴(new > save > new)
}

4) 삭제기능 추가
ProjectController의 /delete에서 삭제하도록 ProjectService, ProjeceRepository 차례로 수정

- ProjectController -

@GetMapping("/delete")
public String deleteProject(@RequestParam("id") long id) {
	projectService.deleteProjectById(id);
	return "redirect:/projects";
}

- ProjectService -

public void deleteProjectById(long id) {
	// 선태한 프로젝트를 삭제하는 메서드
	projectRepository.deleteById(id);
}

5) 유효성 검사 기능 추가
project클래스에 어노테이션으로 유효성검사기능을 추가.
ProjectController의 /save의 매개변수를 @Valid Project project, Errors errors로 수정하여 유효성검사를 마친 project객체와 errors객체(에러발생 시 에러메시지를 담고 이동, 없을 시 내용이 빈 객체만 이동됨)를 받아 error의 내용을 검사하여 에러발생여부를 판단.

- Project클래스 -

@NotBlank(message="프로젝트 이름을 입력해주세요")
private String name;		//프로젝트 이름
private String stage;		//프로젝트 상태 (시작전, 진행중, 완료)

@NotBlank(message="설명을 입력해주세요")
private String description; //설명
@PostMapping("/save")
public String createProject(@Valid Project project, Errors errors, Model model) {	...내용생략...	}


1 수정 시 수정기능, 2 삭제 시 삭제기능 구현.


REST란?

웹 서비스를 만들때 사용되는 제약의 모음.
HTTP URI를 통해 자원을 명시하고 HTTP Method(GET, POST, PUT, DELETE)를 통해 해당 자원에 대한 CURD OPERATION을 적용하는 긋.

RESTful - API란?

HTTP Method

  • GET
    리소스를 조회할 때 사용
    서버에 데이터를 전송할 때는 query를 사용하여 전달 (?data=hello&value=hello)

  • POST
    요청 데이터 처리, 주로 등록에 사용
    message body를 통해 서버로 요청데이터를 전달함

  • PUT
    리소스가 있으면 해당 리소스를 업데이트함

  • DELETE
    리소스를 제거할 때 사용

Non RESTful

  • GET - /GetUserDetailsServlet?userId=1
  • POST - /RegisterUserServlet
  • PUT - /UpdateUserDetailsServlet
  • DELETE - /DeleteUserDetailsServlet?userId=1
    쉽게말해 jsp를 사용했을때 url으로 넘겨주던것을 생각하면 됨.

RESTful

  • GET - /users1
  • POST - /users
  • PUT - /users1
  • DELETE - /users1
    Non RESTful처럼 parameter를 사용하지않고 경로로 처리함. 이 개념은 아직 정확히 알지 못하므로 차차 학습하며 고칠것.

GET - 유저 조회
POST - 유저 생성
PUT - 유저정보 수정
DELETE - 유저 삭제


웹 뿐만 아니라 다른 환경에서도 사용할 수 있는 REST프로젝트 진행.
=> 하기 전 작업부터.

포스트맨 사용하기

서버의 API에 HTTP를 요청하여 확인하기 위함.


사진속 순서에 따라 새 collection을 만들어 이름을 simple book API로 수정, GET방식을 하나 생성하여 이름을 Server로 지정.
URL창에 https://simple-books-api.glitch.me/ 주소 입력.
send해보면 결과가 리턴됨.

GET

GET https://simple-books-api.glitch.me/status 전송 시

위 사진처럼 ok리턴.


https://simple-books-api.glitch.me/books send시 위 사진처럼 6권의 책이 리턴됨.

https://simple-books-api.glitch.me/books?type=fiction&limit=3 주소를 send하면 fiction타입의 3개의 책이 리턴됨.


해당 번호의 책을 한 권 가져옴

POST

주문을 진행하려면 가입이 선행되어야하므로 아래사진대로 가입을 먼저 진행


위 사진대로 가입하기. 이후 나온 토큰을 사용함.


가입 후 발급받은 토큰을 위 사진처럼 넣은 후

{
    "bookId": 1,
    "customerName": "0829kuj"
}


다시 주문내역을 넣어 send하면 정상적으로 주문이 완료되어 주문번호가 리턴됨.

GET으로 https://amazon.com/s?k=iphone 검색 시 아마존의 아이폰 판매주소를 리턴받는다.

좋은 웹페이지 즐겨찾기