How to avoid the “Circular view path” exception wi

2019-01-03 13:57发布

I have the following code in one of my controllers:

@Controller
@RequestMapping("/preference")
public class PreferenceController {

    @RequestMapping(method = RequestMethod.GET, produces = "text/html")
    public String preference() {
        return "preference";
    }
}

I am simply trying to test it using Spring MVC test as follows:

@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());
    }
}

I am getting the following exception:

Circular view path [preference]: would dispatch back to the current handler URL [/preference] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)

What I find strange is that it works fine when I load the "full" context configuration that includes the template and view resolvers as shown below:

<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>

I am well aware that the prefix added by the template resolver ensures that there are not "circular view path" when the app uses this template resolver.

But then how I am supposed to test my app using Spring MVC test? Has anyone got any clue?

14条回答
狗以群分
2楼-- · 2019-01-03 14:25

I solved this problem by using @ResponseBody like below:

@RequestMapping(value = "/resturl", method = RequestMethod.GET, produces = {"application/json"})
    @ResponseStatus(HttpStatus.OK)
    @Transactional(value = "jpaTransactionManager")
    public @ResponseBody List<DomainObject> findByResourceID(@PathParam("resourceID") String resourceID) {
查看更多
劫难
3楼-- · 2019-01-03 14:25

I am using Spring Boot with Thymeleaf. This is what worked for me. There are similar answers with JSP but note that I am using HTML, not JSP, and these are in the folder src/main/resources/templates like in a standard Spring Boot project as explained here. This could also be your case.

@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;
}

Hope this helps.

查看更多
对你真心纯属浪费
4楼-- · 2019-01-03 14:28

Here's an easy fix if you don't actually care about rendering the view.

Create a subclass of InternalResourceViewResolver which doesn't check for circular view paths:

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;
    }
}

Then set up your test with it:

MockMvc mockMvc;

@Before
public void setUp() {
    final MyController controller = new MyController();

    mockMvc =
            MockMvcBuilders.standaloneSetup(controller)
                    .setViewResolvers(new StandaloneMvcTestViewResolver())
                    .build();
}
查看更多
我命由我不由天
5楼-- · 2019-01-03 14:29

Another simple approach:

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);
    }
}
查看更多
甜甜的少女心
6楼-- · 2019-01-03 14:33

I am using Spring Boot to try and load a webpage, not test, and had this problem. My solution was a bit different than those above considering the slightly different circumstances. (although those answers helpled me understand.)

I simply had to change my Spring Boot starter dependency in Maven from:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
</dependency>

to:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

Just changing the 'web' to 'thymeleaf' fixed the problem for me.

查看更多
Animai°情兽
7楼-- · 2019-01-03 14:36

If you are using Spring Boot, then add thymeleaf dependency into your pom.xml:

    <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf-spring4</artifactId>
        <version>2.1.6.RELEASE</version>
    </dependency>
查看更多
登录 后发表回答