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”으로 받아서
다시 보내줄 경로에 넣어주면 된다!