I am considering modifying an existing java web app (with web.xml and applicationContext.xml files and Spring 2.5) to use Spring Boot. What are the implications of this process? I know I will need to create an #Configuration file to declare all of the beans (to eliminate the applicationContext.xml files), but would love some additional insight. Any suggestions are appreciated!
Migration would take several steps. Some of them are:-
Add Spring Boot dependencies to your pom.xml or gradle file.
Define all the XML beans using Java Configuration by #Bean
Define Spring Security if used through Java Configuration
Add application.properties to resources directory and defines all the configuration values like database host,username,password etc
Define your views inside resources/templates
You've to include all the dependencies required. Some of the dependencies are:-
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
You could have some other dependencies too like Spring Security. If your application uses Spring Security you have to provide java configuration for it.
http://www.baeldung.com/spring-boot-security-autoconfiguration
https://spring.io/blog/2014/01/30/migrating-from-spring-framework-3-2-to-4-0-1
Related
I created a Spring Boot project using the Spring Starter Project.
I added web and security modules to the POM file. See below.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
I was expecting the spring.factories for spring-boot-autoconfigure2.7.3.jar to contain the auto-configuration section below. But I don’t see the Auto Configure section. They don’t put that section there anymore?
Auto Configure
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,
org.springframework.boot.autoconfigure.security.servlet.SecurityRequestMatcherProviderAutoConfiguration,
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,
...
I created a Spring Boot demo app with Maven using Spring Initializr (that's my almost the very first usage of Spring). It works, but for some reason doesn't show any pages besides index.html. If I'm right, that's because of configuration in application.properties, but I just don't know, what have I add there.
My project's sources structure:
src
main
java
irimi
springbootdemo
SpringBootDemoApplication.java
SpringBootDemoApplicationController.java
resources
static
index.html
templates
test-form.html
test-page.jsp
application.properties
I tried to add different prefixes and suffixes into application.properties, but nothing works. Just as an example:
spring.mvc.view.prefix=/templates/
spring.mvc.view.suffix=.html
Again, index.html opens perfectly.
Maybe, it would be good to show here my dependences too:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
That's an error page:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Sat Jan 15 11:49:12 MSK 2022
There was an unexpected error (type=Not Found, status=404).
No message available
If my error is really in application.properties, what have I put there?
With Default Rendering with template
If you are using default "/resources/templates" for rendering view.Spring Boot only includes auto-configuration support for the following templating engines:
FreeMarker
Groovy
Thyme-leaf
Velocity
Example:
Step1:
For using thymeleaf you should add dependency either with gradle and maven
Gradle:
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf', version: '2.5.4'
OR
Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.5.4</version>
</dependency>
Step2:
Add below code with properties file
(Optional)spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
With MVC support
By default, this handler serves static content from any of /static, /public, /resources, and /META-INF/resources directories that are on the classpath. Since src/main/resources is typically on the classpath by default, we can place any of these directories there.
Only static folder is available for rendering view.You can customise using below code with properties file.By default Spring Boot will serve static content from a folder 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 you can modify that behavior by adding your own WebMvcConfigurerAdapter and overriding the addResourceHandlers method.
spring.mvc.static-path-pattern=/content/**
spring.web.resources.static-locations=classpath:/files/,classpath:/static-files
More information visit
https://docs.spring.io/spring-boot/docs/1.1.5.RELEASE/reference/htmlsingle/#boot-features-spring-mvc-static-content
https://www.baeldung.com/spring-mvc-static-resources
We are using cucumber + selenium to facilitate e2e tests. We are using following dependencies to leverage on spring dependency injection.
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-spring</artifactId>
<version>6.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.6.RELEASE</version>
<scope>provided</scope>
</dependency>
Then we configure spring context using these two classes
#ContextConfiguration(classes = SpringContextConfig.class)
#CucumberContextConfiguration
public class CucumberSpringConfiguration {
}
#PropertySource("application.properties")
#ComponentScan("com.example.e2e")
public class SpringContextConfig {
}
As we can se we properties source is defined explicitly pointing to a given file. Is there a way to achieve the "magic" that Spring Boot does with profiles and properties files?
For example I would expect spring when specifying -Dspring.profiles.active=dev to merge
application-dev.properties with application.properties and giving the final context properties.
As we can se we properties source is defined explicitly pointing to a given file. Is there a way to achieve the "magic" that Spring Boot does with profiles and properties files?
Profile specific configuration files are a Spring Boot feature. So if you are using Spring boot, this should be sufficient to have the active profile picked up:
#SpringBootTest
#CucumberContextConfiguration
public class CucumberSpringConfiguration {
}
From your dependencies however it doesn't look like you are using Spring Boot. There is no other (easy) way to use profile specific configurations files. Consider making your application a Spring Boot application.
As guided by the thread's name, I would like to create a JAVA library by using Spring Boot. I have found this thread: Creating a library jar using Spring boot. However, that thread's objectives seem to be solved by implementing it as a REST API.
Currently, I am developing a Spring-based JAVA library by using Spring Boot. And, I have tried to package as a jar file and let another JAVA application to use it in term of a JAVA library. Unfortunately, I found that when the caller application invokes some methods of the added library, configurations which are defined inside the library do not work at all.
It also shows an error like "CommandLineRunner does not exist".
For more information, a snippet of the pom.xml file is shown below. According to the configuration, I do not include dependencies for web applications.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>2.3.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
When designed in the correct way this should not be a problem at all. But in detail it depends which features you're using. Since Spring supports external library like JPA, Websocket,..
There are two important annotations to develop a library and use it in another project.
The first one is simply #Configuration and the other one is #Import.
Library Project
Put a class in the root package which looks something like this.
#Configuration // allows to import this class
#ComponentScan // Scan for beans and other configuration classes
public class SomeLibrary {
// no main needed here
}
Other Project using the library
As usually put a class in the root package of your project.
#SpringBootApplication
#Import(SomeLibrary.class) // import the library
public class OtherApplication {
// just put your standard main in this class
}
It is important to keep in mind, that other things might be necessary depending on what your using in terms of other frameworks.
For example if your using spring-data the #EntityScan annotation extends the hibernate scan.
I am trying to build a basic MVC app using Spring boot with Hibernate as ORM and MySql as Database. The problem that I am facing is that the jsp views are not getting resolved.
I get a 404 error when I try to fetch the registration form using a GET request with the following URL:
http://localhost:9000/users/register/
This is the set-up that I have in my application.
Directory structure:
-src
-main
-java
-com
ApplicationStart.java
-controllers
UserController.java
-repositories
UserRepository.java
-webapp
-WEB-INF
-jsp
register.jsp
-resources
application.properties
UserController:
#RestController
public class UserController {
private UserRepository userRepository;
#Autowired
public UserController(UserRepository userRepository)
{
this.userRepository = userRepository;
}
#RequestMapping(value = "/users/register", method = RequestMethod.GET)
public String Register()
{
return "register";
}
}
Application.properties:
server.port: 9000
spring.datasource.url: jdbc:mysql://localhost/Contacts
spring.datasource.driverClassName: com.mysql.jdbc.Driver
spring.datasource.username: root
spring.datasource.password:
spring.view.prefix: /WEB-INF/jsp/
spring.view.suffix: .jsp
POM.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.1.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- HIBERNATE -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</dependency>
<!-- MYSQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
</dependencies>
MAIN CLASS
#ComponentScan
#Configuration
#EnableAutoConfiguration
public class ApplicationStart {
public static void main(String[] args)
{
SpringApplication.run(ApplicationStart.class, args);
}
}
This is the current setup of my application. Any help on how to resolve the issue is much appreciated.
Please comment if more information is required.
Thanks-
Spring Boot has limited support for JSP, because of its use of an embedded servlet container. From the Spring Boot reference documentation:
When running a Spring Boot application that uses an embedded servlet container (and is packaged as an executable archive), there are some limitations in the JSP support.
With Tomcat it should work if you use war packaging, i.e. an executable war will work, and will also be deployable to a standard container (not limited to, but including Tomcat). An executable jar will not work because of a hard coded file pattern in Tomcat.
Jetty does not currently work as an embedded container with JSPs.
There is a JSP sample so you can see how to set things up.
Start by making your app an executable war, and make sure that you use Tomcat (check the log when you start the application). Unless you explicitly have stated you Jetty should be included, you are using Tomcat since that is provided by default. Alternatively, try change your view technology, which probably requires more initial work, but can significantly reduce the turnaround time during development, see Hotswapping.
I ran into this problem recently while upgrading an old project that needed to have jsps as the view technology with tomcat as an embedded servlet-container. Caveat: Pick an alternative templating engine, and avoid jsps if you can. But if you can't avoid jsps, and your application is not able to resolve them, at the time of this writing (spring-boot 2.x.x), ensure the following:
Ensure that application packaged as a war and not a jar. Although it is not impossible to get jsps to work with a jar packaging, it is a little complicated due to certain limitations. You could just run them with a war package in a server or container just fine like: java -jar war-filename.war
Verify that your controllers have the #Controller annotation
BUT NOT the annnotation #EnableWebMvc. That's because you are using spring-boot to configure WebMVC for you.
Is your controller being scanned and injected as a component? If you have defined your controllers in a different package, maybe you are missing a #ComponentScan annotation?
Are you jsps located and configured correctly? For example, let's say your jsps are located in /src/main/webapp/WEB-INF/jsp/, then your application.properties should have something like so:
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
Also, since you are using spring-boot, there is no need for your Application to extend the SpringBootServletInitializer. It will work too, but to keep it simple, all you need is a class like below:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
FYI, the minimal set of dependencies needed are mentioned below (Maven Example):
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
</parent>
<dependencies>
<!-- spring-boot dependencies below -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- jstl and jsp compilation support below -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
Agree with #code4kix, If all of this doesn't work, try adding below property in your application.properties file
spring.thymeleaf.enabled=false
In my case that solved my problem
Location of JSP file: src/main/resources -> /META-INF/resources/WEB-INF/jsp/sayHello.jsp
In pom.xml :
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
In application.properties:
spring.mvc.view.prefix= /WEB-INF/jsp/
spring.mvc.view.suffix= .jsp
#For debug reason
logging.level.org.springframework=debug
In Contoller:
#Controller
public class HelloController {
#RequestMapping("say-hello-jsp")
public String sayHelloJsp() {
return "sayHello";
}
}
Intellij still show it as error, but it works
In IntelliJ, if you have the same configurations and it still doesn't work do this:
File -> Invalidate Caches -> mark first 2 lines -> Invalidate and Restart. Then it will work fine