- RestAPI 주소 설계
- Optional
/board/{id}를 updateDTO로 수정해줘
@PutMapping("/user")
public String update(@Valid UserRequest.UpdateDTO updateDTO, Errors errors)BUT 인증과 관련된 (e.g. user update)는 session을 통해서 session의 유저를 수정해줘 라고 해야 된다. user/{id}가 아닌.
admin으로 로그인하게 되면 update가 admin의 정보를 수정하게 된다.
→ updateAdmin 메서드를 만들어서 /admin/user/{id}으로 해야됨 → admin의 id와 session의 id가 다르니까 세션을 꺼내서 세션유저의 getUsername.equals(”admin”)으로 회원정보수정(updateDTO,”받아온 Id”) 해야됨
@RequestBody를 붙여서 x-www-form-urlencoded → application/json으로
로그인만 select인데 아이디/비번이 주소에 노출되면 안되니까 post 방식임
Resp.ok(respDTO); → static으로 해서 가독성이 좋도록 Resp<?> → 모든 타입을 다 받을 수 있으므로 - 로그인이 선행되어야 한다

@PutMapping("/board/{id}")
public @ResponseBody Resp<?> update(@PathVariable("id") Integer id, @Valid @RequestBody BoardRequest.UpdateDTO reqDTO, Errors errors) {
User sessionUser = (User) session.getAttribute("sessionUser");
BoardResponse.DTO respDTO = boardService.글수정하기(reqDTO, id, sessionUser.getId());
return Resp.ok(respDTO);
}
rest 서버 → 장점 : 프론트에 의해 달라지지 않음
http protocol기준으로 만들어야 SSR 서버 이해 가능
진짜 board 정보만 달라고 하는 게 근본.. → 재사용 가능 (update가 아니더라도 board만 필요로 하는 화면에서 사용 가능)
얘는 love reply 등등 뭐가 많아서
@GetMapping("/board/{id}/detail")
public String detail(@PathVariable("id") Integer id, HttpServletRequest request) {
User sessionUser = (User) session.getAttribute("sessionUser");
Integer sessionUserId = (sessionUser == null ? null : sessionUser.getId());
BoardResponse.DetailDTO detailDTO = boardService.글상세보기(id, sessionUserId);
request.setAttribute("model", detailDTO);
return "board/detail";
}여러 화면에서 쓸 수 있는 근본.. updateFormDTO를 쓸 필요가 없음! 걍 DTO 쓰면 됨
board 그대로 돌려주는 근본

updateForm → getBoardOne




jpa 때 lazy로딩때 다 터졋는데 dto쓰니까 Persist context에 든게 없어서 양방향 매핑으로 터지는게 절대 없음
@GetMapping("/")
public @ResponseBody Resp<?> list(@RequestParam(required = false, value = "page", defaultValue = "0") Integer page,
@RequestParam(required = false, value = "keyword", defaultValue = "") String keyword) {
User sessionUser = (User) session.getAttribute("sessionUser");
BoardResponse.ListDTO respDTO;
if (sessionUser == null) {
respDTO = boardService.글목록보기(null, page, keyword);
} else {
respDTO = boardService.글목록보기(sessionUser.getId(), page, keyword);
}
return Resp.ok(respDTO);
}ByteBuddyInterceptor
관리자님 보세요 : Type definition error: [simple type, class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor]
2025-05-07T10:55:12.809+09:00 WARN 16328 --- [nio-8080-exec-2] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor]]
문자-친구-인터셉터?
1 중간 2 존재
1에게 종이 2에게 볼펜 잇음
2가 get요청을 함 중간이 1에게서 종이 가져와서 2에게 전달해줌
2가 get 요청을 중간에게 했는데 종이를 안받음 근데 2가 쓰려고 하면
ByteBuddyInterceptor내가 종이가 있어야 쓸 수 있는데 get요청을 햇는데 달라고 햇는데 안받앗으면 못 씀 =
ByteBuddyInterceptor이제는 3도 생김
db = 1 spring 서버가 중간 3이 json으로 변환하는 친구 buddy 2가 client
2가 get 요청 → 중간이 종이 안받음 → 근데 서버에서 리턴하려고 함 → 먼저 2에게 주는게 아니라 json으로 serializable하려고 함 → getter를 때리려고 함 → 종이 없는데 필요하니까 다시 받으러 감(lazy로딩) → 받으러 갔는데 먼저 json으로 직렬화하고 있으니까 안됨 → lazy로딩 하는 중에 직렬화 하는 것
니가 아직 직렬화 못하니까 기다려줘하고 lazy로딩하고 다시 주면 문제X 근데 안기다리고 직렬화해서 문제
의도는 json 직렬화지만 getter를 때림 → select 하러 감
1,2,중간이 각 스레드
객체는 있는데 비어있음 = 종이를 안받아옴 = 종이만 받고 리모컨은 안받아옴(쟤는 가짜예요)
리모컨 getter 요청했는데 없으니까 채워주러 가야됨 근데 직렬화하고 있음 - 어 데이터 없네 - 터짐

get status, get msg, get body를 할건데
ListDTO 를 다시 get해야 됨

user 객체와 reply 객체가 비어있어서 json으로 직렬화하려고 하니까 터짐!
- 기다리게 설정한다 = json으로 직렬화하려고 할 때 나는 뭘 직렬화하려고 하는지 모르지만 없는 걸 get 요청하면 이건 내가 db에서 들고와야되니까 기다려 라고 설정 가능 = 좋은 방법 아님
- json으로 직렬화할 때 entity로 넘기면 안됨 → dto로 넘겨야 한다. entity 타입이니까 PC에 담겨있어서 lazy 로딩이 됨
DTO에는 유저 객체가 없으니까 lazy 로딩이 발생하지 않는다.

controller에 절대 entity를 넘기지 않는다! 똑같이 생긴 dto 만들어서 넘기자 (깊은 복사로 만들면 됨)
- uri 수정

db에 insert하는 것 / save도 insert 하니까
get과 post로만 한 이유 → 첫번째 프로젝트에서는 javascript 요청 없이 spring에 대한 이해를 중심으로 진행하기 위해서 form 태그만 써서 진행했기 때문에 post를 insert,update,delete 용도로 사용하려고
put과 delete는 javascript로만 가능함, html form tag는 get,post만 사용 가능하다.
post는 insert 요청이지만 http의 기원은 get 요청(논문 쓴거 줘) → 나도 논문 쓴 거 줄게 (post) 까지 가능
http 1.0 프로토콜
논문 수정,삭제도 하면 편해지지 않을까? → get,post 밖에 없어서 post를 insert,update,delete 용도로 쓰자
이제는 rest api로 만들 것 → 프론트 입장 고려x http 1.1 프로토콜(4가지 방식)만 적용하면 됨 → 주소에 동사 안쓴다 - 왜? put, delete 등을 사용 가능하니까 의미가 중복되거든
form 태그가 아닌 json 타입으로 쓸 거니까
rest api에서 삭제는 void를 return한다.(=응답할 데이터가 없다.)
javascript에서는 redirect할 필요없이 dom만 삭제하면 됨
/api 붙이면 json으로 리턴 서버
/s 붙이면 인증 필요
→ 전부 json이니까 api 전부 붙이지 말까? (관리자도 만들어야 되구,, 관리자는 ssr로 만드는게 편하니까.. api붙이자)
로그인을 하고 나서부터 인증이 필요한 것! login에 /s 붙어있으면 서비스를 아예 사용조차 못하게 됨
인증 관련 로직의 주소에는 api를 붙이지 않ㄴ는다.. (회원가입/로그인/로그아웃) → 전세계 컨벤션임
인증 서버는 따로 만들게 됨
RestAPI 서버는 자원을 돌려주는 서버 = resource 서버
인증 서버 = authentication 서버
resource 서버는 여러개가 될 수 있음
인증서버는 실제로 db에서 조회 안함(→ 토큰 배우고 검증만 하면 되기 때문에)
메인페이지는 무조건 “/” 이런 특이한 애들이 잇음 ⇒ @GetMapping({"/","/api/board"}) ("/api/board"가 정확한 주소)
앱 같은 경우 메인페이지 들어갈 때에도 로그인 하도록 구현됨
package shop.mtcoding.blog._core.interceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.web.servlet.HandlerInterceptor;
import shop.mtcoding.blog._core.error.ex.Exception401;
import shop.mtcoding.blog.user.User;
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String uri = request.getRequestURI();
// localhost:8080/s/api/board
System.out.println("uri: " + uri); // /s/api/board
HttpSession session = request.getSession();
User sessionUser = (User) session.getAttribute("sessionUser");
if (uri.startsWith("/s")) {
if (sessionUser == null) throw new Exception401("인증이 필요합니다");
}
return true;
}
}/s는 contains로 처리하게 되면 /boards 같은 경우도 ㅍ함되므로 startWith를 사용하자!
/s/api 주소 설계 완료”
MyRepository 라는 클래스 core디렉토리(전역적으로 쓸거니까)에 만들어서 CRUD를 제네릭 타입으로 만들어 놓으면 나중에 BookmarkRepository extends MyRepository<Bookmark, Long> 이런식으로 해서 타입만 지정해주는 오버라이드 하면 개별적으로 crud는 만들지 않아도 됨
이건 다른거
Share article