본문 바로가기

SpringBoot

SpringBoot(16) - Server, JPA, DB 예제(각 아이디별 회원 정보 수정), 추가 정리 사항

728x90
반응형

1) SpringBoot

   1-1) Server, JPA, DB 예제

      1-1-1) 각 아이디별 회원 정보 수정

   1-2) 추가 정리사항

 

 

 

 

 

1) SpringBoot

1-1) Server, JPA, DB 예제

[src/main/resources] - [templates] 안에 home.html 파일 생성 후 아래와 같이 작성

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>web3</title>
</head>
<body>
	<h1>[ web3 ]</h1>
	
	<p>
		<a href="test">저장 테스트</a>
	</p>
	
	<p>
		<a href="save">사용자 입력값을 저장</a>
	</p>
	
	<p>
		<a href="select">사용자 정보 조회</a>
	</p>
	
	<p>
		<a href="delete">사용자 정보 삭제</a>
	</p>
	
	<p>
		<a href="selectAll">모든 회원 보기</a>
	</p>
</body>
</html>

 

 

 

1-1-1) 각 아이디별 회원 정보 수정

(1) [src/main/resources] - [templates] 안에 selectAll.html 파일 생성 후 아래와 같이 작성

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원 전체조회 결과</title>
<style>
	div {
		width: 100%
	}

	h1, table {
		width: 600px;
		margin: 0 auto;
		text-align: center;
	}
	
	h1 {
		padding-bottom: 50px;
	}

	table, th, td {
		border: 1px solid black;
		border-collapse: collapse;
		font-weight: bold;
	}
	
	th, td {
		width: 150px;
		text-align: center;
	}
	
	th {
		background-color: orange;
		color: white;
	}
	
	th:nth-child(1) {
		width: 50px
	}
	
	td:nth-child(1) {
		width: 50px
	}
</style>
<!-- JQuery 파일을 불러온다. -->
<script th:src="@{/js/jquery-3.7.1.min.js}"></script>
<!-- <script src="js/jquery-3.7.1.min.js"></script> -->
<script>
	function del(id) {
		if (confirm(id + " 회원 정보를 정말 삭제하시겠습니까?")) {
			location.href = "deleteUser?id=" + id;
		}
	}
	
	// ready 함수 안에서 삭제버튼(class가 delButton임)에 click 이벤트 처리
	$(document).ready(function () {
		$(".delButton").click(function() {
			if (!confirm("삭제하시겠습니까?")) {
				return;
			}
			
			// 이벤트가 발생한 버튼 객체의 data-id를 읽어옴
			// let id1 = $(this).attr("data-id");
			// ".data()"는 값을 미리 읽어오기 때문에 ".attr()"보다 속도 면에서 더 빠르다!
			// ".data()"의 경우에는 어차피 "data"가 붙은 속성만 가져올 수 있기에
			// 아래와 같이 "data-"를 생략한 "id" 값만으로 값을 가져올 수 있음!
			let id2 = $(this).data("id");
			
			// 삭제 경로로 요청
			location.href = "deleteUser?id=" + id2;
			
			// 현재 문서를 불러와서 조작하는 함수 : html()
			// 현재 문서를 불러와서 텍스트를 조작하는 함수 : text()
			// value 타입을 읽거나 변경하는 함수 : val()
			// 속성의 이름을 지정하면서 해당 속성을 읽어오는 함수 : attr()
			// 이 경우에는 속성을 수정하는 것이다 >> attr('a', '1')
			// 화면(글자의 영역, 크기 등)을 꾸미는 함수 : css()
			// 해당 클래스명을 추가해주는 함수 : addClass()
			// 해당 클래스명을 제거해주는 함수 : removeClass()
		});
		
		$("#bt").click(function() {
			$("#output").css("background", "blue");
			$("#output").css("width", "500");
			$("#output").css("height", "100");
			$("#output").html("<b>확인용 문구 굵게 표시</b>");
			$("#output").fadeOut("slow");
		});
		
	});
</script>
</head>
<body>
	<div>
		<h1>[ 회원 전체조회 결과 ]</h1>
		
		<table>
	      <tr>
	      	<th>NO.</th>
	        <th>ID</th>
	        <th>ID2</th>
	        <th>삭제</th>
	        <th>삭제2</th>
	        <th>삭제3</th>
	        <th>수정</th>
	      </tr>
	      <tr th:if="${personList == null or personList.isEmpty()}">
	      	<td colspan="4">조회 결과가 없습니다.</td>
	      </tr>
	      <tr th:if="${personList}" th:each="person, num : ${personList}">
			<td th:text="${num.count}"></td>
			<td>
				<a th:href="|view?id=${person.id}|" th:text="${person.id}"></a>
			</td>
			<td>
				<a th:href="@{/info/{userid}(userid=${person.id})}" th:text="${person.id}"></a>
			</td>
			<!-- 경로 : /info/abc -->
			
			<td>
				<a th:href="|deleteUser?id=${person.id}|" th:text="${person.id}">삭제</a>
			</td>
			<!-- /deleteUser?id=abc -->
			
			<td>
				<button id="delBtn">
					<a th:href="|javascript:del('${person.id}')|">삭제</a>
				</button>
			</td>
			
			<!-- JQuery로 아래 버튼의 클릭 이벤트 처리하여 삭제 -->
			<td>
				<button class="delButton" th:data-id="${person.id}">삭제</button>
			</td>
			
			<td>
				<a th:href="|update?id=${person.id}|">수정</a>
			</td>
		  </tr>
	    </table>
	    
	    <div>
	    	출력영역 : <div id="output"></div>
	    	<button id="bt">실행</button>
	    </div>
	    
	</div>
	
</body>
</html>

 

 

(2) [src/main/java] - [net.datasa.web3] 안에 PersonController.java 파일 생성 후 아래와 같이 작성

package net.datasa.web3;

import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@RequiredArgsConstructor
@Controller
public class PersonController {
	
	private final PersonService personService;
	
	@GetMapping("test")
	public String test() {
		personService.test();
		return "redirect:/";
	}
	
	/**
	 * 입력 폼으로 이동
	 * @return Form이 있는 HTML 파일 경로
	 * */
	@GetMapping("save")
	public String save() {
		return "inputForm";
	}
	
	/**
	 * form의 입력값을 받아서 저장
	 * */
	@PostMapping("save")
	public String save(@ModelAttribute PersonDTO dto) {
		log.debug("전달된 값 : {}", dto);
		
		personService.save(dto);
		
		return "redirect:/";
	}
	
	/**
	 * 검색 form으로 이동
	 * @return HTML 파일 경로
	 * */
	@GetMapping("select")
	public String select() {
		return "selectForm";
	}
	
	@PostMapping("select")
	public String select(@RequestParam("id") String id, Model model) {
		PersonDTO dto = personService.select(id);
		
		model.addAttribute("id", id);
		model.addAttribute("person", dto);
		
		return "select";
	}
	
	// 삭제 form으로 이동
	@GetMapping("delete")
	public String delete() {
		return "deleteForm";
	}
	
	// 삭제
	@PostMapping("delete")
	public String delete(@RequestParam("id") String id, Model model) {
		boolean result = personService.delete(id);
		
		// 삭제 여부와 삭제한 아이디를 모델에 저장하고 HTML로 포워딩
		// 1. XXX : 없는 아이디입니다.
		// 2. XXX 회원정보를 삭제했습니다.
		
		model.addAttribute("id", id);
		model.addAttribute("result", result);
		
		return "delete";
	}
	
	// 모든 회원 보기
	@GetMapping("selectAll")
	public String selectAll(Model model) {
		List<PersonDTO> dtoList = personService.selectAll();
		
		// 리스트를 모델에 저장하고 selectAll.html로 포워딩
		// 결과를 화면에 표 형태로 출력한다.
		model.addAttribute("personList", dtoList);
		
		return "selectAll";
	}
	
	// 1명의 회원 상세보기
	@GetMapping("view")
	public String view(@RequestParam("id") String id, Model model) {
		PersonDTO dto = personService.select(id);
		
		model.addAttribute("id", id);
		model.addAttribute("person", dto);
		
		return "select";
	}
	
	// 1명의 회원 상세보기(새로운 버전)
	// 바로 위의 코드와 결과는 동일하지만 주소 보안성이 더 좋다(주소 상 노출되는 정보가 적어 사용자가 임의로 주소부분 값을 수정하여 페이지를 접속할 수 없다)
	// 그래서 위의 방식보다 아래 방식을 더 추천함!
	@GetMapping("/info" + "/{id}")
	public String info(@PathVariable("id") String id, Model model) {
		PersonDTO dto = personService.select(id);
		
		model.addAttribute("id", id);
		model.addAttribute("person", dto);
		
		return "select";
	}
	
	@GetMapping("deleteUser")
	public String deleteUser(@RequestParam("id") String id) {
		personService.delete(id);
		
		return "redirect:selectAll";
	}
	
	// 수정 form으로 이동
	@GetMapping("update")
	public String update(@RequestParam("id") String id, Model model) {
		PersonDTO dto = personService.select(id);
		
		model.addAttribute("person", dto);
		
		return "updateForm";
	}
	
	// 수정한 값 받아서 저장
	@PostMapping("update")
	public String update(@ModelAttribute PersonDTO dto) {
		personService.update(dto);
		
		return "redirect:view?id=" + dto.getId();
	}
}

 

 

(3) [src/main/resources] - [templates] 안에 updateForm.html 파일 생성 후 아래와 같이 작성

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>수정</title>
</head>
<body>
	<h1>[ 수정 ]</h1>
	
	<form action="update" method="post">
		<input type="hidden" name="id" th:value="${person.id}">
		이름    <input type="text" name="name" th:value="${person.name}"><br>
		나이    <input type="number" name="age" th:value="${person.age}"><br>
		<input type="submit" value="수정"><br>
	</form>
</body>
</html>

 

 

(4) [src/main/java] - [net.datasa.web3] 안에 PersonService.java 파일 생성 후 아래와 같이 작성

package net.datasa.web3;

import java.util.ArrayList;
import java.util.List;

//import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import jakarta.persistence.EntityNotFoundException;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Service
@Transactional
public class PersonService {
	
//  이렇게 작성해도 되지만 아래의 방식이 더 권장된다!
//	@Autowired
//	PersonRepository PersonRepository;
	
	private final PersonRepository personRepository;
	
	public void test() {
		PersonEntity entity = new PersonEntity();
		entity.setId("abcde2");
		entity.setName("김길동");
		entity.setAge(22);
		
		personRepository.save(entity);
	}

	public void save(PersonDTO dto) {
		PersonEntity entity = new PersonEntity();
		entity.setId(dto.getId());
		entity.setName(dto.getName());
		entity.setAge(dto.getAge());
		
		personRepository.save(entity);
	}

	public PersonDTO select(String id) {
		// findById() : Primary Key 기준으로 검색을 하는 메서드
		// orElse(null) : 결과가 없으면 "null" 값을 대입하는 메서드
		PersonEntity entity = personRepository.findById(id).orElse(null);
		
		if (entity == null) {
			return null;
		}
		
		PersonDTO dto = new PersonDTO();
		dto.setId(entity.getId());
		dto.setName(entity.getName());
		dto.setAge(entity.getAge());
		
		return dto;
	}

	public boolean delete(String id) {
		boolean result = personRepository.existsById(id);
		
		if (result) {
			personRepository.deleteById(id);
		}
		
		return result;
	}
	
	public List<PersonDTO> selectAll() {
		List<PersonEntity> entityList = personRepository.findAll();
		List<PersonDTO> dtoList = new ArrayList<>();
		
		for (PersonEntity entity : entityList) {
			PersonDTO dto = new PersonDTO();
			dto.setId(entity.getId());
			dto.setName(entity.getName());
			dto.setAge(entity.getAge());
			dtoList.add(dto);
		}
		
		return dtoList;
	}

	public void update(PersonDTO dto) {
		// DB의 정보를 조회
		PersonEntity entity = personRepository.findById(dto.getId())
				.orElseThrow(() -> new EntityNotFoundException());
		
		
		// 값 수정
		entity.setName(dto.getName());
		entity.setAge(dto.getAge());
		
		// 저장
		personRepository.save(entity);
	}
}

 

 

(5) 결과 화면

첫 접속 화면

 

 

"모든 회원 보기" 문구 클릭 시 화면

 

 

"수정" 문구 클릭 시 화면

 

 

 

"이름" 혹은 "나이" 데이터 수정(아래와 같이 내용 수정 후 "수정" 버튼 클릭) 시 결과

- 수정된 사항이 반영된 회원 정보 상세 조회 페이지(view?id="xxx")로 이동 / DB에도 데이터 수정사항 반영

 

 

 

 

 

1-2) 추가 정리사항

템플릿 엔진 : 서버 측에서 실행되는 프로그램

 

입력을 안 했을 때 같이 가야하는 정보는 "hidden"을 통해 보내줘야 한다!

 

html 태그의 입력 form 상 "hidden"을 활용하여 추가로 필요한 정보를 숨겨서 같이 보내줌으로써

"Controller"에서 query string에 넣어서 보내야 하는 정보를 @RequestParam으로 받아서

다시 보내줄 경로에 넣어주면 된다!