8. Spring homepage https://spring.io

최종 업데이트 : 2025-01-30

Spring은 자바 백엔드 개발을 위한 핵심 프레임워크이고,

Spring Boot는 이 Spring을 편리하게 사용할 수 있도록 만든 도구상자라고 생각하면 좋습니다.

Spring Boot는 Spring을 사용하는 개발자들이 빠르게 개발을 시작할 수 있도록 도와줍니다.

Spring → 유연하지만 설정이 복잡한 오리지널기능이라면

Spring Boot → Spring 기반의 편의성 극대화 버전이라고 생각하면됩니다.

물론 kotlin으로 백엔드가 개발가능하지만

자바로 개발하는것이 보편적임으로

자바로 학습하고 개발하는것을 추천드립니다.

    
      
src/main/java/com/api_java/ApijavaApplication.java

package com.api_java;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ApiJavaApplication {
	public static void main(String[] args) {
		SpringApplication.run(ApiJavaApplication.class, args);
	}
}
    
    
  

위 코드는 Spring Boot 프로젝트의 시작점인 ApiJavaApplication.java 파일입니다.

Spring Boot 프로젝트는 main 메소드를 가진 클래스를 시작점으로 합니다.

SpringApplication.run() 메소드는 내장 톰캣 서버를 실행시키는 역할을 합니다.

    
      
api-java/build.gradle

dependencies {
	implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.1'
}

src/main/java/com/api_java/config
/SwaggerConfig.java

package com.api_java.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;

@Configuration
public class SwaggerConfig {
    @Bean
    public OpenAPI openAPI() {
        return new OpenAPI()
                .components(new Components())
                .info(swaggerInfo())
                .addSecurityItem(new SecurityRequirement().addList("JWT"));
    }
 
    private Info swaggerInfo() {
        return new Info()
                .title("api-java")
                .description("Springdoc을 사용한 Swagger UI")
                .version("1.0.0");
    }
}
    
    
  

위 코드는 Spring Boot 프로젝트에 Swagger를 적용하는 코드입니다.

Swagger는 API 문서를 자동으로 생성해주는 도구입니다.

SwaggerConfig.java 파일은 Swagger 설정을 위한 파일입니다.

실행하여 스웨거가 잘 작동하는지 확인합니다.

    
      
src/main/resurces/application.properties

server.port=8000
      
    
  

위 코드는 Spring Boot 프로젝트의 포트를 8000번으로 변경하는 코드입니다.

application.properties 파일은 Spring Boot 프로젝트의 설정파일입니다.

포트번호를 변경하고 실행하여 포트번호가 변경되었는지 확인합니다.

    
      
src/mainjava/com/api_java/signup/SignupRequest.java

package com.api_java.signup;

import jakarta.validation.constraints.NotEmpty;

public class SignupRequest {
  @NotEmpty(message = "ID는 필수입니다.")
  private String id;

  @NotEmpty(message = "Password는 필수입니다.")
  private String password;

  public String getId() {
      return id;
  }

  public void setId(String id) {
      this.id = id;
  }

  public String getPassword() {
      return password;
  }

  public void setPassword(String password) {
      this.password = password;
  }
}
      
    
  

위 코드는 회원가입 요청을 처리하는 SignupRequest.java 파일입니다.

SignupRequest 클래스는 회원가입 요청을 처리하기 위한 DTO(Data Transfer Object)입니다.

DTO는 데이터 전송을 위한 객체로, 데이터베이스와 서비스 사이에서 데이터를 전달하는 역할을 합니다.

사용할 id와 password를 설정해줍니다.

    
      
src/mainjava/com/api_java/response/SuccesResponse.java

package com.api_java.response;

import com.fasterxml.jackson.annotation.JsonProperty;

public class SuccessResponse {

  @JsonProperty("status_code")
  private final int statusCode;

  @JsonProperty("content")
  private final String content;

  public SuccessResponse(int statusCode, String content) {
      this.statusCode = statusCode;
      this.content = content;
  }

  public int getStatusCode() {
      return statusCode;
  }

  public String getContent() {
      return content;
  }
}
      
    
  

위 코드는 성공 응답을 처리하는 SuccessResponse.java 파일입니다.

공통성을 위해 JsonProperty 이용해 status_code로 나오도록 설정합니다.

성공 응답은 status_code와 content로 구성되어 있습니다.

    
      
src/mainjava/com/api_java/exception/CustomException.java

package com.api_java.exception;

import com.fasterxml.jackson.annotation.JsonProperty;

public class CustomException extends RuntimeException {
  
  @JsonProperty("status_code")
  private final int statusCode;
  
  @JsonProperty("content")
  private final String content;

  public CustomException(String content, int statusCode) {
      super(content);
      this.content = content;
      this.statusCode = statusCode;
  }

  public int getStatusCode() {
      return statusCode;
  }

  public String getContent() {
      return content;
  }
}

src/mainjava/com/api_java/exception/GlobalExceptionHandler.java

package com.api_java.exception;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import com.fasterxml.jackson.annotation.JsonProperty;

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(CustomException.class)
    public ResponseEntity<?> handleCustomException(CustomException ex) {
        return ResponseEntity.status(ex.getStatusCode())
                .body(new ErrorResponse(ex.getStatusCode(), ex.getContent()));
    }

    public static class ErrorResponse {
        
        @JsonProperty("status_code")
        private final int statusCode;
        
        @JsonProperty("content")
        private final String content;

        public ErrorResponse(int statusCode, String content) {
            this.statusCode = statusCode;
            this.content = content;
        }

        public int getStatusCode() {
            return statusCode;
        }

        public String getContent() {
            return content;
        }
    }
}
      
    
  

위 코드는 예외 처리를 위한 CustomException.java와 GlobalExceptionHandler.java 파일입니다.

CustomException 클래스는 예외 처리를 위한 커스텀 예외 클래스입니다.

GlobalExceptionHandler 클래스는 예외 처리를 위한 전역 예외 핸들러 클래스입니다.

예외가 발생하면 GlobalExceptionHandler 클래스에서 예외를 처리합니다.

같은 형태로 반환할 수 있도록 SuccessResponse와 형태를 맞춰줍니다.

예외가 발생하면 ErrorResponse로 반환합니다.

    
      
api-java/build.gradle

dependencies {
  implementation 'org.springframework.boot:spring-boot-starter-security'
  implementation 'org.springframework.security:spring-security-crypto:6.4.2'
}


src/main/java/com/api_java/config/SecurityConfig.java

package com.api_java.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf(csrf -> csrf.disable())
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/", 
                    "/swagger-ui/**", 
                    "/v3/api-docs/**", 
                    "/v3/api-docs.yaml", 
                    "/swagger-resources/**", 
                    "/webjars/**",
                    "/api/signup" 
                ).permitAll()
                .anyRequest().authenticated()
            )
            .httpBasic(httpBasic -> {});

        return http.build();
    }
}

src/java/com/api_java/signup/SignupService.java

package com.api_java.signup;

import com.api_java.exception.CustomException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Service
public class SignupService {
  private final Map<String, String> usersDb = new HashMap<>();
  private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

  public void signup(SignupRequest signRequest) {
      String id = signRequest.getId();
      String password = signRequest.getPassword();

      if (usersDb.containsKey(id)) {
          throw new CustomException("이미 사용 중인 ID입니다.", 409);
      }

      String hashedPassword = passwordEncoder.encode(password);
      usersDb.put(id, hashedPassword);
  }  
}
      
    
  

cors 처리를 위해 spring security를 추가하고 암호화를 위해 spring security crypto를 추가합니다.

SecurityConfig.java 파일은 Spring Security 설정을 위한 파일입니다.

SecurityFilterChain 빈을 등록하여 Spring Security 설정을 구성합니다.

csrf를 비활성화하고, 이후에 만들 /api/signup endpoint를 제외한 모든 요청은 인증하도록 설정합니다.

SignupService.java 파일은 회원가입을 처리하는 서비스 클래스입니다.

회원가입 요청을 처리하고, 중복된 ID가 있는 경우 예외를 발생시킵니다.

회원가입 요청을 처리하고, 비밀번호를 암호화하여 저장합니다.

private final Map<String, String> usersDb = new HashMap<>()를 선언하여여

앞에서 만들어둔 SignupRequest를 이용해 이루어집니다.

    
      
src/java/com/api_java/signup/SignupController.java

package com.api_java.signup;

import com.api_java.response.SuccessResponse;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;

@RestController
@RequestMapping("/api")
public class SignupController {

  private final SignupService signupService;

  public SignupController(SignupService signupService) {
      this.signupService = signupService;
  }

  @PostMapping("/signup")
  public ResponseEntity<?> signup(@Valid @RequestBody SignupRequest signupRequest) {
    signupService.signup(signupRequest);
    return ResponseEntity.status(HttpStatus.CREATED)
      .body(new SuccessResponse(HttpStatus.CREATED.value(), "회원가입 성공"));
  }  
}
      
    
  

SignupController.java 파일은 회원가입 요청을 처리하는 컨트롤러 클래스입니다.

회원가입 요청을 처리하고, SignupService 클래스를 이용해 회원가입을 처리합니다.

@RequestMapping("/api"), @PostMapping("/signup") endpoint경로를 지정하고

SignupRequest로 들어오는 데이터를 SignupService를 이용해 처리하고

성공적으로 처리되면 SuccessResponse를, 실패하면 CustomException를 반환합니다.

실행하여 스웨거로 잘 되는지 확인합니다.


Spring Boot를 이용하여 백엔드 개발을 할때 어떤것들이 사용되는지 알아보았습니다.

간단히 회원가입을 위해 프론트와 백엔드가 어떻게 연결되는지

어떤 차이점이 있고 난이도와 차이점을 가볍게 알아봤습니다.

본인에게 맞는 스킬을 선택하여 개발을 선택할 수 있도록

다양한 정보를 제공하고자 합니다.

피드백은 하단의 카카오톡 오픈톡 링크를 이용해 주시면

더욱 더 좋은 컨텐츠를 제공할 수 있도록 노력하겠습니다.

Related Pages

© 2024 Coding Stairs. All rights reserved.