Mam następujący kod w jednym z moich kontrolerów:
@Controller
@RequestMapping("/preference")
public class PreferenceController {
@RequestMapping(method = RequestMethod.GET, produces = "text/html")
public String preference() {
return "preference";
}
}
Po prostu próbuję to przetestować za pomocą testu Spring MVC w następujący sposób:
@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());
}
}
Otrzymuję następujący wyjątek:
Okrągła ścieżka widoku [preferencja]: spowoduje ponowne wysłanie z powrotem do bieżącego adresu URL modułu obsługi [/ preferencje]. Sprawdź konfigurację ViewResolver! (Wskazówka: może to być wynikiem nieokreślonego widoku, z powodu domyślnego generowania nazwy widoku).
Wydaje mi się dziwne, że działa dobrze, gdy ładuję „pełną” konfigurację kontekstu, która zawiera szablon i narzędzia do rozpoznawania widoku, jak pokazano poniżej:
<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>
Doskonale zdaję sobie sprawę, że przedrostek dodany przez program do rozpoznawania szablonów zapewnia, że nie ma „okrągłej ścieżki widoku”, gdy aplikacja używa tego narzędzia do rozpoznawania szablonów.
Ale jak mam przetestować moją aplikację za pomocą testu Spring MVC?
ViewResolver
którego używasz, gdy się nie powiedzie?@RestController
zamiast@Controller
Odpowiedzi:
Nie ma to nic wspólnego z testowaniem Spring MVC.
Gdy nie deklarujesz
ViewResolver
, Spring rejestruje wartość domyślną,InternalResourceViewResolver
która tworzy instancjeJstlView
do renderowaniaView
.JstlView
Klasa rozszerzaInternalResourceView
który jestBold jest mój. Innymi słowy, widok, przed renderowaniem, spróbuje pobrać element
RequestDispatcher
doforward()
. Zanim to zrobisz, sprawdza, co następujegdzie
path
jest nazwa widoku, co zwróciłeś z@Controller
. W tym przykładzie to jestpreference
. Zmiennauri
zawiera identyfikator URI obsługiwanego żądania, którym jest/context/preference
.Powyższy kod zdaje sobie sprawę, że jeśli miałbyś przekazać dalej
/context/preference
, ten sam aplet (ponieważ ten sam obsługiwał poprzedni) obsłużyłby żądanie i wszedłbyś w nieskończoną pętlę.Kiedy deklarujesz a
ThymeleafViewResolver
i aServletContextTemplateResolver
z konkretnymprefix
isuffix
, buduje onView
inaczej, nadając mu ścieżkę podobną doThymeleafView
instancje lokalizują plik względemServletContext
ścieżki przy użyciu rozszerzeniaServletContextResourceResolver
które ostatecznie
Pobiera zasób, który jest względny w stosunku do
ServletContext
ścieżki. Następnie może użyćTemplateEngine
do wygenerowania kodu HTML. Nie ma możliwości, aby doszło tutaj do nieskończonej pętli.źródło
ThymleafViewResolver
View
prefix
suffix
InternalResourceViewResolver
RequestDispatcher
Servlet
/preference
DispatcherServlet
ViewResolver
. AlboThymeleafViewResolver
jak w pytaniu, samodzielnie skonfigurowanyInternalResourceViewResolver
lub zmień nazwę widoku, który zwracasz w kontrolerze.@RequestMapping
Metoda obsługi z adnotacjami zString
typem zwracanym (i nie@ResponseBody
) ma wartość zwracaną obsługiwaną przez a,ViewNameMethodReturnValueHandler
która interpretuje ciąg jako nazwę widoku i używa go do przejścia przez proces, który wyjaśniam w mojej odpowiedzi. W przypadku@ResponseBody
Spring MVC zamiast tego użyje on,RequestResponseBodyMethodProcessor
który zamiast tego zapisuje ciąg bezpośrednio w odpowiedzi HTTP, tj. brak rozdzielczości widoku.Rozwiązałem ten problem używając @ResponseBody jak poniżej:
źródło
List<DomainObject>
.@Controller
→@RestController
Miałem ten sam problem i zauważyłem, że mój kontroler również był oznaczony
@Controller
. Zastąpienie go@RestController
rozwiązało problem. Oto wyjaśnienie Spring Web MVC :źródło
@ControllerAdvice
zhandleXyException
metodą, która zwróciła mój własny obiekt zamiast ResponseEntity. Dodawanie@RestController
na górze@ControllerAdvice
adnotacji zadziałało i problem zniknął.Oto jak rozwiązałem ten problem:
źródło
Używam Spring Boot, aby spróbować załadować stronę internetową, a nie testować, i mam ten problem. Moje rozwiązanie było nieco inne niż te powyżej, biorąc pod uwagę nieco inne okoliczności. (chociaż te odpowiedzi pomogły mi zrozumieć.)
Po prostu musiałem zmienić moją zależność startera Spring Boot w Maven z:
do:
Sama zmiana „sieci” na „tymianek” rozwiązała problem.
źródło
Oto łatwe rozwiązanie, jeśli nie zależy Ci na renderowaniu widoku.
Utwórz podklasę InternalResourceViewResolver, która nie sprawdza ścieżek widoków kołowych:
Następnie skonfiguruj swój test za jego pomocą:
źródło
Jeśli używasz Spring Boot, dodaj zależność thymeleaf do swojego pom.xml:
źródło
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
Dodanie
/
po/preference
rozwiązaniu problemu dla mnie:źródło
W moim przypadku wypróbowałem but Kotlin + Spring i wpadłem w problem Circular View Path. Wszystkie sugestie, które otrzymałem online, nie pomogły, dopóki nie wypróbowałem poniższych:
Pierwotnie dodałem adnotację do mojego kontrolera za pomocą
@Controller
import org.springframework.stereotype.Controller
Następnie otrzymuje
@Controller
się z@RestController
import org.springframework.web.bind.annotation.RestController
I zadziałało.
źródło
jeśli nie korzystałeś z @RequestBody i używasz tylko
@Controller
, najprostszym sposobem naprawienia tego jest użycie@RestController
zamiast@Controller
źródło
Dodaj adnotację
@ResponseBody
do zwrotu metody.źródło
Używam Spring Boot z Thymeleaf. To właśnie zadziałało dla mnie. Istnieją podobne odpowiedzi w przypadku JSP, ale zauważ, że używam HTML, a nie JSP, i znajdują się one w folderze
src/main/resources/templates
jak w standardowym projekcie Spring Boot, jak wyjaśniono tutaj . To może być również Twój przypadek.Mam nadzieję że to pomoże.
źródło
Podczas uruchamiania Spring Boot + Freemarker, jeśli pojawi się strona:
Strona błędu białej etykiety Ta aplikacja nie ma wyraźnego mapowania błędu /, więc widzisz to jako rezerwę.
W spring-boot-starter-parent 2.2.1.RELEASE wersja freemarker nie działa:
spring.freemarker.suffix = .ftl
źródło
W przypadku tymianku:
Właśnie zacząłem używać sprężyny 4 i tymianku, kiedy napotkałem ten błąd, rozwiązano go dodając:
źródło
Podczas korzystania z
@Controller
adnotacji potrzebujesz@RequestMapping
i@ResponseBody
adnotacji. Spróbuj ponownie po dodaniu adnotacji@ResponseBody
źródło
Używam adnotacji do konfiguracji wiosennej aplikacji internetowej, problem rozwiązany przez dodanie
InternalResourceViewResolver
beana do konfiguracji. Mam nadzieję, że to byłoby pomocne.źródło
Dzieje się tak, ponieważ Spring usuwa „preferencję” i ponownie dołącza „preferencję”, tworząc tę samą ścieżkę, co identyfikator Uri żądania.
Dzieje się tak: żądanie Uri: „/ preference”
usuń „preferencję”: „/”
dołącz ścieżkę: „/” + „preferencja”
end string: „/ preference”
To jest wejście w pętlę, o której Spring informuje cię, rzucając wyjątek.
W Twoim interesie jest nadanie innej nazwy widoku, np. „PreferenceView”, lub dowolnej innej.
źródło
spróbuj dodać zależność kompilacji ("org.springframework.boot: spring-boot-starter-thymeleaf") do pliku gradle.Thymeleaf pomaga w mapowaniu widoków.
źródło
W moim przypadku miałem ten problem podczas próby obsługi stron JSP za pomocą aplikacji rozruchowej Spring.
Oto, co zadziałało dla mnie:
application.properties
pom.xml
Aby włączyć obsługę stron JSP, musielibyśmy dodać zależność od tomcat-embed-jasper.
źródło
Kolejne proste podejście:
źródło