728x90

ExceptionHandler는 프로그램 실행 중 예외가 발생했을 때, 이를 적절하게 처리할 수 있도록 도와주는 클래스입니다.

예외가 발생하면, 해당 예외를 처리할 수 있는 가장 가까운 예외 처리기를 찾아 실행시키며, 처리기가 없을 경우 프로그램은 종료됩니다.

ExceptionHandler의 장점은 다음과 같습니다.

  • 예외 처리를 위한 일관된 방법을 제공합니다.
  • 예외가 발생할 경우 처리하기 위한 구조를 제공하므로 코드의 가독성을 높일 수 있습니다.
  • 예외 처리를 통해 프로그램의 안정성과 신뢰성을 높일 수 있습니다.

그러나 ExceptionHandler의 단점도 있습니다.

  • 모든 예외를 처리할 수 없으며, 예외 처리에 대한 일부 책임은 개발자에게 남아 있습니다.
  • 처리되지 않은 예외는 예기치 않은 동작을 일으킬 수 있습니다.

아래는 Java에서 ExceptionHandler 사용하는 간단한 예제입니다.

 

public class Example {
  public static void main(String[] args) {
    try {
      int a = 5 / 0;
    } catch (ArithmeticException e) {
      System.out.println("Cannot divide by zero");
    }
  }
}

 

Controller는 클라이언트의 요청을 받아 해당 요청을 처리합니다.

이 때, 예외가 발생하면 ExceptionHandler를 사용하여 예외 처리를 담당합니다. ExceptionHandler는 예외 처리와 관련된 로직을 담당하므로, Controller에서 처리하는 것이 적절합니다.

 

따라서, 예외 처리를 담당하는 ExceptionHandler 클래스는 일반적으로 Controller 패키지 내부에 위치합니다.

그러나 프로젝트 규모나 구조에 따라 위치가 달라질 있으며, 다른 패키지에 위치해도 상관 없습니다.

중요한 것은 예외 처리 로직을 담당하는 클래스가 Controller에서 처리되는 것입니다.

728x90

 

 

스프링 시큐리티(Spring Security)는 스프링 기반의 애플리케이션에서 보안 관련 처리를 담당하는 프레임워크입니다. 사용자 인증 및 권한 부여와 같은 보안 관련 기능을 간편하게 구현할 수 있습니다.

 

스프링 시큐리티는 다양한 인증 방식을 지원합니다. 폼 인증 방식, OAuth2.0, OpenID Connect 등을 지원하며, 이러한 인증 방식을 사용하여 사용자 인증을 간편하게 처리할 수 있습니다. 또한 스프링 시큐리티는 CSRF(Cross-site request forgery)와 XSS(Cross-site scripting)와 같은 웹 공격에 대한 방어 기능도 제공합니다.

 

스프링 시큐리티는 필터 체인(Filter Chain) 방식으로 동작합니다. 이는 HTTP 요청에 대한 처리를 순차적으로 처리하는 방식으로, 보안 처리도 이러한 필터 체인을 이용하여 처리됩니다. 예를 들어, 사용자 인증 처리를 담당하는 필터와 권한 부여 처리를 담당하는 필터가 존재하며, 이러한 필터들은 필요에 따라 추가하거나 제거할 수 있습니다.

 

스프링 시큐리티는 ACL(Access Control List) 기능을 지원합니다. 이는 객체에 대한 접근 권한을 부여하거나 제한하는 기능으로, 객체 단위로 권한을 관리 있습니다.

 

아래는 접근권한 샘플소스입니다.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  private UserDetailsService userDetailsService;

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
        .antMatchers("/admin/**").hasRole("ADMIN")
        .antMatchers("/user/**").hasAnyRole("ADMIN", "USER")
        .antMatchers("/").permitAll()
        .and().formLogin()
        .and().logout().logoutUrl("/logout")
        .and().csrf().disable();
  }

  @Autowired
  public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
  }

  @Bean
  public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
  }

}

 

위의 코드는 스프링 시큐리티를 사용하여 보안 설정을 구현한 예시입니다. 코드에서는 /admin/** 경로에 대해서는 ADMIN 권한이 있어야 접근할 있고, /user/** 경로에 대해서는 ADMIN 또는 USER권한 모두 접근할 수 있습니다

728x90

API서버 구성요소 중 응답이 있는데 Response구성하는 여러가지 방법 중

직접 Headerd와 body, ErrorCode를 써서 구성하는 방법입니다.

 

기본적으로 ResponseEntity.status(HttpStatus.OK)를 사용해서 응답을 할 수도 있지만,

프로젝트를 진행할 때에 팀원끼리 약속된 응답형식과 코드를 통해 사용을 할수도 있습니다.

 

Response중 먼저 Header class를 작성해 줍니다.

public class ApiHeader {
    private int resultCode; // 성공 200, 실패다 999, 600
    private String  codeName; // success, fail, NOT_FOUND_USER

    public ApiHeader(int resultCode, String codeName) {
        this.resultCode = resultCode;
        this.codeName = codeName;
    }

    public int getResultCode() {
        return resultCode;
    }

    public String getCodeName() {
        return codeName;
    }

}

httpStatus에도 200 OK, 404 Not Found가 있는거처럼 resultCode와 resultName을 담을수 있는 Header를 생성해주고

클라이언트로 데이터를 전달 할 Body클래스도 만들어 줍니다.

public class ApiBody <T>{

    private T data;

    private T msg;

    public ApiBody(T data, T msg){
        this.data = data;
        this.msg = msg;
    }

    public T getData(){
        return data;
    }

    public T getMsg(){
        return msg;
    }

}

데이터는 여러 타입의 데이터가 들어올 수 있으니 

제네릭 타입을 사용해 줍니다.

body 또한 프로젝트에 따라서 약속해주면 되는데 예제에서는 data,msg 두가지를 body에 담겠습니다.

 

다음 컨트롤러에서 헤더와 바디를 담아서 보낼 ApiResponse class입니다.

 

public class ApiResponse<T> {

    private ApiHeader header;

    private ApiBody body;

    private static int SUCCESS = 200;

    public ApiResponse(ApiHeader header, ApiBody body) {
        this.header = header;
        this.body = body;

    }

    public ApiResponse(ApiHeader header) {
        this.header = header;

    }

    public static <T> ApiResponse<T> OK(T data) {
        return new ApiResponse<T>(new ApiHeader(SUCCESS, "SUCCESS"), new ApiBody(data,null));
    }

    public static <T> ApiResponse<T> fail(ErrorCode errorCode) {
        return new ApiResponse(new ApiHeader(errorCode.getCode(), errorCode.name()), new ApiBody(null, errorCode.getMessage()));
    }
}

성공일때와 실패 두가지 함수가 있는데 

성공시에는 200 SUCCESS와 함께 전달할 data를 리턴해주고 

실패시에는 예외처리에 맞게 ErrorCode에서 code값과 name을 가져와서 리턴해줍니다.

 

ErrorCode는 ENUM을 통해서 관리를 해주는데 

아래와 같이 약속된 ErrorCode를 사용해서 처리를 해주면 됩니다.

public enum ErrorCode {
    FAIL(999, "실패"),
    NOT_SUPPORTED_METHOD(998, "NOT_SUPPORTED_METHOD"),
    NOT_FOUND_USER(100, "NOT_FOUND_USER"),
    NOT_FOUND_TOKEN(101, "NOT_FOUND_TOKEN"),
    MALFORMED_ERROR(102, "MALFORMED_ERROR")
    ;

    private int code;
    private String message;

    ErrorCode(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}

성공시와 실패시 예를 보자면 아래처럼 간단하게 사용도 할 수 있고,

ExceptionHandler를 통해서 예외처리 관리도 가능합니다.

다음 포스팅에서는 ExceptionHandler에 관해 작성해 보겠습니다.


@RequestMapping(method = RequestMethod.GET, value="/getUser")
    public @ResponseBody ApiResponse<UserDTO> getUser(HttpServletRequest request, String user_id){
		if(user_id == null){
        	return ApiResponse.fail(ErrorCode.FAIL); 
        }
        return ApiResponse.OK(userService.getUser(user_id));
    }

 

728x90

개발을 하다보면 resource를 분리해서 사용할 경우가 필요합니다.

예를들어 로컬, 개발, 운영별로 resource를 분리시킬수도 있고

DB별로 oracle, mysql에 따라 쿼리문이 다르기때문에 resoure를 분리해서 사용할 수도 있습니다.

 

이번 포스팅에서는 maven빌드시 profile을 지정해서 패키징을하는 방법입니다.

저는 maria디비와 tibero디비를 같이 사용하는프로젝트가 있어서

그 프로젝트를 바탕으로 작성했습니다.

 

우선 아래 이미지처럼 2개의 resource폴더를 생성해줍니다

그런다음 pom.xml에 profile과 resources의 directory를 추가해 줍니다.

우선 <build> 블럭 위에 프로필즈를 추가하는데 id는 war파일을 생성할때 프로필에 입력할 id값이고

env는 resource폴더명에 들어갈 값입니다.

 <profiles>
        <profile>
            <id>maria</id>
            <properties>
                <env>maria</env>
            </properties>
        </profile>
        <profile>
            <id>tibero</id>
            <properties>
                <env>tibero</env>
            </properties>
        </profile>
    </profiles>

profiles를 추가했으면 다음에는 <build>블록 안에 가장위쪽에 resource를 추가해줍니다.

<build>
        <resources>
            <resource>
                <directory>src/main/resources-${env}</directory>
            </resource>
        </resources>
        
        ...
        
</build>

이렇게 작성을 해주면 directory의 ${env}에 위에 선언한 값이 들어가서 

profile에따라 resource-tibero 또는 resource-maria를 사용하게 됩니다.

 

intellij경우는 Tool Windows > maven 창이 있어서 창을 열면 아래 이미지처럼 profile을 따로 입력안하고 선택해서 

패키징을 할수 있습니다.

이클립스경우는 maven build에 들어가면 profile을 입력하는 부분이 있는거로 알고있습니다.

 

하지만 프로필을 바꾸면서 패키징을 해도 전에 사용하던 프로필로 패키징이 될때가 있어서

저는 패키징하전에 클린을 꼭 해줍니다.

 

이상 maven빌드시 resource를 분리해서 사용하는 방법이였습니다. 

+ Recent posts