Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,23 +1,87 @@
package site.icebang.common.exception;

/**
* 데이터 중복 상황에서 발생하는 예외 클래스입니다.
*
* <p>이 예외는 데이터베이스나 컬렉션에서 이미 존재하는 데이터를 중복해서 생성하거나 저장하려고 할 때 발생합니다. 주로 유니크 제약 조건 위반이나 비즈니스 로직상 중복을
* 허용하지 않는 경우에 사용됩니다.
*
* <h3>사용 예제:</h3>
*
* <pre>{@code
* // 사용자 이메일 중복 체크
* if (userRepository.existsByEmail(email)) {
* throw new DuplicateDataException("이미 존재하는 이메일입니다: " + email);
* }
*
* // 상품 코드 중복 체크
* try {
* productService.createProduct(product);
* } catch (DataIntegrityViolationException e) {
* throw new DuplicateDataException("중복된 상품 코드입니다", e);
* }
* }</pre>
*
* @author jys01012@gmail.com
* @since v0.0.1-alpha
*/
public class DuplicateDataException extends RuntimeException {

/**
* 상세 메시지 없이 새로운 {@code DuplicateDataException}을 생성합니다.
*
* @since v0.0.1-alpha
*/
public DuplicateDataException() {
super();
}

/**
* 지정된 상세 메시지와 함께 새로운 {@code DuplicateDataException}을 생성합니다.
*
* @param message 상세 메시지 (나중에 {@link Throwable#getMessage()} 메서드로 검색됨)
* @since v0.0.1-alpha
*/
public DuplicateDataException(String message) {
super(message);
}

/**
* 지정된 상세 메시지와 원인과 함께 새로운 {@code DuplicateDataException}을 생성합니다.
*
* <p>{@code cause}와 연관된 상세 메시지가 이 예외의 상세 메시지에 자동으로 포함되지는 않습니다.
*
* @param message 상세 메시지 (나중에 {@link Throwable#getMessage()} 메서드로 검색됨)
* @param cause 원인 (나중에 {@link Throwable#getCause()} 메서드로 검색됨). {@code null} 값이 허용되며, 원인이 존재하지 않거나
* 알 수 없음을 나타냄
* @since v0.0.1-alpha
*/
public DuplicateDataException(String message, Throwable cause) {
super(message, cause);
}

/**
* 지정된 원인과 상세 메시지와 함께 새로운 {@code DuplicateDataException}을 생성합니다. 상세 메시지는 {@code (cause==null ?
* null : cause.toString())}로 설정됩니다. (일반적으로 {@code cause}의 클래스와 상세 메시지를 포함)
*
* @param cause 원인 (나중에 {@link Throwable#getCause()} 메서드로 검색됨). {@code null} 값이 허용되며, 원인이 존재하지 않거나
* 알 수 없음을 나타냄
* @since v0.0.1-alpha
*/
public DuplicateDataException(Throwable cause) {
super(cause);
}

/**
* 지정된 상세 메시지, 원인, suppression 활성화 여부, 그리고 writable stack trace 여부와 함께 새로운 {@code
* DuplicateDataException}을 생성합니다.
*
* @param message 상세 메시지
* @param cause 원인. ({@code null} 값이 허용되며, 원인이 존재하지 않거나 알 수 없음을 나타냄)
* @param enableSuppression suppression이 활성화되는지 또는 비활성화되는지 여부
* @param writableStackTrace stack trace가 writable해야 하는지 여부
* @since v0.0.1-alpha
*/
protected DuplicateDataException(
String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,61 @@

import org.springframework.stereotype.Component;

/**
* 보안이 강화된 랜덤 패스워드를 생성하는 유틸리티 클래스입니다.
*
* <p>이 클래스는 소문자, 대문자, 숫자, 특수문자를 포함한 강력한 패스워드를 생성합니다. 생성된 패스워드는 각 문자 유형을 최소 하나씩 포함하도록 보장됩니다.
*
* <h3>사용 예제:</h3>
*
* <pre>{@code
* @Autowired
* private RandomPasswordGenerator passwordGenerator;
*
* // 기본 길이(12자)로 패스워드 생성
* String password1 = passwordGenerator.generate();
*
* // 사용자 지정 길이로 패스워드 생성
* String password2 = passwordGenerator.generate(16);
* }</pre>
*
* @author jys01012@gmail.com
* @since v0.0.1-alpha
*/
@Component
public class RandomPasswordGenerator {

/** 소문자 알파벳 문자 집합 */
private static final String LOWERCASE = "abcdefghijklmnopqrstuvwxyz";

/** 대문자 알파벳 문자 집합 */
private static final String UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

/** 숫자 문자 집합 */
private static final String DIGITS = "0123456789";

/** 특수문자 집합 */
private static final String SPECIAL_CHARS = "!@#$%^&*()-_+=<>?";

/** 암호학적으로 안전한 난수 생성기 */
private final SecureRandom random = new SecureRandom();

/**
* 지정된 길이의 랜덤 패스워드를 생성합니다.
*
* <p>생성되는 패스워드는 다음 규칙을 준수합니다:
*
* <ul>
* <li>최소 길이는 8자입니다
* <li>소문자, 대문자, 숫자, 특수문자를 각각 최소 1개씩 포함합니다
* <li>모든 문자는 무작위로 섞여서 배치됩니다
* </ul>
*
* @param length 생성할 패스워드의 길이 (8보다 작으면 8로 조정됩니다)
* @return 생성된 랜덤 패스워드
* @throws IllegalArgumentException length가 음수인 경우
* @since v0.0.1-alpha
*/
public String generate(int length) {
if (length < 8) {
length = 8;
Expand Down Expand Up @@ -49,13 +94,28 @@ public String generate(int length) {
.toString();
}

// 특정 문자열에서 랜덤으로 한 문자 선택
/**
* 지정된 문자 집합에서 랜덤으로 한 문자를 선택합니다.
*
* @param charSet 선택할 문자들이 포함된 문자열
* @return 선택된 랜덤 문자
* @throws IllegalArgumentException charSet이 null이거나 빈 문자열인 경우
* @since v0.0.1-alpha
*/
private char getRandomChar(String charSet) {
int randomIndex = random.nextInt(charSet.length());
return charSet.charAt(randomIndex);
}

// 기본 길이로 비밀번호 생성
/**
* 기본 길이(12자)로 랜덤 패스워드를 생성합니다.
*
* <p>이는 {@code generate(12)}를 호출하는 것과 동일합니다.
*
* @return 12자 길이의 랜덤 패스워드
* @see #generate(int)
* @since v0.0.1-alpha
*/
public String generate() {
return generate(12); // 기본 길이를 12로 설정
}
Expand Down
Loading