Spring-boot with Tapestry configuration - java

Does anyone have any reference project with Spring-boot and Tapestry5? I can't seem to find any samples.
I have diificulties in configuring the tapestry bean & Context using a #configuration class without an web.xml.

This should be what you're looking for https://github.com/trust-wenderson/tapestry-spring

I've been looking for such an example myself, and I happen to have found one today:
https://github.com/code8/tapestry-boot
The tapestry-boot library implements following features:
bootstraps tapestry framework inside embedded servlet container managed by spring-boot
provides injection of spring-services into tapestry-services
provides injection of tapestry-services into spring-services
To use tapestry-boot simple marks tapestry application module with
#TapestryApplication annotation.
See DemoApplicationTests.

This works for me:
Register TapestrySpringFilter
#Bean
public FilterRegistrationBean tapesSpringFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new TapestrySpringFilter());
registration.setName("app");
registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
return registration;
}
Add context aprameters to application.yml
server:
context_parameters:
tapestry:
use-external-spring-context: true
app-package: com.test.admin
development-modules: ...
qa-modules: ...
I also had to use executable War to avoid problems with loading static files.
Perhaps this approach will not allow you to access the tapestry beans from the spring context.

Related

Differences between #MapperScan and #Bean MapperScannerConfigurer

I have a multi-datasource web application with following technique:
Spring boot 1.5.12
Mybats-Spring-boot-starter 1.3.2
And I prefered Java based configuration. Therefore, I have Datasource1Config.java and Datasource2Config.java.
I defined SqlSessionTemplate respectively, and using MapperScannerConfigure to inject my mapper. Following is for datasource1, and the datasource2 just substitute the number.
#Bean(name = "dataSource1MapperScannerConfigurer")
public MapperScannerConfigurer msc() {
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setSqlSessionFactoryBeanName("dataSource1SqlSessionFactory");
msc.setSqlSessionTemplateBeanName("dataSource1SqlSessionFactory");
msc.setBasePackage("demo.mybatisspring.mapper.ds1");
return msc;
}
And then, the error happend
file [C:\...target\classes\demo\mybatisspring\mapper\ds1\UserMapper.class] required a single bean, but 2 were found:
- dataSource1SqlSessionFactory: defined by method 'sqlSessionFactoryBean' in class path resource [demo/mybatisspring/config/DataSource1Config.class]
- dataSource2SqlSessionFactory: defined by method 'sqlSessionFactoryBean2' in class path resource [demo/mybatisspring/config/DataSource2Config.class]
However, if I inject mappers with #MapperScan as following, everything will work fine. (also worked fine when one using #MapperScan and the other using #Bean MapperScannerConfigurer)
#MapperScan(basePackages = "demo.mybatisspring.mapper.ds1", sqlSessionTemplateRef = "dataSource1SqlSessionFactory")
public class DataSource1Config {...}
#MapperScan(basePackages = "demo.mybatisspring.mapper.ds2", sqlSessionTemplateRef = "dataSource2SqlSessionFactory")
public class DataSource2Config {...}
I've tried to trace with debug mode and search so many articles on internet, still can not get the answer instead. So if anyone can help me?
Thanks for your time.
I think answer is here. https://mybatis.org/spring/mappers.html
Scanning for mappers There is no need to register all your mappers one
by one. Instead, you can let MyBatis-Spring scan your classpath for
them.
There are three different ways to do it:
Using the element. Using the annotation #MapperScan
Using a classic Spring xml file and registering the
MapperScannerConfigurer Both and #MapperScan are
features introduced in MyBatis-Spring 1.2.0. #MapperScan requires
Spring 3.1+.
Since 2.0.2, mapper scanning feature support a option
(lazy-initialization) that control lazy initialization
enabled/disabled of mapper bean. The motivation for adding this option
is supporting a lazy initialization control feature supported by
Spring Boot 2.2. The default of this option is false (= not use lazy
initialization). If developer want to use lazy initialization for
mapper bean, it should be set to the true expressly.

Spring : Configuration of both MVC and WebSocket in one web app

I'm currently working on a Spring web application which makes use of both Spring MVC and Spring Websocket. The configuration is annotation based. I'm using the AbstractAnnotationConfigDispatcherServletInitializer class as initializer, and I am confused about the servlet mappings I should provide, and the way I should do so.
I'd like to have all my MVC controller mapped under "/webservices/" path, and my Websocket endpoint to be under "/websockets/".
Among my #Configuration classes, one is dedicated to configure Spring MVC (#EnableWebMVC) and another one is dedicated to Spring WebSocket (#EnableWebSocketMessageBroker).
I implemented my initializer as follows :
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] {WebMVCConfiguration.class, WebSocketConfiguration.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/webservices/*","/websockets/*"};
}
Also please note that I imported all of my configuration classes through the use of #Import on my Root Configuration class. I'm not sure if I should import the MVC and Websocket configuration though, as I already declared them in the getServletConfigClasses() method... But I did.
Anyway, It worked fine this way until now. But I recently added the use of #PropertySource annotation to my app (To inject my app properties through the use of #Value("${}") expressions), and thanks to that I noticed that at least the WebSocket Configuration class is ... scanned (?) twice : The first time with the #Value field value properly injected, but not the second time (Which caused an error).
While troubleshooting I noticed that I don't have this "double scanning" problem when I remove the WebSocketConfiguration class from the getServletConfigClasses() method : it is scanned only once, with the property valye properly injected. What surprised me is that even without declaring the WebSocketConfiguration in getServletConfigClasses(), the "/websockets" endpoints still works ! My guess is that it is scanned thanks to the #Import on my Root config class... but then how Spring knows it should bind the WebSocketConfiguration to the "/websockets" path ?
All of this made me wonder about my understanding of when / how I should import configurations classes. So here are my questions :
Do I really need to declare two servlet mappings to keep my services and websockets paths separated as they are ?
Is it necessary to declare as much Servlet Config classes as I have Servlet Mappings ? (Seeing how removing the WebSocketConfiguration class from getServletConfigClasses() didn't alter the WebSocket functionality... Or is it just a fluke ?)
Will Spring use the same DispatcherServlet for all the Servlet Config classes ? Or will it create one for each mapping I provide ?
From what I tried it looks like Spring cannot inject properties through the use of #Value in the configuration classes provided thanks to getServletConfigClasses()... It works only when it is imported via #Import, or a standard component scanning. Does it seems logical to you ?
Thanks for your help !

Spring Boot Actuator for custom Servlet

I noticed Spring Boot Actuator only works if your application uses Spring MVC (DispatcherServlet) to handle endpoints. By default, this servlet is included if you add the module spring-boot-starter-web into your project.
Once this servlet exists, the class EndpointWebMvcAutoConfiguration customize the Spring MVC to support endpoints and other management properties.
For record, my application implements a Vaadin Servlet to navigate on screens, so is there any way to enable Spring Boot Actuator in this case?
You won't be able to reuse the EndpointWebMVCAutoConfiguration class as it is explicitly conditionnal on DispatcherServlet.class. If you look at the implementation, you'll see that the Actuator has a lot of dependencies on Spring MVC.
It would be a little ballzy but you could consider implementing your own autoconfiguration class inspired by EndpointWebMVCAutoConfiguration.
I wish you good luck if you go down that path ;)
You can have both. If you have a VaadinServlet, you can try with something like:
#SpringBootApplication
public class AdminApplication {
#Bean
public ServletRegistrationBean<SpringVaadinServlet> springVaadinServlet() {
SpringVaadinServlet servlet = new SpringVaadinServlet();
ServletRegistrationBean<SpringVaadinServlet> registrationBean = new ServletRegistrationBean<>(servlet, "/your-web-app/*");
registrationBean.setLoadOnStartup(1);
registrationBean.setName("VaadinServlet");
return registrationBean;
}
}
#SpringUI(path = "/")
public class VaadinUI extends UI {
...
}
Notice the need for a registration name, a custom servlet mapping URL, and custom path in the #SpringUI annotation.
You can find a running demo here.

Spring boot multi module servletDispatchers

I have a following project structure
-Project
|-config
| |-modules
| |-admin
| |-web
|- platform
Platform is the project that contains the spring-boot start class,
Platform has a dependency on config and config had dependencies on everything in the directory modules
Platform is also the module that gets started with the mvn spring-boot:run command.
The thing I am trying to accomplish is that the modules admin and web (both web apps) have their own mapping like
/admin
/web
The following code represents an controller in the admin module, the web module also contains a similar controller (thats the point)
#Controller
public class AdminController {
#RequestMapping("/")
public String adminController() {
return "admin";
}
}
Here some code for the configuration of the admin module
#Configuration
public class Config implements EmbeddedServletContainerCustomizer {
#Autowired
protected WebApplicationContext webApplicationContext;
#Autowired
protected ServerProperties server;
#Autowired(required = false)
protected MultipartConfigElement multipartConfig;
protected DispatcherServlet createDispatcherServlet() {
AnnotationConfigEmbeddedWebApplicationContext webContext = new AnnotationConfigEmbeddedWebApplicationContext();
webContext.setParent(webApplicationContext);
webContext.scan("some.base.package");
return new DispatcherServlet(webContext);
}
protected ServletRegistrationBean createModuleDispatcher(DispatcherServlet apiModuleDispatcherServlet) {
ServletRegistrationBean registration =
new ServletRegistrationBean(apiModuleDispatcherServlet,
"/admin");
registration.setName("admin");
registration.setMultipartConfig(this.multipartConfig);
return registration;
}
#Bean(name = "adminsServletRegistrationBean")
public ServletRegistrationBean apiModuleADispatcherServletRegistration() {
return createModuleDispatcher(createDispatcherServlet());
}
public void customize(ConfigurableEmbeddedServletContainer container) {
container.setContextPath("/admin");
}
}
Something similar goes for the web module
I have tried the implement the some of the given answers.
Using multiple dispatcher servlets / web contexts with spring boot
Spring Boot (JAR) with multiple dispatcher servlets for different REST APIs with Spring Data REST
And lots of googling
When I let the component scan, scan both modules (removing the ComponentScan filter)
I get an a Ambiguous mapping found exception, saying that both controller methods dispatch to the same path "/"
But when disabling the component scan on one of the modules, then indeed the admin modules get mapped to /admin.
when I disable both controllers, I see that the /web and /admin dispatchServlets get mapped.
So I understand the exception but I dont understand how to resolve this.
For me its a must that I can do this per module and I dont want to map it using
#RequestMapping("/admin")
on the controller class
I also tried specifying the contextPath and servletPath in the application.properties
So my question is: what would be the best approach to reach my goal, or am I trying to use spring-boot for something it was not ment for.
Edit
A Proof of concept would be nice
So I found the solution.
You can take a look here at this link
You`ll have to register the dispatcher servlets in the main application and dont use the #SpringBootApplication annotation.
For a complete example just checkout the project and check the code
EDIT: later this week ill provide a detailed answer
What you should do is that put your AdminController and WebController in separate packages.
some.base.admin.package
some.base.web.package
And in the corresponding configurations scan only your required package to register the DispatcherServlet
Admin Config
webContext.scan("some.base.admin.package");
Web Config
webContext.scan("some.base.web.package");
This way in the corresponding WebApplicationContext for each DispatcherServlet only one mapping will be available for "/"

How do I specify multiple templateLoaderPaths for Freemarker in Spring Boot?

I need to specify multiple template loader paths for FreeMarker in a Spring Boot web application but the FreeMarkerAutoConfigurationClass only let me specify one path using the spring.freemarker.templateLoaderPath property, which uses the setTemplateLoaderPath method in the FreeMarkerConfigurationFactory. However, this class allows me to set multiple path using the setTemplateLoaderPaths method. Which is the best way to override this auto-configuration class and specify multiple loader paths? I don't really understand well the Spring Java config classes and I want an example for this before write the code I need. I'm using Spring Boot 1.1.2. Thanks in advance.
You'll need to provide your own bean of type org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer with your desired configuration. To do so, add something similar to the following to one of your application's Java configuration classes:
#Bean
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPaths("one", "two", "three");
// Apply further configuration as needed
return configurer;
}
Update: the latest Spring Boot 1.2 snapshots now accept a comma-separated list for the spring.freemarker.templateLoaderPath property allowing you to specify multiple paths without declaring a custom FreeMarkerConfigurer bean.

Categories