블로그

저니

스프링 가이드 목록 2022

* page : https://spring.io/guides     클릭하시면 해당 페이지로 넘어갑니다. 🍃 Building a RESTful Web Service Scheduling Tasks Consuming a RESTful Web Service Building Java Projects with Gradle Building Java Projects with Maven Accessing Relational Data using JDBC with Spring Uploading Files Authenticating a User with LDAP Messaging with Redis Messaging with RabbitMQ Accessing Data with Neo4j Validating Form Input Building a RESTful Web Service with Spring Boot Actuator Messaging with JMS Creating a Batch Service Securing a Web Application Building a Hypermedia-Driven RESTful Web Service Accessing Data in Pivotal GemFire Integrating Data Caching Data with Pivotal GemFire Managing Transactions Accessing Data with JPA Accessing Data with MongoDB Serving Web Content with Spring MVC Converting a Spring Boot JAR Application to a WAR Creating Asynchronous Methods Handling Form Submission Building an Application with Spring Boot Using WebSocket to build an interactive web application Working a Getting Started guide with STS Consuming a RESTful Web Service with AngularJS Consuming a RESTful Web Service with jQuery Enabling Cross Origin Requests for a RESTful Web Service Consuming a SOAP web service Accessing JPA Data with REST Accessing Neo4j Data with REST Accessing MongoDB Data with REST Accessing Data in Pivotal GemFire with REST Producing a SOAP web service Caching Data with Spring Deploying to Cloud Foundry from STS Spring Boot with Docker Working a Getting Started guide with IntelliJ IDEA Creating CRUD UI with Vaadin Service Registration and Discovery Centralized Configuration Testing the Web Layer Accessing data with MySQL Creating a Multi Module Project Creating API Documentation with Restdocs Messaging with Google Cloud Pub/Sub Building a Reactive RESTful Web Service Consumer Driven Contracts Accessing Vault Vault Configuration Accessing Data Reactively with Redis Deploying a Spring Boot app to Azure Building a Gateway Client-Side Load-Balancing with Spring Cloud LoadBalancer Spring Cloud Stream Spring Cloud Data Flow Spring Cloud Task Spring Boot Kubernetes Accessing data with R2DBC Spring Cloud Circuit Breaker Guide Observability with Spring Building a Guide with VS Code Accessing Data with Cassandra Spring Security Architecture Spring Boot Docker Spring on Kubernetes Building REST services with Spring Spring Security and Angular React.js and Spring Data REST Spring Boot and OAuth2 Building web applications with Spring Boot and Kotlin Spring Boot with Kotlin Coroutines and RSocket Metrics and Tracing with Spring     var list = Array.from(document.getElementsByClassName('guide-link')); list.forEach((e) => { console.log('* [' + e.innerHTML + '](http://spring.io' + e.getAttribute('href') + ')'); }); 출처 : https://okky.kr/article/1209730

백엔드스프링프레임워크가이드springframeworkbackendguides

도롱이

[인프런 워밍업 클럽_0기] 1주차, 첫 번째 발자국 #1

1주차, 첫 번째 발자국 1주차는 어려운 내용은 딱히 없었다! 어느정도 기반기가 있었다면 다들 어렵지 않게 해냈었을 것 같다.강의 요약은 강의를 들으면서 노션에 하나하나 요약했기 때문에 노션 링크를 남긴다.https://abalone-copper-ebe.notion.site/d2e9b3e27b3348abbde60994cf627ebd?pvs=4 그래도 너무 노션 링크만 띡 남기면 정 없으니 한 번 쭉 훑어보며 하루하루 대략적으로 어떤 것을 공부했고, 어떤 것들을 알게 되었나 작성해보자. Day2 02/19 서버 개발을 위한 환경 설정 및 네트워크 기초(1~5강 + 52강)첫 날은 프로젝트 소스를 다운받고, 프로젝트의 spring boot 버전을 2.7점대에서 3.0.x로 업데이트를 진행했다.Java, IntelliJ, PostMan, MySQL, Git은 이미 설치가 되어 있어서 따로 영상을 챙겨보진 않았다.52강을 들으면서 느낀 건 안 그래도 저번에 2점대 버전에서 3점대 버전으로 마이그레이션 하려는 시도를 했었었는데, 그때는 spring이라는 프레임워크를 잘 몰랐었던 때고, 3점대가 나온지 얼마 안돼서 정보도 그렇게 많지 않아 장렬히 실패했었던 기억이 있었다. 이번에도 에러가 엄청 날까봐 걱정을 많이 했는데 강의가 잘 정리되어 있어 어렵지 않게 마이그레이션 할 수 있었다. MySQL이 원래 깔려 있어서 비밀번호 입력하는 부분만 빼면 말이다! (MySQL 오류) 본격적으로 강의를 들어가기 전에 Java를 공부하기 전에 알아두면 좋을 것들!이라는 유튜브를 두 개 시청했다. 사실 Java를 공부한지는 꽤 됐는데 JVM의 이점 부분만 대략적으로 알았지 JRE나 JDK은 스킵하고 넘어갔었다. JVM이 제일 중요하다고 알려져있으니까. 이번 강의에서 본격적인 내용을 시작하기 전에 한 번 짚어주는 유튜브가 있어서 별 거 아닌데도 갑자기 많은 생각이 들기 시작했다.나는 왜 Java를 공부하면서 이런 것들도 몰랐을까?나는 Java를 잘 안다고 할 수 있을까?대충 공부함으로써 내가 얻을 수 있는 것들이 뭐였을까?라는 생각들이 스쳐지나 갔다...! 앞으로는 조금 더 꼼꼼한 사람이 돼야 겠다는 목표도 생겼다...! 본격적인 강의 시작에서는 Spring Boot 프로젝트를 실행하는 법과 네트워크, HTTP, API, GET API를 공부했다. 강사님이 최대한 이해하기 쉽게 이것 저것 비유해가면서 얘기해주셔서 이해가 잘 됐었던 거 같다.제일 기억에 남는 것은 함수 파라미터를 변수에서 객체로 변경한 이유가 기억에 남았다. 초보 입장에서는 이런 부분을 놓치는경우가 많고, 생각조차 안 나는 경우가 많은데 이렇게 사소한 것 까지도 짚어주시면서 강의를 진행해주시니 더 꼼꼼하게 코드를 작성할 수 있던 거 같다. 미션https://devhan.tistory.com/318어노테이션에 관한 미션이었다.어노테이션을 단순히 쓰라해서 사용하기만 했는데 어노테이션의 역할이 한 개만 있는 것이 아니라 목적에 따른 다양한 종류의 어노테이션이 있다는 걸 알게되었다!강사님의 코멘트어노테이션이 '마법' 같은 일을 해주기 위해서는 리플렉션이라는 기술이 사용된다.리플렉션은 라이브러리나 프레임워크를 개발할 때 간혹 사용되는 기술로, 코드를 직접적으로 호출하지 않고 코드를 제어하는 기술이다.   Day3 02/20 첫 HTTP API 개발 (6~10강) Day3에서는 GET API 이외에 POST API 개발, User 생성 API 개발, User 조회 API 개발, MySQL 사용에 대해서 공부했다.이번에도 기초적인 부분을 다루었기 때문에 딱히 어려운 것은 없었다. 강의를 따라가면서 느낀 건 API 스펙을 정하는 부분이 아주 좋았다! 다른 강의에서는 API 스펙을 정하는 부분이 없이 그냥 말로만 진행하는 강의도 다수 있었는데 이 강의에서는 미리 API 스펙을 알려주니 스펙을 보고 먼저 개발해본 다음에 강의를 들으면서 고치거나 할 수 있어서 좋았다. 미션https://devhan.tistory.com/319여태 했던 미션 중에 제일 오래 걸린 미션이 아닌가 싶다.. 왜냐면 미션 하는 중에 에러가 발생했기 때문!에러 내용은 @RequestBody 사용 시 해당 DTO 생성자에 파라미터가 한 개만 존재하는 생성자가 있고, 기본 생성자가 없어서 발생하는 에러였다.해결 방법은 @JsonCreator를 기존 생성자 메서드에 붙여주거나, 기본 생성자를 만들어주면 된다.강사님의 코멘트1번 - 본인이라면 DTO 쪽에 사칙 연산 기능을 넣었을 것이다. Service 계층의 코드를 깔끔하게 만들기 위해서는 일부 계산 로직을 DTO 쪽으로 넣는 방법을 사용할 수 있다.2번 - LocalDate를 사용! query parameter가 1개라서 바로 LocalDate를 사용해서 요청을 받을 것 같다.3번 - List를 받아보도록 연습! POST API + List 필드가 있는 DTO를 사용하면 쉽게 해결할 수 있다.  Day4 02/21 기본적인 데이터베이스 사용법 (11~13강)이번 강의에서는 MySQL에서 DDL, DML을 이용해 테이블을 생성 및 삭제, 데이터의 CRUD, Spring Boot에서 MySQL 연동을 해봤다. 이번 강의에서는 에러가 발생했다! MySQL 설정 시 발생하는 에러였는데 간단한 구글링을 통해 빠르게 해결할 수 있었다. (MySQL 연동 오류) 기본적인 SQL 문법을 간단하게 훑어 넘어가는 식으로 강의가 진행됐다. 기초가 없었으면 약간 따라가기 힘들었을 것 같기도 하다!그리고 User 테이블을 생성하고 Java 코드를 메모리에 저장하는 방식에서 데이터베이스(MySQL)에 저장하는 방식으로 변경하도록 코딩했다. 이번 강의에서 람다가 처음으로 나왔는데 람다에 대해서 따로 공부해본 적이 없어서 생소하게만 다가왔다. 이번에 람다를 보면서 OT때 강사님이 얘기했던 모던자바 인 액션 책을 꼭 공부해봐야겠다고 생각했다..! 미션https://devhan.tistory.com/320 익명 클래스와 람다에 대해 알아보는 시간이었다.이번 미션을 하면서 하루라도 빨리 모던자바 인 액션을 읽어야겠다고 생각해 책을 얼른 구매했다. Day5 02/22 데이터베이스를 사용해 만드는 API (14~16강)이번 강의에서는 JdbcTemplate을 사용한 API 개발을 구현하기 위해 기존에 있던 코드들을 변경하는 강의 내용이었다.User 업데이트, 삭제 부분을 코딩하는거였는데 14강에서는 단순히 변경만 했고 15강에서는 예외 상황을 대비해 예외 코드를 추가했다! 이 코드가 제일 신기했는데, 결과가 하나라도 있으면 0을 반환하게하는 코드이다. 그리고 최종적으로 0은 List로 반환된다.결과가 0건이면 빈 List가 반환된다! 미션https://devhan.tistory.com/321이번엔 Fruit 테이블을 생성하고, 요구사항에 맞는 API들을 개발하는 미션이었다.제일 고민이었던 건 판매 여부의 컬럼명과 데이터를 0과 1로 할지 아니면 Enum을 사용해서 String으로 저장할지 고민했는데 상태값이 두 개밖에 없어서 그냥 0과 1을 사용했다.강사님 코멘트select * from table을 사용하고 덧셈을 하는 경우는 데이터베이스에서 서버로 네트워크를 타고 모든 데이터가 넘어온 이후에 서버에서 직접 덧셈 -> 네트워크 대역폭도 많이 잡아 먹고 서버의 연산 비용도 들어감.반면 sum()을 사용하면 합산 결과만 네트워크를 타고 이동하며, 서버는 그 결과를 DTO로 감싸 전송만 하면 되기에 네트워크 및 연산 비용이 훨씬 저렴하다.이런 다양한 방법을 비교할 수 있으려면 1) 일차적으로는 방법들을 알아야하고 (지식의 넓이) 2) 다음으로는 각 방법의 매커니즘을 이해해야 함(지식의 깊이)Day6 02/23 클린코드의 개념과 첫 리팩토링 (17~18강)이번 강의에서는 좋은 코드(Clean Code)의 개념과 기존에 작성했던 코드를 Layered Architecture로 변경하는 작업을 했다.클린 코드는 아직 읽어보지 않았지만 워낙 유명한 책이라 강의에서 만난게 마치 오래전에 알던 친구를 만난 것처럼 재밌었다! 이 기회에 또 읽어봐야할 책이 하나 더 늘었다..!클린 코드에서 가장 기억에 남았던 건 유명 회사 앱이 클린 코드로 코드를 작성하지 않아 점차 망해가는 얘기였다. 그런 얘기가 떠돌아다닐 정도로 코드의 깔끔함은 앞으로의 유지보수에 있어 많은 부분에서 좋은 효과를 줄 수 있다는 걸 배웠다!클린 코드 얘기는 너무 많이 들었지만 어떻게 해야 깔끔하고 좋은 코드인지 가늠하기는 어려웠다. 나는 솔루션 회사에 재직해서 spring boot를 실무에서 쓸 일이 없어서 더욱 가늠이 안 갔던 거 같다. 이번 강의를 통해 조금이나마 클린 코드로 가는 틀을 잡을 수 있어서 좋았다!그리고 또 Layered Architecture란 이름을 알게되었다. Controller, Service, Repository로 구성된 애플리케이션은 여태 수도 없이 보았던 거 같은데 이런 명칭이 있는지는 처음 알았다. 대부분 그냥 MVC 패턴이라하며 갑자기 뭉뚱그려 넘어가서 몰랐었던 거 같다.  미션https://devhan.tistory.com/322작성된 주사위 놀이 코드에 클린 코드를 적용해 리팩토링해보는 미션이었다.제일 고민됐던 것은 Dice를 클래스로 따로 뺄지 말지였다.뭔가 빼면 과하게 빼는 거 같기도 하고,,? Main 메서드에 너무 아무것도 없는 거 같아 뭔가 심심해보이기도 했다.그리고 그 다음으로 고민했던 건 한 걸음 더! 내용이었다.주사위의 범위가 달라지더라도 코드를 적게 수정할 수 있도록 하는 거였는데 사용자에게 주사위 면체의 정보를 입력받을까 하다가 그런 얘기는 나와있지 않아서 그냥 Dice 클래스에 면체와 관련된 필드와 생성자를 추가해주었다..!마지막 1주차 느낀점 정리나는 되게 무언가를 대충 아는 정도였던 거 같다.하루빨리 자바8과 관련된 책을 읽고 지식을 습득해야 할 것 같다. (람다 관련 응용이 아예 안 되는 중이다.)클린 코드의 책도 읽고 클린 코드의 감을 잡아보도록 해야겠다.직장인이라 시간적 여유가 매우 부족해서 아쉬웠다. 저번주 주말에 미리미리 진도를 안빼놨었으면 진작에 수료 기준에 벗어날 뻔했다..! 직장인이니 남들보다 더 미리미리 진도를 나가야겠다. 이번주에만 글쎄 야근을 3일이나 해서 죽는 줄 알았다...생각보다 내가 강의를 잘 따라가고 있는 거 같다. 뭐 실력적으로 잘은 모르겠지만 그래도 꾸준히 놓치지 않고 하려는 모습이 약간은 기특해보일정도! 앞으로도 놓치지말고 꾸준히해서 이번 스터디를 완주했으면 좋겠다!   

백엔드인프런워밍업클럽스터디최태현자바와스프링부트로생애최초서버만들기SpringBootbackend

유진

4주차 발자국 | 인프런 워밍업 클럽 2기 - 백엔드

인프런 워밍업 클럽 2기입문자를 위한 Spring Boot with Kotlin(https://inf.run/bXQQQ) 강의를 듣고 작성하였습니다Spring SecuritySpring Security는 Spring Boot 애플리케이션에 보안 기능을 손쉽게 통합할 수 있는 프레임워크입니다. 인증(Authentication)과 권한(Authorization) 관리 기능을 제공하여 애플리케이션을 보호하는 데 사용되며, OAuth2, JWT 같은 다양한 보안 프로토콜도 지원합니다.dependencies { implementation("org.springframework.boot:spring-boot-starter-security") }@Configuration class SecurityConfiguration { @Bean fun filterChain(httpSecurity: HttpSecurity): SecurityFilterChain? { return httpSecurity .authorizeHttpRequests { authorizeHttpRequests -> authorizeHttpRequests .requestMatchers(AntPathRequestMatcher("/**")).authenticated() .anyRequest().permitAll() }.csrf { csrf -> csrf.disable() }.headers { headers -> headers.addHeaderWriter(XFrameOptionsHeaderWriter(XFrameOptionsHeaderWriter.XFrameOptionsMode.SAMEORIGIN)) }.formLogin { formLogin -> formLogin.defaultSuccessUrl("/") }.logout { logout -> logout.logoutRequestMatcher(AntPathRequestMatcher("/logout")) .logoutSuccessUrl("/") }.build() } } /* * NestJS에서는 strategy, Guard 를 사용하여 인증/인가처리를 구현합니다. * strategy 에서는 JWT, oauth 등의 보안 프로토콜을 정의하고 적용할 수 있습니다. * Guard를 정의하고 개별 request 위에 데코레이터로 적용할 수 있습니다 (global 적용도 가능) */ password encodehttps://velog.io/@glencode/Spring-Security-Crypto를-사용한-비밀번호-암호화시큐리티에 관한 강의를 아직 듣지 않았을 때, 패스워드 암호화를 해야하는 요구사항이 있어서 적용해보았던 내용을 기록합니다.dependencies { implementation("org.springframework.security:spring-security-crypto") }@Configuration class AuthConfig { @Bean fun passwordEncoder(): PasswordEncoder { return BCryptPasswordEncoder() } }의존성을 추가하고 config 를 정의합니다@Service class UserService( private val userRepository: UserRepository, private val passwordEncoder: PasswordEncoder, // and so on.. ) {...}/* * dto.password는 사용자로부터 입력받은 password * user.password는 DB에 encode 하여 저장된 password */ // encode val encodedPassword = passwordEncoder.encode(dto.password) // compare if(!passwordEncoder.matches(dto.password, user.password)) { throw BadRequestException("비밀번호가 틀렸습니다.") }passwordEncoder 를 주입하고 위 매서드를 사용하여 활용할 수 있습니다. /* * nodejs 에서는 bcrypt를 사용하여 구현할 수 있습니다. * const bcrypt = require('bcrypt'); */ // encode const encodedPassword = await bcrypt.hash(password, 10); // salt = 10 // compare if (!(await bcrypt.compare(password, user.password))) { throw new BadRequestException("비밀번호가 틀렸습니다.") } ControllerAdvice@RestControllerAdvice는 @ControllerAdvice와 @ResponseBody의 기능을 결합한 어노테이션으로, REST API에서 예외를 처리할 때 주로 사용됩니다.모든 컨트롤러에 대해 JSON이나 XML과 같은 형태로 일관된 응답을 반환할 수 있습니다.@ControllerAdvice는 Spring MVC에서 예외 처리, 데이터 바인딩, 모델 객체의 변환 등을 전역적으로 관리할 수 있게 도와주는 어노테이션입니다.서버 내부에서 입력 오류에 대한 경우를 전부 BadRequestException 으로 사용하고 message 를 다양하게 주고 있었는데, 실제로 에러가 발생했을 때 message가 오지 않아서 몹시 불편함을 느꼈습니다.직접 입력한 메시지를 응답에 뿌려주기 위해 검색 후에 아래와 같은 GlobalExceptionHandler 를 구현하였습니다.@RestControllerAdvice class GlobalExceptionHandler { @ExceptionHandler(BadRequestException::class) fun handleBadRequest(ex: BadRequestException): ResponseEntity<Map<String, String>> { val errorResponse = mapOf( "timestamp" to LocalDateTime.now().toString(), "status" to HttpStatus.BAD_REQUEST.value().toString(), "error" to "Bad Request", "message" to (ex.message ?: "잘못된 요청입니다."), ) return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse) } }# 에러 응답 예시 { "timestamp": "2024-10-23T04:22:59.959124", "status": "400", "error": "Bad Request", "message": "먼저 입실해주세요" } /* NestJS ExceptionFilter * 위와 동일한 작업을 하는 코드 */ @Catch(BadRequestException) export class GlobalExceptionFilter implements ExceptionFilter { catch(exception: BadRequestException, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse<Response>(); const message = exception.getResponse() as string; const errorResponse = { timestamp: new Date().toISOString(), status: HttpStatus.BAD_REQUEST, error: 'Bad Request', message: message || '잘못된 요청입니다.', }; response.status(HttpStatus.BAD_REQUEST).json(errorResponse); } } 작은 회고처음의 결심과 다르게, 강의 일정을 따라가는게 쉽지않았습니다. (게으르기 때문일까요~,,) 그래도 계속 하다보니 아주 조금...? 스프링에 대해 알아가는 느낌이 들어 정말 재밌었습니다. 꾸준히 노력해서, 프레임워크 상관없이 능숙하게 작업할 수 있는 백엔드 개발자가 되겠습니다.프로젝트에 아직 @TODO 가 많은데, 시작한 프로젝트는 돌아오는 주까지 열심히 해서 잘 마무리하고 싶습니다. 학부생 때가 HTML의 마지막이라, 타임리프 작업이 가장 오래걸렸습니다... (사실 아직도 끝나지 않았습니다)원래 쓰던 프레임워크와 비교해가며 이해하고 공부하는데, 이게 도움이 되었는지 아니었는지는 아직 잘 모르겠습니다. 아마 더 많이 사용해보는 시간이 필요할 거 같습니다. 공부법이든, 코딩 습관이든, 나만의 Best Practice 를 찾아가는 과정은 참 어려운거 같아요. 이번에 워밍업클럽을 통해 (!오랜만에!) 완강도 하고, 프로젝트도 하고, 강사님과 컨택할 수 있는 시간도 가지게 되어 정말 좋았습니다. + 온라인 세션에서 받은 이력서 피드백이 정말 많은 도움이 되었습니다. 이 자리를 빌려 감사의 마음을 전해드립니다 🙂다음번에도 이런 기회가 온다면 다른 강의로 신청해보려고 합니다. 이 과정을 기획하고 관리하신 인프런 운영자님과, a-z까지 한 과정에 깔끔하게 담아내신 강사님 정말 고생많으셨습니다! 수료식에서 보아요 ( •͈૦•͈ )

backend

유진

Node.js 개발자의 코-프링 적응기(2) | 인프런 워밍업 클럽 2기 - 백엔드

인프런 워밍업 클럽 2기입문자를 위한 Spring Boot with Kotlin(https://inf.run/bXQQQ) 강의를 듣고 작성하였습니다. h2자바로 구현된 인 메모리 DB 입니다. 애플리케이션이 종료되면 모든 메모리가 삭제됩니다.(휘발성) 프로젝트 내부에 임베드 해서 브라우저를 통해 매니징을 할 수 있다는 점이 특이했습니다. 겪은 오류 - user 테이블이 생기지 않음예전에 회사에서 user 테이블에 대해 데이터베이스를 명시하지 않아 오류가 발생한 적이 있었는데, 비슷한 상황인거 같아, 테이블 이름을 명시하였습니다.https://velog.io/@readnthink/DataJpaTest사용시-user-table-예약어-에러엔티티 정의 어노테이션@Table 와 @Entity테이블은 물리적인 정보, 엔티티는 논리적인 정보를 정의하는 걸까? 싶었는데, 아니었던 것 같습니다. 아예 목적이 좀 다른 느낌..?@Entity is useful with model classes to denote that this is the entity or table@Table is used to provide any specific name to your table if you want to provide any different namehttps://stackoverflow.com/questions/18732646/name-attribute-in-entity-and-tablehttps://www.inflearn.com/community/questions/75556 엔티티랑 테이블 어노테이션 내부에 들어가도 자세하게 테이블 옵션을 정의한다기보다는 느낌보다는 정말 bean임을 명시하기 위한 식별자라고 생각이 들었습니다. // Sequelize entity 정의 예시 @Table({ tableName: 'charge', timestamps: true, paranoid: true, createdAt: 'created_at', deletedAt: 'deleted_at', }) export class ChargeEntity extends Model<ChargeAttributes, ChargeCreationAttributes> implements ChargeAttributes {..} /* * node.js 의 Sequelize 라는 ORM에서는 @Table 에 이렇게 다양한 옵션이 존재해서 이런 차이가 있구나~~ 했었습니다. * 개인적으로는 이렇게 테이블에 옵션 때려박아두는 것 보다는 어노테이션(=데코레이터)을 여러개 사용하는 것이 낫다고 생각했습니다 */  @Id 와 @GeneratedValuehttps://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/idhttps://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/generatedvalue@Id @GeneratedValue(strategy = GenerationType.IDENTITY) // mysql auto_increment @Column(name = "report_id") /* column mapping */ var id: Long? = null /* spring에서 null로 보내면, DB에서 auto_increment */둘 다 엔티티 정의에서 기본키를 정의할 때 사용합니다. @Id는 말 그대로 기본키라는 것을 식별하기 위해 사용합니다. 함께 사용하는 GeneratedValue는, 기본키에 대한 생성 전략을 정의합니다. (전략 타입은 아래 표)https://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/generationtype이번 수업에서는 db 에 기본키 생성을 위임하는 GenerationType.IDENTITY 를 사용하였습니다. // Sequelize PK 정의 예시 @Column({ field: 'charge_id', primaryKey: true, autoIncrement: true, type: DataType.INTEGER, }) id: number; /* * 여긴 없지만 @PrimaryKey 라는 데코레이터가 존재합니다. @Id와 같은 역할을 할 듯,, * autoIncrement: true, 외에 다른 옵션이 없었는데, @GeneratedValue 는 컨트롤할수 있는 범위가 넓은 것 같아 좋았습니다. */ @Columnhttps://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/column@Column(name = "phone", nullable = false) /* column mapping */ var phone: String = phonename 은 말 그대로 물리 컬럼명을 이어주는 역할을 합니다. 사실 모든 경우에 대해, @Column을 해줘야 하는 줄 알았는데요, (DB에서 스네이크케이스, spring에서는 카멜케이스 )강의에서 "알아서 바꿔준다" 하고 슥 넘어간 거 같아 궁금해서 찾아보았습니다. By default, Spring Boot configures the physical naming strategy with CamelCaseToUnderscoresNamingStrategyhttps://docs.spring.io/spring-boot/how-to/data-access.html이렇게 스프링 부트에 내장되어 있는 전략에 영향을 받는 것으로? 우선 이해를 해 보았습니다.스프링이 참 딥해서,, 문서같은걸 뒤적거려도 확신이 잘 안서네요 ;ㅁ; nullable 은 default 가 true 이기 때문에 필요한 경우에만 명시해주면 됩니다!맨 위에 링크한 문서에, 각종 옵션들에 대한 default 가 나와있으니 개발할때 참고하면 좋을 것 같습니다.@Enumeratedhttps://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/enumerated@Enumerated(value = EnumType.STRING) var category: ReportType = ReportType.valueOf(category)말 그대로, enum 타입이어야 함을 명시합니다. (옵션은 아래 표) https://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/enumtype연관관계@ManyToManyhttps://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/manytomany다대다(n-m) 관계일 때 사용합니다.n-m 관계의 경우 아래 사진처럼 1-n / n-1 이렇게 분리하는게 약간 >국룰< 입니다.문서에서도 @Jointable 을 사용해 중간 테이블을 지정하라고 되어 있습니다.https://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/jointablemany-to-many는 정말 은근,, 사용할 일이 없었던 전적이 있어서 슥 넘어가겠습니다. @ManyToOne @OneToManyhttps://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/onetomanyhttps://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/manytoone@OneToMany( targetEntity = Post::class, fetch = FetchType.LAZY, cascade = [CascadeType.ALL] ) @JoinColumn(name = "user_id") var post: MutableList<Post> = mutableListOf()일대다 관계를 명시하는 어노테이션입니다. 관계를 맺고 있는 양쪽 테이블에 항상 모두 쓸 필요는 없고, 데이터가 필요한 부분에만 사용합니다. 이런 어노테이션의 경우 @OneToMany 앞(One)에 있는게 나고 타겟이 뒤(Many) 에 합니다.위 같은 코드가 User Entity 클래스 내부에 작성된 내용이라면, User(1) - UserTime(N) 입니다. 개인적으로 ORM의 관계는 요걸 헷갈리지 않는거부터 시작이라고 생각합니다..fetch 는 엔티티에서 항상 연관된 테이블의 정보를 가져올지 아닐지 선택합니다. (N+1 관련해서는 나중에 정리하겠습니다)cascade는 참조 무결성을 위한 키워드입니다. CascadeType.ALL 은 아래 표의 나머지들을 모두 적용하겠다는 뜻입니다.The value cascade=ALL is equivalent to cascade={PERSIST, MERGE, REMOVE, REFRESH, DETACH}.https://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/cascadetype // Sequelize 관계 정의 예시 // user 테이블 @HasMany(() => PostEntity) posts: PostEntity[]; // post 테이블 @BelongsTo(() => UserEntity) user: UserEntity; @OneToOnehttps://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/onetoone@OneToOne( targetEntity = UserTime::class, fetch = FetchType.LAZY, cascade = [CascadeType.ALL] ) @JoinColumn(name = "user_id") lateinit var timeInfo: UserTime일대일 관계를 명시할 때 사용합니다. user와 user가 사용한 시간인 userTime이 1-1 관계를 맺고 있는 경우의 예시입니다.  // Sequelize 관계 정의 예시 // user 테이블 @HasOne(() => UserTimeEntity) userTime: UserTime; // userTime 테이블 @BelongsTo(() => UserEntity) user: UserEntity; @JoinColumnhttps://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/joincolumn조인의 기준? 되는 컬럼을 지정합니다.  프로젝트데이터베이스 관련해서 정의를 추가하였습니다. 근데 이번에 블로그 쓰면서 잘못 작성하고 그런걸 좀 찾아서 다시 해야할거같습니다. ....  

backend

채널톡 아이콘