'SpringBoot' 카테고리의 다른 글
회원가입 구현 (1) | 2024.10.21 |
---|---|
AJAX를 통한 삭제 기능 (2) | 2024.10.21 |
수정 기능 구현 (0) | 2024.10.20 |
REST API 에러처리 (1) | 2024.10.18 |
에러 처리 (1) | 2024.10.18 |
회원가입 구현 (1) | 2024.10.21 |
---|---|
AJAX를 통한 삭제 기능 (2) | 2024.10.21 |
수정 기능 구현 (0) | 2024.10.20 |
REST API 에러처리 (1) | 2024.10.18 |
에러 처리 (1) | 2024.10.18 |
회원가입
로그인 기능 (0) | 2024.10.22 |
---|---|
AJAX를 통한 삭제 기능 (2) | 2024.10.21 |
수정 기능 구현 (0) | 2024.10.20 |
REST API 에러처리 (1) | 2024.10.18 |
에러 처리 (1) | 2024.10.18 |
ajax란 ?
gpt 참고
페이지를 다시 로드하지 않고 비동기적으로 서버와 통신한다
주로 JSON 형식을 사용하고
JSON
key value 값으로 구성된 객체로 이루어진 배열
ex>
{
"name": "John",
"age": 30,
"city": "Seoul"
}
또 자바스크립트를 사용해서 이루어진다
ajax를 통해 리스트의 항목을 삭제해보자
<div>
<h4 th:text="${item.title}"></h4>
<p th:text="${item.price}"></p>
<a th:href="@{'/modify/' + ${ item.id } }">
<button >수정</button>
</a>
<button class="delete_btn">삭제</button>
</div>
일단 삭제버튼 생성
community 무료버전은 스크립트가 안된다고 한다
그래서 30일 무료체험버전 다운로드해서 해야될듯 하다
로그인 기능 (0) | 2024.10.22 |
---|---|
회원가입 구현 (1) | 2024.10.21 |
수정 기능 구현 (0) | 2024.10.20 |
REST API 에러처리 (1) | 2024.10.18 |
에러 처리 (1) | 2024.10.18 |
현재 이미지를 누르면 상세페이지로 넘어가는데 수정 기능이 있으면 좋겠다
<div class="card" th:each="item : ${items}">
<a th:href="@{'/detail/' + ${ item.id } }">
<img src="https://placehold.co/300">
</a>
<div>
<h4 th:text="${item.title}"></h4>
<p th:text="${item.price}"></p>
<a th:href="@{'/modify/' + ${ item.id } }">
<button >수정</button>
</a>
</div>
</div>
모든 상품목록에 수정 기능이 필요하니 타임리프 반복문 안에 a태그로 modify로 id값을 가져가게 만들어준다
@GetMapping("/modify/{id}")
String modify(Model model,
@PathVariable Integer id) {
var item = itemService.findById(id);
if (item.isPresent()) {
model.addAttribute("detail", item.get());
} else {
return "redirect:/list";
}
return "modify";
}
url로 이동하게 만들어뒀으니 그걸 잡아주는 컨트롤러가 필요하다
GetMapping 같은 경우는 modify/변하는 id 값으로 받아주고
먼저 기본적으로 등록되있는 값을 보여주기 위해 modify라는 html안에
데이터베이스 안에 아이템의 정보를 넣어준다
또 널값일 수 있으니 if문으로 해주고
modify.html을 반환
<form action="/update" method="POST">
<input type="hidden" th:value=${detail.id} name="id">
<input type="text" th:value="${detail.title}" name="title">
<input type="text" th:value="${detail.price}" name="price">
<button type="submit" > 수정완료 </button>
</form>
id 값은 보일 필요는 없지만 쓸 곳이 있으니 히든으로 생성해놓는다
또 여기서 th:value라는게 있는데 input 태그 안에 기본적으로 값이 들어가있으려면
th:value를 사용해서 채워놓을 수 있다
그리고 이번에도 사용자에게 받은 값을 전송해야하기 때문에 form 태그 안에 감싸준다
이번엔 update로 보내주기 때문에
컨트롤러로 넘어간다
@PostMapping("/update")
String modifyPost(Integer id,String title, Integer price) {
itemService.modify(id, title, price);
return "redirect:/list";
}
update로 들어왔을 때 id, title, price 값을 기본 id값과 사용자에게 받은 title, price 값을 가지고 또 서비스로 넘어간다
public void modify(Integer id, String title, Integer price) {
var item = itemRepository.findById(id).orElse(null);
item.setTitle(title);
item.setPrice(price);
itemRepository.save(item);
}
이건 서비스 쪽에 modify인데
일단 save 라는게 새로 추가하는 뜻도 있는데
자체가 id값이 중복되는 값이 있을경우 수정으로 바뀌게 된다고 한다
또 save 안에는 Entity 객체가 들어와야하는데
var item = itemRepository.findById(id)
이렇게만 받아왔을 경우
Optional
상태이기 때문에 .orElse(null)로 변경해주는거 같다
gpt가 orElse(null)은 엔티티가 존재하지 않을 경우 null을 반환하는 방법이라고 한다
맞는거같다
이렇게 수정기능 완성 ~
+ 강의 확인해보니 save 라는게 새로운 Entity여도 id값이 중복이면 수정이 가능하다
public void modify(Integer id, String title, Integer price) {
Item item = new Item();
item.setId(id);
item.setTitle(title);
item.setPrice(price);
itemRepository.save(item);
}
이런식으로도 접근이 가능하다 !
회원가입 구현 (1) | 2024.10.21 |
---|---|
AJAX를 통한 삭제 기능 (2) | 2024.10.21 |
REST API 에러처리 (1) | 2024.10.18 |
에러 처리 (1) | 2024.10.18 |
상품 상세 페이지 (1) | 2024.10.16 |
타임리프를 쓰는 경우에는 알아서 error.html로 보내주지만
단순히 데이터만 이동시키는 REST API 같은 경우는 다른 방법이 필요하다
@GetMapping("/dd")
@ResponseBody
String error() {
try {
} catch (Exception e) {
return "에러";
}
return "잘됨";
}
try {
에러가 날 수 있는 코드 ex>
if (result.isPresent()) {
model.addAttribute("detail", result.get());
} else {
return "redirect:/list";
}
} catch (
catch 블록은 항상 예외 클래스 타입을 명시해줘야한다
이렇게 많지만 모든 예외를 포괄하는게
Exception 이다
) {
에러가 날 시 사용될 코드
}
강제로 에러가 나게도 가능하다
@GetMapping("/dd")
@ResponseBody
String error() {
try {
throw new Exception("db 저장 에러");
} catch (Exception e) {
System.out.println(e.getMessage());
return "에러";
}
}
throw new Exception() 을 통해서 에러가 나게도 가능하다
또 sout를 통해 e.getMessage를 사용했는데
에러가 난 이유에 대한 메세지를 반환한다
종류가 많
또 그냥 에러처리만 사용할 순 없는데
위에 처럼 try catch 문으로 예외처리를 해주거나
@GetMapping("/dd")
@ResponseBody
String error() throws Exception {
throw new Exception("db저장 에러");
}
이런 식으로 함수 옆에 throws Exception을 붙여줘야한다
REST API 에서 문자만 보내는거보다 에러코드와 함께 보내줄 수 있다
@GetMapping("/dd")
ResponseEntity<String> error() {
try {
throw new Exception("db 저장 에러");
} catch (Exception e) {
return ResponseEntity.status(400).body("에러이유");
}
}
ResponseEntity를 통해 가능하다
return 하는 곳에
ResponseEntity
.status는 상태코드
2xx 정상작동
4xx 유저원인
5xx 서버원인
.body는 그 html에 바디에 이유 같은걸 실어서 보낼 수 있다
또 .status에 상태코드 입력하는걸 모르겠다면
에러코드를 모아둔 함수도 있다
HttpStatus하고 뒤에 .을 찍어보면 사용할 수 있는 에러코드들이 있다
try catch를 사용해도 못잡는 url에 관한 부분도 있고
try 내부에서만 에러처리가 가능하기 때문에 스프링에서 제공해주는
Spring boot에서 제공하는 기능이 있다
@ExceptionHandler(Exception.class)
ResponseEntity<String> error() {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("에러");
}
이렇게 위에 @ExcpetionHandler(Exception.class)를 달아줄 시
해당 클래스 내에 있는 모든 오류가 날 시 이 부분으로 넘겨준다
근데 또 클래스 자체가 여러개일 경우에 하나하나 집어넣는것도 일이니
따로 클래스를 새로 만들어서 모든곳에 적용되게 만들 수 있다
@ControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handler() {
return ResponseEntity.status(400).body("모든 컨트롤러 에러시 발동");
}
}
따로 클래스를 생성해서 @ControllerAdvice를 달아놓고
그안에 예외처리에 대해서 작성해놓으면
모든 클래스에서 발동된다
기본 컨트롤러에도 ExceptionHandler를 통해서 에러처리를 해두었다면
컨트롤러 내부에 있는 에러처리가 우선이 된다
또 @ExceptionHandler() 괄호안의 들어가는 부분으로 특정 상황에서만 에러처리가 가능하다
현재는 Exception.class로 모든 에러를 처리하는데
예를 들어 url 타입에 정수형이 들어와야하는데 문자열이 들어올시 실행창에 에러이름이 나온다
MethodArgumentTypeMismatchException 이런 식으로 나오게 되는데
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public ResponseEntity<String> handler() {
return ResponseEntity.status(400).body("숫자가 들어와야함");
}
이런식으로 타입이 매치되지 않았을 때에 대한 에러처리도 가능하다
AJAX를 통한 삭제 기능 (2) | 2024.10.21 |
---|---|
수정 기능 구현 (0) | 2024.10.20 |
에러 처리 (1) | 2024.10.18 |
상품 상세 페이지 (1) | 2024.10.16 |
navbar 만들기 (th:fragment, th:replace) (1) | 2024.10.16 |
@GetMapping("/detail/{id}")
String detail(Model model,
@PathVariable Integer id) {
var result = itemRepository.findById(id);
if (result.isPresent()) {
model.addAttribute("detail", result.get());
} else {
return "redirect:/list";
}
return "detail.html";
}
예를 들어 상품의 상세정보로 가는 페이지에 url 마지막은 정수형의 id가 들어와야한다
하지만 다른 문자열이나 들어올 시
이런 페이지로 가진다 유저 입장에서 보면 난감할거다
타임리프를 의존성에 추가 후 사용중이라면
templates 폴더내에 error.html을 만들어놓을시 자동으로 보내준다
여기서 이제 에러페이지를 만들어주면 된다
error 페이지에서만 사용할 수 있는 타임리프 문법이 또 있다
<p th:text="${status}"></p>
HTTP 상태 코드를 반환해준다
<p th:text="${error}"></p>
오류의 요약 정보를 반환
<p th:text="${path}"></p>
어느 경로에서 문제가 발생했는지 반환
<p th:text="${message}"></p>
오류 메시지 또는 상태 메시지를 반환
<p th:text="${exception}"></p>
발생한 예외 객체의 이름이나 설명을 반환
수정 기능 구현 (0) | 2024.10.20 |
---|---|
REST API 에러처리 (1) | 2024.10.18 |
상품 상세 페이지 (1) | 2024.10.16 |
navbar 만들기 (th:fragment, th:replace) (1) | 2024.10.16 |
사이트 내에서 입력받은 상품 추가 (1) | 2024.10.16 |
GetMapping url에
{작명} 을 사용시
ex > GetMapping("/detail/{아무거나}")
시에 모든 문자들을 허용한다
@GetMapping("/detail/{id}")
String detail() {
return "detail.html";
}
이러면 url 주소가 /detail/ 뒤에 뭐가 오든
detail.html로 옮겨준다
지금은 db에 모든 정보가 아닌 id값을 통한 상세 정보가 필요하다
Optional result = itemRepository.findById(1);
레포지토리에 findById 를 통해서 id를 입력해서 그 id에 해당하는 정보만 반환하게 된다
여기서 반환되는 타입은 Optional 인데
Optional 이란 null 이거나 null이 아닐수도 있다는것이다
id를 만약 찾는데 db에는 100가지의 옷을 등록해놨는데
101번을 찾는다면 null 일 수도 있기 때문이다
그래서 if문으로 반환되는 변수에 값이 있는지 확인하고 막아줘야한다
Optional.isPresent() 로 안에 내용이 존재하는지 boolean 값으로 반환해준다
또 그안에 값을 꺼낼 땐 .get으로 꺼내준다
if (result.isPresent()) {
model.addAttribute("detail", result.get());
} else {
return "redirect:/list";
}
안에 값이 존재할 경우 모델에 db 정보를 넣어주고
존재하지 않을 경우에는 list 페이지로 되돌아간다
원래는 에러페이지 만들고 하는데 아직 만들지 않았으니
list로 돌아가게 만들었다
@GetMapping("/detail/{id}")
String detail(Model model,
@PathVariable Integer id) {
var result = itemRepository.findById(id);
if (result.isPresent()) {
model.addAttribute("detail", result.get());
} else {
return "redirect:/list";
}
return "detail.html";
}
GetMapping 시에 {여기에 작명을 한 이유}
는 @PathVariable로 뒤에 들어온 값들을 가져올 수 있다
상세정보는 id 값에 따라서 정보들이 달라야하기 때문에 id 값으로 정보들을 html에 넣어준다
<h4 th:text="${detail.title}"></h4>
<p th:text="${detail.price}"></p>
detail.html 같은 경우 타임리프 문법으로 가져온 정보들을 채워주면 된다
REST API 에러처리 (1) | 2024.10.18 |
---|---|
에러 처리 (1) | 2024.10.18 |
navbar 만들기 (th:fragment, th:replace) (1) | 2024.10.16 |
사이트 내에서 입력받은 상품 추가 (1) | 2024.10.16 |
접근 권한 (access modifiers (0) | 2024.10.15 |
여러 페이지에서 사용하는 내비게이션 바 같은 경우는
<div class="nav">
<a class="logo">SpringMall</a>
<a href="/list">List</a>
<a href="/write">Write</a>
</div>
이렇게 만든다고 하면 계속 만들어주는 것도 일이다
그래서 이 ui 자체를 조각으로 분리해서 여러 곳에서도 사용이 가능하다
따로 nav.html 식으로 파일을 만들어준다
그 안에
<div class="nav" th:fragment="navbar">
<a class="logo">SpringMall</a>
<a href="/list">List</a>
<a href="/write">Write</a>
</div>
위에 코드하고 다를게 없어보이지만 th:frament="변수명" 이 추가되었다
타임리프 문법 추가시 다른곳에서도 다른 타임리프 문법으로 추가가 가능하다
<div th:replace="~{ nav.html::navbar }"></div>
사용할 페이지에 아무 div 만들고
th:replace="~{ 경로::변수명 }" 입력시
위 div가 갈아치워진다
th:insert 로도 추가도 가능하지만
갈아치우는게 일반적
에러 처리 (1) | 2024.10.18 |
---|---|
상품 상세 페이지 (1) | 2024.10.16 |
사이트 내에서 입력받은 상품 추가 (1) | 2024.10.16 |
접근 권한 (access modifiers (0) | 2024.10.15 |
HTML에 서버데이터 넣기 (0) | 2024.10.14 |