programing

스프링 MVC 테스트를 사용하여 "원형 뷰 경로" 예외를 피하는 방법

easyjava 2023. 2. 28. 23:48
반응형

스프링 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, ofJstlViewView.

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 버전 프리마커가 작동하지 않습니다.

  1. Freemarker 파일의 이름을 .ftl에서 .ftlh로 변경합니다.
  2. 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

반응형