Eu tenho o seguinte código em um dos meus controladores:
@Controller
@RequestMapping("/preference")
public class PreferenceController {
@RequestMapping(method = RequestMethod.GET, produces = "text/html")
public String preference() {
return "preference";
}
}
Estou simplesmente tentando testá-lo usando o teste Spring MVC da seguinte maneira:
@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());
}
}
Estou recebendo a seguinte exceção:
Caminho de visualização circular [preferência]: seria despachado de volta para a URL do manipulador atual [/ preferência] novamente. Verifique a configuração do ViewResolver! (Dica: isso pode ser o resultado de uma exibição não especificada, devido à geração de nome de exibição padrão.)
O que acho estranho é que funciona bem quando carrego a configuração de contexto "completa" que inclui o modelo e os resolvedores de visualização, conforme mostrado abaixo:
<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>
Estou bem ciente de que o prefixo adicionado pelo resolvedor de modelo garante que não haja "caminho de visualização circular" quando o aplicativo usa esse resolvedor de modelo.
Mas então como devo testar meu aplicativo usando o teste Spring MVC?
ViewResolver
você usa quando está falhando?@RestController
vez de@Controller
Respostas:
Isso não tem nada a ver com o teste Spring MVC.
Quando você não declara a
ViewResolver
, o Spring registra um padrãoInternalResourceViewResolver
que cria instâncias deJstlView
para renderizar oView
.A
JstlView
classe estende oInternalResourceView
que éOusado é meu. Em outras palavras, a visualização, antes da renderização, tentará obter um
RequestDispatcher
para o qualforward()
. Antes de fazer isso, ele verifica o seguinteonde
path
está o nome da visualização, o que você retornou do@Controller
. Neste exemplo, é issopreference
. A variáveluri
contém o uri da solicitação que está sendo tratada, que é/context/preference
.O código acima percebe que se você fosse encaminhar para
/context/preference
, o mesmo servlet (já que o mesmo tratou do anterior) trataria a solicitação e você entraria em um loop infinito.Quando você declara a
ThymeleafViewResolver
e aServletContextTemplateResolver
com umprefix
e específicosuffix
, ele constrói oView
diferente, dando a ele um caminho comoThymeleafView
instâncias localizam o arquivo em relação aoServletContext
caminho usando umServletContextResourceResolver
que eventualmente
Isso obtém um recurso que é relativo ao
ServletContext
caminho. Ele pode então usar oTemplateEngine
para gerar o HTML. Não há como um loop infinito acontecer aqui.fonte
ThymleafViewResolver
oView
é resolvido como um arquivo relativo aprefix
esuffix
você fornece. Quando você não usa isso resolve, o Spring usa um padrãoInternalResourceViewResolver
que encontra recursos com umRequestDispatcher
. Este recurso pode ser umServlet
. Nesse caso, é porque o caminho é/preference
mapeado para o seuDispatcherServlet
.ViewResolver
. Tanto oThymeleafViewResolver
como em sua pergunta, seu próprio configuradoInternalResourceViewResolver
ou mude o nome da visão que você está retornando em seu controlador.@RequestMapping
método de manipulador anotado com umString
tipo de retorno (e não@ResponseBody
) tem seu valor de retorno manipulado por umViewNameMethodReturnValueHandler
que interpreta String como um nome de visualização e o usa para passar pelo processo que explico em minha resposta. Com@ResponseBody
, Spring MVC irá usar oRequestResponseBodyMethodProcessor
que, em vez disso, grava a String diretamente na resposta HTTP, ou seja. sem resolução de visualização.Resolvi esse problema usando @ResponseBody como abaixo:
fonte
List<DomainObject>
.@Controller
→@RestController
Eu tive o mesmo problema e notei que meu controlador também foi anotado com
@Controller
. Substituí-lo por@RestController
resolveu o problema. Aqui está a explicação do Spring Web MVC :fonte
@ControllerAdvice
com umhandleXyException
método nele, que retornou meu próprio objeto em vez de um ResponseEntity. Adicionar@RestController
em cima da@ControllerAdvice
anotação funcionou e o problema desapareceu.Foi assim que resolvi esse problema:
fonte
Estou usando o Spring Boot para tentar carregar uma página da web, não para testar, e tive esse problema. Minha solução foi um pouco diferente das anteriores, considerando as circunstâncias ligeiramente diferentes. (embora essas respostas tenham me ajudado a entender.)
Eu simplesmente tive que mudar minha dependência inicial do Spring Boot no Maven de:
para:
Apenas mudar a 'web' para 'thymeleaf' resolveu o problema para mim.
fonte
Aqui está uma solução fácil se você realmente não se importa em renderizar a visualização.
Crie uma subclasse de InternalResourceViewResolver que não verifica os caminhos de visualização circular:
Em seguida, configure seu teste com ele:
fonte
Se você estiver usando Spring Boot, adicione a dependência thymeleaf em seu pom.xml:
fonte
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
Adicionar
/
depois/preference
resolveu o problema para mim:fonte
No meu caso, eu estava experimentando a inicialização Kotlin + Spring e entrei no problema Circular View Path. Todas as sugestões que recebi online não puderam ajudar, até que tentei o seguinte:
Originalmente, anotei meu controlador usando
@Controller
import org.springframework.stereotype.Controller
Eu então substituí
@Controller
por@RestController
import org.springframework.web.bind.annotation.RestController
E funcionou.
fonte
se você não usou um @RequestBody e está usando apenas
@Controller
, a maneira mais simples de corrigir isso é usando em@RestController
vez de@Controller
fonte
Adicione a anotação
@ResponseBody
ao seu método return.fonte
Estou usando o Spring Boot com Thymeleaf. Isto é o que funcionou para mim. Existem respostas semelhantes com JSP, mas observe que estou usando HTML, não JSP, e elas estão na pasta
src/main/resources/templates
como em um projeto Spring Boot padrão, conforme explicado aqui . Este também pode ser o seu caso.Espero que isto ajude.
fonte
Ao executar Spring Boot + Freemarker se a página aparecer:
Whitelabel Error Page Este aplicativo não possui mapeamento explícito para / error, então você está vendo isso como um fallback.
No spring-boot-starter-parent 2.2.1.RELEASE versão freemarker não funciona:
spring.freemarker.suffix = .ftl
fonte
Para Thymeleaf:
Acabei de começar a usar spring 4 e thymeleaf, quando encontrei este erro, ele foi resolvido adicionando:
fonte
Ao usar
@Controller
anotação, você precisa@RequestMapping
e@ResponseBody
anotações. Tente novamente depois de adicionar anotação@ResponseBody
fonte
Eu uso a anotação para configurar o aplicativo da web do spring, o problema resolvido adicionando um
InternalResourceViewResolver
bean à configuração. Espero que seja útil.fonte
Isso está acontecendo porque o Spring está removendo "preferência" e acrescentando a "preferência" novamente fazendo o mesmo caminho que o Uri da solicitação.
Acontecendo assim: solicitar Uri: "/ preferência"
remova "preferência": "/"
acrescentar caminho: "/" + "preferência"
string final: "/ preferência"
Isso é entrar em um loop que o Spring notifica lançando uma exceção.
É melhor do seu interesse dar um nome de visualização diferente, como "preferênciaView" ou qualquer coisa que você desejar.
fonte
tente adicionar a dependência de compilação ("org.springframework.boot: spring-boot-starter-thymeleaf") ao seu arquivo gradle.Thymeleaf ajuda a mapear visualizações.
fonte
No meu caso, tive esse problema ao tentar servir páginas JSP usando o aplicativo Spring boot.
Aqui está o que funcionou para mim:
application.properties
pom.xml
Para habilitar o suporte para JSPs, precisaríamos adicionar uma dependência em tomcat-embed-jasper.
fonte
Outra abordagem simples:
fonte