스프링 MVC 테스트를 사용하여 "원형 뷰 경로" 예외를 피하는 방법
컨트롤러 중 하나에 다음 코드가 있습니다.
@Controller
@RequestMapping("/preference")
public class PreferenceController {
@RequestMapping(method = RequestMethod.GET, produces = "text/html")
public String preference() {
return "preference";
}
}
저는 단지 다음과 같이 스프링 MVC 테스트를 사용하여 테스트하려고 합니다.
@ContextConfiguration
@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class PreferenceControllerTest {
@Autowired
private WebApplicationContext ctx;
private MockMvc mockMvc;
@Before
public void setup() {
mockMvc = webAppContextSetup(ctx).build();
}
@Test
public void circularViewPathIssue() throws Exception {
mockMvc.perform(get("/preference"))
.andDo(print());
}
}
다음과 같은 예외가 발생합니다.
원형 뷰 경로 [기본 설정]: 현재 핸들러 URL [/기본 설정]로 다시 디스패치됩니다.View Resolver 설정을 확인합니다.이는 기본 뷰 이름 생성으로 인해 지정되지 않은 뷰가 원인일 수 있습니다.)
이상한 점은 다음과 같이 템플릿과 뷰 리졸버를 포함하는 "전체" 컨텍스트 설정을 로드하면 정상적으로 동작한다는 것입니다.
<bean class="org.thymeleaf.templateresolver.ServletContextTemplateResolver" id="webTemplateResolver">
<property name="prefix" value="WEB-INF/web-templates/" />
<property name="suffix" value=".html" />
<property name="templateMode" value="HTML5" />
<property name="characterEncoding" value="UTF-8" />
<property name="order" value="2" />
<property name="cacheable" value="false" />
</bean>
이 템플릿 리졸버를 사용할 때 템플릿 리졸바에 의해 추가된 접두사가 "원형 뷰 경로"가 없음을 잘 알고 있습니다.
그런데 어떻게 스프링 MVC 테스트를 사용해서 내 앱을 테스트해야 하나요?
@Controller→@RestController
도 같은 에 '코멘트'가 있는 을 알게 .@Controller로 대체하다@RestController문제를 해결했습니다.다음은 Spring Web MVC의 설명입니다.
@RestController는 그 자체가 @Controller 및 @ResponseBody로 메타 주석화되어 모든 메서드가 유형 수준의 @ResponseBody 주석을 상속하므로 HTML 템플릿을 사용한 뷰 해상도 및 렌더링과 비교하여 응답 본문에 직접 쓰는 컨트롤러를 나타냅니다.
이 문제는 다음과 같이 @Response Body를 사용하여 해결했습니다.
@RequestMapping(value = "/resturl", method = RequestMethod.GET, produces = {"application/json"})
@ResponseStatus(HttpStatus.OK)
@Transactional(value = "jpaTransactionManager")
public @ResponseBody List<DomainObject> findByResourceID(@PathParam("resourceID") String resourceID) {
이것은 Spring MVC 테스트와는 관계가 없습니다.
하지 않은ViewResolver 에는 인 「스프링」이 되어 있습니다.InternalResourceViewResolver which, 의, 의, 의, 성, 됩, of, of, of, of, of, of, of, ofJstlView에 View.
JstlView이 연장되다InternalResourceView, ★★★★★★★★★★★★★★★★.
동일한 웹 응용 프로그램 내의 JSP 또는 기타 리소스 래퍼입니다.모델 개체를 요청 속성으로 공개하고 javax.servlet을 사용하여 지정된 리소스 URL로 요청을 전송합니다.Request Dispatcher.
이 뷰의 URL은 RequestDispatcher 전송 또는 include 메서드에 적합한 웹 응용 프로그램 내의 리소스를 지정합니다.
강조해 주세요.는 렌더링 전에 , 는, 뷰, 뷰, 뷰, 뷰, 뷰, 뷰, 뷰, in, in, in, in, in, in, in, in, in, in, in, in, in, in, in, in, in, inRequestDispatcher 쪽으로forward() 전에 다음
if (path.startsWith("/") ? uri.equals(path) : uri.equals(StringUtils.applyRelativePath(uri, path))) {
throw new ServletException("Circular view path [" + path + "]: would dispatch back " +
"to the current handler URL [" + uri + "] again. Check your ViewResolver setup! " +
"(Hint: This may be the result of an unspecified view, due to default view name generation.)");
}
서 ''는path는 뷰명으로, 「」에서 한 것입니다.@Controller예에서는요,이 예에서는요.preferenceuri처리 (URI)를하고 있습니다.는 URI입니다./context/preference.
는 만약 , 당신이 으로 이동해야 것을 합니다./context/preference같은 서블릿(앞의 서블릿이 처리되었기 때문에)이 요구를 처리하면, 엔드리스 루프가 됩니다.
「 」를 선언했을 ThymeleafViewResolver a. a. a.ServletContextTemplateResolver의 「」을 붙여prefix ★★★★★★★★★★★★★★★★★」suffix '만들다'를 만들어요.View 말하면,, 길을 주다, 길을 주다.
WEB-INF/web-templates/preference.html
ThymeleafView는 instance에 인 .ServletContext(''를 )ServletContextResourceResolver
templateInputStream = resourceResolver.getResourceAsStream(templateProcessingParameters, resourceName);`
결국엔
return servletContext.getResourceAsStream(resourceName);
이렇게 이, this, , 에, 에, 에 상대적인 수 있습니다.ServletContext할 수 .TemplateEngineHTML html html html html 。 여기서 무한 루프가 일어날 리가 없습니다.
이 문제를 해결한 방법은 다음과 같습니다.
@Before
public void setup() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/jsp/view/");
viewResolver.setSuffix(".jsp");
mockMvc = MockMvcBuilders.standaloneSetup(new HelpController())
.setViewResolvers(viewResolver)
.build();
}
또한 .xml 파일에서 이를 위한 bean을 만들 수 있습니다.
<bean id = "viewResolver" class = "org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
</bean
Spring Boot을 사용하여 테스트가 아닌 웹 페이지를 로드하려고 하는데 이 문제가 발생하였습니다.나의 해결책은 약간 다른 상황을 고려했을 때 위와 조금 달랐다.(하지만 그 대답으로 나는 이해할 수 있었다.)
Maven의 Spring Boot Starter 의존 관계를 다음과 같이 변경해야 했습니다.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
대상:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
'웹'을 '타임스 리프'로 바꾸는 것만으로 문제가 해결되었습니다.
뷰 렌더링을 실제로 신경 쓰지 않는 경우 다음과 같은 간단한 해결책이 있습니다.
순환 보기 경로를 확인하지 않는 Internal Resource View Resolver 하위 클래스를 만듭니다.
public class StandaloneMvcTestViewResolver extends InternalResourceViewResolver {
public StandaloneMvcTestViewResolver() {
super();
}
@Override
protected AbstractUrlBasedView buildView(final String viewName) throws Exception {
final InternalResourceView view = (InternalResourceView) super.buildView(viewName);
// prevent checking for circular view paths
view.setPreventDispatchLoop(false);
return view;
}
}
그런 다음 테스트를 설정합니다.
MockMvc mockMvc;
@Before
public void setUp() {
final MyController controller = new MyController();
mockMvc =
MockMvcBuilders.standaloneSetup(controller)
.setViewResolvers(new StandaloneMvcTestViewResolver())
.build();
}
Spring Boot를 사용하는 경우 pom.xml에 Tymeleaf 의존관계를 추가합니다.
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring4</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
를 하지 않은 @RequestBody사용만 하고 있습니다.@Controller 은 를 사용하는 @RestController@Controller
" " " / 후에/preference츠키노
@Test
public void circularViewPathIssue() throws Exception {
mockMvc.perform(get("/preference/"))
.andDo(print());
}
저 같은 경우에는 Kotlin + Spring Boot을 시험해 보다가 Circular View Path 문제에 빠졌습니다.온라인으로 받은 모든 제안은 아래를 시도할 때까지 도움이 되지 않았습니다.
.@Controller
import org.springframework.stereotype.Controller
그 후 교체했습니다.@Controller@RestController
import org.springframework.web.bind.annotation.RestController
그리고 그것은 성공하였다.
타이메리프이게 나한테 효과가 있었어. 답변이 만, JSP가HTML을 답변은 JSP의 경우 JSP의 경우 HTML의 경우 .이것들은 폴더에 있습니다.src/main/resources/templates표준 스프링 부트 프로젝트와 같은 기능을 제공합니다.이것은 당신의 경우도 될 수 있습니다.
@InjectMocks
private MyController myController;
@Before
public void setup()
{
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(myController)
.setViewResolvers(viewResolver())
.build();
}
private ViewResolver viewResolver()
{
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("classpath:templates/");
viewResolver.setSuffix(".html");
return viewResolver;
}
이게 도움이 됐으면 좋겠다.
을 추가합니다.@ResponseBody이치노
[ Spring Boot + Freemarker ](Spring Boot + 프리마커 실행 시) 페이지가 나타나면 다음 절차를 수행합니다.
Whitelabel Error Page 이 응용 프로그램에는 / 오류에 대한 명시적인 매핑이 없으므로 이를 폴백으로 볼 수 있습니다.
spring-boot-starter-parent 2.2.1의 경우.RELEASE 버전 프리마커가 작동하지 않습니다.
- Freemarker 파일의 이름을 .ftl에서 .ftlh로 변경합니다.
- application.properties: spring에 추가합니다.freemarker.freemarker-request-attributes = true
spring.freemarker.freemarker = .ftl
Tymeleaf의 경우:
방금 스프링 4와 티멜리프를 사용하기 시작했는데, 이 오류가 발생했을 때 다음을 추가하여 해결되었습니다.
<bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine" />
<property name="order" value="0" />
</bean>
사용시@Controller주석, 필요한 경우@RequestMapping그리고.@ResponseBody주석입니다.주석을 추가한 후 다시 시도@ResponseBody
주석을 사용하여 스프링 웹 앱을 구성하는데, 이 문제는 추가함으로써 해결됩니다.InternalResourceViewResolver를 설정합니다.도움이 되었으면 좋겠어요.
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.example.springmvc" })
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Bean
public InternalResourceViewResolver internalResourceViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/jsp/");
resolver.setSuffix(".jsp");
return resolver;
}
}
이는 Spring이 "preference"를 삭제하고 "preference"를 다시 추가하여 요청 URI와 동일한 경로를 만들기 때문에 발생합니다.
다음과 같은 현상이 발생합니다:request URI: "/preference"
"기본 설정" 제거: "/"
추가 경로: "/"+" 기본 설정"
끝 문자열: "/preference"
스프링이 예외를 던져 알려주는 루프에 들어갑니다.
"PreferenceView" 등의 다른 뷰 이름을 붙이는 것이 가장 좋습니다.
compile.springframework를 추가해 보겠습니다.boot:spring-boot-sysmeleaf")를 그래들파일에 의존시킵니다.Tymeleaf는 뷰를 매핑하는 데 도움이 됩니다.
제 경우 스프링 부트애플리케이션을 사용하여 JSP 페이지를 서비스하려고 할 때 이 문제가 발생했습니다.
다음과 같은 이점이 있습니다.
application.properties
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
pom.xml
JSP 지원을 이노블로 만들려면 tomcat-embedded-jasper 의존관계를 추가해야 합니다.
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
이 경우 스프링 부트2 및 jdk11의 원형 뷰 경로는 index.html로 리다이렉트하여 수정되었습니다.
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("redirect:/index.html");
}
};
xml 파일에 보기 재설정 추가
<bean id = "viewResolver" class = "org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
</bean
아래 의존관계를 pom.xml에 추가한 후에도 원형 뷰 경로 오류가 발생할 경우 프로젝트 우클릭 -> 메이븐 -> 프로젝트 새로고침
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
@Controller를 @RestController =>로 바꿉니다.@Controller를 사용하는 경우 컨트롤러로부터 데이터를 수신한viewResolver를 정의하여 사용자에게 표시해야 합니다.한편, @RestController = > 에서는, viewResolver 가 필요 없는 전송 JSON 에 Rest API = > 를 사용하고 있습니다.
또 다른 간단한 접근법:
package org.yourpackagename;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(PreferenceController.class);
}
public static void main(String[] args) {
SpringApplication.run(PreferenceController.class, args);
}
}
언급URL : https://stackoverflow.com/questions/18813615/how-to-avoid-the-circular-view-path-exception-with-spring-mvc-test