🌐 웹(서버‑렌더링) vs 📱 앱(REST API)에서의 차이

레이어 웹 사이트 (Thymeleaf + Spring MVC) 모바일/SPA 백엔드 (React Native, Flutter 등 클라이언트를 위한 REST)
controller @Controller + Modelreturn "view.html"뷰 이름을 리턴해서 HTML 렌더링 @RestControllerreturn ResponseEntity<DTO>JSON / XML 반환 (뷰 X)
dto 화면에 넣을 값만 담은 ViewDto (ex. 날짜 포맷 변환 완료) 모바일/프론트가 필요로 하는 JSON 스키마용 DTO (ex. ✅·❌ 플래그, 페이징 커서)
converter 엔티티→ViewDto 변환 시 날짜→문자열 포맷 맞추기 등 엔티티→ApiDto 변환 + 링크, 상태코드 포함 (HATEOAS, 커스텀 에러)
service / repository / domain 같다! 비즈니스 로직·DB 계층은 재사용 ↔ 다만 서비스단에서 트랜잭션 범위캐싱 전략을 API 성격에 맞춰 미세 조정할 수 있음

Controller‑DTO‑Converter 부분만 “응답 형태”에 맞춰 바뀌고, Service‑Repository‑Domain은 그대로 재사용한다.

계층 🌐 웹 (Server‑Side Rendering) 📱 앱/SPA (REST API)
Controller java @Controller @RequestMapping("/boards") public class BoardWebController {   @GetMapping("/{id}")   public String detail(@PathVariable Long id, Model model) {       BoardViewDto dto = boardSvc.getView(id);       model.addAttribute("board", dto);       return "board/detail"; // templates/board/detail.html   } } java @RestController @RequestMapping("/api/boards") public class BoardApiController {   @GetMapping("/{id}")   public ResponseEntity<BoardApiDto> detail(@PathVariable Long id){       BoardApiDto dto = boardSvc.getApi(id);       return ResponseEntity.ok(dto);   } }
DTO java // 화면 맞춤 DTO – 문자열 포맷, 댓글 수 추가 public record BoardViewDto(   Long id, String title, String writer, String createdDate, int replyCount ){ } java // API DTO – ISO 날짜, 하이퍼링크 포함 public record BoardApiDto(   Long id, String title, String writer, LocalDateTime createdAt, URI self ){ }
Validation java @PostMapping("/write") public String write(@Valid @ModelAttribute BoardForm form,          BindingResult errors){ if(errors.hasErrors()) return "board/write"; boardSvc.save(form); return "redirect:/boards"; } java @PostMapping public ResponseEntity<?> write(@Valid @RequestBody BoardWriteReq req){ boardSvc.save(req); return ResponseEntity.status(201).build(); }
예외 처리 java @ControllerAdvice public class WebErrorAdvice {   @ExceptionHandler(NotFoundEx.class)   public String notFound(){ return "error/404"; } } java @RestControllerAdvice public class ApiErrorAdvice {   @ExceptionHandler(NotFoundEx.class)   public ResponseEntity<ApiError> notFound(NotFoundEx e){ return ResponseEntity.status(404).body(new ApiError(e)); } }
Security 세션/쿠키 기반 로그인 → formLogin() 토큰(JWT) → http.addFilter(new JwtAuthFilter(...))
템플릿/응답 Thymeleaf, <div th:text="${board.title}"> JSON: { "id":1,"title":"..." }
페이지네이션 Page<Board> → Model에 넣고 Thymeleaf로 <a href="?page=${p}"> GET /api/boards?page=3{ "content":[...], "page":3, "total":10 }
파일 업로드 MultipartFile 받아서 ⇒ redirect 모바일은 S3 Presigned URL 받아 직접 업로드 → URL만 서버에 저장

핵심 패턴 차이 요약

  1. Controller 어노테이션
  2. DTO 형태
  3. 에러·인증 응답 형식
  4. 프론트에서 데이터 소비 방법

즉, Service/Repository/Entity는 그대로 재사용하고,

“외부에 노출되는 계층” (Controller–DTO–Error Handling–Security Filter)만

응답 포맷에 맞춰 갈라진다—이게 두 구현의 실질적인 코드 차이입니다.

일단 REST API를 사용해 만들어 보았다

mysql설치 후 연동까지 해보았다

image.png

image.png

image.png

image.png

깃에 모든 코드는 올려놓았다