우주먼지

💡 상담사 기능

 

요구사항

Open-Session-in-view 옵션: false (트랜잭션 내부의 프록시객체 초기화 필요)

@ManyToOne 단방향 매핑으로 진행
FetchType : Lazy

1. 상담사 등록 (관리자만 등록 가능)
2. 상담사 로그인
3. 상담사 전체 조회 (관리자의 마이페이지)
4. 상담사 수정 (상담사 마이페이지)
5. 상담사 삭제 (괸라자만 삭제 가능)

💡 소스코드

 

Entity

@Entity
@Getter
@Setter
@NoArgsConstructor
public class Counselor extends BaseEntity{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long counselorId;

    @Column(unique = true, length = 50, nullable = false)
    @Email
    private String email;

    @Column(length = 200)
//    @Pattern(regexp = "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[@!%*#?&])[A-Za-z\\d@!%*#?&]{8,}$")
    private String password;
    @Column(nullable = false, length = 20)
    private String counselorName;
    //실명

    @Column(length = 10)
    private String birth;
    // 생년월일

    @Column
    private String graduated;
    //학력

    @Column(length = 200)
    private String profile;
    //프로필 이미지

    @Column
    private String career;
    //경력
    @Column
    private String introduce;
    //소개

    @Column(length = 100)
    private String expertiseField;

    @Enumerated(EnumType.STRING)
    @Column(nullable = false, length = 10)
    private Role role;

//    @Enumerated(EnumType.STRING)
//    @Column(nullable = false, length = 10)
//    private MemberType memberType;

    @Column(length = 250)
    private String refreshToken;

    private LocalDateTime tokenExpirationTime;
    @Builder
    public Counselor(Long counselorId, String email, String password,String expertiseField, String counselorName, String birth, String graduated, String profile, String career, String introduce) {
        this.counselorId = counselorId;
        this.email = email;
        this.expertiseField = expertiseField;
        this.password = password;
        this.counselorName = counselorName;
        this.birth = birth;
        this.graduated = graduated;
        this.profile = profile;
        this.career = career;
        this.introduce = introduce;
    }


    public void updateRefreshToken(JwtTokenDto jwtTokenDto) {
        this.refreshToken = jwtTokenDto.getRefreshToken();
        this.tokenExpirationTime = DateTimeUtils.convertToLocalDateTime(jwtTokenDto.getRefreshTokenExpireTime());
    }
}

 

DTO

public class CounselorDto {
    @Getter
    public static class Post {

        private String profile;
        //프로필 이미지

        private String counselorName;
        //실명

        private String birth;

        private String graduated;
        //학력

        private String expertiseField;
        @Email
        private String email;

        private String password;

        private String confirmPassword;

        private String career;

        private String introduce;

    }

    @Getter
    public static class Login {
        private String email;
        private String password;
    }

    @Getter
    @NoArgsConstructor
    public static class Patch{
        private Long counselorId;

        private String password;

        private String newPassword;

        private String confirmNewPassword;

        public void updateCounselorId(Long counselorId) {
            this.counselorId = counselorId;
        }
    }

    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    @Getter
    @Setter
    public static class Response {

        private Long counselorId;

        private String profile;
        //프로필 이미지

        private String counselorName;
        //실명

        private String birth;

        private String graduated;
        //학력

        private String email;

        private String password;

        private String career;

        private String introduce;

        private String expertiseField;

        private Role role;

//        private MemberType memberType;

        private String refreshToken;

        private LocalDateTime tokenExpirationTime;
    }

    @Getter @Setter
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class LoginResponse {

        private String grantType;

        private String accessToken;

        @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
        private Date accessTokenExpireTime;

        private String refreshToken;

        @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
        private Date refreshTokenExpireTime;

        private Role role;

        public static CounselorDto.LoginResponse of(JwtTokenDto jwtTokenDto, Role role){
            return LoginResponse.builder()
                    .role(role)
                    .grantType(jwtTokenDto.getGrantType())
                    .accessToken(jwtTokenDto.getAccessToken())
                    .accessTokenExpireTime(jwtTokenDto.getAccessTokenExpireTime())
                    .refreshToken(jwtTokenDto.getRefreshToken())
                    .refreshTokenExpireTime(jwtTokenDto.getRefreshTokenExpireTime())
                    .build();
        }
    }

    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    @Getter
    @Setter
    public static class MyPageResponse {

        private Long counselorId;
        private Role role;
        private String email;
        private String counselorName;
        private String password;
    }
}

 

Mapper

@Mapper(componentModel = "spring")
public interface CounselorMapper {

    Counselor counselorPostDtoToCounselor(CounselorDto.Post counselorPostDto);

    CounselorDto.Response counselorToCounselorResponse(Counselor counselor);

    Counselor counselorLoginDtoToCounselor(CounselorDto.Login counselorLogindto);

    CounselorDto.MyPageResponse counselorToMyPageResponse(Counselor counselor);

    @Mapping(source = "newPassword", target = "password")
    Counselor counselorPatchDtoToCounselor(CounselorDto.Patch counselorPatchDto);

    List<CounselorDto.MyPageResponse> counselorsToCounselorMyPageResponses(List<Counselor> counselors);
}

 

Repository

public interface CounselorRepository extends JpaRepository<Counselor, Long> {
    Optional<Counselor> findByEmail(String email);
}

 

Service

@Service
@RequiredArgsConstructor
public class CounselorService {

    private final CounselorRepository counselorRepository;

    private final TokenManager tokenManager; //for 토큰 생성

    private final JasyptConfig jasyptConfig; //for 암호화

    /**
     * 상담사 등록(회원가입)
     */
    public Counselor createCounselor(Counselor counselor) {
        validateDuplicateCounselor(counselor); //동일 이메일 확인

//        counselor.setMemberType(MemberType.DEFAULT); //상담사는 자체회원가입 밖에 없음
        counselor.setRole(Role.COUNSELOR);
        counselor.setPassword(encryptPassword(counselor.getPassword()));

        return counselorRepository.save(counselor);
    }

    /**
     * 상담사 로그인
     */
    public CounselorDto.LoginResponse login(Counselor counselor) {
        JwtTokenDto jwtTokenDto;
        Optional<Counselor> optionalCounselor = findCounslerByEmail(counselor.getEmail());

        if (optionalCounselor.isEmpty()) {
            throw new EntityNotFoundException(ErrorCode.COUNSELOR_NOT_EXISTS);
        }

        Counselor findCounselor = optionalCounselor.get();

        if (!decryptPassword(findCounselor.getPassword()).equals(counselor.getPassword())) {
            throw new AuthenticationException(ErrorCode.WRONG_PASSWROD);
        }

        jwtTokenDto = tokenManager.createJwtTokenDto(findCounselor.getCounselorId(), findCounselor.getRole());

        findCounselor.updateRefreshToken(jwtTokenDto); //토큰값 설정
        counselorRepository.save(findCounselor); //db에 토큰 업데이트

        return CounselorDto.LoginResponse.of(jwtTokenDto, findCounselor.getRole());
    }

    /**
     * 상담사 목록 조회
     */
    @Transactional(readOnly = true)
    public Page<Counselor> findMembers(int page, int size) {
        Page<Counselor> findAllCounselor = counselorRepository.findAll(
                PageRequest.of(page,size, Sort.by("counselorId").descending())
        );
        return findAllCounselor;
    }

    /**
     * 상담사 수정
     */
    public Counselor updateCounselor(Counselor counselor) {
        Counselor findCounselor = findVerifiedCounselorByCounselorId(counselor.getCounselorId());

        String password = encryptPassword(counselor.getPassword());
        findCounselor.setPassword(password);

        return counselorRepository.save(findCounselor);
    }

    /**
     * 상담사 삭제
     */
    public void deleteCounselor(Long counselorId) {
        counselorRepository.deleteById(counselorId);
    }

    /**
     * 로그인한 상담사 정보 조회
     */
    @Transactional(readOnly = true)
    public Counselor getLoginCounselor(HttpServletRequest httpServletRequest) {
        String authorizationHeader = httpServletRequest.getHeader("Authorization");
        String accessToken = authorizationHeader.split(" ")[1]; // Bearer askdhqwdkjwqbdkjwqbdkjqwbdkjwqb

        Claims tokenClaims = tokenManager.getTokenClaims(accessToken);
        Long counselorId = Long.valueOf((Integer) tokenClaims.get("memberId"));
        return findVerifiedCounselorByCounselorId(counselorId);
    }

    /**
     * 상담사 중복 확인
     */
    private void validateDuplicateCounselor(Counselor counselor) {
        Optional<Counselor> optionalCounselor = findCounslerByEmail(counselor.getEmail());
        if(optionalCounselor.isPresent()){
            throw new BusinessException(ErrorCode.ALREADY_REGISTERED_COUNSELOR);
        }
    }

    /**
     * 상담사 존재 확인
     */
    @Transactional(readOnly = true)
    public Counselor findVerifiedCounselorByCounselorId(Long counselorId) {
        return counselorRepository.findById(counselorId)
                .orElseThrow(() -> new EntityNotFoundException(ErrorCode.COUNSELOR_NOT_EXISTS));
    }

    private Optional<Counselor> findCounslerByEmail(String email) {
        return counselorRepository.findByEmail(email);
    }

    /**
     * 비밀번호 암호화
     */
    public String encryptPassword(String password){
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
        encryptor.setPoolSize(4);
        encryptor.setPassword(jasyptConfig.getPassword());
        encryptor.setAlgorithm("PBEWithMD5AndTripleDES");

        return encryptor.encrypt(password);
    }

    /**
     * 비밀번호 복호화
     */
    public String decryptPassword(String password){
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
        encryptor.setPoolSize(4);
        encryptor.setPassword(jasyptConfig.getPassword());
        encryptor.setAlgorithm("PBEWithMD5AndTripleDES");

        return encryptor.decrypt(password);
    }
}

 

Controller

@RestController
@RequestMapping("/api/counselors")
@Validated
@RequiredArgsConstructor
public class CounselorController {

    private final CounselorService counselorService;

    private final CounselorMapper counselorMapper;

    /**
     * 상담사 등록
     */
    @PostMapping("/new")
    public ResponseEntity postCounselor(@Valid @RequestBody CounselorDto.Post counselorPostDto){
        if(!counselorPostDto.getPassword().equals(counselorPostDto.getConfirmPassword())){ //비밀번호와 비밀번호 확인이 같지 않으면
            throw new AuthenticationException(ErrorCode.PASSWORD_MISMATCH); //에러 발생
        }

        Counselor counselor = counselorService.createCounselor(counselorMapper.counselorPostDtoToCounselor(counselorPostDto));
        CounselorDto.Response response = counselorMapper.counselorToCounselorResponse(counselor);

        return new ResponseEntity<>(
                new SingleResponseDto<>(response), HttpStatus.OK
        );
    }

    /**
     * 상담사 로그인
     * 기본 회원과 다르게 MemberType 사용되지 않음
     */
    @PostMapping("/login")
    public ResponseEntity loginCounselor(@Valid @RequestBody CounselorDto.Login counselorLogindto){

        CounselorDto.LoginResponse jwtTokenResponseDto = counselorService.login(counselorMapper.counselorLoginDtoToCounselor(counselorLogindto));

        return new ResponseEntity<>(
                new SingleResponseDto<>(jwtTokenResponseDto), HttpStatus.OK
        );
    }

    /**
     * 상담사 조회(상담사 정보 수정 페이지)
     */
//    @GetMapping("/look-up/{counselorId}")
//    public ResponseEntity getCounselor(@PathVariable("counselorId")@Positive Long counselorId){
//        Counselor counselor = counselorService.findVerifiedCounselorByCounselorId(counselorId);
//        CounselorDto.MyPageResponse response = counselorMapper.counselorToMyPageResponse(counselor);
//
//        return new ResponseEntity<>(
//                new SingleResponseDto<>(response), HttpStatus.OK
//        );
//    }

    /**
     * 상담사 조회 수정
     */
    @GetMapping("/look-up")
    public ResponseEntity getCounselor(HttpServletRequest httpServletRequest){
        Counselor counselor = counselorService.getLoginCounselor(httpServletRequest);
        CounselorDto.MyPageResponse response = counselorMapper.counselorToMyPageResponse(counselor);

        return new ResponseEntity<>(
                new SingleResponseDto<>(response), HttpStatus.OK
        );
    }

    /**
     * 상담사 전체 조회
     */
    /**
     * 회원 전체 조회
     * todo: 상담 횟수 필드 추가
     */
    @GetMapping("/total-look-up")
    public ResponseEntity getMembers(@Positive @RequestParam("page") int page,
                                     @Positive @RequestParam("size") int size){
        Page<Counselor> pageCounselors = counselorService.findMembers(page-1, size);
        List<Counselor> counselors = pageCounselors.getContent();

        return new ResponseEntity<>(new MultiResponseDto<>(
                counselorMapper.counselorsToCounselorMyPageResponses(counselors), pageCounselors)
                ,HttpStatus.OK);
    }

    /**
     * 상담사 정보 수정
     */
    @PatchMapping("/edit/{counselorId}")
    public ResponseEntity updateCounselor(@PathVariable("counselorId")@Positive Long counserlorId,
                                          @Valid @RequestBody CounselorDto.Patch counselorPatchDto){
        counselorPatchDto.updateCounselorId(counserlorId);

        Counselor preCounselor = counselorService.findVerifiedCounselorByCounselorId(counserlorId);

        if (!counselorPatchDto.getNewPassword().equals(counselorPatchDto.getConfirmNewPassword())) {
            throw new EntityNotFoundException(ErrorCode.PASSWORD_MISMATCH);
        }

        String password = counselorService.decryptPassword(preCounselor.getPassword());

        if (!password.equals(counselorPatchDto.getPassword())) {
            throw new AuthenticationException(ErrorCode.WRONG_PASSWROD);
        }

        Counselor counselor = counselorService.updateCounselor(counselorMapper.counselorPatchDtoToCounselor(counselorPatchDto));
        CounselorDto.MyPageResponse response = counselorMapper.counselorToMyPageResponse(counselor);

        return new ResponseEntity<>(
                new SingleResponseDto<>(response), HttpStatus.OK
        );
    }

    /**
     * 상담사 삭제
     */
    @DeleteMapping("/delete/{counselorId}")
    public ResponseEntity deleteCounselor(@PathVariable("counselorId") @Positive Long counselorId){
        counselorService.deleteCounselor(counselorId);

        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }
}

'Project > Main Project' 카테고리의 다른 글

💻 기능 개발 - 결제  (0) 2023.01.27
💻 기능 개발 - 프로그램  (0) 2023.01.27
💻 기능 개발 - 공지사항  (0) 2023.01.26
💻 기능 개발 - 게시물  (0) 2023.01.26
💻 기능 개발 - 회원  (0) 2023.01.26
profile

우주먼지

@o귤o

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

검색 태그