I have very simple hello world created with spring boot (just starter web, no thymeleaf etc.).
I want to handle /hello url and it should produces view from /static/view.html
I have /static/view.html and simple method in my controller:
#RequestMapping("/hello")
public String hello2() {
return "hello.html";
}
The problem is that it causes error:
Circular view path [hello.html]: would dispatch back to the current
handler URL [/hello.html] again
I figured out that it does not matter if I visit /hello or /hello.html, Spring treats them the same.
How can I return simple, static html with the same name as the url path and which object in spring mvc/boot causes mapping url like /example.html to just /example?
You have to perform next steps:
Introduce MVC configuration:
#Configuration
#EnableWebMvc
public class MvcConfiguration extends WebMvcConfigurerAdapter{
#Bean
public ViewResolver getViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/");
return resolver;
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
Put your hello.html into /src/main/webapp/WEB-INF folder
Make sure you have compile dependencies like this:
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.apache.tomcat.embed:tomcat-embed-jasper")
I posted gradle code, if you have maven use similar xml.
NOTE Step 3 is the most important step because if you're using spring boot it applies auto-configurations depending on what you have in classpath. For instance if you add thymeleaf dependency
compile("org.springframework.boot:spring-boot-starter-thymeleaf")
that will most likelly break the code because thymeleaf will introduce its own auto-configured view resolver.
Delete the method in your controller. A #RequestMapping is not needed for static content.
Related
I want to create an custom method argument Resolver using Spring WebFlux. I am following link but its seem to be not working.
I am able to create the custom argument resolver using WebMvc.
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
public class MyContextArgumentResolver implements HandlerMethodArgumentResolver {
#Override
public boolean supportsParameter(MethodParameter parameter) {
return MyCustomeObject.class.isAssignableFrom(parameter.getParameterType())
}
#Override
public Mono<Object> resolveArgument(MethodParameter parameter, BindingContext bindingContext,
ServerWebExchange exchange) {
.....
return Mono.just(new MyCustomeObject())
}
Please note that i am using HandlerMethodArgumentResolver from .web.reactive. package.
My AutoConfiguration file look like
#Configuration
#ConditionalOnClass(EnableWebFlux.class) // checks that WebFlux is on the class-path
#ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)//checks that the app is a reactive web-app
public class RandomWebFluxConfig implements WebFluxConfigurer {
#Override
public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
MyContextArgumentResolver[] myContextArgumentResolverArray = {contextArgumentResolver()};
configurer.addCustomResolver(myContextArgumentResolverArray );
}
#Bean
public MyContextArgumentResolver contextArgumentResolver() {
return new MyContextArgumentResolver ();
}
My spring.factories looks like
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.XXXX.XXX.XXX.RandomWebFluxConfig
Please note that above configuration is part of the jar which is added in Spring WebFlux Boot project enabled using #EnableWebFlux .
It seems you're conflating two different problems here.
First, you should make sure that your method argument resolver works in a regular project.
For that, you need a #Configuration class that implements the relevant method in WebFluxConfigurer. Your code snippet is doing that but with two flaws:
Your configuration is using #EnableWebFlux, which is disabling the WebFlux auto-configuration in Spring Boot. You should remove that
it seems you're trying to cast a list of MethodArgumentResolver into a single instance and that's probably why things aren't working here. I believe your code snippet could be just:
configurer.addCustomResolver(contextArgumentResolver());
Now the second part of this question is about setting this up as a Spring Boot auto-configuration. I guess that you'd like WebFlux applications to automatically get that custom argument resolvers if they depend on your library.
If you want to achieve that, you should first make sure to read up a bit about auto-configurations in the reference documentation. After that, you'll realize that your configuration class is not really an auto-configuration since it will be applied in all cases.
You should probably add a few conditions on that configuration like:
#ConditionalOnClass(EnableWebFlux.class) // checks that WebFlux is on the classpath
#ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) // checks that the app is a reactive web app
Hi I am currently working on a web project that uses thymeleaf and also JSF (its a legacy system and we can only slowly migrate to thymeleaf thats why JSF is still there and cannot be removed from one day to another since this is a lot of work). Thymeleaf is configured to resolve the views in the webapp directory that lie under the directory "thymeleaf". This works perfectly if I deploy the application directly on a tomcat server. Also pages from other directories then the "thymeleaf" directory are also resolved by the JSF framework.
I added some integration tests in JUnit that are using SpringBoot. Inside these tests I got the problem that thymeleaf now is trying to resolve any page in any directory. JSF is completely ignored and I got a whole bunch of JUnit tests failing because of that. Is there any point why thymeleaf ignores its configuration and wants to resolve all files?
Here is my complete thymeleaf configuration, and as I said this works perfectly if I deploy it on a standalone tomcat.
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
this.applicationContext = applicationContext;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
String imagesPattern = "/images/**";
String imagesLocation = basePath() + "resources/images/";
registry.addResourceHandler(imagesPattern).addResourceLocations(imagesLocation);
log.info("added resourceHandler (pathPattern: '{}'), (resourceLocation: '{}')",
imagesPattern,
imagesLocation);
String cssPattern = "/css/**";
String cssLocation = basePath() + "resources/css/";
registry.addResourceHandler(cssPattern).addResourceLocations(cssLocation);
log.info("added resourceHandler (pathPattern: '{}'), (resourceLocation: '{}')", cssPattern, cssLocation);
}
#Bean(name = "basepath")
public String basePath()
{
String basepath = "";
File file = new File(Optional.ofNullable(System.getenv("THYMELEAF_APP_RESOURCES"))
.orElse("thymeleaf-resources/"));
if (file.exists())
{
basepath = "file:" + file.getAbsolutePath();
}
if (!basepath.endsWith("/"))
{
basepath += "/";
}
log.info("basepath: {}", basepath);
return basepath;
}
#Bean
#Description("Thymeleaf View Resolver")
public ThymeleafViewResolver viewResolver(String basePath)
{
log.info("setting up Thymeleaf view resolver");
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine(basePath));
viewResolver.setCharacterEncoding("UTF-8");
viewResolver.setCache(true);
return viewResolver;
}
public SpringTemplateEngine templateEngine(String basePath)
{
log.info("setting up Thymeleaf template engine.");
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver(basePath));
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
private ITemplateResolver templateResolver(String basePath)
{
log.info("setting up Thymeleaf template resolver");
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix(basePath + "thymeleaf/views/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCacheable(false);
return resolver;
}
#Bean
public IMessageResolver thymeleafMessageSource(MessageSource messageSource)
{
SpringMessageResolver springMessageResolver = new SpringMessageResolver();
springMessageResolver.setMessageSource(messageSource);
return springMessageResolver;
}
EDIT
I just found that the problem seems to lie much deeper. Having the dependencies of thymeleaf added into my pom.xml seems to be enough for spring boot to load it into the context... I just deleted my ThymeleafConfig class for testing purposes and still thymeleaf tries to resolve the JSF pages... (yes I did maven clean before executing the test)
EDIT 2
I read it now and tried to exclude the ThymeleafAutoConfiguration class but it does not help. My configurations are still overridden. Here is my configuration for this so far. (And yes this is the ONLY EnableAutoConfiguration annotation in the whole project)
#Configuration
#EnableAutoConfiguration(exclude = {ThymeleafAutoConfiguration.class})
#Import({WebAppConfig.class, ThymeleafConfig.class})
public class SpringBootInitializer extends SpringBootServletInitializer
and my ThymeleafConfig class is already added above.
Having the dependencies of thymeleaf added into my pom.xml seems to be enough for spring boot to load it into the context...
If this has surprised you then I would recommend spending some time to take a step back and read about how Spring Boot works and, in particular, it's auto-configuration feature. This section of the reference documentation is a good place to start.
In short, Spring Boot adopts a convention over configuration approach. If a dependency is on the classpath, Spring Boot assumes that you want to use it, and configures it with sensible defaults. This is what it's doing with Thymeleaf. You can disable this auto-configuration for a specific dependency using the excludes attribute on #SpringBootApplication:
#SpringBootApplication(exclude={ThymeleafAutoConfiguration.class})
public class ExampleApplication {
}
You can also use the spring.autoconfigure.exclude property to provide a comma-separated list of auto-configuration classes to exclude. Each entry in the list should be the fully-qualified name of an auto-configuration class. You could use this property with #TestPropertySource to disable auto-configuration on a test-by-test basis.
I have been struggling with a similar issue for hours and finally found out the root cause.
If you have a dependency to *-data-rest in your pom like this:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
you will have to add Thymeleaf to your pom as well even if you use a another template engine (Freemarker, JSP, ...) everywhere else.
Reason: to expose a JpaRepository as a rest service Spring Boot requires Thymeleaf. I do not understand why this is not defined as a dependency of spring-boot-starter-data-rest so that Maven resolves it automatically.
In my opinion it is a Spring Boot configuration bug.
I get such exception:
javax.servlet.ServletException: Could not resolve view with name 'htmlviews/index.html' in servlet with name 'dispatcher'
org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1211)
org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1011)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:955)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
when I try to connect to fully java configured spring web service.
My configuration classes:
#Configuration
#EnableWebMvc
#ComponentScan({"config", "controller"})
public class MyWebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/htmlviews/**").addResourceLocations("/htmlviews/");
}
}
Initializer:
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{MyWebConfig.class};
}
protected Class<?>[] getServletConfigClasses() {
return null;
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
and controller:
#Controller
public class IndexController {
#RequestMapping(value = "/")
public String getIndexPage() {
return "htmlviews/index.html";
}
#RequestMapping(value = "/{[path:[^\\.]*}")
public String index() {
return "forward:/";
}
}
whole file srtucture is simple :
I am using Idea IDE (also tried in eclipse, same exception) and trying to deploy on tomcat. In pom.xml, I added 'jstl' dependency, but that did not help to resolve problem.
Using xml configuration everything works well. I have no idea what is wrong with my spring java configuration, it is super simple, maybe I forgot something?
Fixed it
Everything started working when I changed spring version from 4.1.0.RELEASE to 4.2.3.RELEASE . I do not why it does not work with 4.1.0.RELEASE. Maybe someone can explain, just curious.
Problem
Spring is trying to find views under your webapp directory. Since you do not have any view resolver, Spring cannot resolve "htmlviews/index.html". In other words, Spring does not know what it is.
You have a Resource Resolver for your html page, which is OK because HTML is static.
Possible Solution 1
In your MyWebConfig class, add the following:
#Override
public void configureViewResolvers(final ViewResolverRegistry registry) {
registry.jsp("/htmlviews/", ".jsp");
}
OR you can do this:
#Bean
public InternalResourceViewResolver jspViewResolver() {
InternalResourceViewResolver resolver= new InternalResourceViewResolver();
resolver.setPrefix("/htmlviews/");
resolver.setSuffix(".jsp");
return resolver;
}
Change your html page to jsp page, I recommend that because jsp is simply more powerful than HTML.
Possible Solution 2
Pult all your htmlviews folder under resources so that Spring can find it according to your Resource Resolver.
Update
It's rarely the case that HTML is needed in a Spring boot app. I highly recommend using a template engine (Thymeleaf is preferred). This way, the sensible default setup is sufficient for most of the multi-page applications.
I was trying to implement demo https://spring.io/guides/gs/securing-web/ but i was facing similar problem, To note- this demo only have html with thymleaf (no JSP) and I missed to add thymleaf dependency(reason of error) earlier it showed error
Circular view path []: would dispatch back to the current handler URL ..error
Then I added bean view resolver and it started to give error .
Could not resolve view with name..error
Finally it worked after removing the bean view resolver and adding dependency for thymleaf. Adding this made my project work.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
Some more help I found to understand all this working at How to avoid the "Circular view path" exception with Spring MVC test
I have a project where data from several sources are being processed into some data structures. After the program is done building these structures, I want it to set up a server that enables users to fine-tune these structures manually. I decided that Spring MVC on an embedded Tomcat server set up using Spring Boot is just what I need.
I want to use Thymeleaf as view technology, and therefore did
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class Main {
public static void main(String... args) throws Exception {
// Lots of initialization ...
SpringApplication.run(Main.class, args);
}
#Bean
public ServletContextTemplateResolver templateResolver() {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
resolver.setPrefix("/resources/views/");
resolver.setSuffix(".html");
resolver.setTemplateMode("HTML5");
resolver.setCacheable(false);
return resolver;
}
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver());
return engine;
}
#Bean
public ViewResolver viewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setOrder(1);
viewResolver.setViewNames(new String[]{"*"});
viewResolver.setCache(false);
return viewResolver;
}
}
and
#Controller
public class WebController {
#RequestMapping(value="/greeting", method=RequestMethod.GET)
public String greeting() {
return "greeting";
}
}
But even though there is a view file at /resources/views/greeting.html, the server's reply to the URL http://localhost:8080/greeting is
org.thymeleaf.exceptions.TemplateInputException: Error resolving template "greeting", template might not exist or might not be accessible by any of the configured Template Resolvers
After stepping through the code in a debugger it appears that at some point, ServletContext, which is supposed to return the view file as a stream, looks in a temporary folder like
C:\Users\Michael\AppData\Local\Temp\tomcat-docbase.971027024999448548.8080
which is empty.
Now I get that I need to either
Have the resources deployed to the temporary folder when the server starts up
Have the server operate in the directory where the resources already are
My problem just is that I don't know how to do either, or which approach is the best. Something tells me that 1 is the better wisdom, but any suggestion is welcome.
Edit
Ok, I ended up with something that seems to work. While Joe's answer definitely helped me get on the way, it also appears that I had to change my Maven configuration in a way that puzzles me.
After putting the template greeting.html into /resources/templates/greeting.html and adding resources to the build path, I got the error
javax.servlet.ServletException: Circular view path [greeting]: would dispatch back to the current handler URL [/word/greeting] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
In other words, Thymeleaf seemed to not be properly configured. After some fiddling I ended up changing the version of spring-boot-starter-parent in pom.xml from 0.5.0.BUILD-SNAPSHOT to 0.5.0.M6:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<!--<version>0.5.0.BUILD-SNAPSHOT</version>-->
<version>0.5.0.M6</version>
</parent>
and removing the version tag from the Thymeleaf dependency
<dependencies>
<!-- ... -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring3</artifactId>
<!--<version>${thymeleaf-spring3-version}</version>-->
</dependency>
</dependencies>
After this, it worked.
Can someone please explain why I needed to change the version of spring-boot-starter-parent to be able to remove the version tag from thymeleaf-spring3, and why that was necessary?
The servlet context root is not the best place for templates in an embedded server. There is a way to do it, but if I were you I would go with the flow and use the classpath. If you allow Spring Boot to configure the template resolver (also recommended) then it will look in classpath:/templates by default. There are several samples that use thymeleaf in the Boot code base, so it should be easy to modify one of those if you have different requirements.
i am working on BIRT reporting tool. which is need to called by spring MVC.
i got one example from spring which is here. in this example, configuration is done via bean. can anyone help me convert this configuration in to xml based configuration ?
#EnableWebMvc
#ComponentScan({ "org.eclipse.birt.spring.core","org.eclipse.birt.spring.example" })
#Configuration
public class BirtWebConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/reports").setViewName("birtView");
}
#Bean
public BirtView birtView() {
BirtView bv = new BirtView();
// bv.setReportFormatRequestParameter("ReportFormat");
// bv.setReportNameRequestParameter("ReportName");
bv.setBirtEngine(this.engine().getObject());
return bv;
}
#Bean
public BeanNameViewResolver beanNameResolver() {
BeanNameViewResolver br = new BeanNameViewResolver();
return br;
}
#Bean
protected BirtEngineFactory engine() {
BirtEngineFactory factory = new BirtEngineFactory();
return factory;
}
}
I wants a similar configuration in xml file.
There's really no tool for extracting Spring annotations to Spring bean context xml file. You'll have to do it by hand, shouldn't be too hard as all the Spring annotations functionality can be duplicated into Spring context xml tags.
if you want to use spingmvc, so no need the configuration files.
my solution is that in Birt Script i call the impl java file like this :
sampleService = new Packages.com.example.warlock.service.SampleServiceImpl();
pojo = new Packages.com.example.warlock.entity.Sample();
iterator = sampleService.getSamples().iterator();
because my SampleService is a interface and SampleServiceImpl is impl java, the two java file are not config as #Bean.
At first i want to get the data from ModelMap but failed, so i skip the controller and straight to call Service, then final call the DAO to get the Data from DB