관리 메뉴

CASSIE'S BLOG

99-2강 스프링 부트 롬복과 MapStruct 사용하기 본문

PROGRAMMING/슈퍼코딩 강의 정리

99-2강 스프링 부트 롬복과 MapStruct 사용하기

ITSCASSIE1107 2024. 3. 5. 16:46

 
dto와 entity는 무조건 다른 클래스로 구현해야한다는데 그게 무슨말이야? dto랑 entity랑 어떤점이 다른건지 이해가 잘 안되는데 설명 좀 해줘봐

DTO와 엔티티(Entity)는 소프트웨어 개발에서 다른 역할을 갖는 두 가지 유형의 클래스입니다.

엔티티(Entity):

엔티티는 일반적으로 데이터베이스의 테이블과 매핑되는 클래스입니다.
데이터베이스에 저장되는 정보를 표현하며, 비즈니스 로직이나 데이터 처리 관련 기능을 포함할 수 있습니다.
엔티티 클래스는 데이터베이스 스키마와 밀접하게 연관되어 있으며, 주로 영속성(데이터베이스 저장)과 관련된 작업을 담당합니다.

DTO(Data Transfer Object):

DTO는 데이터를 전송하는 데 사용되는 객체입니다.
주로 클라이언트와 서버 간의 데이터 교환에 사용됩니다.
DTO는 데이터를 담는 용도로만 사용되며, 비즈니스 로직을 갖지 않습니다.
일반적으로 DTO는 특정 요청 또는 응답을 위해 클라이언트와 서버 간에 전송되는 데이터를 캡슐화하는 데 사용됩니다.
일반적으로 엔티티는 데이터베이스와 직접적으로 관련이 있으므로 데이터베이스와 관련된 작업을 수행합니다. 반면에 DTO는 데이터 전송을 위해 사용되며, 비즈니스 로직을 갖지 않기 때문에 순수한 데이터 객체로 간주됩니다.

따라서, DTO와 엔티티는 역할이 다르기 때문에 두 가지 기능을 분리하여 다른 클래스로 구현하는 것이 일반적으로 권장됩니다. 이를 통해 코드의 유지 보수성이 높아지고, 의도치 않은 버그가 발생할 가능성이 줄어듭니다.


엔티티를 가지고 dto를 통해서 데이터를 전송한다 이렇게 생각하면 되는거지?

맞습니다. 일반적으로 엔티티는 데이터베이스와 관련된 비즈니스 로직을 포함하고 있으며, 데이터베이스와의 상호 작용을 담당합니다. 반면에 DTO는 엔티티로부터 필요한 데이터를 추출하여 전송할 목적으로 사용됩니다.

DTO를 사용하여 데이터를 전송하는 이유는 다음과 같습니다:

데이터 전송: 클라이언트와 서버 간의 효율적인 데이터 교환을 위해 사용됩니다. DTO는 오직 데이터 전송을 위한 목적으로 설계되었기 때문에 불필요한 정보를 제거하고 필요한 정보만을 포함시킵니다.

보안: DTO를 사용하면 클라이언트에게 엔티티와 관련된 민감한 정보를 노출하지 않을 수 있습니다. 엔티티에는 데이터베이스와 관련된 다양한 정보가 포함될 수 있지만, DTO를 통해 필요한 정보만을 전송할 수 있습니다.

느슨한 결합: DTO를 사용하면 클라이언트와 서버 간의 결합도를 낮출 수 있습니다. 클라이언트가 엔티티의 내부 구조에 의존하지 않고, DTO의 구조에만 의존함으로써 서버 측 코드를 변경할 때 클라이언트 코드에 영향을 덜 줍니다.

따라서, 엔티티로부터 데이터를 추출하여 DTO를 통해 전송하는 것은 일반적인 설계 방식이며, 이를 통해 시스템의 유연성과 유지 보수성을 높일 수 있습니다.



MapStuct:

Dto랑 Entity연결해주는게 Mapstruct다 이렇게 알고 있으면 되지?

맞습니다! MapStruct는 DTO와 엔티티 사이의 매핑을 자동화하여 개발자가 매핑 코드를 작성하는 노력을 줄여줍니다. 이를 통해 코드의 중복을 피하고 유지보수성을 향상시킬 수 있습니다. 따라서 보다 효율적으로 DTO와 엔티티 간의 데이터 전달 및 변환을 관리할 수 있습니다.


사용법: 
인스턴스를 싱글톤패턴으로 하나 만들고 mapping 으로 연결해주는 게 사용법이다.
 

 

 
qualifiedByName이라는 옵션을 통해서 Custrom함수를 실행할 수 있다고함. 
 

 
보통 변경될 때 Mapstruct를 쓸 수 있다.
 
여기서 이거랑 밑에 부분이랑 똑같은 결과

public List<Item> findAllItem() {
List<ItemEntity> itemEntities = electronicStoreRepository.findAllItems();
return itemEntities.stream().map(Item::new).collect(Collectors.toList());
}

 

public List<Item> findAllItem() {
List<ItemEntity> itemEntities = electronicStoreRepository.findAllItems();
return itemEntities.stream().map((itemEntity -> new Item(itemEntity))).collect(Collectors.toList());
}

 
build.gradle 파일 가서 
//MapStruct
implementation 'org.mapstruct:mapstruct:1.5.3.Final'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.3.Final'
 

 
service하위에 패키지 만들고 ItemEntity를 변환하기 쉽게 하는 Mapper를 구현할 예정
service하위에 패키지 하위에 ItemMapper 인터페이스 만들어줌 

package com.github.supercoding.service.mapper;

public interface ItemMapper {
}

 

 
Spec의 객체안에 따로 있잖아 cpu, capacity 그런것들은 Mapstruct가 잡아내지 못할것이라고함. 
 
before

public List<Item> findAllItem() {
List<ItemEntity> itemEntities = electronicStoreRepository.findAllItems();
return itemEntities.stream().map((itemEntity -> new Item(itemEntity))).collect(Collectors.toList());
}

 
after

public List<Item> findAllItem() {
List<ItemEntity> itemEntities = electronicStoreRepository.findAllItems();
return itemEntities.stream().map(ItemMapper.INSTANCE::itemEntityToItem).collect(Collectors.toList());
}

 
이렇게 바꾸고 실행이 되는지 확인해본다고함. 
 
 


java.lang.NullPointerException: Cannot invoke "com.github.supercoding.service.ElectronicStoreItemService.findAllItem()" because "this.electonicStoreItemService" is null
at cohttp://m.github.supercoding.web.controller.ElectronicStoreController.findAllItem(ElectronicStoreController.java:32) ~[main/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.29.jar:5.3.29]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.29.jar:5.3.29]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.29.jar:5.3.29]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.29.jar:5.3.29]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.29.jar:5.3.29]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.29.jar:5.3.29]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1072) ~[spring-webmvc-5.3.29.jar:5.3.29]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:965) ~[spring-webmvc-5.3.29.jar:5.3.29]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.29.jar:5.3.29]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.29.jar:5.3.29]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:529) ~[tomcat-embed-core-9.0.78.jar:4.0.FR]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.29.jar:5.3.29]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:623) ~[tomcat-embed-core-9.0.78.jar:4.0.FR]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:209) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[tomcat-embed-websocket-9.0.78.jar:9.0.78]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.29.jar:5.3.29]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.29.jar:5.3.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.29.jar:5.3.29]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.29.jar:5.3.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.29.jar:5.3.29]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.29.jar:5.3.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:481) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:926) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1791) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at java.base/java.lang.Thread.run(Thread.java:840) ~[na:na]

2024-03-06 17:06:25.388 ERROR 7368 --- [nio-9090-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException: Cannot invoke "com.github.supercoding.service.ElectronicStoreItemService.findAllItem()" because "this.electonicStoreItemService" is null] with root cause

java.lang.NullPointerException: Cannot invoke "com.github.supercoding.service.ElectronicStoreItemService.findAllItem()" because "this.electonicStoreItemService" is null
at cohttp://m.github.supercoding.web.controller.ElectronicStoreController.findAllItem(ElectronicStoreController.java:32) ~[main/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.29.jar:5.3.29]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.29.jar:5.3.29]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.29.jar:5.3.29]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.29.jar:5.3.29]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.29.jar:5.3.29]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.29.jar:5.3.29]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1072) ~[spring-webmvc-5.3.29.jar:5.3.29]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:965) ~[spring-webmvc-5.3.29.jar:5.3.29]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.29.jar:5.3.29]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.29.jar:5.3.29]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:529) ~[tomcat-embed-core-9.0.78.jar:4.0.FR]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.29.jar:5.3.29]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:623) ~[tomcat-embed-core-9.0.78.jar:4.0.FR]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:209) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[tomcat-embed-websocket-9.0.78.jar:9.0.78]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.29.jar:5.3.29]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.29.jar:5.3.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.29.jar:5.3.29]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.29.jar:5.3.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.29.jar:5.3.29]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.29.jar:5.3.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:481) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:926) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1791) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at java.base/java.lang.Thread.run(Thread.java:840) ~[na:na]

 

 
 
이 에러는 주로 Spring 프레임워크에서 발생하는 것으로, 해당 에러 메시지에서 "this.electronicStoreItemService"가 null이기 때문에 "com.github.supercoding.service.ElectronicStoreItemService.findAllItem()" 메서드를 호출할 수 없다고 나와있습니다.
이 에러가 발생하는 이유는 Spring이 해당 필드를 주입하지 못했기 때문입니다. Spring은 기본적으로 @Autowired 애노테이션을 사용하여 의존성을 주입하거나 생성자 주입을 통해 의존성을 주입합니다.
그러나 이 경우에는 생성자가 없고, @requiredargsconstructor 애노테이션이 사용되었는데도 필드에 final 키워드가 없어서 Spring이 해당 필드를 주입하지 못했을 가능성이 있습니다.
final 키워드가 없는 경우에는 Spring이 필드를 주입하지 못할 수 있으며, 이로 인해 NullPointerException이 발생할 수 있습니다. 하지만 final 키워드를 사용하여 필드를 선언하면, Spring이 해당 필드를 주입하므로 NullPointerException이 발생하지 않습니다.
따라서 final 키워드를 사용하여 필드를 선언하고, @requiredargsconstructor 애노테이션을 사용하여 생성자를 생성하면 Spring이 필드를 주입하므로 이러한 에러를 방지할 수 있습니다.
 
 

 
source는 itemEntity 기준으로 적어준다. 
 

package com.github.supercoding.service.mapper;

import com.github.supercoding.repository.items.ItemEntity;
import com.github.supercoding.web.dto.items.Item;
import com.github.supercoding.web.dto.items.Item;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;

@Mapper
public interface ItemMapper {
// 싱글톤
ItemMapper INSTANCE = Mappers.getMapper(ItemMapper.class);

// 메소드 정의 부분 (Item 클래스 생성자 보면서 참고하면서 ItemEntity가 들어와서 Item만드는 거니까)

Item itemEntityToItem(ItemEntity itemEntity);


}

 
왜 지금 하지도 않았는데 spec 부분이 null이 안 뜨는거지?
 
 
package cohttp://m.github.supercodingspring.service.mapper;

import cohttp://m.github.supercodingspring.repository.items.ItemEntity;
import cohttp://m.github.supercodingspring.web.dto.items.Item;
import cohttp://m.github.supercodingspring.web.dto.items.ItemBody;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;

@Mapper
public interface ItemMapper {

    // 싱글톤
    ItemMapper INSTANCE = Mappers.getMapper(ItemMapper.class);

    // 메소드
    @Mapping(target = "spec.cpu", source = "cpu")
    @Mapping(target = "spec.capacity", source = "capacity")
    Item itemEntityToItem(ItemEntity itemEntity);

    @Mapping(target = "cpu", source = "itemBody.spec.cpu")
    @Mapping(target = "capacity", source = "itemBody.spec.capacity")
    @Mapping(target = "storeId", ignore = true)
    @Mapping(target = "stock", expression = "java(0)")
    ItemEntity idAndItemBodyToItemEntity(Integer id, ItemBody itemBody);
}
 
이 부분 때문에 그런데 그냥 이렇게 놔두기 
 
 
package cohttp://m.github.supercodingspring.web.dto.items;

import cohttp://m.github.supercodingspring.repository.items.ItemEntity;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.Objects;

@Getter
@Setter
@NoArgsConstructor
public class Item {
    private String id;
    private String name;
    private String type;
    private Integer price;
    private Spec spec;
}
 
중간에 하다 넘어감. 
 
굳이 할 필요는 없는 리팩토링 부분이라서 .branch 100 나중에 다시체크해도되고. 넘어가기 

반응형