Back");
+ }
+}
\ No newline at end of file
diff --git a/blade/src/main/java/com/baeldung/blade/sample/RouteExampleController.java b/blade/src/main/java/com/baeldung/blade/sample/RouteExampleController.java
new file mode 100644
index 0000000000..7ba2a270a9
--- /dev/null
+++ b/blade/src/main/java/com/baeldung/blade/sample/RouteExampleController.java
@@ -0,0 +1,78 @@
+package com.baeldung.blade.sample;
+
+import com.baeldung.blade.sample.configuration.BaeldungException;
+import com.blade.mvc.WebContext;
+import com.blade.mvc.annotation.DeleteRoute;
+import com.blade.mvc.annotation.GetRoute;
+import com.blade.mvc.annotation.Path;
+import com.blade.mvc.annotation.PostRoute;
+import com.blade.mvc.annotation.PutRoute;
+import com.blade.mvc.annotation.Route;
+import com.blade.mvc.http.HttpMethod;
+import com.blade.mvc.http.Request;
+import com.blade.mvc.http.Response;
+
+@Path
+public class RouteExampleController {
+
+ private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(RouteExampleController.class);
+
+ @GetRoute("/route-example")
+ public String get() {
+ return "get.html";
+ }
+
+ @PostRoute("/route-example")
+ public String post() {
+ return "post.html";
+ }
+
+ @PutRoute("/route-example")
+ public String put() {
+ return "put.html";
+ }
+
+ @DeleteRoute("/route-example")
+ public String delete() {
+ return "delete.html";
+ }
+
+ @Route(value = "/another-route-example", method = HttpMethod.GET)
+ public String anotherGet() {
+ return "get.html";
+ }
+
+ @Route(value = "/allmatch-route-example")
+ public String allmatch() {
+ return "allmatch.html";
+ }
+
+ @Route(value = "/triggerInternalServerError")
+ public void triggerInternalServerError() {
+ int x = 1 / 0;
+ }
+
+ @Route(value = "/triggerBaeldungException")
+ public void triggerBaeldungException() throws BaeldungException {
+ throw new BaeldungException("Foobar Exception to threat differently");
+ }
+
+ @Route(value = "/user/foo")
+ public void urlCoveredByNarrowedWebhook(Response response) {
+ response.text("Check out for the WebHook covering '/user/*' in the logs");
+ }
+
+ @GetRoute("/load-configuration-in-a-route")
+ public void loadConfigurationInARoute(Response response) {
+ String authors = WebContext.blade()
+ .env("app.authors", "Unknown authors");
+ log.info("[/load-configuration-in-a-route] Loading 'app.authors' from configuration, value: " + authors);
+ response.render("index.html");
+ }
+
+ @GetRoute("/template-output-test")
+ public void templateOutputTest(Request request, Response response) {
+ request.attribute("name", "Blade");
+ response.render("template-output-test.html");
+ }
+}
diff --git a/blade/src/main/java/com/baeldung/blade/sample/configuration/BaeldungException.java b/blade/src/main/java/com/baeldung/blade/sample/configuration/BaeldungException.java
new file mode 100644
index 0000000000..01a030b7e7
--- /dev/null
+++ b/blade/src/main/java/com/baeldung/blade/sample/configuration/BaeldungException.java
@@ -0,0 +1,9 @@
+package com.baeldung.blade.sample.configuration;
+
+public class BaeldungException extends RuntimeException {
+
+ public BaeldungException(String message) {
+ super(message);
+ }
+
+}
\ No newline at end of file
diff --git a/blade/src/main/java/com/baeldung/blade/sample/configuration/GlobalExceptionHandler.java b/blade/src/main/java/com/baeldung/blade/sample/configuration/GlobalExceptionHandler.java
new file mode 100644
index 0000000000..ab7b81c0dc
--- /dev/null
+++ b/blade/src/main/java/com/baeldung/blade/sample/configuration/GlobalExceptionHandler.java
@@ -0,0 +1,25 @@
+package com.baeldung.blade.sample.configuration;
+
+import com.blade.ioc.annotation.Bean;
+import com.blade.mvc.WebContext;
+import com.blade.mvc.handler.DefaultExceptionHandler;
+
+@Bean
+public class GlobalExceptionHandler extends DefaultExceptionHandler {
+
+ private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(GlobalExceptionHandler.class);
+
+ @Override
+ public void handle(Exception e) {
+ if (e instanceof BaeldungException) {
+ Exception baeldungException = (BaeldungException) e;
+ String msg = baeldungException.getMessage();
+ log.error("[GlobalExceptionHandler] Intercepted an exception to threat with additional logic. Error message: " + msg);
+ WebContext.response()
+ .render("index.html");
+
+ } else {
+ super.handle(e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/blade/src/main/java/com/baeldung/blade/sample/configuration/LoadConfig.java b/blade/src/main/java/com/baeldung/blade/sample/configuration/LoadConfig.java
new file mode 100644
index 0000000000..0f1aab1b52
--- /dev/null
+++ b/blade/src/main/java/com/baeldung/blade/sample/configuration/LoadConfig.java
@@ -0,0 +1,23 @@
+package com.baeldung.blade.sample.configuration;
+
+import com.blade.Blade;
+import com.blade.ioc.annotation.Bean;
+import com.blade.loader.BladeLoader;
+import com.blade.mvc.WebContext;
+
+@Bean
+public class LoadConfig implements BladeLoader {
+
+ private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoadConfig.class);
+
+ @Override
+ public void load(Blade blade) {
+ String version = WebContext.blade()
+ .env("app.version")
+ .orElse("N/D");
+ String authors = WebContext.blade()
+ .env("app.authors", "Unknown authors");
+
+ log.info("[LoadConfig] loaded 'app.version' (" + version + ") and 'app.authors' (" + authors + ") in a configuration bean");
+ }
+}
\ No newline at end of file
diff --git a/blade/src/main/java/com/baeldung/blade/sample/configuration/ScheduleExample.java b/blade/src/main/java/com/baeldung/blade/sample/configuration/ScheduleExample.java
new file mode 100644
index 0000000000..c170975818
--- /dev/null
+++ b/blade/src/main/java/com/baeldung/blade/sample/configuration/ScheduleExample.java
@@ -0,0 +1,15 @@
+package com.baeldung.blade.sample.configuration;
+
+import com.blade.ioc.annotation.Bean;
+import com.blade.task.annotation.Schedule;
+
+@Bean
+public class ScheduleExample {
+
+ private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ScheduleExample.class);
+
+ @Schedule(name = "baeldungTask", cron = "0 */1 * * * ?")
+ public void runScheduledTask() {
+ log.info("[ScheduleExample] This is a scheduled Task running once per minute.");
+ }
+}
diff --git a/blade/src/main/java/com/baeldung/blade/sample/interceptors/BaeldungHook.java b/blade/src/main/java/com/baeldung/blade/sample/interceptors/BaeldungHook.java
new file mode 100644
index 0000000000..4d0d178b0d
--- /dev/null
+++ b/blade/src/main/java/com/baeldung/blade/sample/interceptors/BaeldungHook.java
@@ -0,0 +1,17 @@
+package com.baeldung.blade.sample.interceptors;
+
+import com.blade.ioc.annotation.Bean;
+import com.blade.mvc.RouteContext;
+import com.blade.mvc.hook.WebHook;
+
+@Bean
+public class BaeldungHook implements WebHook {
+
+ private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(BaeldungHook.class);
+
+ @Override
+ public boolean before(RouteContext ctx) {
+ log.info("[BaeldungHook] called before Route method");
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/blade/src/main/java/com/baeldung/blade/sample/interceptors/BaeldungMiddleware.java b/blade/src/main/java/com/baeldung/blade/sample/interceptors/BaeldungMiddleware.java
new file mode 100644
index 0000000000..3342cd8b01
--- /dev/null
+++ b/blade/src/main/java/com/baeldung/blade/sample/interceptors/BaeldungMiddleware.java
@@ -0,0 +1,15 @@
+package com.baeldung.blade.sample.interceptors;
+
+import com.blade.mvc.RouteContext;
+import com.blade.mvc.hook.WebHook;
+
+public class BaeldungMiddleware implements WebHook {
+
+ private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(BaeldungMiddleware.class);
+
+ @Override
+ public boolean before(RouteContext context) {
+ log.info("[BaeldungMiddleware] called before Route method and other WebHooks");
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/blade/src/main/java/com/baeldung/blade/sample/vo/User.java b/blade/src/main/java/com/baeldung/blade/sample/vo/User.java
new file mode 100644
index 0000000000..b493dc3663
--- /dev/null
+++ b/blade/src/main/java/com/baeldung/blade/sample/vo/User.java
@@ -0,0 +1,16 @@
+package com.baeldung.blade.sample.vo;
+
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+
+import lombok.Getter;
+import lombok.Setter;
+
+public class User {
+ @Getter @Setter private String name;
+ @Getter @Setter private String site;
+
+ @Override
+ public String toString() {
+ return ReflectionToStringBuilder.toString(this);
+ }
+}
\ No newline at end of file
diff --git a/blade/src/main/resources/application.properties b/blade/src/main/resources/application.properties
new file mode 100644
index 0000000000..ebf365406a
--- /dev/null
+++ b/blade/src/main/resources/application.properties
@@ -0,0 +1,5 @@
+mvc.statics.show-list=true
+mvc.view.404=my-404.html
+mvc.view.500=my-500.html
+app.version=0.0.1
+app.authors=Andrea Ligios
diff --git a/blade/src/main/resources/custom-static/icon.png b/blade/src/main/resources/custom-static/icon.png
new file mode 100644
index 0000000000..59af395afc
Binary files /dev/null and b/blade/src/main/resources/custom-static/icon.png differ
diff --git a/blade/src/main/resources/favicon.ico b/blade/src/main/resources/favicon.ico
new file mode 100644
index 0000000000..ca63a6a890
Binary files /dev/null and b/blade/src/main/resources/favicon.ico differ
diff --git a/blade/src/main/resources/static/app.css b/blade/src/main/resources/static/app.css
new file mode 100644
index 0000000000..9fff13d9b6
--- /dev/null
+++ b/blade/src/main/resources/static/app.css
@@ -0,0 +1 @@
+/* App CSS */
\ No newline at end of file
diff --git a/persistence-modules/hibernate5/transaction.log b/blade/src/main/resources/static/app.js
similarity index 100%
rename from persistence-modules/hibernate5/transaction.log
rename to blade/src/main/resources/static/app.js
diff --git a/blade/src/main/resources/static/file-upload.html b/blade/src/main/resources/static/file-upload.html
new file mode 100644
index 0000000000..b805be81b1
--- /dev/null
+++ b/blade/src/main/resources/static/file-upload.html
@@ -0,0 +1,43 @@
+
+
+
+
+Title
+
+
+
+
+
+
File Upload and download test
+
+
+
+ Back
+
+
+
+
\ No newline at end of file
diff --git a/blade/src/main/resources/static/user-post.html b/blade/src/main/resources/static/user-post.html
new file mode 100644
index 0000000000..ccfc4e8d0b
--- /dev/null
+++ b/blade/src/main/resources/static/user-post.html
@@ -0,0 +1,25 @@
+
+
+
+
+Title
+
+
+
+
+
+
User POJO post test
+
+
+
+
+
+ Back
+
+
+
\ No newline at end of file
diff --git a/blade/src/main/resources/templates/allmatch.html b/blade/src/main/resources/templates/allmatch.html
new file mode 100644
index 0000000000..7a4bfa070f
--- /dev/null
+++ b/blade/src/main/resources/templates/allmatch.html
@@ -0,0 +1 @@
+ALLMATCH called
\ No newline at end of file
diff --git a/blade/src/main/resources/templates/delete.html b/blade/src/main/resources/templates/delete.html
new file mode 100644
index 0000000000..1acb4b0b62
--- /dev/null
+++ b/blade/src/main/resources/templates/delete.html
@@ -0,0 +1 @@
+DELETE called
\ No newline at end of file
diff --git a/blade/src/main/resources/templates/get.html b/blade/src/main/resources/templates/get.html
new file mode 100644
index 0000000000..2c37aa1058
--- /dev/null
+++ b/blade/src/main/resources/templates/get.html
@@ -0,0 +1 @@
+GET called
\ No newline at end of file
diff --git a/blade/src/main/resources/templates/index.html b/blade/src/main/resources/templates/index.html
new file mode 100644
index 0000000000..6b7c2e77ad
--- /dev/null
+++ b/blade/src/main/resources/templates/index.html
@@ -0,0 +1,30 @@
+
+
+
+
+Baeldung Blade App • Written by Andrea Ligios
+
+
+
+
Baeldung Blade App - Showcase
+
+
Manual tests
+
The following are tests which are not covered by integration tests, but that can be run manually in order to check the functionality, either in the browser or in the logs, depending on the case.
+
+
+
+
+
\ No newline at end of file
diff --git a/blade/src/main/resources/templates/my-404.html b/blade/src/main/resources/templates/my-404.html
new file mode 100644
index 0000000000..0fa694f241
--- /dev/null
+++ b/blade/src/main/resources/templates/my-404.html
@@ -0,0 +1,10 @@
+
+
+
+
+ 404 Not found
+
+
+ Custom Error 404 Page
+
+
\ No newline at end of file
diff --git a/blade/src/main/resources/templates/my-500.html b/blade/src/main/resources/templates/my-500.html
new file mode 100644
index 0000000000..cc8438bfd6
--- /dev/null
+++ b/blade/src/main/resources/templates/my-500.html
@@ -0,0 +1,12 @@
+
+
+
+
+ 500 Internal Server Error
+
+
+
Custom Error 500 Page
+
The following error occurred: "${message}"
+
${stackTrace}
+
+
\ No newline at end of file
diff --git a/blade/src/main/resources/templates/post.html b/blade/src/main/resources/templates/post.html
new file mode 100644
index 0000000000..b7a8a931cd
--- /dev/null
+++ b/blade/src/main/resources/templates/post.html
@@ -0,0 +1 @@
+POST called
\ No newline at end of file
diff --git a/blade/src/main/resources/templates/put.html b/blade/src/main/resources/templates/put.html
new file mode 100644
index 0000000000..bdbe6d3285
--- /dev/null
+++ b/blade/src/main/resources/templates/put.html
@@ -0,0 +1 @@
+PUT called
\ No newline at end of file
diff --git a/blade/src/main/resources/templates/template-output-test.html b/blade/src/main/resources/templates/template-output-test.html
new file mode 100644
index 0000000000..233b12fb88
--- /dev/null
+++ b/blade/src/main/resources/templates/template-output-test.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/user-list/user-list.component.spec.ts b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/user-list/user-list.component.spec.ts
new file mode 100644
index 0000000000..9d521807d6
--- /dev/null
+++ b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/user-list/user-list.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { UserListComponent } from './user-list.component';
+
+describe('UserListComponent', () => {
+ let component: UserListComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ UserListComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(UserListComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/user-list/user-list.component.ts b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/user-list/user-list.component.ts
new file mode 100644
index 0000000000..91226695f5
--- /dev/null
+++ b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/app/user-list/user-list.component.ts
@@ -0,0 +1,23 @@
+import { Component, OnInit } from '@angular/core';
+import { User } from '../model/user';
+import { UserService } from '../service/user.service';
+
+@Component({
+ selector: 'app-user-list',
+ templateUrl: './user-list.component.html',
+ styleUrls: ['./user-list.component.css']
+})
+export class UserListComponent implements OnInit {
+
+ users: User[];
+
+ constructor(private userService: UserService) {
+
+ }
+
+ ngOnInit() {
+ this.userService.findAll().subscribe(data => {
+ this.users = data;
+ });
+ }
+}
diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/assets/.gitkeep b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/assets/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/environments/environment.prod.ts b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/environments/environment.prod.ts
new file mode 100644
index 0000000000..3612073bc3
--- /dev/null
+++ b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/environments/environment.prod.ts
@@ -0,0 +1,3 @@
+export const environment = {
+ production: true
+};
diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/environments/environment.ts b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/environments/environment.ts
new file mode 100644
index 0000000000..b7f639aeca
--- /dev/null
+++ b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/environments/environment.ts
@@ -0,0 +1,8 @@
+// The file contents for the current environment will overwrite these during build.
+// The build system defaults to the dev environment which uses `environment.ts`, but if you do
+// `ng build --env=prod` then `environment.prod.ts` will be used instead.
+// The list of which env maps to which file can be found in `.angular-cli.json`.
+
+export const environment = {
+ production: false
+};
diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/favicon.ico b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/favicon.ico
new file mode 100644
index 0000000000..8081c7ceaf
Binary files /dev/null and b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/favicon.ico differ
diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/index.html b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/index.html
new file mode 100644
index 0000000000..1ce7ff1ca6
--- /dev/null
+++ b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+ Spring Boot - Angular Application
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/main.ts b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/main.ts
new file mode 100644
index 0000000000..91ec6da5f0
--- /dev/null
+++ b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/main.ts
@@ -0,0 +1,12 @@
+import { enableProdMode } from '@angular/core';
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+
+import { AppModule } from './app/app.module';
+import { environment } from './environments/environment';
+
+if (environment.production) {
+ enableProdMode();
+}
+
+platformBrowserDynamic().bootstrapModule(AppModule)
+ .catch(err => console.log(err));
diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/polyfills.ts b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/polyfills.ts
new file mode 100644
index 0000000000..af84770782
--- /dev/null
+++ b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/polyfills.ts
@@ -0,0 +1,79 @@
+/**
+ * This file includes polyfills needed by Angular and is loaded before the app.
+ * You can add your own extra polyfills to this file.
+ *
+ * This file is divided into 2 sections:
+ * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
+ * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
+ * file.
+ *
+ * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
+ * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
+ * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
+ *
+ * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
+ */
+
+/***************************************************************************************************
+ * BROWSER POLYFILLS
+ */
+
+/** IE9, IE10 and IE11 requires all of the following polyfills. **/
+// import 'core-js/es6/symbol';
+// import 'core-js/es6/object';
+// import 'core-js/es6/function';
+// import 'core-js/es6/parse-int';
+// import 'core-js/es6/parse-float';
+// import 'core-js/es6/number';
+// import 'core-js/es6/math';
+// import 'core-js/es6/string';
+// import 'core-js/es6/date';
+// import 'core-js/es6/array';
+// import 'core-js/es6/regexp';
+// import 'core-js/es6/map';
+// import 'core-js/es6/weak-map';
+// import 'core-js/es6/set';
+
+/** IE10 and IE11 requires the following for NgClass support on SVG elements */
+// import 'classlist.js'; // Run `npm install --save classlist.js`.
+
+/** IE10 and IE11 requires the following for the Reflect API. */
+// import 'core-js/es6/reflect';
+
+
+/** Evergreen browsers require these. **/
+// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
+import 'core-js/es7/reflect';
+
+
+/**
+ * Required to support Web Animations `@angular/platform-browser/animations`.
+ * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
+ **/
+// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
+
+/**
+ * By default, zone.js will patch all possible macroTask and DomEvents
+ * user can disable parts of macroTask/DomEvents patch by setting following flags
+ */
+
+ // (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
+ // (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
+ // (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
+
+ /*
+ * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
+ * with the following flag, it will bypass `zone.js` patch for IE/Edge
+ */
+// (window as any).__Zone_enable_cross_context_check = true;
+
+/***************************************************************************************************
+ * Zone JS is required by default for Angular itself.
+ */
+import 'zone.js/dist/zone'; // Included with Angular CLI.
+
+
+
+/***************************************************************************************************
+ * APPLICATION IMPORTS
+ */
diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/styles.css b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/styles.css
new file mode 100644
index 0000000000..90d4ee0072
--- /dev/null
+++ b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/styles.css
@@ -0,0 +1 @@
+/* You can add global styles to this file, and also import other style files */
diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/tsconfig.app.json b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/tsconfig.app.json
new file mode 100644
index 0000000000..39ba8dbacb
--- /dev/null
+++ b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/tsconfig.app.json
@@ -0,0 +1,13 @@
+{
+ "extends": "../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../out-tsc/app",
+ "baseUrl": "./",
+ "module": "es2015",
+ "types": []
+ },
+ "exclude": [
+ "test.ts",
+ "**/*.spec.ts"
+ ]
+}
diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/tsconfig.spec.json b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/tsconfig.spec.json
new file mode 100644
index 0000000000..ac22a298ac
--- /dev/null
+++ b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/tsconfig.spec.json
@@ -0,0 +1,19 @@
+{
+ "extends": "../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../out-tsc/spec",
+ "baseUrl": "./",
+ "module": "commonjs",
+ "types": [
+ "jasmine",
+ "node"
+ ]
+ },
+ "files": [
+ "test.ts"
+ ],
+ "include": [
+ "**/*.spec.ts",
+ "**/*.d.ts"
+ ]
+}
diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/typings.d.ts b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/typings.d.ts
new file mode 100644
index 0000000000..ef5c7bd620
--- /dev/null
+++ b/spring-boot-angular/src/main/java/com/baeldung/angularclient/src/typings.d.ts
@@ -0,0 +1,5 @@
+/* SystemJS module definition */
+declare var module: NodeModule;
+interface NodeModule {
+ id: string;
+}
diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/tsconfig.json b/spring-boot-angular/src/main/java/com/baeldung/angularclient/tsconfig.json
new file mode 100644
index 0000000000..a6c016bf38
--- /dev/null
+++ b/spring-boot-angular/src/main/java/com/baeldung/angularclient/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compileOnSave": false,
+ "compilerOptions": {
+ "outDir": "./dist/out-tsc",
+ "sourceMap": true,
+ "declaration": false,
+ "moduleResolution": "node",
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "target": "es5",
+ "typeRoots": [
+ "node_modules/@types"
+ ],
+ "lib": [
+ "es2017",
+ "dom"
+ ]
+ }
+}
diff --git a/spring-boot-angular/src/main/java/com/baeldung/angularclient/tslint.json b/spring-boot-angular/src/main/java/com/baeldung/angularclient/tslint.json
new file mode 100644
index 0000000000..9963d6c395
--- /dev/null
+++ b/spring-boot-angular/src/main/java/com/baeldung/angularclient/tslint.json
@@ -0,0 +1,143 @@
+{
+ "rulesDirectory": [
+ "node_modules/codelyzer"
+ ],
+ "rules": {
+ "arrow-return-shorthand": true,
+ "callable-types": true,
+ "class-name": true,
+ "comment-format": [
+ true,
+ "check-space"
+ ],
+ "curly": true,
+ "deprecation": {
+ "severity": "warn"
+ },
+ "eofline": true,
+ "forin": true,
+ "import-blacklist": [
+ true,
+ "rxjs",
+ "rxjs/Rx"
+ ],
+ "import-spacing": true,
+ "indent": [
+ true,
+ "spaces"
+ ],
+ "interface-over-type-literal": true,
+ "label-position": true,
+ "max-line-length": [
+ true,
+ 140
+ ],
+ "member-access": false,
+ "member-ordering": [
+ true,
+ {
+ "order": [
+ "static-field",
+ "instance-field",
+ "static-method",
+ "instance-method"
+ ]
+ }
+ ],
+ "no-arg": true,
+ "no-bitwise": true,
+ "no-console": [
+ true,
+ "debug",
+ "info",
+ "time",
+ "timeEnd",
+ "trace"
+ ],
+ "no-construct": true,
+ "no-debugger": true,
+ "no-duplicate-super": true,
+ "no-empty": false,
+ "no-empty-interface": true,
+ "no-eval": true,
+ "no-inferrable-types": [
+ true,
+ "ignore-params"
+ ],
+ "no-misused-new": true,
+ "no-non-null-assertion": true,
+ "no-shadowed-variable": true,
+ "no-string-literal": false,
+ "no-string-throw": true,
+ "no-switch-case-fall-through": true,
+ "no-trailing-whitespace": true,
+ "no-unnecessary-initializer": true,
+ "no-unused-expression": true,
+ "no-use-before-declare": true,
+ "no-var-keyword": true,
+ "object-literal-sort-keys": false,
+ "one-line": [
+ true,
+ "check-open-brace",
+ "check-catch",
+ "check-else",
+ "check-whitespace"
+ ],
+ "prefer-const": true,
+ "quotemark": [
+ true,
+ "single"
+ ],
+ "radix": true,
+ "semicolon": [
+ true,
+ "always"
+ ],
+ "triple-equals": [
+ true,
+ "allow-null-check"
+ ],
+ "typedef-whitespace": [
+ true,
+ {
+ "call-signature": "nospace",
+ "index-signature": "nospace",
+ "parameter": "nospace",
+ "property-declaration": "nospace",
+ "variable-declaration": "nospace"
+ }
+ ],
+ "unified-signatures": true,
+ "variable-name": false,
+ "whitespace": [
+ true,
+ "check-branch",
+ "check-decl",
+ "check-operator",
+ "check-separator",
+ "check-type"
+ ],
+ "directive-selector": [
+ true,
+ "attribute",
+ "app",
+ "camelCase"
+ ],
+ "component-selector": [
+ true,
+ "element",
+ "app",
+ "kebab-case"
+ ],
+ "no-output-on-prefix": true,
+ "use-input-property-decorator": true,
+ "use-output-property-decorator": true,
+ "use-host-property-decorator": true,
+ "no-input-rename": true,
+ "no-output-rename": true,
+ "use-life-cycle-interface": true,
+ "use-pipe-transform-interface": true,
+ "component-class-suffix": true,
+ "directive-class-suffix": true
+ }
+}
diff --git a/spring-boot-angular/src/main/java/com/baeldung/application/Application.java b/spring-boot-angular/src/main/java/com/baeldung/application/Application.java
new file mode 100644
index 0000000000..f1155c3106
--- /dev/null
+++ b/spring-boot-angular/src/main/java/com/baeldung/application/Application.java
@@ -0,0 +1,28 @@
+package com.baeldung.application;
+
+import com.baeldung.application.entities.User;
+import com.baeldung.application.repositories.UserRepository;
+import java.util.stream.Stream;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+
+ @Bean
+ CommandLineRunner init(UserRepository userRepository) {
+ return args -> {
+ Stream.of("John", "Julie", "Jennifer", "Helen", "Rachel").forEach(name -> {
+ User user = new User(name, name.toLowerCase() + "@domain.com");
+ userRepository.save(user);
+ });
+ userRepository.findAll().forEach(System.out::println);
+ };
+ }
+}
diff --git a/spring-boot-angular/src/main/java/com/baeldung/application/controllers/UserController.java b/spring-boot-angular/src/main/java/com/baeldung/application/controllers/UserController.java
new file mode 100644
index 0000000000..c101ed771f
--- /dev/null
+++ b/spring-boot-angular/src/main/java/com/baeldung/application/controllers/UserController.java
@@ -0,0 +1,31 @@
+package com.baeldung.application.controllers;
+
+import com.application.entities.User;
+import com.baeldung.application.repositories.UserRepository;
+import java.util.List;
+import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@CrossOrigin(origins = "http://localhost:4200")
+public class UserController {
+
+ private final UserRepository userRepository;
+
+ public UserController(UserRepository userRepository) {
+ this.userRepository = userRepository;
+ }
+
+ @GetMapping("/users")
+ public List getUsers() {
+ return (List) userRepository.findAll();
+ }
+
+ @PostMapping("/users")
+ void addUser(@RequestBody User user) {
+ userRepository.save(user);
+ }
+}
diff --git a/spring-boot-angular/src/main/java/com/baeldung/application/entities/User.java b/spring-boot-angular/src/main/java/com/baeldung/application/entities/User.java
new file mode 100644
index 0000000000..4c346fa5b9
--- /dev/null
+++ b/spring-boot-angular/src/main/java/com/baeldung/application/entities/User.java
@@ -0,0 +1,43 @@
+package com.baeldung.application.entities;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+@Entity
+public class User {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private long id;
+ private final String name;
+ private final String email;
+
+ public User() {
+ this.name = "";
+ this.email = "";
+ }
+
+ public User(String name, String email) {
+ this.name = name;
+ this.email = email;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ @Override
+ public String toString() {
+ return "User{" + "id=" + id + ", name=" + name + ", email=" + email + '}';
+ }
+}
diff --git a/spring-boot-angular/src/main/java/com/baeldung/application/repositories/UserRepository.java b/spring-boot-angular/src/main/java/com/baeldung/application/repositories/UserRepository.java
new file mode 100644
index 0000000000..f8ef5a4c0c
--- /dev/null
+++ b/spring-boot-angular/src/main/java/com/baeldung/application/repositories/UserRepository.java
@@ -0,0 +1,10 @@
+package com.baeldung.application.repositories;
+
+import com.baeldung.application.entities.User;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.stereotype.Repository;
+import org.springframework.web.bind.annotation.CrossOrigin;
+
+@Repository
+@CrossOrigin(origins = "http://localhost:4200")
+public interface UserRepository extends CrudRepository{}
diff --git a/spring-boot-autoconfiguration/pom.xml b/spring-boot-autoconfiguration/pom.xml
index 1c3d8796ed..91692ebfff 100644
--- a/spring-boot-autoconfiguration/pom.xml
+++ b/spring-boot-autoconfiguration/pom.xml
@@ -4,8 +4,8 @@
com.baeldungspring-boot-autoconfiguration0.0.1-SNAPSHOT
- warspring-boot-autoconfiguration
+ warThis is simple boot application demonstrating a custom auto-configuration
diff --git a/spring-boot-autoconfiguration/src/test/java/com/baeldung/SpringContextLiveTest.java b/spring-boot-autoconfiguration/src/test/java/com/baeldung/SpringContextLiveTest.java
new file mode 100644
index 0000000000..494013d1d9
--- /dev/null
+++ b/spring-boot-autoconfiguration/src/test/java/com/baeldung/SpringContextLiveTest.java
@@ -0,0 +1,19 @@
+package com.baeldung;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+
+import com.baeldung.autoconfiguration.MySQLAutoconfiguration;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = MySQLAutoconfiguration.class)
+@WebAppConfiguration
+public class SpringContextLiveTest {
+
+ @Test
+ public void whenSpringContextIsBootstrapped_thenNoExceptions() {
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-bootstrap/README.md b/spring-boot-bootstrap/README.md
index 76b977c129..2186aa8fec 100644
--- a/spring-boot-bootstrap/README.md
+++ b/spring-boot-bootstrap/README.md
@@ -5,3 +5,4 @@
- [Deploying a Spring Boot Application to Cloud Foundry](https://www.baeldung.com/spring-boot-app-deploy-to-cloud-foundry)
- [Deploy a Spring Boot Application to Google App Engine](https://www.baeldung.com/spring-boot-google-app-engine)
- [Deploy a Spring Boot Application to OpenShift](https://www.baeldung.com/spring-boot-deploy-openshift)
+- [Deploy a Spring Boot Application to AWS Beanstalk](https://www.baeldung.com/spring-boot-deploy-aws-beanstalk)
diff --git a/spring-boot-bootstrap/pom.xml b/spring-boot-bootstrap/pom.xml
index 0ffc1820b8..70ebb225c8 100644
--- a/spring-boot-bootstrap/pom.xml
+++ b/spring-boot-bootstrap/pom.xml
@@ -4,16 +4,18 @@
4.0.0com.baeldungspring-boot-bootstrap
- jarspring-boot-bootstrapDemo project for Spring Boot
-
+ jar
+
+ parent-boot-2com.baeldung0.0.1-SNAPSHOT../parent-boot-2
-
+
+ org.springframework.bootspring-boot-starter-web
@@ -82,7 +84,7 @@
openshift0.3.0.RELEASE
- Finchley.SR2
+ Greenwich.RELEASE3.5.37
@@ -164,7 +166,7 @@
org.springframework.cloudspring-cloud-dependencies
- Finchley.SR1
+ Greenwich.RELEASEpomimport
@@ -212,7 +214,7 @@
org.springframework.cloudspring-cloud-dependencies
- Finchley.SR1
+ Greenwich.RELEASEpomimport
@@ -312,7 +314,8 @@
-
+
+ org.apache.maven.plugins
@@ -325,7 +328,8 @@
-
+
+ 4.0.0
diff --git a/spring-boot-bootstrap/src/main/java/com/baeldung/Application.java b/spring-boot-bootstrap/src/main/java/com/baeldung/Application.java
index 567e9b2678..d5a597e48b 100644
--- a/spring-boot-bootstrap/src/main/java/com/baeldung/Application.java
+++ b/spring-boot-bootstrap/src/main/java/com/baeldung/Application.java
@@ -4,12 +4,10 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.web.servlet.ServletComponentScan;
-import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@ServletComponentScan
-@SpringBootApplication
-@ComponentScan("com.baeldung")
+@SpringBootApplication(scanBasePackages = "com.baeldung")
@EnableJpaRepositories("com.baeldung.persistence.repo")
@EntityScan("com.baeldung.persistence.model")
public class Application {
diff --git a/spring-boot-bootstrap/src/main/resources/templates/error.html b/spring-boot-bootstrap/src/main/resources/templates/error.html
index f2b51a1938..ca3a740b71 100644
--- a/spring-boot-bootstrap/src/main/resources/templates/error.html
+++ b/spring-boot-bootstrap/src/main/resources/templates/error.html
@@ -1,19 +1,19 @@
-
+
Error Occurred
-
Error Occurred!
-
+
Error Occurred!
+
[status]
error
message
-
+
-
\ No newline at end of file
+
diff --git a/spring-boot-bootstrap/src/main/resources/templates/home.html b/spring-boot-bootstrap/src/main/resources/templates/home.html
index 5707cfb82a..0428ca1127 100644
--- a/spring-boot-bootstrap/src/main/resources/templates/home.html
+++ b/spring-boot-bootstrap/src/main/resources/templates/home.html
@@ -1,7 +1,7 @@
-
+
Home Page
Hello !
Welcome to Our App
-
\ No newline at end of file
+
diff --git a/spring-boot-client/pom.xml b/spring-boot-client/pom.xml
index fc89931f79..4850849039 100644
--- a/spring-boot-client/pom.xml
+++ b/spring-boot-client/pom.xml
@@ -4,8 +4,8 @@
com.baeldungspring-boot-client0.0.1-SNAPSHOT
- warspring-boot-client
+ warThis is simple boot client application for Spring boot actuator test
diff --git a/spring-boot-crud/pom.xml b/spring-boot-crud/pom.xml
index 749bf9cb5a..73635b0a1c 100644
--- a/spring-boot-crud/pom.xml
+++ b/spring-boot-crud/pom.xml
@@ -3,15 +3,14 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
4.0.0
- com.baeldung.spring-boot-crudspring-boot-crud
- 0.1.0spring-boot-crud
- org.springframework.boot
- spring-boot-starter-parent
- 2.0.6.RELEASE
+ parent-boot-2
+ com.baeldung
+ 0.0.1-SNAPSHOT
+ ../parent-boot-2
@@ -41,11 +40,7 @@
h2runtime
-
-
- UTF-8
- 1.8
-
+ spring-boot-crud
@@ -62,4 +57,10 @@
+
+
+ UTF-8
+ 1.8
+
+
\ No newline at end of file
diff --git a/spring-boot-data/README.md b/spring-boot-data/README.md
new file mode 100644
index 0000000000..21f7303c48
--- /dev/null
+++ b/spring-boot-data/README.md
@@ -0,0 +1,2 @@
+### Relevant Articles:
+- [Formatting JSON Dates in Spring ](https://www.baeldung.com/spring-boot-formatting-json-dates)
\ No newline at end of file
diff --git a/spring-boot-data/pom.xml b/spring-boot-data/pom.xml
new file mode 100644
index 0000000000..9ef4cc69c8
--- /dev/null
+++ b/spring-boot-data/pom.xml
@@ -0,0 +1,122 @@
+
+
+ 4.0.0
+ spring-boot-data
+ war
+ spring-boot-data
+ Spring Boot Data Module
+
+
+ parent-boot-2
+ com.baeldung
+ 0.0.1-SNAPSHOT
+ ../parent-boot-2
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-tomcat
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+ spring-boot
+
+
+ src/main/resources
+ true
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-war-plugin
+
+
+
+ pl.project13.maven
+ git-commit-id-plugin
+ ${git-commit-id-plugin.version}
+
+
+ get-the-git-infos
+
+ revision
+
+ initialize
+
+
+ validate-the-git-infos
+
+ validateRevision
+
+ package
+
+
+
+ true
+ ${project.build.outputDirectory}/git.properties
+
+
+
+
+
+
+
+
+ autoconfiguration
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ integration-test
+
+ test
+
+
+
+ **/*LiveTest.java
+ **/*IntegrationTest.java
+ **/*IntTest.java
+
+
+ **/AutoconfigurationTest.java
+
+
+
+
+
+
+ json
+
+
+
+
+
+
+
+
+
+ com.baeldung.SpringBootDataApplication
+ 2.2.4
+
+
+
\ No newline at end of file
diff --git a/spring-boot-data/src/main/java/com/baeldung/SpringBootDataApplication.java b/spring-boot-data/src/main/java/com/baeldung/SpringBootDataApplication.java
new file mode 100644
index 0000000000..3aa093bb41
--- /dev/null
+++ b/spring-boot-data/src/main/java/com/baeldung/SpringBootDataApplication.java
@@ -0,0 +1,13 @@
+package com.baeldung;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SpringBootDataApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(SpringBootDataApplication.class, args);
+ }
+
+}
diff --git a/spring-boot-data/src/main/java/com/baeldung/jsondateformat/Contact.java b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/Contact.java
new file mode 100644
index 0000000000..f131d17196
--- /dev/null
+++ b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/Contact.java
@@ -0,0 +1,70 @@
+package com.baeldung.jsondateformat;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+public class Contact {
+
+ private String name;
+ private String address;
+ private String phone;
+
+ @JsonFormat(pattern="yyyy-MM-dd")
+ private LocalDate birthday;
+
+ @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime lastUpdate;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public String getPhone() {
+ return phone;
+ }
+
+ public void setPhone(String phone) {
+ this.phone = phone;
+ }
+
+ public LocalDate getBirthday() {
+ return birthday;
+ }
+
+ public void setBirthday(LocalDate birthday) {
+ this.birthday = birthday;
+ }
+
+ public LocalDateTime getLastUpdate() {
+ return lastUpdate;
+ }
+
+ public void setLastUpdate(LocalDateTime lastUpdate) {
+ this.lastUpdate = lastUpdate;
+ }
+
+ public Contact() {
+ }
+
+ public Contact(String name, String address, String phone, LocalDate birthday, LocalDateTime lastUpdate) {
+ this.name = name;
+ this.address = address;
+ this.phone = phone;
+ this.birthday = birthday;
+ this.lastUpdate = lastUpdate;
+ }
+}
diff --git a/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactApp.java b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactApp.java
new file mode 100644
index 0000000000..79037e1038
--- /dev/null
+++ b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactApp.java
@@ -0,0 +1,13 @@
+package com.baeldung.jsondateformat;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class ContactApp {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ContactApp.class, args);
+ }
+
+}
diff --git a/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactAppConfig.java b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactAppConfig.java
new file mode 100644
index 0000000000..7a20ebfa51
--- /dev/null
+++ b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactAppConfig.java
@@ -0,0 +1,33 @@
+package com.baeldung.jsondateformat;
+
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
+
+import java.time.format.DateTimeFormatter;
+
+@Configuration
+public class ContactAppConfig {
+
+ private static final String dateFormat = "yyyy-MM-dd";
+
+ private static final String dateTimeFormat = "yyyy-MM-dd HH:mm:ss";
+
+ @Bean
+ @ConditionalOnProperty(value = "spring.jackson.date-format", matchIfMissing = true, havingValue = "none")
+ public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
+ return new Jackson2ObjectMapperBuilderCustomizer() {
+ @Override
+ public void customize(Jackson2ObjectMapperBuilder builder) {
+ builder.simpleDateFormat(dateTimeFormat);
+ builder.serializers(new LocalDateSerializer(DateTimeFormatter.ofPattern(dateFormat)));
+ builder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(dateTimeFormat)));
+ }
+ };
+ }
+
+}
diff --git a/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactController.java b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactController.java
new file mode 100644
index 0000000000..8894d82fc7
--- /dev/null
+++ b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactController.java
@@ -0,0 +1,77 @@
+package com.baeldung.jsondateformat;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+@RestController
+@RequestMapping(value = "/contacts")
+public class ContactController {
+
+ @GetMapping
+ public List getContacts() {
+ List contacts = new ArrayList<>();
+
+ Contact contact1 = new Contact("John Doe", "123 Sesame Street", "123-456-789", LocalDate.now(), LocalDateTime.now());
+ Contact contact2 = new Contact("John Doe 2", "124 Sesame Street", "123-456-789", LocalDate.now(), LocalDateTime.now());
+ Contact contact3 = new Contact("John Doe 3", "125 Sesame Street", "123-456-789", LocalDate.now(), LocalDateTime.now());
+
+ contacts.add(contact1);
+ contacts.add(contact2);
+ contacts.add(contact3);
+
+ return contacts;
+ }
+
+ @GetMapping("/javaUtilDate")
+ public List getContactsWithJavaUtilDate() {
+ List contacts = new ArrayList<>();
+
+ ContactWithJavaUtilDate contact1 = new ContactWithJavaUtilDate("John Doe", "123 Sesame Street", "123-456-789", new Date(), new Date());
+ ContactWithJavaUtilDate contact2 = new ContactWithJavaUtilDate("John Doe 2", "124 Sesame Street", "123-456-789", new Date(), new Date());
+ ContactWithJavaUtilDate contact3 = new ContactWithJavaUtilDate("John Doe 3", "125 Sesame Street", "123-456-789", new Date(), new Date());
+
+ contacts.add(contact1);
+ contacts.add(contact2);
+ contacts.add(contact3);
+
+ return contacts;
+ }
+
+ @GetMapping("/plain")
+ public List getPlainContacts() {
+ List contacts = new ArrayList<>();
+
+ PlainContact contact1 = new PlainContact("John Doe", "123 Sesame Street", "123-456-789", LocalDate.now(), LocalDateTime.now());
+ PlainContact contact2 = new PlainContact("John Doe 2", "124 Sesame Street", "123-456-789", LocalDate.now(), LocalDateTime.now());
+ PlainContact contact3 = new PlainContact("John Doe 3", "125 Sesame Street", "123-456-789", LocalDate.now(), LocalDateTime.now());
+
+ contacts.add(contact1);
+ contacts.add(contact2);
+ contacts.add(contact3);
+
+ return contacts;
+ }
+
+ @GetMapping("/plainWithJavaUtilDate")
+ public List getPlainContactsWithJavaUtilDate() {
+ List contacts = new ArrayList<>();
+
+ PlainContactWithJavaUtilDate contact1 = new PlainContactWithJavaUtilDate("John Doe", "123 Sesame Street", "123-456-789", new Date(), new Date());
+ PlainContactWithJavaUtilDate contact2 = new PlainContactWithJavaUtilDate("John Doe 2", "124 Sesame Street", "123-456-789", new Date(), new Date());
+ PlainContactWithJavaUtilDate contact3 = new PlainContactWithJavaUtilDate("John Doe 3", "125 Sesame Street", "123-456-789", new Date(), new Date());
+
+ contacts.add(contact1);
+ contacts.add(contact2);
+ contacts.add(contact3);
+
+ return contacts;
+ }
+
+}
diff --git a/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactWithJavaUtilDate.java b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactWithJavaUtilDate.java
new file mode 100644
index 0000000000..5a1c508098
--- /dev/null
+++ b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/ContactWithJavaUtilDate.java
@@ -0,0 +1,69 @@
+package com.baeldung.jsondateformat;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.util.Date;
+
+public class ContactWithJavaUtilDate {
+
+ private String name;
+ private String address;
+ private String phone;
+
+ @JsonFormat(pattern="yyyy-MM-dd")
+ private Date birthday;
+
+ @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
+ private Date lastUpdate;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public String getPhone() {
+ return phone;
+ }
+
+ public void setPhone(String phone) {
+ this.phone = phone;
+ }
+
+ public Date getBirthday() {
+ return birthday;
+ }
+
+ public void setBirthday(Date birthday) {
+ this.birthday = birthday;
+ }
+
+ public Date getLastUpdate() {
+ return lastUpdate;
+ }
+
+ public void setLastUpdate(Date lastUpdate) {
+ this.lastUpdate = lastUpdate;
+ }
+
+ public ContactWithJavaUtilDate() {
+ }
+
+ public ContactWithJavaUtilDate(String name, String address, String phone, Date birthday, Date lastUpdate) {
+ this.name = name;
+ this.address = address;
+ this.phone = phone;
+ this.birthday = birthday;
+ this.lastUpdate = lastUpdate;
+ }
+}
diff --git a/spring-boot-data/src/main/java/com/baeldung/jsondateformat/PlainContact.java b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/PlainContact.java
new file mode 100644
index 0000000000..7e9e53d205
--- /dev/null
+++ b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/PlainContact.java
@@ -0,0 +1,66 @@
+package com.baeldung.jsondateformat;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+public class PlainContact {
+
+ private String name;
+ private String address;
+ private String phone;
+
+ private LocalDate birthday;
+
+ private LocalDateTime lastUpdate;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public String getPhone() {
+ return phone;
+ }
+
+ public void setPhone(String phone) {
+ this.phone = phone;
+ }
+
+ public LocalDate getBirthday() {
+ return birthday;
+ }
+
+ public void setBirthday(LocalDate birthday) {
+ this.birthday = birthday;
+ }
+
+ public LocalDateTime getLastUpdate() {
+ return lastUpdate;
+ }
+
+ public void setLastUpdate(LocalDateTime lastUpdate) {
+ this.lastUpdate = lastUpdate;
+ }
+
+ public PlainContact() {
+ }
+
+ public PlainContact(String name, String address, String phone, LocalDate birthday, LocalDateTime lastUpdate) {
+ this.name = name;
+ this.address = address;
+ this.phone = phone;
+ this.birthday = birthday;
+ this.lastUpdate = lastUpdate;
+ }
+}
diff --git a/spring-boot-data/src/main/java/com/baeldung/jsondateformat/PlainContactWithJavaUtilDate.java b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/PlainContactWithJavaUtilDate.java
new file mode 100644
index 0000000000..daefb15543
--- /dev/null
+++ b/spring-boot-data/src/main/java/com/baeldung/jsondateformat/PlainContactWithJavaUtilDate.java
@@ -0,0 +1,69 @@
+package com.baeldung.jsondateformat;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.util.Date;
+
+public class PlainContactWithJavaUtilDate {
+
+ private String name;
+ private String address;
+ private String phone;
+
+ @JsonFormat(pattern="yyyy-MM-dd")
+ private Date birthday;
+
+ @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
+ private Date lastUpdate;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public String getPhone() {
+ return phone;
+ }
+
+ public void setPhone(String phone) {
+ this.phone = phone;
+ }
+
+ public Date getBirthday() {
+ return birthday;
+ }
+
+ public void setBirthday(Date birthday) {
+ this.birthday = birthday;
+ }
+
+ public Date getLastUpdate() {
+ return lastUpdate;
+ }
+
+ public void setLastUpdate(Date lastUpdate) {
+ this.lastUpdate = lastUpdate;
+ }
+
+ public PlainContactWithJavaUtilDate() {
+ }
+
+ public PlainContactWithJavaUtilDate(String name, String address, String phone, Date birthday, Date lastUpdate) {
+ this.name = name;
+ this.address = address;
+ this.phone = phone;
+ this.birthday = birthday;
+ this.lastUpdate = lastUpdate;
+ }
+}
diff --git a/spring-boot-data/src/main/resources/application.properties b/spring-boot-data/src/main/resources/application.properties
new file mode 100644
index 0000000000..845b783634
--- /dev/null
+++ b/spring-boot-data/src/main/resources/application.properties
@@ -0,0 +1,2 @@
+spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
+spring.jackson.time-zone=Europe/Zagreb
\ No newline at end of file
diff --git a/spring-boot-data/src/test/java/com/baeldung/jsondateformat/ContactAppIntegrationTest.java b/spring-boot-data/src/test/java/com/baeldung/jsondateformat/ContactAppIntegrationTest.java
new file mode 100644
index 0000000000..f76440d1bc
--- /dev/null
+++ b/spring-boot-data/src/test/java/com/baeldung/jsondateformat/ContactAppIntegrationTest.java
@@ -0,0 +1,100 @@
+package com.baeldung.jsondateformat;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = RANDOM_PORT, classes = ContactApp.class)
+@TestPropertySource(properties = {
+ "spring.jackson.date-format=yyyy-MM-dd HH:mm:ss"
+})
+public class ContactAppIntegrationTest {
+
+ private final ObjectMapper mapper = new ObjectMapper();
+
+ @LocalServerPort
+ private int port;
+
+ @Autowired
+ private TestRestTemplate restTemplate;
+
+ @Test
+ public void givenJsonFormatAnnotationAndJava8DateType_whenGet_thenReturnExpectedDateFormat() throws IOException, ParseException {
+ ResponseEntity response = restTemplate.getForEntity("http://localhost:" + port + "/contacts", String.class);
+
+ assertEquals(200, response.getStatusCodeValue());
+
+ List
diff --git a/spring-boot-disable-console-logging/disabling-console-log4j2/pom.xml b/spring-boot-disable-console-logging/disabling-console-log4j2/pom.xml
index 0b360bb366..1cf3eb3e68 100644
--- a/spring-boot-disable-console-logging/disabling-console-log4j2/pom.xml
+++ b/spring-boot-disable-console-logging/disabling-console-log4j2/pom.xml
@@ -6,10 +6,10 @@
- org.springframework.boot
- spring-boot-starter-parent
- 2.1.1.RELEASE
-
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.1.1.RELEASE
+
diff --git a/spring-boot-jasypt/pom.xml b/spring-boot-jasypt/pom.xml
index de0df92678..ae0483f107 100644
--- a/spring-boot-jasypt/pom.xml
+++ b/spring-boot-jasypt/pom.xml
@@ -2,11 +2,10 @@
4.0.0
-
com.example.jasyptspring-boot-jasypt
- jarspring-boot-jasypt
+ jarDemo project for Spring Boot
diff --git a/spring-boot-keycloak/pom.xml b/spring-boot-keycloak/pom.xml
index 3a39d4aa94..b13805b4bf 100644
--- a/spring-boot-keycloak/pom.xml
+++ b/spring-boot-keycloak/pom.xml
@@ -5,9 +5,9 @@
com.baeldung.keycloakspring-boot-keycloak0.0.1
- jarspring-boot-keycloakThis is a simple application demonstrating integration between Keycloak and Spring Boot.
+ jarcom.baeldung
diff --git a/spring-boot-keycloak/src/main/resources/application.properties b/spring-boot-keycloak/src/main/resources/application.properties
index f667d3b27e..6e7da2cb90 100644
--- a/spring-boot-keycloak/src/main/resources/application.properties
+++ b/spring-boot-keycloak/src/main/resources/application.properties
@@ -1,3 +1,6 @@
+### server port
+server.port=8081
+
#Keycloak Configuration
keycloak.auth-server-url=http://localhost:8180/auth
keycloak.realm=SpringBootKeycloak
diff --git a/spring-boot-libraries/pom.xml b/spring-boot-libraries/pom.xml
index c28128c5f0..b448d6fd66 100644
--- a/spring-boot-libraries/pom.xml
+++ b/spring-boot-libraries/pom.xml
@@ -1,144 +1,157 @@
- 4.0.0
- spring-boot-libraries
- war
- spring-boot-libraries
- This is simple boot application for Spring boot actuator test
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
+ spring-boot-libraries
+ spring-boot-libraries
+ war
+ This is simple boot application for Spring boot actuator test
-
- parent-boot-2
- com.baeldung
- 0.0.1-SNAPSHOT
- ../parent-boot-2
-
+
+ parent-boot-2
+ com.baeldung
+ 0.0.1-SNAPSHOT
+ ../parent-boot-2
+
-
-
- org.springframework.boot
- spring-boot-starter-web
-
-
- org.springframework.boot
- spring-boot-starter-tomcat
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+ org.springframework.boot
+ spring-boot-starter-tomcat
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+ org.zalando
+ problem-spring-web
+ ${problem-spring-web.version}
+
-
-
- net.javacrumbs.shedlock
- shedlock-spring
- 2.1.0
-
-
- net.javacrumbs.shedlock
- shedlock-provider-jdbc-template
- 2.1.0
-
+
+
+ net.javacrumbs.shedlock
+ shedlock-spring
+ ${shedlock.version}
+
+
+ net.javacrumbs.shedlock
+ shedlock-provider-jdbc-template
+ ${shedlock.version}
+
-
+
-
- spring-boot
-
-
- src/main/resources
- true
-
-
+
+ spring-boot
+
+
+ src/main/resources
+ true
+
+
-
+
-
- org.apache.maven.plugins
- maven-war-plugin
-
+
+ org.apache.maven.plugins
+ maven-war-plugin
+
-
- pl.project13.maven
- git-commit-id-plugin
- ${git-commit-id-plugin.version}
-
-
- get-the-git-infos
-
- revision
-
- initialize
-
-
- validate-the-git-infos
-
- validateRevision
-
- package
-
-
-
- true
- ${project.build.outputDirectory}/git.properties
-
-
+
+ pl.project13.maven
+ git-commit-id-plugin
+ ${git-commit-id-plugin.version}
+
+
+ get-the-git-infos
+
+ revision
+
+ initialize
+
+
+ validate-the-git-infos
+
+ validateRevision
+
+ package
+
+
+
+ true
+ ${project.build.outputDirectory}/git.properties
+
+
-
+
-
+
-
-
- autoconfiguration
-
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
-
-
- integration-test
-
- test
-
-
-
- **/*LiveTest.java
- **/*IntegrationTest.java
- **/*IntTest.java
-
-
- **/AutoconfigurationTest.java
-
-
-
-
-
-
- json
-
-
-
-
-
-
-
+
+
+ autoconfiguration
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ integration-test
+
+ test
+
+
+
+ **/*LiveTest.java
+ **/*IntegrationTest.java
+ **/*IntTest.java
+
+
+ **/AutoconfigurationTest.java
+
+
+
+
+
+
+ json
+
+
+
+
+
+
+
-
-
- com.baeldung.intro.App
- 8.5.11
- 2.4.1.Final
- 1.9.0
- 2.0.0
- 5.0.2
- 5.0.2
- 5.2.4
- 18.0
- 2.2.4
- 2.3.2
-
+
+
+ com.baeldung.intro.App
+ 8.5.11
+ 2.4.1.Final
+ 1.9.0
+ 2.0.0
+ 5.0.2
+ 5.0.2
+ 5.2.4
+ 18.0
+ 2.2.4
+ 2.3.2
+ 0.23.0
+ 2.1.0
+
diff --git a/spring-boot-libraries/src/main/java/com/baeldung/Application.java b/spring-boot-libraries/src/main/java/com/baeldung/boot/Application.java
similarity index 93%
rename from spring-boot-libraries/src/main/java/com/baeldung/Application.java
rename to spring-boot-libraries/src/main/java/com/baeldung/boot/Application.java
index c1b6558b26..cb0d0c1532 100644
--- a/spring-boot-libraries/src/main/java/com/baeldung/Application.java
+++ b/spring-boot-libraries/src/main/java/com/baeldung/boot/Application.java
@@ -1,4 +1,4 @@
-package org.baeldung.boot;
+package com.baeldung.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
diff --git a/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/SpringProblemApplication.java b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/SpringProblemApplication.java
new file mode 100644
index 0000000000..7ca9881fb9
--- /dev/null
+++ b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/SpringProblemApplication.java
@@ -0,0 +1,19 @@
+package com.baeldung.boot.problem;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration;
+import org.springframework.context.annotation.ComponentScan;
+
+@SpringBootApplication
+@EnableAutoConfiguration(exclude = ErrorMvcAutoConfiguration.class)
+@ComponentScan("com.baeldung.boot.problem")
+public class SpringProblemApplication {
+
+ public static void main(String[] args) {
+ System.setProperty("spring.profiles.active", "problem");
+ SpringApplication.run(SpringProblemApplication.class, args);
+ }
+
+}
diff --git a/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/advice/ExceptionHandler.java b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/advice/ExceptionHandler.java
new file mode 100644
index 0000000000..18df103733
--- /dev/null
+++ b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/advice/ExceptionHandler.java
@@ -0,0 +1,16 @@
+package com.baeldung.boot.problem.advice;
+
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.zalando.problem.spring.web.advice.ProblemHandling;
+
+@ControllerAdvice
+public class ExceptionHandler implements ProblemHandling {
+
+ // The causal chain of causes is disabled by default,
+ // but we can easily enable it by overriding the behavior:
+ @Override
+ public boolean isCausalChainsEnabled() {
+ return true;
+ }
+
+}
diff --git a/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/advice/SecurityExceptionHandler.java b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/advice/SecurityExceptionHandler.java
new file mode 100644
index 0000000000..8013cbf5c3
--- /dev/null
+++ b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/advice/SecurityExceptionHandler.java
@@ -0,0 +1,9 @@
+package com.baeldung.boot.problem.advice;
+
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.zalando.problem.spring.web.advice.security.SecurityAdviceTrait;
+
+@ControllerAdvice
+public class SecurityExceptionHandler implements SecurityAdviceTrait {
+
+}
\ No newline at end of file
diff --git a/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/configuration/ProblemDemoConfiguration.java b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/configuration/ProblemDemoConfiguration.java
new file mode 100644
index 0000000000..f5e6a6b99a
--- /dev/null
+++ b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/configuration/ProblemDemoConfiguration.java
@@ -0,0 +1,19 @@
+package com.baeldung.boot.problem.configuration;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.zalando.problem.ProblemModule;
+import org.zalando.problem.validation.ConstraintViolationProblemModule;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+@Configuration
+public class ProblemDemoConfiguration {
+
+ @Bean
+ public ObjectMapper objectMapper() {
+ // In this example, stack traces support is enabled by default.
+ // If you want to disable stack traces just use new ProblemModule() instead of new ProblemModule().withStackTraces()
+ return new ObjectMapper().registerModules(new ProblemModule().withStackTraces(), new ConstraintViolationProblemModule());
+ }
+}
diff --git a/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/configuration/SecurityConfiguration.java b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/configuration/SecurityConfiguration.java
new file mode 100644
index 0000000000..0cb8048981
--- /dev/null
+++ b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/configuration/SecurityConfiguration.java
@@ -0,0 +1,31 @@
+package com.baeldung.boot.problem.configuration;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.zalando.problem.spring.web.advice.security.SecurityProblemSupport;
+
+@Configuration
+@EnableWebSecurity
+@Import(SecurityProblemSupport.class)
+public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
+
+ @Autowired
+ private SecurityProblemSupport problemSupport;
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.csrf().disable();
+
+ http.authorizeRequests()
+ .antMatchers("/")
+ .permitAll();
+
+ http.exceptionHandling()
+ .authenticationEntryPoint(problemSupport)
+ .accessDeniedHandler(problemSupport);
+ }
+}
diff --git a/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/controller/ProblemDemoController.java b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/controller/ProblemDemoController.java
new file mode 100644
index 0000000000..50f1ad5137
--- /dev/null
+++ b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/controller/ProblemDemoController.java
@@ -0,0 +1,56 @@
+package com.baeldung.boot.problem.controller;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.http.MediaType;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baeldung.boot.problem.dto.Task;
+import com.baeldung.boot.problem.problems.TaskNotFoundProblem;
+
+@RestController
+@RequestMapping("/tasks")
+public class ProblemDemoController {
+
+ private static final Map MY_TASKS;
+
+ static {
+ MY_TASKS = new HashMap<>();
+ MY_TASKS.put(1L, new Task(1L, "My first task"));
+ MY_TASKS.put(2L, new Task(2L, "My second task"));
+ }
+
+ @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
+ public List getTasks() {
+ return new ArrayList<>(MY_TASKS.values());
+ }
+
+ @GetMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
+ public Task getTasks(@PathVariable("id") Long taskId) {
+ if (MY_TASKS.containsKey(taskId)) {
+ return MY_TASKS.get(taskId);
+ } else {
+ throw new TaskNotFoundProblem(taskId);
+ }
+ }
+
+ @PutMapping("/{id}")
+ public void updateTask(@PathVariable("id") Long id) {
+ throw new UnsupportedOperationException();
+ }
+
+ @DeleteMapping("/{id}")
+ public void deleteTask(@PathVariable("id") Long id) {
+ throw new AccessDeniedException("You can't delete this task");
+ }
+
+}
diff --git a/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/dto/Task.java b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/dto/Task.java
new file mode 100644
index 0000000000..a5f39474e7
--- /dev/null
+++ b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/dto/Task.java
@@ -0,0 +1,32 @@
+package com.baeldung.boot.problem.dto;
+
+public class Task {
+
+ private Long id;
+ private String description;
+
+ public Task() {
+ }
+
+ public Task(Long id, String description) {
+ this.id = id;
+ this.description = description;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+}
diff --git a/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/problems/TaskNotFoundProblem.java b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/problems/TaskNotFoundProblem.java
new file mode 100644
index 0000000000..cc3f21d4a5
--- /dev/null
+++ b/spring-boot-libraries/src/main/java/com/baeldung/boot/problem/problems/TaskNotFoundProblem.java
@@ -0,0 +1,16 @@
+package com.baeldung.boot.problem.problems;
+
+import java.net.URI;
+
+import org.zalando.problem.AbstractThrowableProblem;
+import org.zalando.problem.Status;
+
+public class TaskNotFoundProblem extends AbstractThrowableProblem {
+
+ private static final URI TYPE = URI.create("https://example.org/not-found");
+
+ public TaskNotFoundProblem(Long taskId) {
+ super(TYPE, "Not found", Status.NOT_FOUND, String.format("Task '%s' not found", taskId));
+ }
+
+}
diff --git a/spring-boot-libraries/src/main/java/com/baeldung/scheduling/shedlock/TaskScheduler.java b/spring-boot-libraries/src/main/java/com/baeldung/scheduling/shedlock/TaskScheduler.java
index b1b1ad921f..060afe660e 100644
--- a/spring-boot-libraries/src/main/java/com/baeldung/scheduling/shedlock/TaskScheduler.java
+++ b/spring-boot-libraries/src/main/java/com/baeldung/scheduling/shedlock/TaskScheduler.java
@@ -7,9 +7,9 @@ import org.springframework.stereotype.Component;
@Component
class TaskScheduler {
- @Scheduled(cron = "*/15 * * * * *")
+ @Scheduled(cron = "*/15 * * * *")
@SchedulerLock(name = "TaskScheduler_scheduledTask", lockAtLeastForString = "PT5M", lockAtMostForString = "PT14M")
public void scheduledTask() {
System.out.println("Running ShedLock task");
}
-}
\ No newline at end of file
+}
diff --git a/spring-boot-libraries/src/main/resources/application-problem.properties b/spring-boot-libraries/src/main/resources/application-problem.properties
new file mode 100644
index 0000000000..7d0b0a2720
--- /dev/null
+++ b/spring-boot-libraries/src/main/resources/application-problem.properties
@@ -0,0 +1,3 @@
+spring.resources.add-mappings=false
+spring.mvc.throw-exception-if-no-handler-found=true
+spring.http.encoding.force=true
diff --git a/spring-boot-libraries/src/test/java/com/baeldung/boot/problem/controller/ProblemDemoControllerIntegrationTest.java b/spring-boot-libraries/src/test/java/com/baeldung/boot/problem/controller/ProblemDemoControllerIntegrationTest.java
new file mode 100644
index 0000000000..5ced1034c4
--- /dev/null
+++ b/spring-boot-libraries/src/test/java/com/baeldung/boot/problem/controller/ProblemDemoControllerIntegrationTest.java
@@ -0,0 +1,101 @@
+package com.baeldung.boot.problem.controller;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+
+import com.baeldung.boot.problem.SpringProblemApplication;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = SpringProblemApplication.class)
+@AutoConfigureMockMvc
+public class ProblemDemoControllerIntegrationTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @Test
+ public void whenRequestingAllTasks_thenReturnSuccessfulResponseWithArrayWithTwoTasks() throws Exception {
+ mockMvc.perform(get("/tasks").contentType(MediaType.APPLICATION_JSON_VALUE))
+ .andDo(print())
+ .andExpect(jsonPath("$.length()", equalTo(2)))
+ .andExpect(status().isOk());
+ }
+
+ @Test
+ public void whenRequestingExistingTask_thenReturnSuccessfulResponse() throws Exception {
+ mockMvc.perform(get("/tasks/1").contentType(MediaType.APPLICATION_JSON_VALUE))
+ .andDo(print())
+ .andExpect(jsonPath("$.id", equalTo(1)))
+ .andExpect(status().isOk());
+ }
+
+ @Test
+ public void whenRequestingMissingTask_thenReturnNotFoundProblemResponse() throws Exception {
+ mockMvc.perform(get("/tasks/5").contentType(MediaType.APPLICATION_PROBLEM_JSON_VALUE))
+ .andDo(print())
+ .andExpect(jsonPath("$.title", equalTo("Not found")))
+ .andExpect(jsonPath("$.status", equalTo(404)))
+ .andExpect(jsonPath("$.detail", equalTo("Task '5' not found")))
+ .andExpect(status().isNotFound());
+ }
+
+ @Test
+ public void whenMakePutCall_thenReturnNotImplementedProblemResponse() throws Exception {
+ mockMvc.perform(put("/tasks/1").contentType(MediaType.APPLICATION_PROBLEM_JSON_VALUE))
+ .andDo(print())
+ .andExpect(jsonPath("$.title", equalTo("Not Implemented")))
+ .andExpect(jsonPath("$.status", equalTo(501)))
+ .andExpect(status().isNotImplemented());
+ }
+
+ @Test
+ public void whenMakeDeleteCall_thenReturnForbiddenProblemResponse() throws Exception {
+ mockMvc.perform(delete("/tasks/2").contentType(MediaType.APPLICATION_PROBLEM_JSON_VALUE))
+ .andDo(print())
+ .andExpect(jsonPath("$.title", equalTo("Forbidden")))
+ .andExpect(jsonPath("$.status", equalTo(403)))
+ .andExpect(jsonPath("$.detail", equalTo("You can't delete this task")))
+ .andExpect(status().isForbidden());
+ }
+
+ @Test
+ public void whenMakeGetCallWithInvalidIdFormat_thenReturnBadRequestResponseWithStackTrace() throws Exception {
+ mockMvc.perform(get("/tasks/invalid-id").contentType(MediaType.APPLICATION_PROBLEM_JSON_VALUE))
+ .andDo(print())
+ .andExpect(jsonPath("$.title", equalTo("Bad Request")))
+ .andExpect(jsonPath("$.status", equalTo(400)))
+ .andExpect(jsonPath("$.stacktrace", notNullValue()))
+ .andExpect(status().isBadRequest());
+ }
+
+ @Test
+ public void whenMakeGetCallWithInvalidIdFormat_thenReturnBadRequestResponseWithCause() throws Exception {
+ mockMvc.perform(get("/tasks/invalid-id").contentType(MediaType.APPLICATION_PROBLEM_JSON_VALUE))
+ .andDo(print())
+ .andExpect(jsonPath("$.title", equalTo("Bad Request")))
+ .andExpect(jsonPath("$.status", equalTo(400)))
+ .andExpect(jsonPath("$.cause", notNullValue()))
+ .andExpect(jsonPath("$.cause.title", equalTo("Internal Server Error")))
+ .andExpect(jsonPath("$.cause.status", equalTo(500)))
+ .andExpect(jsonPath("$.cause.detail", containsString("For input string:")))
+ .andExpect(jsonPath("$.cause.stacktrace", notNullValue()))
+ .andExpect(status().isBadRequest());
+ }
+
+}
diff --git a/spring-boot-logging-log4j2/pom.xml b/spring-boot-logging-log4j2/pom.xml
index ad678a14cf..6cc60da52c 100644
--- a/spring-boot-logging-log4j2/pom.xml
+++ b/spring-boot-logging-log4j2/pom.xml
@@ -3,8 +3,8 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0spring-boot-logging-log4j2
- jarspring-boot-logging-log4j2
+ jarDemo project for Spring Boot Logging with Log4J2
@@ -40,12 +40,12 @@
org.springframework.bootspring-boot-starter-log4j
- 1.3.8.RELEASE
+ ${spring-boot-starter-log4j.version}org.graylog2gelfj
- 1.1.16
+ ${gelfj.version}compile
@@ -71,5 +71,7 @@
com.baeldung.springbootlogging.SpringBootLoggingApplication
+ 1.3.8.RELEASE
+ 1.1.16
diff --git a/spring-boot-mvc/README.md b/spring-boot-mvc/README.md
index bf32e4fc7c..0e1ac5a8ce 100644
--- a/spring-boot-mvc/README.md
+++ b/spring-boot-mvc/README.md
@@ -9,4 +9,5 @@
- [Display RSS Feed with Spring MVC](http://www.baeldung.com/spring-mvc-rss-feed)
- [A Controller, Service and DAO Example with Spring Boot and JSF](https://www.baeldung.com/jsf-spring-boot-controller-service-dao)
- [Cache Eviction in Spring Boot](https://www.baeldung.com/spring-boot-evict-cache)
-- [Setting Up Swagger 2 with a Spring REST API](http://www.baeldung.com/swagger-2-documentation-for-spring-rest-api)
\ No newline at end of file
+- [Setting Up Swagger 2 with a Spring REST API](http://www.baeldung.com/swagger-2-documentation-for-spring-rest-api)
+- [Conditionally Enable Scheduled Jobs in Spring](https://www.baeldung.com/spring-scheduled-enabled-conditionally)
diff --git a/spring-boot-mvc/pom.xml b/spring-boot-mvc/pom.xml
index b219e53431..e17c1d39b9 100644
--- a/spring-boot-mvc/pom.xml
+++ b/spring-boot-mvc/pom.xml
@@ -1,66 +1,77 @@
-
- 4.0.0
- spring-boot-mvc
- jar
- spring-boot-mvc
- Module For Spring Boot MVC
+
+ 4.0.0
+ spring-boot-mvc
+ spring-boot-mvc
+ jar
+ Module For Spring Boot MVC
-
- parent-boot-2
- com.baeldung
- 0.0.1-SNAPSHOT
- ../parent-boot-2
-
+
+ parent-boot-2
+ com.baeldung
+ 0.0.1-SNAPSHOT
+ ../parent-boot-2
+
-
+
-
- org.springframework.boot
- spring-boot-starter-web
-
-
- org.apache.tomcat.embed
- tomcat-embed-jasper
-
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.apache.tomcat.embed
+ tomcat-embed-jasper
+
+
+ org.springframework.boot
+ spring-boot-starter-tomcat
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-thymeleaf
+
-
-
- org.glassfish
- javax.faces
- 2.3.7
-
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
+
+
+ org.glassfish
+ javax.faces
+ 2.3.7
+
-
-
- com.rometools
- rome
- ${rome.version}
-
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
-
-
- org.hibernate.validator
- hibernate-validator
-
-
- javax.validation
- validation-api
-
-
- org.springframework.boot
- spring-boot-starter-validation
-
+
+
+ com.rometools
+ rome
+ ${rome.version}
+
-
+
+
+ org.hibernate.validator
+ hibernate-validator
+
+
+ javax.validation
+ validation-api
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+
io.springfoxspringfox-swagger2
@@ -72,26 +83,32 @@
${spring.fox.version}
-
+
+ org.apache.tomcat.embed
+ tomcat-embed-jasper
+ provided
+
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
- com.baeldung.springbootmvc.SpringBootMvcApplication
- JAR
-
-
-
-
+
-
- 2.9.2
-
- 1.10.0
- com.baeldung.springbootmvc.SpringBootMvcApplication
-
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ com.baeldung.springbootmvc.SpringBootMvcApplication
+ JAR
+
+
+
+
+
+
+ 2.9.2
+
+ 1.10.0
+ com.baeldung.springbootmvc.SpringBootMvcApplication
+
diff --git a/spring-boot-mvc/src/main/java/com/baeldung/accessparamsjs/App.java b/spring-boot-mvc/src/main/java/com/baeldung/accessparamsjs/App.java
new file mode 100644
index 0000000000..c16e784dd2
--- /dev/null
+++ b/spring-boot-mvc/src/main/java/com/baeldung/accessparamsjs/App.java
@@ -0,0 +1,12 @@
+package com.baeldung.accessparamsjs;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class App {
+
+ public static void main(String[] args) {
+ SpringApplication.run(App.class, args);
+ }
+}
diff --git a/spring-boot-mvc/src/main/java/com/baeldung/accessparamsjs/Controller.java b/spring-boot-mvc/src/main/java/com/baeldung/accessparamsjs/Controller.java
new file mode 100644
index 0000000000..8759f1bcd6
--- /dev/null
+++ b/spring-boot-mvc/src/main/java/com/baeldung/accessparamsjs/Controller.java
@@ -0,0 +1,32 @@
+package com.baeldung.accessparamsjs;
+
+import java.util.Map;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.servlet.ModelAndView;
+
+/**
+ * Sample rest controller for the tutorial article
+ * "Access Spring MVC Model object in JavaScript".
+ *
+ * @author Andrew Shcherbakov
+ *
+ */
+@RestController
+public class Controller {
+
+ /**
+ * Define two model objects (one integer and one string) and pass them to the view.
+ *
+ * @param model
+ * @return
+ */
+ @RequestMapping("/index")
+ public ModelAndView thymeleafView(Map model) {
+ model.put("number", 1234);
+ model.put("message", "Hello from Spring MVC");
+ return new ModelAndView("thymeleaf/index");
+ }
+
+}
diff --git a/spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduleJobsByProfile.java b/spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduleJobsByProfile.java
new file mode 100644
index 0000000000..33cd44331f
--- /dev/null
+++ b/spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduleJobsByProfile.java
@@ -0,0 +1,20 @@
+package com.baeldung.scheduling;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+
+@Configuration
+public class ScheduleJobsByProfile {
+
+ private final static Logger LOG = LoggerFactory.getLogger(ScheduleJobsByProfile.class);
+
+ @Profile("prod")
+ @Bean
+ public ScheduledJob scheduledJob()
+ {
+ return new ScheduledJob("@Profile");
+ }
+}
diff --git a/spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduledJob.java b/spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduledJob.java
new file mode 100644
index 0000000000..df7cefcd3c
--- /dev/null
+++ b/spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduledJob.java
@@ -0,0 +1,21 @@
+package com.baeldung.scheduling;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.scheduling.annotation.Scheduled;
+
+public class ScheduledJob {
+
+ private String source;
+
+ public ScheduledJob(String source) {
+ this.source = source;
+ }
+
+ private final static Logger LOG = LoggerFactory.getLogger(ScheduledJob.class);
+
+ @Scheduled(fixedDelay = 60000)
+ public void cleanTempDir() {
+ LOG.info("Cleaning temp directory via {}", source);
+ }
+}
diff --git a/spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduledJobsWithBoolean.java b/spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduledJobsWithBoolean.java
new file mode 100644
index 0000000000..b03de61641
--- /dev/null
+++ b/spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduledJobsWithBoolean.java
@@ -0,0 +1,28 @@
+package com.baeldung.scheduling;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.Scheduled;
+
+@Configuration
+public class ScheduledJobsWithBoolean {
+
+ private final static Logger LOG = LoggerFactory.getLogger(ScheduledJobsWithBoolean.class);
+
+ @Value("${jobs.enabled:true}")
+ private boolean isEnabled;
+
+ /**
+ * A scheduled job controlled via application property. The job always
+ * executes, but the logic inside is protected by a configurable boolean
+ * flag.
+ */
+ @Scheduled(fixedDelay = 60000)
+ public void cleanTempDirectory() {
+ if(isEnabled) {
+ LOG.info("Cleaning temp directory via boolean flag");
+ }
+ }
+}
diff --git a/spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduledJobsWithConditional.java b/spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduledJobsWithConditional.java
new file mode 100644
index 0000000000..081c8d990a
--- /dev/null
+++ b/spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduledJobsWithConditional.java
@@ -0,0 +1,20 @@
+package com.baeldung.scheduling;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class ScheduledJobsWithConditional
+{
+ /**
+ * This uses @ConditionalOnProperty to conditionally create a bean, which itself
+ * is a scheduled job.
+ * @return ScheduledJob
+ */
+ @Bean
+ @ConditionalOnProperty(value = "jobs.enabled", matchIfMissing = true, havingValue = "true")
+ public ScheduledJob runMyCronTask() {
+ return new ScheduledJob("@ConditionalOnProperty");
+ }
+}
diff --git a/spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduledJobsWithExpression.java b/spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduledJobsWithExpression.java
new file mode 100644
index 0000000000..577a01f241
--- /dev/null
+++ b/spring-boot-mvc/src/main/java/com/baeldung/scheduling/ScheduledJobsWithExpression.java
@@ -0,0 +1,23 @@
+package com.baeldung.scheduling;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.Scheduled;
+
+@Configuration
+public class ScheduledJobsWithExpression
+{
+ private final static Logger LOG =
+ LoggerFactory.getLogger(ScheduledJobsWithExpression.class);
+
+ /**
+ * A scheduled job controlled via application property. The job always
+ * executes, but the logic inside is protected by a configurable boolean
+ * flag.
+ */
+ @Scheduled(cron = "${jobs.cronSchedule:-}")
+ public void cleanTempDirectory() {
+ LOG.info("Cleaning temp directory via placeholder");
+ }
+}
diff --git a/spring-boot-mvc/src/main/java/com/baeldung/scheduling/SchedulingApplication.java b/spring-boot-mvc/src/main/java/com/baeldung/scheduling/SchedulingApplication.java
new file mode 100644
index 0000000000..913e2137f8
--- /dev/null
+++ b/spring-boot-mvc/src/main/java/com/baeldung/scheduling/SchedulingApplication.java
@@ -0,0 +1,16 @@
+package com.baeldung.scheduling;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+@SpringBootApplication
+@EnableScheduling
+public class SchedulingApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(SchedulingApplication.class, args);
+ }
+
+}
+
diff --git a/spring-boot-mvc/src/main/resources/application.properties b/spring-boot-mvc/src/main/resources/application.properties
index 709574239b..6dab470c84 100644
--- a/spring-boot-mvc/src/main/resources/application.properties
+++ b/spring-boot-mvc/src/main/resources/application.properties
@@ -1 +1,2 @@
-spring.main.allow-bean-definition-overriding=true
\ No newline at end of file
+spring.main.allow-bean-definition-overriding=true
+spring.thymeleaf.view-names=thymeleaf/*
\ No newline at end of file
diff --git a/spring-boot-mvc/src/main/resources/templates/thymeleaf/index.html b/spring-boot-mvc/src/main/resources/templates/thymeleaf/index.html
new file mode 100644
index 0000000000..4939d0ea50
--- /dev/null
+++ b/spring-boot-mvc/src/main/resources/templates/thymeleaf/index.html
@@ -0,0 +1,29 @@
+
+
+
+Access Spring MVC params
+
+
+
+
+
+
+ Number=
+
+ Message=
+
+
Data from the external JS file (due to loading order)
+
+
+
Asynchronous loading from external JS file (plain JS)
+
+
+
Asynchronous loading from external JS file (jQuery)