1. 💡 상담사 기능
요구사항
Open-Session-in-view 옵션: false (트랜잭션 내부의 프록시객체 초기화 필요)
@ManyToOne 단방향 매핑으로 진행
FetchType : Lazy
1. 상담사 등록 (관리자만 등록 가능)
2. 상담사 로그인
3. 상담사 전체 조회 (관리자의 마이페이지)
4. 상담사 수정 (상담사 마이페이지)
5. 상담사 삭제 (괸라자만 삭제 가능)
2. 💡 소스코드
2.1. Entity
<java />
@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());
}
}
2.2. DTO
<code />
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;
}
}
2.3. Mapper
<code />
@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);
}
2.4. Repository
<code />
public interface CounselorRepository extends JpaRepository<Counselor, Long> {
Optional<Counselor> findByEmail(String email);
}
2.5. Service
<java />
@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);
}
}
2.6. Controller
<code />
@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 |