name generation error spring spring-mvc circular-reference thymeleaf spring-mvc-test

generation - Cómo evitar la excepción "Ruta de vista circular" con la prueba Spring MVC



circular view path error spring boot (12)

Tengo el siguiente código en uno de mis controladores:

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

Simplemente estoy tratando de probarlo usando la prueba Spring MVC de la siguiente manera:

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

Recibo la siguiente excepción:

Ruta de vista circular [preferencia]: se volvería a enviar a la URL del controlador actual [/ preference]. ¡Comprueba tu configuración de ViewResolver! (Sugerencia: puede ser el resultado de una vista no especificada, debido a la generación de nombre de vista predeterminada).

Lo que me parece extraño es que funciona bien cuando cargo la configuración de contexto "completa" que incluye la plantilla y los resolvedores de vista como se muestra a continuación:

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

Soy muy consciente de que el prefijo agregado por la resolución de la plantilla garantiza que no haya una "ruta de vista circular" cuando la aplicación utiliza esta resolución de plantilla.

Pero ¿cómo se supone que debo probar mi aplicación usando la prueba Spring MVC? Alguien tiene alguna pista?


Al usar la anotación @Controller , necesita las anotaciones @RequestMapping y @ResponseBody . Vuelve a intentarlo luego de agregar la anotación @ResponseBody


Aquí hay una solución fácil si no te importa renderizar la vista.

Cree una subclase de InternalResourceViewResolver que no compruebe las rutas de vista circular:

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

Luego configura tu prueba con ella:

MockMvc mockMvc; @Before public void setUp() { final MyController controller = new MyController(); mockMvc = MockMvcBuilders.standaloneSetup(controller) .setViewResolvers(new StandaloneMvcTestViewResolver()) .build(); }


Así es como resolví este problema:

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


Esto está sucediendo porque Spring está eliminando "preferencia" y añadiendo nuevamente la "preferencia" haciendo la misma ruta que la solicitud Uri.

Pasando así: solicite Uri: "/ preferencia"

eliminar "preferencia": "/"

anexar ruta: "/" + "preferencia"

cadena final: "/ preferencia"

Esto se está metiendo en un ciclo que Spring te notifica lanzando una excepción.

Lo mejor es que le interese dar un nombre de vista diferente como "preferenceView" o cualquier cosa que desee.


Esto no tiene nada que ver con las pruebas Spring MVC.

Cuando no declara un ViewResolver , Spring registra un InternalResourceViewResolver predeterminado que crea instancias de JstlView para renderizar la View .

La clase JstlView extiende InternalResourceView que es

Wrapper para un JSP u otro recurso dentro de la misma aplicación web. Expone objetos de modelo como atributos de solicitud y reenvía la solicitud a la URL de recurso especificada utilizando javax.servlet.RequestDispatcher.

Se supone que una URL para esta vista especifica un recurso dentro de la aplicación web, adecuado para el método forward o include de RequestDispatcher.

Bold es mío. En otras palabras, la vista, antes de la representación, intentará obtener un RequestDispatcher al que forward() . Antes de hacer esto, comprueba lo siguiente

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.)"); }

donde path es el nombre de la vista, lo que devolvió del @Controller . En este ejemplo, eso es preference . La variable uri contiene el uri de la solicitud que se maneja, que es /context/preference .

El código anterior se da cuenta de que si tuviera que reenviar a /context/preference , el mismo servlet (ya que el mismo manejaba el anterior) manejaría la solicitud y entraría en un ciclo sin fin.

Cuando declara un ThymeleafViewResolver y un ServletContextTemplateResolver con un prefix y suffix específicos, construye la View diferente, dándole una ruta como

WEB-INF/web-templates/preference.html

ThymeleafView instancias de ThymeleafView ubican el archivo relativo a la ruta ServletContext utilizando un ServletContextResourceResolver

templateInputStream = resourceResolver.getResourceAsStream(templateProcessingParameters, resourceName);`

que eventualmente

return servletContext.getResourceAsStream(resourceName);

Esto obtiene un recurso que es relativo a la ruta ServletContext . Luego puede usar TemplateEngine para generar el HTML. No hay forma de que un ciclo sin fin pueda suceder aquí.


Estoy usando Spring Boot para intentar cargar una página web, no para probar, y tuve este problema. Mi solución fue un poco diferente a las anteriores considerando las circunstancias ligeramente diferentes. (Aunque esas respuestas me ayudaron a entenderlo.)

Simplemente tuve que cambiar mi dependencia de arranque Spring Boot en Maven desde:

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

a:

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

Simplemente cambiando la ''web'' a ''thymeleaf'' me arregló el problema.


Otro enfoque simple:

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


Para Thymeleaf:

Acabo de empezar a usar la primavera 4 y la hoja de tomillo, cuando encontré este error, se resolvió añadiendo:

<bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver"> <property name="templateEngine" ref="templateEngine" /> <property name="order" value="0" /> </bean>


Resolví este problema usando @ResponseBody como a continuación:

@RequestMapping(value = "/resturl", method = RequestMethod.GET, produces = {"application/json"}) @ResponseStatus(HttpStatus.OK) @Transactional(value = "jpaTransactionManager") public @ResponseBody List<DomainObject> findByResourceID(@PathParam("resourceID") String resourceID) {


Si está utilizando Spring Boot, agregue la dependencia de thymeleaf en su pom.xml:

<dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring4</artifactId> <version>2.1.6.RELEASE</version> </dependency>


Utilizo la anotación para configurar la aplicación web Spring, el problema se solucionó agregando un bean InternalResourceViewResolver a la configuración. Espero que sea útil.

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


@Controller@RestController

Tuve el mismo problema y noté que mi controlador también estaba anotado con @Controller . Reemplazarlo con @RestController resolvió el problema. Aquí está la explicación de Spring Web MVC :

@RestController es una anotación compuesta que está meta-anotada con @Controller y @ResponseBody que indica un controlador cuyos métodos heredan la anotación @ResponseBody de nivel de tipo y, por lo tanto, escribe directamente en el cuerpo de respuesta frente a la resolución y representación de la vista con una plantilla HTML.