<aside> 1️⃣ 에러 상황
</aside>
jakarta.servlet.ServletException: Request processing failed: org.thymeleaf.exceptions.TemplateInputException: Error resolving template [board/save], template might not exist or might not be accessible by any of the configured Template Resolvers
Caused by: org.thymeleaf.exceptions.TemplateInputException: Error resolving template [board/save], template might not exist or might not be accessible by any of the configured Template Resolvers
<aside> 2️⃣ 작성한 코드
</aside>
@Slf4j
@RequiredArgsConstructor
@RequestMapping("/board")
@Controller
public class BoardController {
private final BoardService boardService;
@PostMapping("/save")
public void getBoard(@RequestBody BoardRequest request) {
boardService.saveBoard(request);
}
}
@Import(TestSecurityConfig.class)
@DisplayName("[Board] - 컨트롤러 테스트")
class BoardControllerTest extends ControllerTestSupport {
@Autowired private MockMvc mockMvc;
@Autowired private ObjectMapper objectMapper;
@MockBean private BoardRepository boardRepository;
@MockBean private BoardService boardService;
@DisplayName("실제 사용자가 게시글을 작성하고 저장하면 게시글이 저장된다.")
@Test
void test1() throws Exception {
//given
User user = createUser();
Board board = createBoard(user, "테스트 데이터");
BoardRequest request = BoardRequest.of(board);
//when
mockMvc.perform(post("/board/save")
.content(objectMapper.writeValueAsString(request))
.contentType(MediaType.APPLICATION_JSON)
)
.andDo(print())
.andExpect(status().isOk());
}
private Board createBoard(User user, String title) {
return Board.of(title,
"테스트",
10,
20,
user
);
}
private User createUser() {
return User.of(
"wlsdks12",
"wlsdks12",
"wlsdks",
"[email protected]",
RoleType.ADMIN,
UserStatus.Y
);
}
}
@Profile("test")
@Import(TestSecurityConfig.class) // 테스트 설정 클래스 적용
@WebMvcTest({
ChatMainController.class,
BoardController.class
})
public abstract class ControllerTestSupport {
}
/**
* 테스트에 필요한 security관련 설정을 여기서 전부 처리하기위해 만들었다.
*/
@TestConfiguration
public class TestSecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(authorize ->
authorize.anyRequest().permitAll()
);
return http.build();
}
}
<aside> 3️⃣ 문제 파악
</aside>
<aside> 4️⃣ 문제 해결
</aside>
@Controller
어노테이션을 사용하는 경우, 스프링은 기본적으로 뷰를 반환하려고 시도한다. 위의 코드에서는 **void
**를 반환하므로 스프링은 URL 경로와 일치하는 뷰를 찾으려고 시도하게 된다. 이 경우 URL 경로가 **/save
**이므로, 스프링은 **save
**라는 이름의 뷰를 찾으려고 시도한다.@RestController
어노테이션을 사용하면 된다. **@RestController
**는 **@Controller
**와 **@ResponseBody
**를 합친 것으로, 반환 값이 HTTP 응답 본문에 직접 쓰여지게 된다.@RestController
public class YourControllerClass {
@PostMapping("/save")
public void getBoard(@RequestBody BoardRequest request) {
boardService.saveBoard(request);
}
}