묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결
스프링 도커 데이터베이스 연결 오류
현재 이것이 백엔드 개발이다 with 자바편 책을 보면서 학습중입니다.스프링부트에 도커에서 실행되는 데이터베이스(mysql)를 연동하려고 하는데 위와 같은 에러가 발생합니다.스프링부트 pom.xml 내용 중 mysql 의존성 부분application.properties 부분도커 컨테이너 생성에서 mysql 버전Application.java 책에서 나온 내용과 동일하게 진행했으며 스키마, 데이터베이스 테이블까지 만든 상태입니다. 어떤 것이 잘못된 건지 감이 잡히지 않습니다. 도움 부탁드려요
-
미해결
스프링, 리액트로도 웹게임을 구현할 수 있을까요?
안녕하세요 컴퓨터공학 전공을 하고 있는 대학생입니다.스프링부트와 리액트로 웹사이트를 만든 경험자들과 함께 이번엔 웹게임을 만들어보려고 합니다 .웹게임에 관심 있던 사람들인지라 방탈출 게임으로 여러 개의 방을 탐험하며, 퍼즐을 풀어 탈출구를 찾는 게임을 만들어보려고 하는데 스프링과 리액트로 웹게임을 만든 사례를 많이 찾아보지 못해서 여기다가 물어보아요!각방에는 문제나 퍼즐이 있고, 이를 해결해야 탈출할 수 있는 주고백엔드에서 방과 퍼즐 데이터를 관리하고 프론트에서 방을 시각적으로 표현하고, 사용자 입력을 통해 퍼즐을 해결모든 방을 통과하면 게임이 종료되고, 승리 메시지 표시하는 방식으로 제작을 해보고 싶은데,스프링부트와 리액트로 웹게임을 제작해보신 분들 이러한 틀로 게임을 만들 수 있을지와 경험담을 들어보고 싶습니다 !!
-
미해결
토비님의 스프링, 스프링 부트 강의 중 뭘 먼저 듣는게 좋을까요?
스프링 부트 웹백엔드 개발자입니다. 토비님 강의가 있다는 소식을 접해서 들어보려고 하는데 스프링 강의와 스프링 부트 강의가 있더라구요. 둘 다 들으면 좋겠지만, 동시에 들을 수는 없잖아요. 그래서 뭘 먼저 듣는게 좋을지 고민이 되는데 스프링 부트는 강의를 들어봤는데, 스프링은 강의는 커녕 부트 없이 생으로 개발해본적이 없습니다. 스프링 강의 먼저 들어보는게 낫겠죠?
-
미해결
JPA @Query 로는 동적쿼리 작성은 불가능한가요?
QueryDSL로는 구현이 어려워, 네이티브 쿼리를 작성하려고 합니다.그런데, where 조건을 동적으로 작성해야하는데... @Query의 경우 동적쿼리가 불가능한가요?
-
미해결
QueryDSL 에서 중복된 데이터를 제거하고, 집계함수(count, sum 등)을 적용하는 방법에 대해 조언 구합니다!
JOIN으로 인해서, 아래와 같이 중복되는 데이터가 발생했습니다.id | price1 50001 50002 60002 6000따라서, Distinct를 통해 아래와 같이 중복데이터를 제외하고, groupBy(id)를 통해 id별로 price의 sum을 구해야 합니다.id | price1 50002 6000이를 쿼리로 짜야한다면... JOIN 이후 Distinct를 적용한 서브쿼리를 From으로 조회해서 다시 groupBy(id) 를 통해 price의 sum을 구해야하는데요...위와 같이, subquery를 from 으로 조회해야 한다면... QueryDSL 을 통해 subquery를 from으로 조회하는 문법과 관련한 내내용을 아시는 분 계실까요 ㅠ(링크라도 부탁드립니다 ㅠ)아니면 혹시 다른 방법이 있을까요?- 본래 집계함(count, sum 등)수와 distinct 를 동시에 사용할 수 있는 것으로 압니다. 그런데 QueryDSL의 경우 countDistinct() 는 존재하는데... sumDisctinct()는 없는 것 같더라고요. 선배님들의 도움 절실히 부탁드립니다 ㅠ
-
미해결
스프링에서 @CreatedBy 와 AuditorAware 의 활용에 질문 드립니다!
@CreatedBy을 이용하면, 디비에 데이터가 입력될 때마다 작성자의 정보를 자동으로 기입할 수 있어서 많은 분들이 이용하시고 있습니다. 그리고 해당 @CreatedBy 값에 들어 갈 값은 AuditorAware을 통해 만들 수가 있는데요.<Q. 질문>그러나 만일.. 아래와 같이 생성시 점에서 ID 값과 Name 을 입력해 주어야한 다면... AuditorAware를 어떻게 이용해서 아래의 내용을 기입할 수 있는지 알고계신 분 있으실까요?(@CreatedBy 가 특정 AuditorAware 파일을 지정할 수 있으면 될 것 같은데... 방법을 못찾았습니다 ㅠ)@CreatedByprivate Long creatorId;@CreatedByprivate Stirng creatorName;
-
미해결
Controller와 RestController를 분리해야 하나요?
스프링부트 프로젝트를 설계하고 있는데, 지금까지는 그냥 @Controller에 api 요청도 @ResponseBody로 다 때려박는 식으로 코딩을 했습니다.그런데 api 요청만을 따로 관리하는 @RestController를 생성하는 것이 나중에 유지보수에 더 편할까요?Controller들의 분리 및 관리를 어떻게 하는 것인지 궁금합니다.
-
미해결
인프런 김영한 강사님 강의 듣고있는데 포트오류 생깁니다
Web server failed to start. Port 8080 was already in use. Identify and stop the process that's listening on port 8080 or configure this application to listen on another port. 이 문구들이 나오는데 김영한 강사님께서 이전 포트8080을 끄고 다음 것을 진행하라고 하셨습니다.그런데 애초에 중지버튼에 불이 들어와있지 않습니다.
-
미해결
스프링부트 배포 jar파일 실행 시 Failed to configure a DataSource:에러
스프링부트 프로젝트 배포를 하고있습니다.yml파일에 rds 관련 설정들 적어주었고 로컬에서도 db연결과 실행에 문제없고 ./gradlew clean build -x test 까지는 빌드가 잘 됩니다.근데 /build/libs 가서 생성된 jar 파일을 실행하기만 하면 db연결 에러가 뜨는데 이 부분에 대해 아시는 분 계신가요..?***************************APPLICATION FAILED TO START***************************Description:Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.Reason: Failed to determine a suitable driver classAction:Consider the following:If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).
-
미해결
스프링부트 테스트에서 @AuthenticationPrincipal UserDetails userDetails 테스트
컨트롤러 테스트에서 @AuthenticationPrincipal UserDetails userDetails에 해당하는 부분을 테스트하려고 하는데 계속 실패해서 질문드립니다 ㅠㅠ // 회원 탈퇴 @DeleteMapping("/{memberId}") @Tag(name = "member") @Operation(summary = "삭제 API", description = "유저를 삭제하는 API입니다.") @PreAuthorize("hasRole('ROLE_USER') or hasRole('ROLE_ADMIN')") public String remove(@PathVariable Long memberId, @AuthenticationPrincipal UserDetails userDetails) { try { String email = userDetails.getUsername(); log.info("email : " + email); String remove = memberService.removeUser(memberId, email); return remove; } catch (Exception e) { return "회원탈퇴 실패했습니다. :" + e.getMessage(); } }이런식으로 프론트가 헤더에 accessToken을 보내주면 검증을 한 후 @AuthenticationPrincipal UserDetails userDetails이거로 정보를 가져와서 권한과 해당 유저인지 체크 후 처리하는 로직을 구성하고 있는데 이거를 테스트할 때 막혔습니다.일단 구글에서 검색해서 나온 방법들을 다 사용해도 실패가 뜨네요.↓구글에서 나온 방법 적용@Retention(RetentionPolicy.RUNTIME) @WithSecurityContext(factory = WithAuthUserSecurityContextFactory.class) public @interface WithAuthUser { String user() default "test@test.com"; String role() default "USER"; }public class WithAuthUserSecurityContextFactory implements WithSecurityContextFactory<WithAuthUser> { @Override public SecurityContext createSecurityContext(WithAuthUser annotation) { String email = annotation.user(); String role = annotation.role(); MemberEntity member = MemberEntity.builder() .memberId(1L) .email(email) .memberPw("dudtjq8990!") .memberName("테스터") .memberRole(Role.valueOf(role)) .nickName("테스터") .memberPoint(0) .provider(null) .providerId(null) .address(AddressEntity.builder() .memberAddr("서울시 강남구") .memberZipCode("103-332") .memberAddrDetail("102") .build()) .build(); UserDetails userDetails = new PrincipalDetails(member); Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); SecurityContext context = SecurityContextHolder.createEmptyContext(); context.setAuthentication(authentication); return context; } } @Test @WithAuthUser void remove() throws Exception { Long id = 1L; String email = "test@test.com"; mockMvc.perform(delete("/api/v1/users/{memberId}", id) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()); verify(memberService).removeUser(id, email); } org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: No primary or single unique constructor found for interface org.springframework.security.core.userdetails.UserDetails 이런 오류가 발생합니다. 찾아보니까 UserDetails를 구현한 클래스 PrincipalDetails에 생성자가 없어서 나오는 오류라고 하는데 문제는 해당 클래스에 기본 생성자가 있다는 것입니다. 생성자가 있는데 계속 없다고 에러가 발생합니다. @ㅇNoArgsConstructorㅇ
-
미해결
사용자가 기존 데이터 수정시에 null 구분 어떻게하시나요?
회원이 회원정보를 변경하였습니다.변경된 데이터는 "자기소개" 부분이며, 값을 비워버렸습니다.그럼 백엔드 입장에서는 아래 두가지 경우를 어떻게 구분할 수 있을까요?이 경우 사용자가 값을 비운건지?그게 아니면, 수정을 안해서 null 인 건지 제가 찾은 방법은수정시에도 모든 컬럼 갑을 받아서 기존 DB의 로우 전체를 업데이트 시킨다.사용자가 의도적으로 필드를 비워둔 경우 null 이 아닌, null을 의미하는 다른 대체 문자를 이용한다.- 이 경우 null 은 필드변경이 없는 경우 이외에 보편적으로 이용하는 방법이나 스마트한 방법이 있을까요...?
-
미해결
프로젝트 리팩토링
제가 포트폴리오를 목적으로 스프링부트 즉, 백엔드를 맡았고 리액트와 진행했는데 프로젝트는 완성이 되었지만 리팩토링을 하고 있으면 좋을거 같은 기능들을 추가하려고 할 때 그러면 백엔드에서는 만들지만 화면은 구성을 못하니 그냥 건들지 말아야 할까요 아니면 백엔드에서 구현하더라도 그냥 포폴에는 언급하지 말아야 하나요? 포트폴리오 용으로 만들고 나서 코드를 가독성 있게 리팩토링하고 갑자기 아 이런 기능이 있었으면 좋았겠는데 그런 생각들이 들어서 백엔드에서라도 구현할까 하다가 연습용이면 모를까 포폴용이라 어떻게 해야할지 헷갈리네요
-
미해결
saveAndFlush 저장후 QueryDsl 조회 문의
@Transactional public AccessTokenResponse signup(MemberRequest request) { Member member = request.toMember(passwordEncoder); MemberDetails memberDetails = memberRepository .findMemberDetailsByMemberId(memberRepository.saveAndFlush(member).getId()) .orElseThrow(RuntimeException::new);맨아래서, 2번째 줄에서 member의 정보를 DB에 저장합니다.: saveAndFlush 이용그리고 나서 QueryDSL로 작성된 findMemberDetailsByMemberId 으로 해당 멤버의 정보를 조회해 왔습니다.: 그러나, 해당 쿼리로는 조회된 값이 없어 null 이 반환되었습니다. 확인해보니, saveAndFlush를 통해 해당 멤버의 정보가 즉각 DB에 반영되지 않아서 QueryDSL 로된 쿼리로 해당 멤버의 정보가 조회되지 않은 것인데요. 제가 알기로 saveAndFlush를 이용하면 즉각 DB에 반영되는 것으로 알고있었는데... 아닌가요?이런 경우 어떤 방법으로 해결할 수 있을지 조언 주시면 감사하겠습니다!(member 정보 저장 후, querydsl로 조회해올 수 있는 방법)
-
미해결
JPA saveAndFlush 이후 QueryDSL 조회에 관한 질문드려요.
@Transactional public AccessTokenResponse signup(MemberRequest request) { Member member = request.toMember(passwordEncoder); MemberDetails memberDetails = memberRepository .findMemberDetailsByMemberId(memberRepository.saveAndFlush(member).getId()) .orElseThrow(RuntimeException::new);맨아래서, 2번째 줄에서 member의 정보를 DB에 저장합니다.: saveAndFlush 이용그리고 나서 QueryDSL로 작성된 findMemberDetailsByMemberId 으로 해당 멤버의 정보를 조회해 왔습니다.: 그러나, 해당 쿼리로는 조회된 값이 없어 null 이 반환되었습니다. 확인해보니, saveAndFlush를 통해 해당 멤버의 정보가 즉각 DB에 반영되지 않아서 QueryDSL 로된 쿼리로 해당 멤버의 정보가 조회되지 않은 것인데요. 제가 알기로 saveAndFlush를 이용하면 즉각 DB에 반영되는 것으로 알고있었는데... 아닌가요?선배님들의 조언 부탁드립니다 ㅠ
-
미해결
OneToOne관계 Insert 질문있습니다..
안녕하세요 JPA를 공부하고 테스트하는과정에서 문제가 생겨 질문드립니다..ㅠㅠ사용자테이블(USER)비밀번호테이블(PASSWORD) 2개가 있고,각각 USER_ID를 키값으로 가지고 있습니다. 사용자 테이블 Entity비밀번호 Entity 회원가입 사용자정보(userInfo)를 입력하면 비밀번호(userPwd) 테이블에도 같이 insert되게 하고싶습니다. 여기서 문제가 생기는데 Setter함수를 되도록이면 쓰지말라고해서 생성자 초기화를 이용하여 테스트중인데생성자를 만드는과정에서 어떻게 생성을 해야될지 모르겠습니다..userInfo 생성자에 userPwd를 넣는게 맞는건지... 예상되는 insertUserInfo테이블 admin, 기타정보들UserPwd테이블 admin, 1234 아시는분있으면 도움좀 부탁드리겠습니다..ㅠㅠ감사합니다.
-
미해결
JPA 문제
public ResponseEntity<?> updateBoard(Long boardId, CreateBoardDTO boardDTO, String memberEmail) { try { // 게시글 조회 BoardEntity findBoard = boardRepository.findByBoardId(boardId) .orElseThrow(EntityNotFoundException::new); log.info("게시글 닉네임 : " + findBoard.getMember().getNickName()); // 유저 조회 MemberEntity findUser = memberRepository.findByEmail(memberEmail); log.info("유저 : " + findUser); // 받아온 유저를 조회하고 그 유저 정보와 게시글에 담긴 유저가 일치하는지 boolean equalsEmail = findUser.getEmail().equals(findBoard.getMember().getEmail()); if(equalsEmail) { // 수정할 내용, 유저정보, 게시글을 작성할 때 받은 상품의 정보를 넘겨준다. findBoard = BoardEntity.builder() .boardId(findBoard.getBoardId()) .title(boardDTO.getTitle()) .content(boardDTO.getContent()) .item(findBoard.getItem()) .member(findBoard.getMember()) .boardSecret(BoardSecret.UN_LOCK) .build(); BoardEntity updateBoard = boardRepository.save(findBoard); BoardDTO returnBoard = BoardDTO.toBoardDTO(updateBoard, findUser.getNickName()); log.info("게시글 : " + returnBoard); return ResponseEntity.ok().body(returnBoard); } else { return ResponseEntity.badRequest().body("일치하지 않습니다."); } } catch (Exception e) { e.printStackTrace(); return ResponseEntity.badRequest().body("수정하는데 실패했습니다. : " + e.getMessage()); } }package com.example.shopping.entity.board; import com.example.shopping.domain.board.BoardDTO; import com.example.shopping.domain.board.BoardSecret; import com.example.shopping.domain.board.CreateBoardDTO; import com.example.shopping.domain.comment.CommentDTO; import com.example.shopping.entity.Base.BaseEntity; import com.example.shopping.entity.comment.CommentEntity; import com.example.shopping.entity.item.ItemEntity; import com.example.shopping.entity.member.MemberEntity; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import javax.persistence.*; import java.util.ArrayList; import java.util.List; @Entity(name = "board") @Table @Getter @NoArgsConstructor public class BoardEntity extends BaseEntity { @Id @GeneratedValue @Column(name = "board_id") private Long boardId; @Column(length = 300, nullable = false) private String title; private String content; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id") private MemberEntity member; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "item_id") private ItemEntity item; @Enumerated(EnumType.STRING) private BoardSecret boardSecret; // 댓글 // 여기에 적용해야 합니다. 보통 게시물을 삭제해야 이미지가 삭제되므로 // 게시물이 주축이기 때문에 여기에 cascade = CascadeType.ALL을 추가 // orphanRemoval = true도 게시글을 삭제하면 // 댓글도 삭제되므로 여기서 작업을 해야합니다. @OneToMany(mappedBy = "board", cascade = CascadeType.ALL, orphanRemoval = true) @OrderBy("commentId asc ") private List<CommentEntity> commentEntityList = new ArrayList<>(); @Builder public BoardEntity(Long boardId, String title, String content, MemberEntity member, ItemEntity item, BoardSecret boardSecret, List<CommentEntity> commentEntityList) { this.boardId = boardId; this.title = title; this.content = content; this.member = member; this.item = item; this.boardSecret = boardSecret; this.commentEntityList = commentEntityList; } // 게시글 DTO를 엔티티로 변환 public static BoardEntity toBoardEntity(BoardDTO board, MemberEntity member, ItemEntity item) { BoardEntity boardEntity = com.example.shopping.entity.board.BoardEntity.builder() .boardId(board.getBoardId()) .title(board.getTitle()) .content(board.getContent()) .member(member) .item(item) .build(); // 댓글 처리 List<CommentDTO> commentDTOList = board.getCommentDTOList(); for (CommentDTO commentDTO : commentDTOList) { CommentEntity commentEntity = CommentEntity.toCommentEntity(commentDTO, member, boardEntity); boardEntity.commentEntityList.add(commentEntity); } return boardEntity; } /* 비즈니스 로직 */ // 게시글 작성 public static BoardEntity createBoard(CreateBoardDTO boardDTO, MemberEntity member, ItemEntity item) { return com.example.shopping.entity.board.BoardEntity.builder() .title(boardDTO.getTitle()) .content(boardDTO.getContent()) // 본인이 작성한 글은 읽을 수 있어야하기 때문에 UN_ROCK .boardSecret(BoardSecret.UN_LOCK) .member(member) .item(item) .build(); } // 문의글 상태 변화 public void changeSecret(BoardSecret secret) { this.boardSecret = secret; } } package com.example.shopping.domain.board; import com.example.shopping.domain.comment.CommentDTO; import com.example.shopping.entity.board.BoardEntity; import com.example.shopping.entity.comment.CommentEntity; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.ToString; import javax.validation.constraints.NotNull; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Collections; import java.util.List; @Getter @ToString @NoArgsConstructor public class BoardDTO { @Schema(description = "문의글 번호", example = "1", required = true) private Long boardId; @Schema(description = "문의글 제목", required = true) @NotNull(message = "문의글 제목은 필 수 입력입니다.") private String title; @Schema(description = "문의글 본문") private String content; @Schema(description = "유저 닉네임") private String nickName; @Schema(description = "문의글 작성 시간") private LocalDateTime regTime; @Schema(description = "관리자 답변") private List<CommentDTO> commentDTOList = new ArrayList<>(); @Schema(description = "문의글이 본인글인지 확인") private BoardSecret boardSecret; @Builder public BoardDTO(Long boardId, String title, String content, String nickName, LocalDateTime regTime, List<CommentDTO> commentDTOList, BoardSecret boardSecret) { this.boardId = boardId; this.title = title; this.content = content; this.nickName = nickName; this.regTime = regTime; this.commentDTOList = commentDTOList; this.boardSecret = boardSecret; } // 엔티티를 DTO로 변환하는 작업 public static BoardDTO toBoardDTO(BoardEntity board, String nickName) { // 게시글 댓글 처리 List<CommentEntity> commentEntityList = board.getCommentEntityList(); List<CommentDTO> commentDTOS = new ArrayList<>(); // 엔티티 댓글을 DTO 리스트에 담아주는 작업을 진행하고 있다. if (commentEntityList != null) { for (CommentEntity commentEntity : commentEntityList) { CommentDTO commentDTO = CommentDTO.toCommentDTO(commentEntity); commentDTOS.add(commentDTO); } } else { // commentEntityList가 null일 경우 빈 리스트로 초기화 commentDTOS = Collections.emptyList(); } return BoardDTO.builder() .boardId(board.getBoardId()) .title(board.getTitle()) .content(board.getContent()) .nickName(nickName) .commentDTOList(commentDTOS) .regTime(LocalDateTime.now()) .boardSecret(board.getBoardSecret()) .build(); } } 수정 문구인데 로그를 확인하면 게시글 로그까지 제대로 나오는 것을 볼 수있는데 근데 리턴이 안되고 400번 오류가 발생하는데 body에 적은 내용은 안나오는 상황입니다. 로그까지 찍혔는데 왜 리턴이 안되는 걸까요?? 아무 에러 표시도 안나옵니다.
-
미해결
ec2재부팅 후 ec2 주소 접근 불가능 !!!!! (스프링 배포)
https://velog.io/@dasd412/ec2-%EC%9E%AC%EB%B6%80%ED%8C%85-%ED%9B%84-%EC%97%B0%EA%B2%B0-%EB%B6%88%EA%B0%80-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0이걸 참고해도 보안 다시 해도 전 여전히 안되더라구요.. 결론적으로 배포를 성공했고 배포한 주소가 회원가입에 접근을 못해서 시큐리티 설정 때문에 그런줄 알았는데 여기서 멈췄어야 했나봅니다..로컬에서는 되고 ec2주소로는 접속이 안되어서 찾아보던 중 ec2를 재부팅 하면 해결된다고 해서 따라 했더니https://github.com/jojoldu/freelec-springboot2-webservice/issues/485 이제는 아예 ec2주소에 접근이 불가능합니다 ㅠㅠㅠㅠㅠ 이걸 해결해야 하는데 어떡하나요..
-
미해결
JWT 에러
ECDSA signing keys must be PrivateKey instances. 이거는 대체 무슨에러죠 ? ㅠㅠ해결방법이 안나오네요 ㅠㅠ
-
미해결
cannot resolve symbol 'name' 오류
cannot resolve symbol 'name'오류가 뜨는데 구글링해서 나온 방법으로도 해결이 안되네요ㅠㅠ 어떤게 잘못됐는지 알려주세요
-
미해결
배포에 대한 질문이 있습니다. 급합니다 ㅠㅠ
현재 프론트하고 백엔드하고 배포를 따로 하려고 하는데이 배포를 언제까지 유지해야 하는지가 궁금합니다.포폴에 배포 링크를 담아주고 취업할 때 까지 유지해야 하는지 아니면 배포하고 시연 이미지 첨부한 설명을 포폴에 담고 배포를 종료해도 되는지 어떻게 해야하는지 궁금합니다. 알려주시면 감사하겠습니다 ㅠㅠ (__) 꾸벅