ChatGPT로 공부하는 Optional
❓ Java 에서 Optional이란?
❓ Optional은 항상 Generic 형태인가?
❓ Optional 사용 예시
import java.util.Optional;
public class OptionalExample {
public static void main(String[] args) {
String value = "Hello, World!"; // 값이 있는 경우
Optional<String> optionalValue = Optional.of(value); // Optional 객체 생성
// 값이 있는 경우
if (optionalValue.isPresent()) {
System.out.println("Value is present: " + optionalValue.get());
}
// 값이 없는 경우
Optional<String> emptyOptional = Optional.empty(); // 빈 Optional 객체 생성
String defaultValue = "Default Value";
String result = emptyOptional.orElse(defaultValue); // 값이 없을 경우 기본 값 제공
System.out.println("Result: " + result);
// 값이 없는 경우 작업 수행
emptyOptional.ifPresent(val -> System.out.println("Value is absent"));
// 값 변환
Optional<Integer> lengthOptional = optionalValue.map(String::length); // 문자열 길이 변환
lengthOptional.ifPresent(len -> System.out.println("Length: " + len));
}
}
❓ Spring에서 Optional 은?
public Optional<User> findUserById(Long userId) {
// userId에 해당하는 User를 찾아서 반환, 값이 없는 경우 Optional.empty() 반환
// ...
}
public void updateUser(Optional<Long> userId, String name) {
// userId가 제공되었을 경우 해당 userId의 User 정보를 업데이트, 값이 없는 경우 무시
// ...
}
@Entity
public class User {
@Id
private Long id;
private String name;
private Optional<String> email; // email이 선택적으로 제공될 수 있는 경우
// ...
}
❓ Repository Interface에서 JpaRepository를 extends하며 Optional을 사용하는 경우
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface UserRepository extends JpaRepository<User, Long> {
// Optional을 사용하여 값이 없는 경우 처리
Optional<User> findByUsername(String username);
// 여러 개의 파라미터에 대한 Optional 사용
Optional<User> findByIdAndIsActive(Long userId, boolean isActive);
// Optional을 사용하지 않고 값이 없는 경우 처리
void deleteByUsername(String username);
}
❓ findBy 와 그 외의 메서드같은 경우는 누가 제공해주고있지 ?
JpaRepository ? Spring boot ? Optional ?
findBy
와 같은 메소드는 Spring Data JPA가 제공하는 기능입니다.❓ Spring Data JPA가 제공하는 기능들의 종류?
Spring Data Jpa 공식문서
5.1.3. Query Methods
Keyword | Sample | JPQL snippet |
---|---|---|
Distinct | findDistinctByLastnameAndFirstname | select distinct … where x.lastname = ?1 and x.firstname = ?2 |
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is, Equals | findByFirstname,findByFirstnameIs,findByFirstnameEquals | … where x.firstname = ?1 |
Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
LessThan | findByAgeLessThan | … where x.age < ?1 |
LessThanEqual | findByAgeLessThanEqual | … where x.age <= ?1 |
GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
After | findByStartDateAfter | … where x.startDate > ?1 |
Before | findByStartDateBefore | … where x.startDate < ?1 |
IsNull, Null | findByAge(Is)Null | … where x.age is null |
IsNotNull, NotNull | findByAge(Is)NotNull | … where x.age not null |
Like | findByFirstnameLike | … where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound with appended %) |
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (parameter bound with prepended %) |
Containing | findByFirstnameContaining | … where x.firstname like ?1 (parameter bound wrapped in %) |
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | … where x.lastname <> ?1 |
In | findByAgeIn(Collection ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection ages) | … where x.age not in ?1 |
True | findByActiveTrue() | … where x.active = true |
False | findByActiveFalse() | … where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstname) = UPPER(?1) |
❓ JpaRepository를 extends하지 않으면 쓸수 없나 ?
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository;
import java.util.Optional;
public interface UserRepository extends Repository<User, Long> {
// 직접 구현한 username을 기준으로 User 엔티티 조회
@Query("SELECT u FROM User u WHERE u.username = ?1")
Optional<User> findByUsername(String username);
}
❓ JPA Repository를 상속받고도 @Query를 통해 구현할 수 있어 ?
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
@Query("SELECT u FROM User u WHERE u.username = :username")
Optional<User> findByUsername(@Param("username") String username);
}
❓ JPA를 extends 하지 않고 직접 Repository 인터페이스를 구현하고 사용하려면 꼭 Query를 사용해야 하나?
@Repository
public class UserRepositoryImpl implements UserRepository {
@PersistenceContext
private EntityManager entityManager;
@Override
public Optional<User> findByUsername(String username) {
// 직접 원하는 로직을 구현
// 예시: JPQL 쿼리를 사용하여 사용자를 조회하고 Optional로 반환
return entityManager.createQuery("SELECT u FROM User u WHERE u.username = :username", User.class)
.setParameter("username", username)
.getResultList()
.stream()
.findFirst();
}
}
package com.sparta.spring_lv1_assignment.Repository;
import com.sparta.spring_lv1_assignment.entity.Board;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
//Spring JPA -> interface 끼리의 상속은 extends
public interface BoardRepository extends JpaRepository<Board, Long> { // <레포지토리랑 연결할 테이블 클래스, id 타입>
// spring jpa 에서는 id로 조회하는 것 밖에 제공되지 않기 때문에
// 특정 게시글의 제목이나 내용으로 검색하기 위해서 query method 를 사용
Optional<Board> findByBoardTitle(String boardTitle);
Optional<Board> findByBoardIdAndUsername(Long boardId, String username);
}
// 게시글 수정
@Transactional
public BoardResponseDto updateBoard(BoardRequestDto.Update updateDto, HttpServletRequest request) {
// 지금 요청중인 사용자의 정보
User user = checktoken(request);
// 요청중인 게시글의 정보
Board board = checkBoard(updateDto.getBoardId());
if (user.getRole() == UserRoleEnum.***USER***){
boardRepository.findByBoardIdAndUsername(updateDto.getBoardId(), user.getUsername()).orElseThrow(
() -> new NoSuchElementException("본인의 글만 수정할 수 있습니다.")
);
}
board.update(updateDto);
return new BoardResponseDto(board);
}