I'm trying to build a standalone web application using Spring Boot and Thymeleaf. The application runs fine from IntelliJ IDEA, but I'm not able to run the jar on its own. Apparently the templates are not included.
My project is structured as follows:
├── src
│ └── main
│ ├── java
│ │ └── my
│ │ └── domain
│ │ └── application
│ │ ├── domain
│ │ ├── service
│ │ ├── web
│ │ ├── ApplicationConfig.java
│ │ ├── SecurityConfig.java
│ │ ├── ThymeleafConfig.java
│ │ └── WebConfig.java
│ ├── resources
│ │ ├── application.properties
│ │ └── log4j.properties
│ └── webapp
│ ├── resources
│ │ ├── jquery.js
│ │ └── style.css
│ └── WEB-INF
│ └── views
│ ├── layout.html
│ ├── login.html
│ └── menu.html
└── pom.xml
ApplicationConfig:
#Bean
public DataSource dataSource() {
...
}
#Bean
public SessionBean sessionBean() {
return new SessionBean();
}
public static void main(String[] args) {
SpringApplication.run(ApplicationConfig.class, args);
}
ThymeleafConfig:
#Bean
public TemplateResolver templateResolver(){
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver();
templateResolver.setPrefix("/WEB-INF/views/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML5");
return templateResolver;
}
#Bean
public SpringTemplateEngine templateEngine(){
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
templateEngine.addDialect(new LayoutDialect());
return templateEngine;
}
#Bean
public ViewResolver viewResolver(){
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver() ;
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setOrder(1);
return viewResolver;
}
WebConfig:
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
I managed to include the WEB-INF folder by adding it as resource in pom.xml, but the views are still not resolved.
Have you tried removing the WEB-INF folder completely and sticking everything in resources as is done in this guide?
Related
Here my error message:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in cat.gencat.clt.git.backend.controller.PersonController required a bean of type 'cat.gencat.clt.git.backend.repositories.PersonRepository' that could not be found.
Action:
Consider defining a bean of type 'cat.gencat.clt.git.backend.repositories.PersonRepository' in your configuration.
My controller:
#RestController
#RequestMapping(value = "/persons")
#RequiredArgsConstructor
class PersonController {
private final PersonRepository persons;
#GetMapping("")
public Flux<Person> all() {
return this.persons.findAll();
}
}
And:
#Repository
public interface PersonRepository extends ReactiveCrudRepository<Person, String> {
}
Also, I've enabled #EnableR2dbcRepositories.
I don't quite figure out what am i doing wrong.
Any ideas?
EDIT
src/main/java
└── cat
└── gencat
└── clt
└── git
└── backend
├── BackendApplication.java
├── configuration
│ ├── GitConfiguration.java
│ ├── GitProperties.java
│ ├── LoginProperties.java
│ └── TokenProperties.java
├── controller
│ ├── GicarController.java
│ └── PersonController.java
├── model
│ └── Person.java
├── repositories
│ └── PersonRepository.java
├── SavePersonRunner.java
└── security
├── JWTProvider.java
└── SecurityConfiguration.java
Have you used #SpringBootApplication annotaion in your main file i.e. BackendApplication.java? Note that this annotaion has the feature of #ComponentScan which scans the packages for creating the beans which are to be managed by spring(spring's ioc container)
Can you check/share the file BackendApplication.java
In your PersonRepository interface, extend R2dbcRepository instead of ReactiveCrudRepository I don't know the reason but I had the same issue and that fixed it.
This is my project structure (MWE):
.
├── build.gradle
└── src
├── main
│ └── java
│ └── af
│ └── aps
│ ├── Application.java
│ └── config
│ └── MVCConfig.java
└── public
└── index.html
build.gradle
ext.appVersion = '0.0.1'
buildscript {
ext.springBootVersion = '2.0.4.RELEASE'
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'war'
repositories {
mavenCentral()
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
compile('org.springframework.boot:spring-boot-starter-web') // mvc
// compile group: 'com.sun.faces', name: 'jsf-api', version: '2.2.18'
// compile group: 'com.sun.faces', name: 'jsf-impl', version: '2.2.18'
}
Application.java
package app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Application.class);
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
MVCConfig.java
package app.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
public class MVCConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations("file:/home/hamid/workspace/java/app/src/public/")
.setCachePeriod(0);
}
}
index.html
<!DOCTYPE html>
<html>
<head>
<title>Home page</title>
</head>
<body>The home page</body>
</html>
I'm trying to serve the static resources from the file system. It does work. I can see the home page and when I change it and refresh the browser, I see the changes but when I add the JSF libraries to my project, I get a 404 error that the static resources cannot be found. I've googled all I can and searched the docs but I can't figure out what is wrong.
The folder src/public isn't in the classpath, so it's contents cant be served by spring-boot.
Just move src/public to src/main/resources/public and everything should work fine.
I have a very simple project structure this way
.
├── build.gradle
├── {gradle stuff}
└── src
├── main
│ ├── java
│ │ └── my_app
│ │ ├── ByeByer.java
│ │ ├── Greeter.java
│ │ ├── Helloer.java
│ │ ├── MyApp.java
│ │ └── MyConfig.java
│ └── resources
│ └── application.properties
└── test
├── java
│ └── my_app
│ └── e2e
│ ├── E2EConfig.java
│ ├── E2ESteps.java
│ └── MyE2ETest.java
└── resources
└── features
└── myFeature.feature
The code for the classes is the following.
Interface Greeter:
public interface Greeter {
public String greet();
}
It's basically a dummy interface for a greetings generator.
We have two implementation of this interface, a ByeByer, which returns "Bye bye" and Helloer, which returns "Hello".
The main is in MyApp:
#SpringBootApplication
public class MyApp {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(MyApp.class, args);
}
}
And the configuration is the following:
#Configuration
public class MyConfig {
#Bean
Greeter byebyer(){
return new ByeByer();
}
}
defining that in production, the Greeter implementation we want to use is the one generating the "Bye bye" message.
The test part is basically a scenario like this:
Feature: Just a feature
Scenario: Just a scenario
Given just a given
When just a when
Then just a then
And the step definition class for it is:
#SpringBootTest(
classes = {MyApp.class})
public class E2ESteps implements En{
#Autowired
Greeter greeter;
public E2ESteps() {
Given("^just a given$", () -> { });
When("^just a when$", () -> { });
Then("^just a then$", () -> {
assertEquals("Hello", greeter.greet());
});
}
}
I'm passing MyApp.class because I want to use the same configuration as in production, but I want to override only the Greeter implementation, so that it returns "Hello" during the test.
The test runner is simply:
#RunWith(Cucumber.class)
#CucumberOptions(
glue = { "my_app.e2e"},
features = "classpath:features"
)
public class MyE2ETest {
}
How do I amend my project so that I use the same dependency tree as the production one, but overriding only certain beans (in this case the production Greeter implementation)?
I am having trouble with spring-boot setting up a simple application when the Application.java, controller (#Controller), services (#Service) and repositories (#Repository) are in different packages.
I know it's a common issue and I've found here that it's a matter of setting up the #ComponentScan annotation in the main class.
However, despite doing this, I still get a 404 error when I try to access my REST service.
Here's my project structure :
main
├── java
│ ├── application
│ │ └── Application.java
│ ├── controllers
│ │ └── CategoryController.java
│ ├── dto
│ │ └── ReturnMessage.java
│ ├── entities
│ │ ├── Category.java
│ │ ├── Post.java
│ │ └── User.java
│ ├── repositories
│ │ └── CategoryRepository.java
│ ├── services
│ │ ├── CategoryService.java
│ │ └── CategoryServiceImpl.java
│ └── utils
│ └── Constants.java
Here's my Application.java :
package application;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#EnableJpaRepositories
#SpringBootApplication
#Configuration
#ComponentScan("main.java")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
And the beginning of my CategoryController.java :
#RestController
public class CategoryController {
#Autowired
CategoryService categoryService;
/**
* Retourne la liste des catégories
*/
#RequestMapping(value = Constants.REST_BASE_URL + "/categories", method = RequestMethod.GET)
public List<Category> readAll() {
return categoryService.readAll();
}
Constants.REST_BASE_URL is "rest/", and I get a 404 error when I call localhost:8080/rest/categories. I tried removing the base URL and it changed nothing. It works if I put the controller in the Application.java class.
Any guess as to why it is not working ? I'm new to Spring-boot so there may be something obvious that I forgot to do.
Thanks.
The problem is your #ComponentScan annotation. You've configured it to look in a package named main.java, however you have no such package in your application. The packages that you do have are:
application
controllers
dto
entities
repositories
services
utils
You could list all of these packages:
#ComponentScan({"application", "controllers", "dto", "entities", "repositories", "services", "utils"})
However, this would be rather unconventional.
It's more conventional for all of your packages to have a common root. If you place your Application class in this package there's then no need for an explicit #ComponentScan at all. Something like this:
main
├── java
| | foo
│ │ ├── Application.java
| │ ├── controllers
| │ │ └── CategoryController.java
| │ ├── dto
| │ │ └── ReturnMessage.java
| │ ├── entities
│ │ ├── Category.java
│ │ ├── Post.java
│ │ ├── User.java
| │ ├── repositories
| │ │ └── CategoryRepository.java
| │ ├── services
| │ │ ├── CategoryService.java
| │ │ └── CategoryServiceImpl.java
| │ └── utils
| │ └── Constants.java
Your package names would now be:
foo
foo.controllers
foo.dto
foo.entities
foo.repositories
foo.services
foo.utils
And your Application class being in the foo package will meant that component scanning is enabled for it and all of its sub-packages without you having to explicitly configure it.
I am trying to create a web application using Spring Boot and Thymeleaf and am having trouble getting the template to use the messages defined in a properties file. Instead of the message defined in the properties file, it is instead showing ??form.welcome_en_GB?? The console isn't logging any errors.
The project structure is like this
──┬ 🗁 src
│ └─── 🗁 main
│ ├─── 🗁 java
│ │ └─── 🗁 com
│ │ └─── 🗁 package
│ │ ├─── 🗁 controller
│ │ │ └─── FormController.java
│ │ ├─── Application.java
│ │ └─── ServletInitializer.java
│ └─── 🗁 resources
│ ├─── 🗁 static
│ │ └─── home.html
│ ├─── 🗁 templates
│ │ ├─── form.html
│ │ └─── form.properties
│ └─── application.properties
└─── pom.xml
Application.java
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
ServletInitializer.java
public class ServletInitializer extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
FormController.java
#Controller
#RequestMapping("/form")
public class FormController {
private static final Logger log = LoggerFactory.getLogger(FormController.class);
#RequestMapping(value = "/new", method = RequestMethod.GET)
public ModelAndView getNewReportForm() {
log.info("New form requested");
ModelAndView mav = new ModelAndView("form");
return mav;
}
}
form.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Form</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" type="text/css" media="all"/>
</head>
<body>
<p th:text="#{form.welcome}">Welcome!</p>
</body>
</html>
form.properties
form.welcome=Hello there!
I believe that changing the name of form.properties to messages.properties and locating it in the root of your resources folder should allow spring boot to pick it up automagically.
When I have multiple message files I explicitly list them in a MessageSource bean so that the MVC auto-configuration picks them up, e.g.:
#Bean
public MessageSource messageSource() {
final ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasenames("classpath:/some-mvc-messages", "classpath:/some-other-mvc-messages", "classpath:/another-projects/mvc-messages");
messageSource.setUseCodeAsDefaultMessage(true);
messageSource.setDefaultEncoding("UTF-8");
messageSource.setCacheSeconds(5);
return messageSource;
}
I Have the same Issue while using messages.properties file
The issue was #EnableAutoConfiguration not added in my Spring boot file
#SpringBootApplication
#EnableAutoConfiguration
public class Run {
public static void main(String[] args) {
SpringApplication.run(Run.class, args);
System.out.println("Run");
}
}
After added its work