With introduction of 5th version, Spring has changed the default URL pattern matching mechanism from AntPathMatcher to PathPattern class. Spring Boot 2.1, which is based on Spring 5.1 version, does not follow this chage, as AntPathMatcher it still used for the processing:
#GetMapping("/spring5/{*id}") //PathPattern implementation, compilation error
#GetMapping("/spring5/**") // AntPathMatcher implementation, works fine
Is there a way to enable PathPattern matching mechanisms for Spring Boot 2.1 applications?
Ant Matcher will work with
/spring5/**
and normal path pattern will work with
#GetMapping("/spring5/{*id}")
public void methodName(#PathVariable String id)
try and add #PathVariable as well and it will work for you.
I am using Spring mvc, and i found out this solution for Spring mvc:
In your webApplicationcontext configuration file, override the "configurePathMatch" method as follows:
#Configuration
public class WebConfig implements WebMvcConfigurationSupport {
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setPatternParser(new PathPatternParser());
}
As Spring mvc official document states:
"setPatternParser(PathPatternParser patternParser): Enable use of parsed PathPatterns as described in AbstractHandlerMapping.setPatternParser(PathPatternParser)."
Hope this will help you somehow!
Related
So I have a React app I want to serve from my Spring app (ala this blog). As part of my gradle build task, I run the npm build command and copy the resulting files to /build/resources/main/static. This works fine and I can access my app at mysite.com/index.html, but I want to control who has access more granularly. As such, I applied #EnableWebMvc to my app, but from there, I can't seem to get my API controller to actually serve the view from the build directory. It seems no matter where I put it, it doesn't like serving directly from /build. Any way to make this work?
The handler looks like:
#Controller
class MyController {
#RequestMapping("/")
fun index(): String {
return "index"
}
}
As indicated in the Spring Boot documentation, you do not need - in fact, it is not recommended - to use #EnableWebMvc when using Spring Boot. They state, when describing Spring MVC auto-configuration:
Spring Boot provides auto-configuration for Spring MVC that works well with most applications.
And:
If you want to keep those Spring Boot MVC customizations and make more MVC customizations (interceptors, formatters, view controllers, and other features), you can add your own #Configuration class of type WebMvcConfigurer but without #EnableWebMvc.
In the guide, they continue when describing static content handling:
By default, Spring Boot serves static content from a directory called /static (or /public or /resources or /META-INF/resources) in the classpath or from the root of the ServletContext. It uses the ResourceHttpRequestHandler from Spring MVC so that you can modify that behavior by adding your own WebMvcConfigurer and overriding the addResourceHandlers method.
In your example, following this advice, you can indicate the static resource handling location with something like (sorry, I am not fluent in Kotlin, forgive for write the example in Java):
#Controller
public class MyController implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/static/**")
.addResourceLocations("classpath:/static")
;
}
#GetMapping(path = "/")
public String index() {
return "index";
}
}
Please, adapt the paths in addResourceHandlers to your needs.
You can of course place this method in an ad hoc #Configuration.
Having said that, if when you say granular you mean security, the best approach you can take is to configure Spring Security and provide the necessary authorization rules: please, see the relevant documentation.
I'm working on upgrading an Spring Framework 4-based application to Spring Framework 5, and one of the differences between them is that ControllerClassNameHandlerMapping has been removed(deprecated since spring framework 4.3).
An example of its behavior:
#Controller
// thanks to ControllerClassNameHandlerMapping, this next annotation is unnecessary
// #RequestMapping("example")
public class ExampleController {
// this is automatically bound to POST /example/someMethod
// even though I didn't set any "path"
#RequestMapping(method = RequestMethod.POST)
public void someMethod() {
}
Is there any way to mimick this behavior on spring framework 5? Upgrading over 300 controllers to the same behavior using #RequestMapping and path is a very daunting task, and we're fine with ControllerClassNameHandlerMapping's behavior for now.
You can update context path in your configuration:
server:
servlet:
context-path: /example
I have a custom naming strategy in a Spring app with Hibernate:
public class MyCustomPhysicalNamingStrategy implements PhysicalNamingStrategy {
#Override
public Identifier toPhysicalTableName(Identifier identifier, JdbcEnvironment jdbcEnvironment) {
return Identifier.toIdentifier("my_custom_table_name");
}
// ...
}
The Spring documentation says I can tell Hibernate to use it either by setting spring.jpa.hibernate.naming.physical-strategy (which works fine), or like this:
Alternatively, if ImplicitNamingStrategy or PhysicalNamingStrategy beans are available in the application context, Hibernate will be automatically configured to use them
I need to use this second method, as I need to pass some info from Spring's context to my naming strategy. However, I can't get it to work.
I'm creating the bean in the following configuration class:
#Configuration
public class PersistenceConfiguration {
#Bean
public PhysicalNamingStrategy physicalNamingStrategy() {
return new MyCustomPhysicalNamingStrategy();
}
}
What am I missing here?
Thanks in advance.
EDIT: I'm on Spring Boot/Spring JPA 1.5.9.RELEASE, which gives me Hibernate core v.5.0.12.Final and Hibernate JPA API 2.1.
It seems that this is only supported with spring boot 2.
See: https://github.com/spring-projects/spring-boot/blob/v2.0.3.RELEASE/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java#L95
This file is not present in spring boot 1.5: https://github.com/spring-projects/spring-boot/tree/v1.5.14.RELEASE/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa
(HibernateJpaAutoConfiguration.java doesn't have it)
Sniffy is a cool little project:
Sniffy counts the number of executed SQL queries and provides an API for validating them It is designed for unit tests and allows you to test if particular method doesn't make more than N SQL queries Especially it's useful to catch the ORM N+1 problem at early stages
It also provides a servlet filter which injects HTML into a page with a popup showing you executed queries. The documentation explains how to configure it for a traditional web.xml based application but not Spring Boot. I managed to register the servlet filter by adding this bean to an #Configuration class:
#Bean
public FilterRegistrationBean snifferFilter()
{
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
SnifferFilter filter = new SnifferFilter();
filter.setInjectHtml(true);
filterRegistrationBean.setFilter(filter);
filterRegistrationBean.setName("sniffer");
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
I also updated the JDBC url, the documentation says:
add sniffer: prefix to the JDBC connection url For example jdbc:h2:~/test should be changed to sniffer:jdbc:h2:mem:
So I added the following to my application.yml:
spring.datasource.url: sniffer:jdbc:mysql://localhost:3306
But when I start my application it fails with this error:
URL must start with 'jdbc'
Sniffy author here!
Indeed as of version 3.0.7 (April 2016) you have to specify the driver class name explicitly in your Spring Boot application. There's an open issue in a bug tracker to configure it automatically.
By the way sniffy 3.0.5 introduced an out-of-the box support of Spring Boot using #EnableSniffy annotation, so you do not have to create the FilterRegistrationBean yourself anymore - just put the annotation to your application class like this:
import io.sniffy.boot.EnableSniffy;
#SpringBootApplication
#EnableAutoConfiguration
#EnableSniffy
public class Application {
public static void main(String[] args) throws ClassNotFoundException {
SpringApplication.run(Application.class, args);
}
}
I managed to figure out the problem, Spring Boot makes extensive use of auto configuration and was trying to detect the DatabaseDriver from the connection string. As the connection string no longer starts with jdbc it was encountering a problem.
It was simply a case of specifying the driver-class-name in my application.yml rather than letting Spring Boot trying to auto detect it:
spring.datasource.driver-class-name: io.sniffy.MockDriver
I am trying to set up Spring AOP without any XML and wonder how to enable auto-proxying this way.
Defining an AutoProxyCreator-bean works, but isn't there an easier way?
This is what my #Configuration looks like:
#Configuration
public class Context {
#Bean
public AnnotationAwareAspectJAutoProxyCreator annotationAwareAspectJAutoProxyCreator() {
return new AnnotationAwareAspectJAutoProxyCreator();
};
...
}
All other beans are scanned in by AnnotationConfigApplicationContext.
Spring 3.0.x doesn't provide easy ways to replace XML namespace extensions (such as <aop:aspectj-autoproxy>) in #Configuration.
An upcoming Spring 3.1 will support special annotations for this purpose, such as #EnableAspectJAutoProxy.
Finally I found an aesthetically pleasing way to add the AnnotationAwareAspectJAutoProxyCreator:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AnnotationAwareAspectJAutoProxyCreator.class);
context.scan("com.myDomain");
context.refresh();