J'ai le code suivant dans l'un de mes contrôleurs:
@Controller
@RequestMapping("/preference")
public class PreferenceController {
@RequestMapping(method = RequestMethod.GET, produces = "text/html")
public String preference() {
return "preference";
}
}
J'essaie simplement de le tester en utilisant le test Spring MVC comme suit:
@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());
}
}
Je reçois l'exception suivante:
Chemin de vue circulaire [préférence]: renvoie à nouveau à l'URL du gestionnaire actuel [/ préférence]. Vérifiez votre configuration ViewResolver! (Conseil: cela peut être le résultat d'une vue non spécifiée, en raison de la génération de nom de vue par défaut.)
Ce que je trouve étrange, c'est que cela fonctionne bien lorsque je charge la configuration de contexte "complète" qui comprend le modèle et les résolveurs de vue comme indiqué ci-dessous:
<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>
Je suis bien conscient que le préfixe ajouté par le résolveur de modèle garantit qu'il n'y a pas de "chemin de vue circulaire" lorsque l'application utilise ce résolveur de modèle.
Mais alors comment je suis censé tester mon application à l'aide du test Spring MVC?
ViewResolver
vous utilisez en cas d'échec?@RestController
place de@Controller
Réponses:
Cela n'a rien à voir avec les tests Spring MVC.
Lorsque vous ne déclarez pas a
ViewResolver
, Spring enregistre une valeur par défautInternalResourceViewResolver
qui crée des instances deJstlView
pour le rendu duView
.La
JstlView
classe s'étendInternalResourceView
qui estLe gras est à moi. En d'autres termes, la vue, avant le rendu, essaiera d'obtenir un
RequestDispatcher
vers lequelforward()
. Avant de faire cela, il vérifie les éléments suivantsoù
path
est le nom de la vue, ce que vous avez renvoyé du@Controller
. Dans cet exemple, c'estpreference
. La variableuri
contient l'URI de la demande en cours de traitement, qui est/context/preference
.Le code ci-dessus se rend compte que si vous deviez transférer vers
/context/preference
, le même servlet (puisque le même a géré le précédent) gérerait la demande et vous entreriez dans une boucle sans fin.Lorsque vous déclarez a
ThymeleafViewResolver
et aServletContextTemplateResolver
avec unprefix
et spécifiquesuffix
, il construitView
différemment, en lui donnant un chemin commeThymeleafView
les instances localisent le fichier par rapport auServletContext
chemin en utilisant unServletContextResourceResolver
qui finalement
Cela obtient une ressource relative au
ServletContext
chemin. Il peut ensuite utiliser leTemplateEngine
pour générer le HTML. Il n'y a aucun moyen qu'une boucle sans fin puisse se produire ici.la source
ThymleafViewResolver
leView
est résolu comme un fichier relatif àprefix
et quesuffix
vous fournissez. Lorsque vous n'utilisez pas cette résolution, Spring utilise une valeur par défautInternalResourceViewResolver
qui recherche les ressources avec unRequestDispatcher
. Cette ressource peut être un fichierServlet
. Dans ce cas, c'est parce que le chemin/preference
correspond à votreDispatcherServlet
.ViewResolver
. Soit leThymeleafViewResolver
comme dans votre question, votre propre configuréInternalResourceViewResolver
ou modifiez le nom de la vue que vous renvoyez dans votre contrôleur.@RequestMapping
méthode de gestionnaire annotée avec unString
type de retour (et non@ResponseBody
) a sa valeur de retour gérée par unViewNameMethodReturnValueHandler
qui interprète la chaîne comme un nom de vue et l'utilise pour suivre le processus que j'explique dans ma réponse. Avec@ResponseBody
, Spring MVC utilisera à la placeRequestResponseBodyMethodProcessor
qui écrit la chaîne directement dans la réponse HTTP, c'est-à-dire. pas de résolution de vue.J'ai résolu ce problème en utilisant @ResponseBody comme ci-dessous:
la source
List<DomainObject>
.@Controller
→@RestController
J'ai eu le même problème et j'ai remarqué que mon contrôleur était également annoté avec
@Controller
. Le remplacer par a@RestController
résolu le problème. Voici l'explication de Spring Web MVC :la source
@ControllerAdvice
avec unehandleXyException
méthode, qui a renvoyé mon propre objet au lieu d'un ResponseEntity. L'ajout@RestController
en plus de l'@ControllerAdvice
annotation a fonctionné et le problème est parti.Voici comment j'ai résolu ce problème:
la source
J'utilise Spring Boot pour essayer de charger une page Web, pas pour tester, et j'ai eu ce problème. Ma solution était un peu différente de celles ci-dessus compte tenu des circonstances légèrement différentes. (bien que ces réponses m'ont aidé à comprendre.)
J'ai simplement dû changer ma dépendance de démarrage Spring Boot dans Maven de:
à:
Le simple fait de changer le «web» en «thymeleaf» a résolu le problème pour moi.
la source
Voici une solution simple si vous ne vous souciez pas du rendu de la vue.
Créez une sous-classe de InternalResourceViewResolver qui ne vérifie pas les chemins de vue circulaire:
Ensuite, configurez votre test avec:
la source
Si vous utilisez Spring Boot, ajoutez la dépendance thymeleaf dans votre pom.xml:
la source
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
L'ajout
/
après avoir/preference
résolu le problème pour moi:la source
Dans mon cas, j'essayais Kotlin + Spring Boot et je suis entré dans le problème du chemin de vue circulaire. Toutes les suggestions que j'ai reçues en ligne ne pouvaient pas aider, jusqu'à ce que j'essaye ce qui suit:
À l'origine, j'avais annoté ma manette en utilisant
@Controller
import org.springframework.stereotype.Controller
J'ai ensuite remplacé
@Controller
par@RestController
import org.springframework.web.bind.annotation.RestController
Et ça a marché.
la source
si vous n'avez pas utilisé de @RequestBody et que vous utilisez uniquement
@Controller
, le moyen le plus simple de résoudre ce problème consiste à utiliser@RestController
au lieu de@Controller
la source
Ajoutez l'annotation
@ResponseBody
à votre retour de méthode.la source
J'utilise Spring Boot avec Thymeleaf. C'est ce qui a fonctionné pour moi. Il existe des réponses similaires avec JSP, mais notez que j'utilise HTML, pas JSP, et celles-ci se trouvent dans le dossier
src/main/resources/templates
comme dans un projet Spring Boot standard, comme expliqué ici . Cela pourrait aussi être votre cas.J'espère que cela t'aides.
la source
Lors de l'exécution de Spring Boot + Freemarker si la page apparaît:
Page d'erreur Whitelabel Cette application n'a pas de mappage explicite pour / error, vous voyez donc cela comme une solution de secours.
Dans la version spring-boot-starter-parent 2.2.1.RELEASE, freemarker ne fonctionne pas:
spring.freemarker.suffix = .ftl
la source
Pour Thymeleaf:
Je viens de commencer à utiliser spring 4 et thymeleaf, lorsque j'ai rencontré cette erreur, elle a été résolue en ajoutant:
la source
Lorsque vous utilisez l'
@Controller
annotation, vous avez besoin@RequestMapping
et@ResponseBody
annotations. Réessayez après avoir ajouté une annotation@ResponseBody
la source
J'utilise l'annotation pour configurer l'application Web Spring, le problème résolu en ajoutant un
InternalResourceViewResolver
bean à la configuration. J'espère que ce serait utile.la source
Cela se produit parce que Spring supprime la «préférence» et ajoute à nouveau la «préférence» en effectuant à nouveau le même chemin que la requête Uri.
Se déroulant comme ceci: request Uri: "/ preference"
supprimer "préférence": "/"
ajouter le chemin: "/" + "préférence"
chaîne de fin: "/ préférence"
C'est entrer dans une boucle que le Spring vous notifie en lançant une exception.
Il est préférable dans votre intérêt de donner un nom de vue différent comme "préférenceView" ou tout ce que vous voulez.
la source
essayez d'ajouter une dépendance de compilation ("org.springframework.boot: spring-boot-starter-thymeleaf") à votre fichier gradle. Thymeleaf aide à mapper les vues.
la source
Dans mon cas, j'ai eu ce problème en essayant de servir des pages JSP à l'aide de l'application Spring Boot.
Voici ce qui a fonctionné pour moi:
application.properties
pom.xml
Pour activer la prise en charge des JSP, nous aurions besoin d'ajouter une dépendance sur tomcat-embed-jasper.
la source
Une autre approche simple:
la source