Spring Boot
Spring Framework 기반의 Java 백엔드 프레임워크. 자동 설정과 내장 서버로 빠르게 프로덕션 수준의 앱을 만든다.
프로젝트 구조
src/main/java/com/example/
├── config/ 설정 클래스
├── controller/ HTTP 요청 처리
├── service/ 비즈니스 로직
├── repository/ DB 접근
├── domain/ 엔티티
├── dto/ 요청/응답 객체
└── exception/ 예외 처리
src/main/resources/
├── application.yml 설정 파일
└── application-{profile}.yml
application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: 1234
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: validate # create | update | validate | none
show-sql: false
properties:
hibernate:
format_sql: true
server:
port: 8080
logging:
level:
com.example: DEBUG레이어별 어노테이션
Controller
@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
@GetMapping
public ResponseEntity<List<UserResponse>> getUsers() {
return ResponseEntity.ok(userService.findAll());
}
@GetMapping("/{id}")
public ResponseEntity<UserResponse> getUser(@PathVariable Long id) {
return ResponseEntity.ok(userService.findById(id));
}
@PostMapping
public ResponseEntity<UserResponse> createUser(
@RequestBody @Valid UserCreateRequest request
) {
return ResponseEntity.status(HttpStatus.CREATED)
.body(userService.create(request));
}
@PutMapping("/{id}")
public ResponseEntity<UserResponse> updateUser(
@PathVariable Long id,
@RequestBody @Valid UserUpdateRequest request
) {
return ResponseEntity.ok(userService.update(id, request));
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.delete(id);
return ResponseEntity.noContent().build();
}
}Service
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class UserService {
private final UserRepository userRepository;
public List<UserResponse> findAll() {
return userRepository.findAll().stream()
.map(UserResponse::from)
.toList();
}
public UserResponse findById(Long id) {
User user = userRepository.findById(id)
.orElseThrow(() -> new NotFoundException("사용자를 찾을 수 없습니다."));
return UserResponse.from(user);
}
@Transactional
public UserResponse create(UserCreateRequest request) {
User user = User.create(request.name(), request.email());
return UserResponse.from(userRepository.save(user));
}
}Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
boolean existsByEmail(String email);
@Query("SELECT u FROM User u WHERE u.name LIKE %:name%")
List<User> searchByName(@Param("name") String name);
}전역 예외 처리
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(NotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(NotFoundException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse(e.getMessage()));
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidation(
MethodArgumentNotValidException e
) {
String message = e.getBindingResult().getFieldErrors().stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.joining(", "));
return ResponseEntity.badRequest().body(new ErrorResponse(message));
}
}주요 어노테이션
| 어노테이션 | 설명 |
|---|---|
@SpringBootApplication |
앱 진입점 (컴포넌트 스캔 포함) |
@RestController |
@Controller + @ResponseBody |
@Service |
서비스 레이어 빈 |
@Repository |
저장소 레이어 빈 |
@Component |
일반 빈 |
@Configuration |
설정 클래스 |
@Bean |
빈 등록 메서드 |
@Transactional |
트랜잭션 관리 |
@Valid |
요청 검증 |
@Value |
설정값 주입 |
@Profile |
프로파일별 빈 활성화 |
빌드 & 실행
./gradlew build
./gradlew bootRun
./gradlew test
# JAR 실행
java -jar build/libs/myapp-0.0.1.jar
java -jar myapp.jar --spring.profiles.active=prod