앞서 설명드린 배포방식은 FE에서 개발하기 편하도록 jar파일만 배포하여서
http://{퍼블릭IP}:8080
로 요청을 보냈을 때 원하는 데이터가 전달될 수 있도록 개발환경을 설정하기 위해 설정했던 방식이었습니다. 하지만 이젠 기본적인 로직 개발이 완성되어서 React+Spring boot를 완벽하게 합쳐서 하나의 파일로써 배포를 해야되므로 FE와 BE를 합쳐서 배포해보겠습니다.
일반적으로 bootJar를 통해 배포파일을 만들고 실행하면 localhost:8080/ 은 잘 수행되어서 저희가 구현했던 로그인 페이지로 잘 이동하는 모습을 볼 수 있습니다. 하지만 App.jsx에서 Routes로 설정해놓은 /search 나 /profile 같은 경로(localhost:8080/search) 로 이동하게 되면 /error 에 대한 매핑이 없다는 형식으로 404 Not Found 에러가 뜨면서 Whit Page가 뜨는 것을 볼 수 있습니다.
이를 해결하기 위해 /error 에 매핑되는 컨트롤러를 추가적으로 작성할 필요가 있습니다.
다른 블로그들을 참고해보면 Spring boot 버전이 이전 버전이라 getErrorPath()함수를 override하는 방식으로 에러를 해결하는 것을 볼 수 있었는데요, 하지만 Spring boot 2.5.x 버전이상을 사용하시는 분들은 @Override getErrorPath()함수를 하면 에러가 발생하는 것을 볼 수 잇습니다. 이는 2.5.x버전 이상 부턴 getErrorPath()함수가 ErrorController에 존재하지 않기 때문입니다. 따라서 아래와 같은 코드를 작성해준다면 기존에 getErrorPath()함수를 override한것과 동일한 효과로 로직을 구현할 수 있습니다.
기존에 작성하신 api Controller를 모아놓은 폴더에 ExceptionApiController라는 이름의 자바클래스 파일을 생성해줍니다.(저의 경우 api/ExceptionApiController)
# ExceptionController.java
package team_project.beer_community.api;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.Objects;
@Controller
public class ExceptionApiController implements ErrorController {
@GetMapping({"/", "error"})
public String index(){
return "index.html";
}
@RequestMapping(value = "/error")
public String handleNoHandleFoundException(HttpServletResponse response, HttpServletRequest request) {
return "/error";
}
}
현재로썬 간단하게 처리하기 위해 String 타입으로 "/error"로만 return 했지만 추가적으로 status code를 전달하거나 로직을 더 구체화하고 싶으시다면 handleNoHandleFoundException()함수를
@RequestMapping(value = "/error")
public ResponseEntity<Objcet> handleNoHandleFoundException(HttpServletResponse response, HttpServletRequest request) {
int status = response.getStatus();
HttpHeaders headers = new HttpHeaders();
System.out.println("status = " + status); // 오류상태
System.out.println("request.getRequestURI() = " + request.getRequestURI()); // 요청주소
if (Objects.equals(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) {
Map<String, Object> body = Map.of("error", "Not Found","timestamp", System.currentTimeMillis());
System.out.println("handleNoHandleFoundException/equals/body = " + body);
return new ResponseEntity<Objcet>(body, headers, HttpStatus.NOT_FOUND);
}
return new ResponseEntity<Objcet>(body, headers, HttpStatus.NOT_FOUND);
}
이와 같은 형식을 작성해주시면 됩니다.
이렇게 되면 /error 를 만나더라도 우리가 원하는 FE단의 index.html로 잘 랜더링되는 것을 볼 수 있습니다.