java-v16 Record에 대한 자바 공식문서 '클릭'
레코드 사용
- 간결하고 불변성을 요구하는 간단한 데이터 전송에 적합
- 코드의 가독성과 간결함을 우선시할 때 유리
클래스 사용
- 복잡한 로직, 상태 관리, 확장성이 필요할 때 유리
- 유연성과 커스텀 로직이 중요한 상황에 적합
class로 dto 생성 (차이 강조를 위해 lombok사용 안했습니다.)
public class UserDto {
private final String name;
private final String email;
public UserDto(String name, String email) {
this.name = name;
this.email = email;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
@Override
public boolean equals(Object o) {
~~~
}
@Override
public int hashCode() {
~~~
}
@Override
public String toString() {
~~~
}
}
record로 dto 생성 어노테이션 하나 없이 게터, 세터(기본 생성자), equals(), hashCode(), toString() 알아서 다해줌
public record UserDto(String name, String email) {}
끝
@RequiredArgsConstructor
@RestController
@RequestMapping("/api")
public class UserApiController {
private final UserService userService;
@PostMapping("/signup")
public ResponseEntity<User> signup(@RequestBody AddUserRequest request) {
User newUser = userService.save(request);
return ResponseEntity.ok()
.body(newUser);
}
}
@RequiredArgsConstructor
@Service
public class UserService {
private final UserRepository userRepository;
// @Transactional
public User save(AddUserRequest request) {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
return userRepository.save(request.toEntity());
}
}
@Table(name = "users")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Entity
public class User implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", updatable = false)
private Long id;
@Column(name = "email", nullable = false, unique = true)
private String email;
@Column(name = "password")
private String password;
@Column(name = "nickname", unique = true)
private String nickname;
@Builder
public User(String email, String password, String nickname) {
this.email = email;
this.password = password;
this.nickname = nickname;
}
public User update(String nickname) {
this.nickname = nickname;
return this;
}
/*
getAuthorities(): 사용자가 시스템에서 어떤 일을 할 수 있는지 결정하는 '키'와 같은 역할
ex) 사용자가 어떤 페이지를 볼 수 있거나, 어떤 작업을 수행할 수 있는지를 결정하는 데 사용
ex) 온라인 쇼핑몰 시스템: 사용자가 로그인하면, 시스템은 getAuthorities()를 호출 => 이 사용자에게 어떤 권한이 있는지 확인
코드에서 return List.of(new SimpleGrantedAuthority("user"));는 이 사용자가 '일반 사용자(user)' 권한을 가지고 있음을 나타냄
'일반 사용자' 권한을 가진 사람은 쇼핑몰에서 쇼핑을 할 수 있지만, 상품을 추가하거나 가격을 변경하는 등의 관리자 기능은 사용할 수 없음
즉, getAuthorities() 메서드는 사용자가 시스템 내에서 할 수 있는 일의 '범위'를 정의
이를 통해 어떤 사용자가 특정 기능을 사용할 수 있는지, 또는 특정 페이지에 접근할 수 있는지를 시스템이 결정할 수 있게 해줌
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of(new SimpleGrantedAuthority("user"));
}
@Override
public String getUsername() {
return email;
}
@Override
public String getPassword() {
return password;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
public record AddUserRequest(
String email,
String password,
String nickname
) {
// 컴팩트 생성자를 사용하여 유효성 검사 수행
public AddUserRequest {
if (!isValidEmail(email)) {
throw new IllegalArgumentException("이메일 형식 지켜라.");
}
if (password == null || password.length() <= 4) {
throw new IllegalArgumentException("비번이 4자리 이상은 돼야지 바보야.");
}
}
private static boolean isValidEmail(String email) {
String emailRegex = "^([\\w\\.\\_\\-])*[a-zA-Z0-9]+([\\w\\.\\_\\-])*([a-zA-Z0-9])+([\\w\\.\\_\\-])+@([a-zA-Z0-9]+\\.)+[a-zA-Z0-9]{2,8}$";
return email != null && Pattern.matches(emailRegex, email);
}
public User toEntity() {
return User.builder()
.email(email)
.password(password)
.nickname(nickname)
.build();
}
}
spring security를 의존성에 넣어놔서 이걸 해놔야 포스트맨으로 실습가능
@Slf4j
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// CSRF, 기본 HTTP 인증 설정 비활성화. security6 형식으로 작성.
http.csrf(csrf -> csrf.disable())
.httpBasic(httpBasic -> httpBasic.disable());
http.authorizeHttpRequests(auth -> auth
.requestMatchers(new AntPathRequestMatcher("/api/signup")).permitAll()
.requestMatchers(new AntPathRequestMatcher("/api/**")).authenticated()
.anyRequest().permitAll());
return http.build();
}
}
레코드레코드찍찍찍 레코드레코드찍찍찍
/