#service

질문 2
해시태그 없이 키워드만 일치하는 질문은 개수에 포함되지 않아요.

3달 전 · 김현균 님의 질문

클린아키텍처에서 Application 레이어는 꼭 필요할까요?

클린+레이어드 아키텍처를 공부하면서 Usecase와 Facade 같은 Application 레이어에 대해서 처음 알게되었습니다. 처음엔 하나에 모아서 service들을 호출할 수 있네? 좋잖아? 라는 생각이었는데, 실제로 코드를 작성하다보면 단순 서빙만을 하는 경우가 더 많아서 복잡성만 증가하는 느낌을 받은 적이 있습니다. 저는 개인적으로 MSA 에서는 Event로 도메인간 연결이 이뤄지니까 Application 레이어가 오히려 코드 복잡성만 높히지만, Monolithic에서는 유의미하게 동작하는 것 같습니다. 그래서 Application 레이어는 아키텍처에 따라 선택될 수 있지 않을까? 라고 생각이 들더라고요. Application 레이어의 유무가 꽤나 논쟁이 있는 주제라고 들었는데, 여러분은 어떻게 생각하시나요?

개발자

#클린아키텍처

#application레이어

#backend

#msa

#facade

답변 0

댓글 0

조회 107

3달 전 · tiptok 님의 질문

스프링부트 레이어드 아키텍쳐는 어떤 방식을 권장/선호 하나요?예시있습니다!

전형적인 걸로는 1. Controller > Service > ServiceImpl > Dao > DaoImpl(xml 호출) 이러한 방식이 있습니다. 이번에 변경을 위하여 몇가지를 생각해보았는데 2. Controller > Service > ServiceImpl(mapper 호출 + 비즈니스 로직) 3. Controller > Service > ServiceImpl(Dao 호출 + 비즈니스 로직) + Dao(mapper 호출) 이렇게 2개를 생각하고 있습니다 . 2번의 경우는 dao역할과 비즈니스 로직이 전부 serviceImpl에 들어가있다보니 gpt도 권장하지 않는 방식이고 저도 마음에 잘 들진 않는데 파일이나 소스의 양이 줄어든다는 장점이 있긴 해보입니다. 솔직히 Controller > Service > ServiceImpl > Dao > DaoImpl 처럼 극단적으로 계층을 나누는 것도 생각해보았는데 이렇게 극단적인 것보다는 3번이 나아보이긴 합니다. 다들 몇 번을 권장하나요? 참고로 개인프로젝트입니다! 기존엔 Controller > Service > ServiceImpl > Dao > DaoImpl(sqlSession.~ 호출) 방식을 사용했습니다. 안정성을 위하여 mapper 방식으로 변경할 겸 구조도 변경하는 게 나아보여 질문드립니다! 한가지더, Dao나 DaoImpl 명칭을 Repository.java, RepositoryImpl.java 로 변경하는 거에 대해선 어떻게 생각하시나요?

개발자

#스프링부트

#구조

#레이어드-아키텍처

답변 0

댓글 0

조회 103

3달 전 · nexter 님의 새로운 답변

스프링부트 코드 작성

연합동아리에서 활동 중인 대학생입니다. 프로젝트에서 스프링부트를 사용하는 백엔드를 맡고 있는데, 코드를 작성하는 법을 아직 모르겠습니다. 개념은 알겠으나 말그대로 로직을 직접 작성할때면 감이 너무 안오는데.... 공부를 어떻게 하면 좋을까요? 당장은 gpt한테 답변받은 코드를 위주로 쓰다가 오류가 생기면 그때그때 수정하고 있습니다ㅜ 장기적으로도 이게 좋은 방법은 아니라는걸 알겠는데 Service, Controller에서 로직을 써내려가기가 너무 추상적인 느낌이라 잘 모르겠습니다...ㅜㅜ 너무 답답하네요 스스로도

개발자

#springboot

#스프링부트

#백엔드

#웹개발

#공부법

답변 7

댓글 0

추천해요 6

보충이 필요해요 2

조회 2,202

9달 전 · 정지환 님의 질문 업데이트

IT병특 신입 지원 시 유관경력

중소기업에서 22년도 07월 ~ 24년도 9월 병특으로 근무했고, 현재 소집 해제되었으나 사측에서 조건을 파격적으로 올려주어서 계속 재직중인 상태입니다. 제 현재 직무는 모바일 쪽인데 백엔드 신입으로의 전향을 희망합니다. https://recruit.navercorp.com/micro/teamnaver2024/service 위 네이버 신입 공채를 보면 유관 경력 1년 이상은 지원 불가인데 IT 병특 경력이 엄청 애매하네요. 모바일로 근무했으니 백엔드 지원 시 유관 경력이 없다고 봐도 괜찮을까요?

개발자

#이직

#신입

#병역특례

#중고신입

#유관경력

답변 0

댓글 0

조회 56

일 년 전 · 유길종 님의 답변 업데이트

data fetching은 어디서 하는 게 좋은 것일까요?

안녕하세요. 저는 프론트엔드 개발자가 되기 위해 공부중인 취준생입니다. 피드백을 적극 환영하기에 많은 피드백 혹은 의견을 많이 남겨주시면 감사하겠습니다. 저는 데이터 페칭을 어디서 하는 게 좋을지 고민 중이라 글을 남깁니다. 아래와 같이 3개로 글을 구성해봤습니다. 1. 현재 개발상황 2. 현재 저의 데이터 페칭 위치 3. 궁금한 점 1. 현재 개발상황 저는 개인 프로젝트로 Next.js와 React Query를 사용하여 개발하고 있습니다. 현재 Next.js의 App Router를 사용 중이며, 프로젝트 구조는 아래와 같습니다. app: page.tsx, layout.tsx components: 최소 2번 반복 사용되는 재사용 가능한 컴포넌트 container: 일반적인 컴포넌트 (조합 등) hook, service 등 2. 현재 저의 데이터 페칭 위치 현재 데이터 페칭은 최상단의 app -> page.tsx에서 수행하고 있으며, 자식 컴포넌트에는 데이터를 props로 전달하고 있습니다. 이러한 이유는 prop drilling이 발생하더라도 데이터 페칭을 한 곳에서 처리하면 코드 이해가 쉬울 것 같아서입니다. 현재로서는 전역 상태 라이브러리를 사용하지 않아 최대 4단계까지 prop drilling이 발생하고 있지만, 전역 상태 라이브러리를 도입하면 prop drilling 문제는 해결될 것으로 생각하고 있습니다. 추가적으로 현재 이렇게 구현하면서 data fetch할때 필요한 query값들도 최상단에서 관리해야하는 불편함이 있었습니다. -> 최상단에서 관리해야 하는 상태값이 늘어남 3. 궁금한 점 3-1. 아래의 2가지 data fetching 방법 중 어느것이 적절한지? 합리적인지 의견이 궁금합니다. - 최상단에서 Fetching - 장점 : 한 곳에서 Fetching하기에 코드 일관성, 가독성, 코드를 이해하는데 좋다고 생각 - 단점 : prop drilling, 추가적인 전역 상태 관리 해야한다고 생각 - 필요한 컴포넌트에서 Fetching - 장점 : 필요한 컴포넌트에서 fetching 하기에 prop driling과 같은 불필요한 코드 작성 할 필요 x - 단점 : 어떤 컴포넌트에서 fetching 했는지 파악하기 힘들어짐 3-2. 현재 최상단에서 모든 데이터 페칭을 하고 props로 전달하는 방식 vs 필요한 컴포넌트에서 데이터 페칭을 하는 두 가지 방식 중 어느 것이 더 많이 사용되는 패턴인지 궁금합니다. 3-3. React Query는 서버 상태 관리, 캐싱, Optimistic Update와 같은 기능을 위해 도입했습니다. 그러나 prop drilling을 해결하기 위해 React Query에서 가져온 서버 데이터를 전역 상태 라이브러리에 담게 되면 서버와 클라이언트 상태를 구분하는 의미가 없어지는 것 같다는 생각이 듭니다. 제가 잘못 사용하고 있는것인지 궁금합니다.

개발자

#next.js

#redux

#react-query

#frontend

#신입

답변 3

댓글 0

조회 181

일 년 전 · 이양일 님의 답변 업데이트

JPA를 사용해서 부모(1)와 자식 목록(N)을 가져올 때 쿼리를 2번 발생시키나요?

안녕하세요. JPA와 QueryDSL을 사용하여 개발을 하고 있는 홍길동입니다. 예를 들어 상품 테이블(부모)과 옵션 테이블(자식 목록) 정보를 조회하는 service에서 쿼리를 보통 2번 발생시키는지 궁금합니다. 저는 부모 조회 쿼리 1번, 자식 목록 조회 쿼리 1번 총 2번의 쿼리를 발생시키고 있습니다. 다른분들은 현업에서 부모와 자식의 데이터를 가져와야 하는 경우 쿼리를 몇번 발생시키는지 궁금합니다.

개발자

#jpa

#자식데이터-조회

답변 1

댓글 0

추천해요 1

조회 520

일 년 전 · 익명 님의 질문

Top 10 Best Rated - Lists of the Best Products, Services and Reviews

Top 10 Best Rated is a comparison platform that brings you useful top 10 lists worldwide covering a wide variety of products and services that can help you save time and money. Visit now https://top10bestrated.com

개발자

#top-10

#best

#rated

답변 0

댓글 0

보충이 필요해요 2

조회 16

일 년 전 · 포크코딩 님의 새로운 답변

Python cloud service

Python으로 작성된 ai 분석 api를 Cloud에 올려서 serverless로 하고 싶습니다 요청 처리에 대해 짧게는 10초 길게는 몇 분동안 (영상 길이에 따라) 분석을 수행하는데, 추천해줄만한 것들이 무엇이 있는지 질문드립니다

개발자

#python

#cloud

#aws

#lambda

#ec2

답변 1

댓글 0

조회 36

일 년 전 · 익명 님의 새로운 댓글

springboot 테스트코드 작성 방법

테스트코드에 관해 공부하게되었습니다. 정해진 답은 없는 것 같은데 잘못 이해하고 사용하고 있다는 생각이 들어서 질문 글을 올리게 되었습니다. 선배님들의 도움이필요합니다. 유저와 게시글 entity가 있고 게시글을 생성하는 기능을 controller service repository 로 작성했습니다. 1. 단위테스트를 작성할때 mock을 사용하여 Service.save 메서드에 대해 any()와 같이 저장할 객체와 저장된 객체를 제가 직접 지정하다보니 끼워맞춰서 성공을 받아내는 느낌이 강해서 어떻게 사용해야 하는지 궁금합니다. 2. 여러 글들을 읽어보고 고민해보니 Service.duplicate와 같이 이메일 중복체크와 같은 예외가 발생하는 것은 단위테스트로 작성하고 나머지 즉, crud와 같이 DB를 사용해야하는 기능은 controller 통합테스트를 작성해서 확인해야할 것 같은데 맞는 생각인지 궁금합니다. 3. controller 통합테스트에서 update와 같이 의존성이 많이 엮여있을 때 작성방법이 궁금합니다. 제가 생각한 바는 아래와같은데 어디까지 직접생성해주어야 할까요.. - 사용자를 저장하고 게시글도 저장한다. - 게시글을 읽어와 사용자가 게시글의 작성자인지 확인한다 - 게시글을 수정한다 - 수정된 게시글에서 빈 값은 없는지 등 유효성 검사를 하고 게시글을 저장한다 - 다시 게시글을 읽어와서 정상적으로 수정되었는지 확인한다. 아직 부족한것이 많아 단어사용이나 방식이 정말 바보같을 수 있는 부분 양해부탁드립니다. 긴 글 읽어주셔서 감사드립니다. 마지막으로 혹시 참고할 만한 springboot 테스트 코드나 책 또는 강의가 있다면 알려주시면 좋겠습니다. 정말 감사드립니다.

개발자

#spring-boot

#spring

#spring-data

#testcode

#tdd

답변 1

댓글 1

추천해요 19

보충이 필요해요 1

조회 2,372

일 년 전 · cozy 님의 새로운 답변

스프링부트에서 클린코드 사용 관련 질문

안녕하세요 선생님들 현업에서는 정말 아무 생각없이 사용하고 있는 개발 방식이었는데 클린 코드라는 책을 접하면서 고민이 되는 부분이 하나 있습니다. SpringBoot ServiceImpl 구현 부분에서 만약 로그인 API를 개발한다는 가정하에, 로그인 API 에는 수많은 기능들이 포함될 수 있습니다.(유효성 검증, 비밀번호 5회 연속 시 잠금, 권한에 따른 페이지 이동 기능 등등) 하지만 클린 코드의 원칙 상 '되도록 하나의 메소드는 하나의 기능만을 포함한다.' 라는 원칙에 위배되기 때문에 각각의 기능을 분리하여 작성하는 것이 맞을듯 합니다. 그러나 각각의 수많은 부가기능(이 될수도 있는)들을 만들면 인터페이스와 클래스의 개수도 그만큼 늘어나게 되고 개발에 소요되는 시간도 늘어납니다. 실제로 제가 있었던 SI회사에서는 하나의 큰 기능(로그인 API) 자체를 기준으로 메소드를 만들고 부가 기능들을 모두 하나로 구현하였습니다. SI 특성 상 마감시간 내에 빨리 완성시켜주고 빠지면 땡이기 때문에 이런 것이라 생각되는데 만약 시간적인 압박이 있는 SI개발에서 두 부분중 어떤 원칙을 지키는 것이 효율적인지에 대한 고민이 되는데 길을 좀 알려주시면 감사드리겠습니다.

개발자

#스프링부트

답변 1

댓글 0

추천해요 1

조회 119

일 년 전 · 익명 님의 질문

React Spring 배포과정 중 의문의 404

react + spring boot로 진행하는 프로젝트가 현재 cloudtype이라는 플랫폼으로 배포중에 있습니다. 문제는 정확한 서버주소를 호출하는 것 같음에 불구하고 404 에러가 발생하여 해결하지 못하고 있습니다. 현재, 아래 사진과 같은 로그가 클라이언트, 서버에 각각 발생합니다. 서버에서는 다음과 같이 구성되어있고 @RestController @RequestMapping("/v1/login") @RequiredArgsConstructor @CrossOrigin(origins = "https://web-secondchance-front-bug-1cupyg2klvnmgdft.sel5.cloudtype.app") public class KakaoController { private final KakaoService kakaoService; private final Logger LOGGER = LoggerFactory.getLogger(KakaoController.class); @PostMapping("/kakao-login") public ResponseEntity<UserDto> kakaoLogin(@RequestBody KakaoLoginDto kakaoLoginDto) { String code = kakaoLoginDto.getCode(); LOGGER.info("Get Code from FrontEnd : {}", code); LOGGER.info("Request getAccessToken()"); kakaoLoginDto = kakaoService.getAccessToken(code); String accessToken = kakaoLoginDto.getAccess_token(); LOGGER.info("access_token : {}", accessToken); if(accessToken != null){ UserDto userDto = kakaoService.getUserInfo(accessToken); return ResponseEntity.ok(userDto); } else { return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); } // accessToken이 null임에도 getUserInfo를 부름. // 안부르게 끔 위의 방법을 포함하여 // 1. map에서 true, false를 사용하여 해봄 // 2. getAccessToken을 map객체로 반환하게끔 하여 accessToken이 있으면 true, 없으면 false로 하여 isEmpty 함수로 체크하여 부름 // 위의 두 방법 전부 소용없음. 그냥 getUserInfo를 부름. } @PostMapping("/kakao-logout") public String kakaoLogout(){ return "ok"; } } 현재 리액트에서는 다음과 같이 axios.post로 접근하여 code를 전달합니다. 무엇이 문제일까요?

개발자

#react

#spring-boot

#배포

#404

답변 0

댓글 0

추천해요 1

조회 162

일 년 전 · 디큐 님의 새로운 답변

aws 비용이 RDS에서 너무 많이 나가는데 비용절감 방법이 있을까요?

aws Cost Explorer에서 RDS 비용이 다른 항목에 비해 비용이 많이 나가는데요.. 아래 Amazon Web Services Korea LLC 서비스별 요금 정보에서 보면 "USD 0.120 per hour per vCPU running RDS Extended Support for MySQL 5.7 in Year 1, Year 2 2,972 vCPU-hour USD 356.64" 위의 항목이 제일 많이 나가고 있는데요. * 할당량 * DB 인스턴스 (2/40) 할당된 스토리지 (0.08 TB/100 TB) * 인스턴스 정보 * dev-ds MySQL Community ap-northeast-2a db.t3.small DB 엔진 버전 8.0.36 prod-rds MySQL Community ap-northeast-2a db.t3.medium DB 엔진 버전 8.0.36 사용중인 스토리지 양도 적은데 어떤 이유로 과금이 많이 되는걸까요? aws 전문가님들!~ 답변 부탁드릴게요^^~ * 청구서 상세정보 * "Relational Database Service USD 480.57 Asia Pacific (Seoul) USD 480.57 Amazon Relational Database Service for MySQL Community Edition USD 472.71 USD 0.052 per db.t3.small Single-AZ instance hour (or partial hour) running MySQL 744 Hrs USD 38.69 USD 0.104 per db.t3.medium Single-AZ instance hour (or partial hour) running MySQL 744 Hrs USD 77.38 USD 0.120 per hour per vCPU running RDS Extended Support for MySQL 5.7 in Year 1, Year 2 2,972 vCPU-hour USD 356.64 Amazon Relational Database Service Provisioned Storage USD 7.86 $0.00 per GB-month of provisioned GP2 storage under monthly free tier running MySQL 20 GB-Mo USD 0.00 $0.131 per GB-month of provisioned gp2 storage running MySQL 30 GB-Mo USD 3.93 $0.131 per GB-month of provisioned GP3 storage running MySQL 30 GB-Mo USD 3.93 Elastic Compute Cloud USD 143.00 Asia Pacific (Seoul) USD 143.00 Amazon Elastic Compute Cloud NatGateway USD 43.93 $0.059 per GB Data Processed by NAT Gateways 0.448 GB USD 0.03 $0.059 per NAT Gateway Hour 744 Hrs USD 43.90 Amazon Elastic Compute Cloud running Linux/UNIX USD 79.46 $0.026 per On Demand Linux t3.small Instance Hour 744 Hrs USD 19.34 $0.0288 per On Demand Linux t2.small Instance Hour 744 Hrs USD 21.43 $0.052 per On Demand Linux t3.medium Instance Hour 744 Hrs USD 38.69" 답변 부탁드릴게요. 감사합니다^^!

개발자

#aws

#rds

#과금

#aws-rds

답변 1

댓글 0

조회 532

일 년 전 · 이양일 님의 새로운 답변

스프링부트 ServiceInterface에 요청문 작성

안녕하세요 MSA아키텍처를 적용한 개인프로젝트 진행중에 궁금한 사항이 생겨서 글 작성합니다 회원정보 수정을 한 뒤 수정이 정상적으로 완료되었을 때 클라이언트에 완료되었다는 메세지와 함께 로그아웃 메서드를 실행시키고 싶어서 public interface IUserInfoService { @PostMapping(value = "security/v1/logout") void logout(); } 이렇게 서비스 인터페이스에 작성을 해두고 컨트롤러에서 userInfoService.logout(); 으로 호출하여 실행하는데 권장되는 방법인지, 더 좋은 방법이 있는지 궁금해서 질문드립니다

개발자

#springboot

#java

#spring-security

#msa

답변 1

댓글 0

추천해요 1

조회 338

일 년 전 · 박해인 님의 질문

Streamli app Azure에 배포시.

Python Streamlit으로 앱을 하나 작성 했고 Docker image로 빌드해서 azure container repository에 푸쉬 했습니다. 그리고 이미지를 기반으로 app service를 띄웠는데요. 로컬에서는 아무 문제 없이 작동이 되는데 리모트로 올라가니 streamlit cookie manager 및 feedback component를 로딩하질 못 합니다. (사실 쿠키 매니저는 설치한 적이 없어서 왜 문제가 되는지 더더욱 잘 모르겠네요) 에러 문구에는 네트워크 레이턴시나 프록시 이슈로 컴퍼넌트를 로딩 못 하는 걸수 있다 라고 하는데 혹시 관련해서 비슷한 이슈 해결하신분 계실까요?

개발자

#streamlit

#azure

#docker

#appservice

답변 0

댓글 0

조회 84

일 년 전 · 포크코딩 님의 새로운 답변

Nodejs 백엔드 구조짜는법

안녕하세요 취직은 못했구 풀스택으로 Reactjs Nodejs사용해서사이드 프로젝트를 하고있는 뉴비개발자입니당 Nodejs를 백엔드로 사용하고 있는데 폴더구조를 어떻게 잡아야할지 항상 고민이 해결되지 않아 개발자분들의 의견을 구합니다 ㅠㅠ 제 나름대로 Web.js를 루트로 두고 Routes폴더에 api 경로에 따라 나뉠수 있게 폴더를 두고 Db를 사용하거나 함수들은 각각 Service라는 폴더를, 자주사용되는 데이터는 model이라는 폴더에 dto를 사용해서 두고있는뎅 이 구조가 좋은 방식일지 항상 생각하는데 조언을 구할 수가 없어서 어떤 방식으로 구조를 잡으면 좋을지 개발자님들의 조언을 부탁합니다...

개발자

#node.js

#구조

답변 1

댓글 0

조회 147

일 년 전 · 장성호 님의 답변 업데이트

여기서 의존성 주입이 어떻게 이뤄질 수 있는 지 궁금합니다.

안녕하세요 이제 막 스프링부트 공부를 시작한 3학년 학생입니다. 다름이 아니라 스프링부트를 공부하던 중 아래와 같은 의문이 생겨 질문드립니다. @SpringBootApplication @ConfigurationPropertiesScan public class SburRestDemoApplication { public static void main(String[] args) { SpringApplication.run(SburRestDemoApplication.class, args); } } @ConfigurationProperties(prefix = "greeting") class Greeting { private String name; private String coffee; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getCoffee() { return coffee; } public void setCoffee(String coffee) { this.coffee = coffee; } } 제가 이해하기로는 @Component(service, repository, controller 등) 어노테이션이 클래스에 부착되어 있어야 해당 클래스의 객체를 스프링 컨테이너에 의해 의존성 주입을 할 수 있다고 알고 있는데, @ConfigurationProperties 어노테이션은 내부를 아무리 찾아도 위에서 언급한 어노테이션을 가지고 있지 않았습니다. 하지만, @RestController @RequestMapping("/greeting") class GreetingController { private final Greeting greeting; public GreetingController(Greeting greeting) { this.greeting = greeting; } @GetMapping String getGreeting() { return greeting.getName(); } @GetMapping("/coffee") String getNameAndCoffee() { return greeting.getCoffee(); } } @RestController 에 의해(@RestController는 내부에 controller 어노테이션이 있더라구요) 스프링 컨테이너로부터 의존성 주입을 받을 수 있는 GreetingController는 greeting 객체를 받아서 생성자 메서드를 실행하므로 스프링 컨테이너에서 Greeting 클래스의 객체를 의존성 주입 받을 수 있는 지 확인해보고 위에서 언급한대로 Greeting은 등록되어 있지 않으므로 오류가 날거라 예상했습니다. 하지만, 아무런 문제없이 자동으로 public GreetingController(Greeting greeting) { this.greeting = greeting; } greeting 객체가 주입이 되었고 실행되었습니다. 제가 이해한 내용이 어디서 틀렸는 지 궁금합니다.

개발자

#spring-boot

#java

답변 2

댓글 0

조회 628

일 년 전 · 김병연(Vintz) 님의 새로운 댓글

리액트 쿼리 로직을 커스텀 훅으로 만들 때, 어디까지 추상화를 하시나요?

안녕하세요. 현재 프로젝트에서 기존 데이터 페칭 로직들을 전부 리액트 쿼리로 옮기면서, 고민이 생겨 질문을 드립니다. 클라이언트 상태와 서버 상태로 폴더를 나누고, 쿼리 로직들을 커스텀 훅으로 만들고 있습니다. 그런데 이 커스텀 훅의 추상화를 어디까지 해야할지 고민이 됩니다. 3개의 서비스 페이지가 있고, 사용하는 쿼리 내부의 로직이 비슷할 경우, 아래의 두 가지 방법을 생각해 봤습니다: 1. 재사용을 위해 매개변수로 URL, URL parameter, Query key를 추가 2. 유지보수를 위해 URL parameter만 매개변수로 추가하고, 개별 커스텀 훅 생성 예시 코드로, 1번의 코드는 `useDashboard('/data', startDate, endDate, 'service01/dashboard');` 이런식으로 사용을 하고, 2번의 코드는 `useService01Dashboard(startDate, endDate);, useService02Dashboard(startDate, endDate);...` 이렇게 사용을 합니다. 현재는 2번의 방식으로 구현을 하고 있습니다. 그 이유로는 불러오는 서버 데이터가 대부분 동일하지만 다른 경우도 있어서 타입을 다르게 줘야했고, URL을 쉽게 구분하기가 어려워서 한 곳에서 관리하고 싶었습니다(URL이 REST API 설계와 다소 거리가 있습니다.). 결론은, 함수 호출자의 입장(데이터를 불러오는 함수)에서 어디까지 알아야하나?가 고민입니다. 리액트 쿼리 깃허브에서 예시도 보고, 이렇게 글을 쓰다보니 현재로썬 2번이 더 맞다고 생각이 들긴 합니다. 여러분은 보통 어떤식으로 구현을 하시는지 궁금해서 이렇게 질문을 드리게 되었습니다. 어떤 의견이라도 좋으니 답변을 주시면 정말 감사할 것 같습니다!

개발자

#react

#react-query

답변 1

댓글 1

조회 172

일 년 전 · 익명 님의 질문

nextjs에서 랜더링 시점 바꾸기

안녕하세요! nextjs 프로젝트 진행중에 궁금증이 생겼습니다. 현재 Sidebar 컴포넌트에서 카카오맵이 불러와져야 작업을 할 수 있는 상태입니다. 카카오 맵은 children 에서 랜더링되기 때문에 아래와 같이 코드작성시, Sidebar 랜더링 시점에 kakao is not defined 라는 오류가 뜹니다. 혹시 Sidebar를 좀 늦게 랜더링 할 수 있을까요? export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="en"> <body className={inter.className}> <div id="login-modal" /> <section className="flex h-screen"> <nav className=" h-full bg-slate-100"> <Sidebar /> </nav> {children} </section> </body> <Script src={`//dapi.kakao.com/v2/maps/sdk.js?appkey=${APIKEY}&libraries=services,clusterer`} strategy="beforeInteractive" /> </html> ); }

개발자

#nextjs

#reactjs

답변 0

댓글 0

조회 62

일 년 전 · 익명 님의 새로운 댓글

여러분들은 어디에 log를 남기시나요?

안녕하세요 백엔드 개발자를 준비중인 학생입니다! log를 남기는 위치가 궁금하여 찾아보고 있는데 일단 다 남겨놓고 필요 없는 곳을 지우자 라는 생각을 하며 log를 작성했습니다 그러다 보니 service부분 controller부분 다 남기게 되었는데 http 요청하면 controller에서도 찍히고 service에서도 찍히는 현상이 생기더라고요! service가 찍히면 controller도 실행이 된거다 라는 생각을 가지게 되었어요 그래서 log를 잘 남기는 법을 찾아보다가 선배 개발자분들의 의견이 궁금해서 글을 남깁니다!

개발자

#스프링

#log

답변 1

댓글 1

조회 87

일 년 전 · 강병진 님의 답변 업데이트

타입스크립트에서 리턴타입을 어디까지 명시해야할까요?

안녕하세요 nest 프레임워크로 부트캠프에서 공부중인 학생입니다. 타입스크립트를 사용해서 진행하고 있는데 nest는 메서드 리턴타입을 유추해주기 때문에 명시할 필요는 없다고 합니다. 현업에서는 어떻게 사용하는게 정석인가요? 사진은 service에 메서드입니다. 모든 계층에서 메서드의 리턴타입을 명시해야한는건지 궁금합니다.

개발자

#node

#typescript

답변 1

댓글 0

조회 242

일 년 전 · 다형 님의 답변 업데이트

aws spring boot 배포 오류

안녕하세요 백엔드 공부 중인 학생입니다. aws ec2로 Spring boot 프로젝트를 배포 시도 중에 있습니다. (maven, java 8, jar) java -jar jar파일명.jar 명령어로 배포 시도 중에 에러메세지가 도저히 해결이 안되어서 도움 요청드립니다.. 도와주신다면 감사하겠습니다.. 아 참고로 rds로 데이터베이스 생성하지 않고 mysql(workbench)로 데이터베이스 생성했습니다 <오류메세지> Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. 2024-02-07 04:33:35.742 ERROR 31012 --- [ main] o.s.boot.SpringApplication : Application run failed org.springframework.context.ApplicationContextException: Failed to start bean 'webServerStartStop'; nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat server at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:181) ~[spring-context-5.3.22.jar!/:5.3.22] at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54) ~[spring-context-5.3.22.jar!/:5.3.22] at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:356) ~[spring-context-5.3.22.jar!/:5.3.22] at java.lang.Iterable.forEach(Iterable.java:75) ~[na:1.8.0_392] at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:155) ~[spring-context-5.3.22.jar!/:5.3.22] at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:123) ~[spring-context-5.3.22.jar!/:5.3.22] at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:935) ~[spring-context-5.3.22.jar!/:5.3.22] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586) ~[spring-context-5.3.22.jar!/:5.3.22] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) ~[spring-boot-2.7.2.jar!/:2.7.2] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734) [spring-boot-2.7.2.jar!/:2.7.2] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) [spring-boot-2.7.2.jar!/:2.7.2] at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) [spring-boot-2.7.2.jar!/:2.7.2] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) [spring-boot-2.7.2.jar!/:2.7.2] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) [spring-boot-2.7.2.jar!/:2.7.2] at com.se.social.SocialApplication.main(SocialApplication.java:13) [classes!/:0.0.1-SNAPSHOT] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_392] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_392] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_392] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_392] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) [social-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) [social-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) [social-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65) [social-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] Caused by: org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat server at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.start(TomcatWebServer.java:229) ~[spring-boot-2.7.2.jar!/:2.7.2] at org.springframework.boot.web.servlet.context.WebServerStartStopLifecycle.start(WebServerStartStopLifecycle.java:43) ~[spring-boot-2.7.2.jar!/:2.7.2] at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:178) ~[spring-context-5.3.22.jar!/:5.3.22] ... 22 common frames omitted Caused by: java.lang.IllegalArgumentException: standardService.connector.startFailed at org.apache.catalina.core.StandardService.addConnector(StandardService.java:238) ~[tomcat-embed-core-9.0.65.jar!/:na] at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.addPreviouslyRemovedConnectors(TomcatWebServer.java:282) ~[spring-boot-2.7.2.jar!/:2.7.2] at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.start(TomcatWebServer.java:213) ~[spring-boot-2.7.2.jar!/:2.7.2] ... 24 common frames omitted Caused by: org.apache.catalina.LifecycleException: Protocol handler start failed at org.apache.catalina.connector.Connector.startInternal(Connector.java:1077) ~[tomcat-embed-core-9.0.65.jar!/:na] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[tomcat-embed-core-9.0.65.jar!/:na] at org.apache.catalina.core.StandardService.addConnector(StandardService.java:234) ~[tomcat-embed-core-9.0.65.jar!/:na] ... 26 common frames omitted Caused by: java.net.SocketException: Permission denied at sun.nio.ch.Net.bind0(Native Method) ~[na:1.8.0_392] at sun.nio.ch.Net.bind(Net.java:461) ~[na:1.8.0_392] at sun.nio.ch.Net.bind(Net.java:453) ~[na:1.8.0_392] at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:222) ~[na:1.8.0_392] at org.apache.tomcat.util.net.NioEndpoint.initServerSocket(NioEndpoint.java:275) ~[tomcat-embed-core-9.0.65.jar!/:na] at org.apache.tomcat.util.net.NioEndpoint.bind(NioEndpoint.java:230) ~[tomcat-embed-core-9.0.65.jar!/:na] at org.apache.tomcat.util.net.AbstractEndpoint.bindWithCleanup(AbstractEndpoint.java:1227) ~[tomcat-embed-core-9.0.65.jar!/:na] at org.apache.tomcat.util.net.AbstractEndpoint.start(AbstractEndpoint.java:1313) ~[tomcat-embed-core-9.0.65.jar!/:na] at org.apache.coyote.AbstractProtocol.start(AbstractProtocol.java:614) ~[tomcat-embed-core-9.0.65.jar!/:na] at org.apache.catalina.connector.Connector.startInternal(Connector.java:1074) ~[tomcat-embed-core-9.0.65.jar!/:na] ... 28 common frames omitted <전체> . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.7.2) 2024-02-07 04:33:27.975 INFO 31012 --- [ main] com.se.social.SocialApplication : Starting SocialApplication v0.0.1-SNAPSHOT using Java 1.8.0_392 on ip-172-31-39-15 with PID 31012 (/home/ubuntu/socialboardPJ/target/social-0.0.1-SNAPSHOT.jar started by ubuntu in /home/ubuntu/socialboardPJ/target) 2024-02-07 04:33:27.980 INFO 31012 --- [ main] com.se.social.SocialApplication : No active profile set, falling back to 1 default profile: "default" 2024-02-07 04:33:29.591 INFO 31012 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode. 2024-02-07 04:33:29.681 INFO 31012 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 76 ms. Found 1 JPA repository interfaces. 2024-02-07 04:33:30.960 INFO 31012 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 80 (http) 2024-02-07 04:33:30.986 INFO 31012 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2024-02-07 04:33:30.987 INFO 31012 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.65] 2024-02-07 04:33:31.641 INFO 31012 --- [ main] org.apache.jasper.servlet.TldScanner : At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time. 2024-02-07 04:33:31.880 INFO 31012 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2024-02-07 04:33:31.880 INFO 31012 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 3717 ms 2024-02-07 04:33:32.215 INFO 31012 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... 2024-02-07 04:33:32.569 INFO 31012 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. 2024-02-07 04:33:32.659 INFO 31012 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default] 2024-02-07 04:33:32.822 INFO 31012 --- [ main] org.hibernate.Version : HHH000412: Hibernate ORM core version 5.6.10.Final 2024-02-07 04:33:33.157 INFO 31012 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.1.2.Final} 2024-02-07 04:33:33.383 INFO 31012 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQL8Dialect 2024-02-07 04:33:34.255 INFO 31012 --- [ main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform] 2024-02-07 04:33:34.266 INFO 31012 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' 2024-02-07 04:33:34.906 WARN 31012 --- [ main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning 2024-02-07 04:33:35.616 WARN 31012 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Failed to start bean 'webServerStartStop'; nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat server 2024-02-07 04:33:35.620 INFO 31012 --- [ main] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' 2024-02-07 04:33:35.624 INFO 31012 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... 2024-02-07 04:33:35.646 INFO 31012 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed. 2024-02-07 04:33:35.650 INFO 31012 --- [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat] 2024-02-07 04:33:35.676 INFO 31012 --- [ main] ConditionEvaluationReportLoggingListener : Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. 2024-02-07 04:33:35.742 ERROR 31012 --- [ main] o.s.boot.SpringApplication : Application run failed org.springframework.context.ApplicationContextException: Failed to start bean 'webServerStartStop'; nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat server at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:181) ~[spring-context-5.3.22.jar!/:5.3.22] at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54) ~[spring-context-5.3.22.jar!/:5.3.22] at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:356) ~[spring-context-5.3.22.jar!/:5.3.22] at java.lang.Iterable.forEach(Iterable.java:75) ~[na:1.8.0_392] at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:155) ~[spring-context-5.3.22.jar!/:5.3.22] at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:123) ~[spring-context-5.3.22.jar!/:5.3.22] at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:935) ~[spring-context-5.3.22.jar!/:5.3.22] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586) ~[spring-context-5.3.22.jar!/:5.3.22] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) ~[spring-boot-2.7.2.jar!/:2.7.2] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734) [spring-boot-2.7.2.jar!/:2.7.2] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) [spring-boot-2.7.2.jar!/:2.7.2] at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) [spring-boot-2.7.2.jar!/:2.7.2] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) [spring-boot-2.7.2.jar!/:2.7.2] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) [spring-boot-2.7.2.jar!/:2.7.2] at com.se.social.SocialApplication.main(SocialApplication.java:13) [classes!/:0.0.1-SNAPSHOT] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_392] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_392] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_392] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_392] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) [social-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) [social-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) [social-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65) [social-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] Caused by: org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat server at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.start(TomcatWebServer.java:229) ~[spring-boot-2.7.2.jar!/:2.7.2] at org.springframework.boot.web.servlet.context.WebServerStartStopLifecycle.start(WebServerStartStopLifecycle.java:43) ~[spring-boot-2.7.2.jar!/:2.7.2] at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:178) ~[spring-context-5.3.22.jar!/:5.3.22] ... 22 common frames omitted Caused by: java.lang.IllegalArgumentException: standardService.connector.startFailed at org.apache.catalina.core.StandardService.addConnector(StandardService.java:238) ~[tomcat-embed-core-9.0.65.jar!/:na] at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.addPreviouslyRemovedConnectors(TomcatWebServer.java:282) ~[spring-boot-2.7.2.jar!/:2.7.2] at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.start(TomcatWebServer.java:213) ~[spring-boot-2.7.2.jar!/:2.7.2] ... 24 common frames omitted Caused by: org.apache.catalina.LifecycleException: Protocol handler start failed at org.apache.catalina.connector.Connector.startInternal(Connector.java:1077) ~[tomcat-embed-core-9.0.65.jar!/:na] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[tomcat-embed-core-9.0.65.jar!/:na] at org.apache.catalina.core.StandardService.addConnector(StandardService.java:234) ~[tomcat-embed-core-9.0.65.jar!/:na] ... 26 common frames omitted Caused by: java.net.SocketException: Permission denied at sun.nio.ch.Net.bind0(Native Method) ~[na:1.8.0_392] at sun.nio.ch.Net.bind(Net.java:461) ~[na:1.8.0_392] at sun.nio.ch.Net.bind(Net.java:453) ~[na:1.8.0_392] at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:222) ~[na:1.8.0_392] at org.apache.tomcat.util.net.NioEndpoint.initServerSocket(NioEndpoint.java:275) ~[tomcat-embed-core-9.0.65.jar!/:na] at org.apache.tomcat.util.net.NioEndpoint.bind(NioEndpoint.java:230) ~[tomcat-embed-core-9.0.65.jar!/:na] at org.apache.tomcat.util.net.AbstractEndpoint.bindWithCleanup(AbstractEndpoint.java:1227) ~[tomcat-embed-core-9.0.65.jar!/:na] at org.apache.tomcat.util.net.AbstractEndpoint.start(AbstractEndpoint.java:1313) ~[tomcat-embed-core-9.0.65.jar!/:na] at org.apache.coyote.AbstractProtocol.start(AbstractProtocol.java:614) ~[tomcat-embed-core-9.0.65.jar!/:na] at org.apache.catalina.connector.Connector.startInternal(Connector.java:1074) ~[tomcat-embed-core-9.0.65.jar!/:na] ... 28 common frames omitted

개발자

#aws

#springboot

#배포

답변 1

댓글 0

조회 615

일 년 전 · 익명 님의 새로운 댓글

Docker Hub Image Push 후에 EC2에서 자동으로 Pull -> service start하기

현재 GithubAction으로 Spring Boot jar 파일을, 도커 빌드, 도커 푸시까지 완료해서 도커 허브에 private repo에 올려놓는데 까지는 성공했습니다. 여기서 두번째 단계로, ssh action을 사용하지 않고 private subnet에 위치한 EC2 instance에서 푸시된 도커 이미지를 가져와서 compose up을 하고 싶습니다. 이걸 수행할 수 있는 팁이나 방법이 있을까요? self-hosted라는게 보이는데 잘 모르겠더라구요.. 제가 찾지 못하는 팁이나 자료들 부탁드립니다! 감사합니다!

개발자

#docker

#ci/cd

#spring-boot

#githubaction

답변 1

댓글 1

보충이 필요해요 1

조회 125

일 년 전 · 김지섭 님의 질문 업데이트

MSA 환경에서 ABAC 기반의 권한시스템을 어떻게 구현하는게 좋을까요?

안녕하세요 현재 진행중인 프로젝트에 MSA를 적용하여 구현하고 있는 백엔드 꿈나무입니다. 빈번하게 일어나는 권한 검증을 효율적이고 높은 가용성을 확보할 수 있도록 하기 위해서 여러 방법을 모색하던 중, 다른 분들의 의견이 어떨지 하여 QnA를 올려보게 되었습니다. 우선 저희 프로젝트는 User, Device, Organization, Team, License 이렇게 5가지 개념이 있습니다. 사용자가 장비에 접근할 때에는 본인이 소속된 Org에 해당 장비가 존재하는지, 접근하는 동작에 대해서 해당 org가 License를 보유하고 있는지, 소속된 팀 또는 본인에게 해당 장비에 해당 동작을 승인받았는지 등 수많은 조건들에 의해 ABAC가 계산되게 됩니다. 하지만 MSA 환경으로 인해 테이블을 쉽게 join하지 못할 뿐더러, 가능하더라도 상당한 고부하 작업이 될 것이라고 생각합니다. 그래서 CQRS 패턴을 이용해서 license가 만료되거나 팀의 권한이 수정되는 등, 사용자와 장비간의 권한이 수정이 되는 command가 수신되면, 그것을 권한 담당 서비스에 비동기로 전달하여 특정 사용자가 특정 장비에 어떤 동작에 대한 제어가 가능한지를 저장(캐싱)하고 있다가 권한을 검사해야되면 간단하게 query하는 형태로 구현하는 것이 적합할 것이라고 판단했습니다. 이 패턴을 구현하기 위한 두가지 방법을 고안해보았습니다. [Permission Service] 별도의 permission 서비스를 만들고 캐시용도로 redis를 연결해두고, 권한 검사 요청이 들어왔을 때 Cache Miss가 된다면 Api Gateway 패턴과 유사하게 여러 서비스에 각각 정보를 요청하여 최종적인 권한 정보를 Aggregate 하여 전달하고, 캐시에 보관하는 방식입니다 [권한 관리 Infra Service] Google의 Zanzibar와 같이 권한을 관리하고 복잡한 쿼리를 처리해주는 서비스를 이용하는 방식입니다. 오픈소스로 구현된 SpiceDB를 고려하고 있습니다. Permission Service를 만드는 경우, 본인이 보유한 정보가 부족할 경우 능동적으로 정보를 Pull하여 권한 정보를 가져오는 반면, 양측에 별도 인터페이스를 구현해야되는 단점이 있고, 이미 있는 서비스를 사용하면 구현이 쉬워지는 반면, 해당 서비스에서 능동적인 Pull이 불가능하고, 권한 Query 정보가 최신인지 판단하고 업데이트하는 것을 각 서비스에서 각각 담당해야되기 때문에 별도 서비스를 분리하는 것에 비해 Responsibility Segregation이 부족하다고도 느꼈습니다. 무엇보다 관리해야될 인프라 요소가 늘어난 것은 덤이구요. 규모에 비해서 과한 고민을 하고 있는것이 아닌가 하는 생각도 들고, 그래도 더 나은 방법으로 서비스를 만들어가고 싶기도 합니다. ABAC를 적용하는 대부분의 서비스에서 이러한 고민을 적절히 잘 해결하여 서비스가 되고 있을텐데, 정답은 없겠지만 선배님들의 조언을 듣고 싶습니다!

개발자

#msa

#cqrs

답변 0

댓글 0

추천해요 2

조회 140

일 년 전 · 김태현 님의 새로운 댓글

sql문 부적합합니다..

spring boot 4 에서 웹개발프로젝트를 진행중입니다.. jsp페이지에서 받아온 searchText값을 쿼리문으로 비교 후 foodinfolist를 반환해주는데 sql developer에서는 SELECT * FROM foodinfolist WHERE food_name LIKE '%' || '치킨' || '%'; 해당 코드가 정상동작 돼서 잘 검색하지만 mapper.xml에서 <mapper namespace="com.springproj.dietwebservice.repository.IFoodInfoDAO"> <select id="findfoodinfo" parameterType="java.lang.String" resultType="com.springproj.dietwebservice.domain.FoodInfoVO">> <![CDATA[ SELECT * FROM foodinfolist WHERE food_name LIKE '%' || #{searchText} || '%' ]]> </select> </mapper> 해당 코드를 실행하면 sql문이 부적합합니다 라고 에러가 발생합니다.. 뭐가 문제인지 모르겠습니다.. searchText: 치킨 으로 데이터도 잘 담겨오는데.. 2024-01-31T16:24:22.500+09:00 ERROR 8208 --- [nio-8090-exec-9] o.a.c.c.C.[.[.[/].[dispatcherServlet]  : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.jdbc.BadSqlGrammarException: ### Error querying database. Cause: java.sql.SQLSyntaxErrorException: ORA-00900: SQL 문이 부적합합니다 선배님들 조언부탁드립니다..

개발자

#sql

#spring-boot

답변 4

댓글 2

추천해요 1

조회 589

일 년 전 · 조찬우 님의 답변 업데이트

iOS 개발 시, 사용자 개인정보 조회 및 전송 범위에 대한 질문(DevceID/MACAdress/IP)

안녕하세요. iOS 개발하면서 어려움이 있어서 이렇게 질문 남깁니다. Q. iOS 디바이스에서 활동기록을 서버로 전송하고 싶은데, DeviceID 혹은 MAC 주소를 조회해서 서버에 전송하는 행위가 법적이나 애플 약관상 이슈가 없는지 궁금합니다. 제가 검색해보면, Apple 정책은 다음과 같습니다. 링크: https://developer.apple.com/app-store/user-privacy-and-data-use/ "Can I fingerprint or use signals from the device to try to identify the device or a user? No. Per the Apple Developer Program License Agreement, you may not derive data from a device for the purpose of uniquely identifying it. Examples of user or device data include, but are not limited to: properties of a user’s web browser and its configuration, the user’s device and its configuration, the user’s location, or the user’s network connection. Apps that are found to be engaging in this practice, or that reference SDKs (including but not limited to Ad Networks, Attribution services, and Analytics) that are, may be rejected from the App Store." 제가 인지하기론, 디바이스를 특정짓는 정보는 서버에 전송하는 것을 불법으로 알고 있는데, 제가 암묵지로만 알고 있다보니, 정확한 근거를 찾고 싶어서 질문드립니다! 긴글 읽어주셔서 감사합니다!

개발자

#ios

#privacy

#security

#programming

#아이폰

답변 2

댓글 2

조회 187

일 년 전 · 장성호 님의 답변 업데이트

node.js controller service 분리 상태코드반환 책임 질문..

제가 node.js 로 토이프로젝트 진행중에 있는데 코드를 controller와 service 를 분리해서 진행하고있습니다. 예를 들면 예매 기능을 구현한다고하면 예매 성공까지 검증해야하는 로직이 3개라고 치면 1. 컨트롤러에서 해당 서비스코드의 3개의 함수를 각각 실행해서 해당 상태코드와 에러메세지를 작성해 반환할지 아니면 2. 컨트롤러에서 하나의 서비스코드 함수를 실행해 서비스코드에서 해당 상태코드와 에러메세지를 컨트롤러에 전달해 반환할지 고민입니다. 상태코드를 서비스계층 부분에서 담아도 될지 의문이듭니다.

개발자

#node.js

#mvc

#controller

#service

답변 1

댓글 0

조회 451

2년 전 · 익명 님의 질문

Nest.js에서 TypeOrm의 0.3버전에서는 @EntityRepository를 비활성화 시켰는데, 개발자분들께서는 이 이유에 대해 알고계시나요?

안녕하세요, 현재 NestJs를 공부하고 있는 취준생입니다. Typeorm의 0.2버전에서는 @Entityrepository를 제공해서, respository 레이어에 DB에 직접적으로 접근하는 코드(예: create, findOne 등)를 작성해왔었는데, 이번에 최신버전으로 업데이트되면서 해당 데코레이터를 비활성 시켰더라구요.. 그러다보니 Service 레이어에 임포트되는 라이브러리와 구현되는 로직이 더 길어지는 불편함이 있어 현재는 Custom Repository 방식을 사용하고 있습니다. 그러다 문득 TypeORM 측에서는 뭔가 이유가 있어 비활성화를 한 것 같은데.. Nestjs를 사용하고 계시는 개발자분들도 비슷하게 Cutsom Repository를 많이 사용하고 계신지, 아니면 service레이어에서 모두 해결하고 계신지 궁금합니다 예전에 레이어를 분리해서 사용했을 때는 예를 들어 "데이터를 조회하는 api을 구현하기 위해, repository레이어에서 findOne() 메서드만 실행시키고 그 값을 반환하는 A라는 함수를 정의하고 Service 레이어에서는 A함수를 불러와 바로 실행했을 때 결과는 동일하게 나왔던 경우"에는 굳이 새로운 메서드를 만들 필요가 있는가? 에 대해 의문을 가졌던 적은 있었는데, 소규모가 아닌 대규모 프로젝트에서도 별 차이가 없는건가요..?

개발자

#node.js

답변 0

댓글 0

조회 101

2년 전 · 장준영 님의 답변 업데이트

Spring에서 레이어드 아키텍처 관련 코드 패턴 질문

안녕하세요 개발을 진행하는 도중 코드 디자인 관련해서 궁금한 점이 생겨, 여러 선배님들께 질문을 드려봅니다 검색 목록 조회 시, 많은 parameter 처리 방법 특정 검색화면을 표시하기 위해 필요한 값들인 등록일 검색 날짜, 검색어와 같은 부문을 Controller 에서 modelattribue 로 받았는데 필드 수가 10개 이상 됩니다. 문제는 해당 field 들을 서비스 > 레포지토리 까지 옮겨야 하는데 modelattribute 객체를 사용하자니 view 에 종속 된 객체를 옮기는 게 맞을까 라는 의문이 들고, 각 field 를 모두 꺼내자니 메서드 마다 10개씩 파라미터 받는게 또 아닌 것 같다는 생각이 들었습니다. 이러한 상황들은 어떤식으로 처리하시는 지 궁금합니다. JPA 를 사용 중인데, open in view 속성을 막아놔서 service 레이어에서 entity를 dto로 변환하는 작업을 진행합니다. 이때 궁금한 점은 해당 method 에서 반환 시 다른 entity의 field값 하나가 필요한 경우가 간혹 있다는 것 입니다. 해당 dto 에 field 를 추가하자니 해당 값이 필요없는 경우에도 다른 entity를 조회하여 db select 나가는게 싫고 객체를 하나 더 만들자니, 다른 상황에서도 비슷한 경우가 많아 객체가 너무 많아질 것 같아 고민입니다. 계속 해서 좋은 방법을 고민하고 찾아봤지만, 결론이 나질 않아 선배님들께 질문 드려 봅니다.

개발자

#java

#spring

#jpa

답변 1

댓글 0

추천해요 1

조회 720

2년 전 · 지헌 님의 질문 업데이트

스프링부트 서비스 코드 작성 기법

현재 학교에서 웹서비스를 만드는 프로젝트를 진행하고있습니다 진행하는 프로젝트의 코드 중 일부분이 저로서는 이해가 잘 안되는 코드가 있어서 질문드립니다 Service부분의 일부 코드입니다 웹 크롤링 api를 사용하여 시장정보를 가져와 mapper의 두가지 기능(delete와 insert)를 사용하고 있는데 제가 이해한 바로는 스케쥴링을 통해 api를 호출할 때마다 delete쿼리를 실행하고 다시 insert쿼리를 실행시키는 방식인데 정말 이방법 밖에 없는지 궁금합니다 또한 mapper interface에서 정의한 기능 여러개가 service interface에서 하나의 기능으로 합쳐지는 코드로 작성하는 방법에 대한 의견도 궁금합니다 많이 가르쳐주시면 감사하겠습니다

개발자

#java

#spring-boot

답변 0

댓글 0

조회 67

2년 전 · 강병진 님의 새로운 답변

Azure nginx ip (HTTP) ssl 인증서 발급

App Servie 가아닌 Azure vm 을통해 http://ip주소 로 배포 완료하였고, https로 변경하여 배포하려고합니다. App Service Certificate는 AppService로 연동된 웹만 발급이 가능한걸로 나와있는데 vm을통해 nginx연결한 flask 를 https로 배포하기위해선 어떻게 해야하나요?

개발자

#azure

#cloud

#ssl

#flask

#python

답변 1

댓글 0

조회 151