SpringBoot
Introduction
- Framework to build microservices
- common non-functional features
- not zero code generation
- not a web or application server
- provides starter projects
- embedded server (incl. in application jar)
- externalized configuration
Installation
Concepts
- SpringBoot Autoconfiguration: by scanning the classpath
- Dispatcher Servlet
- SpringBoot Actuator (for monitoring)
Rest
- see here
Beans
- Beans are specified by annotations e.g.
@Bean, @Component, @Service, @Repositoryetc. or by XML configuration - A java class becomes Spring Bean only when it is created by Spring
- On startup/runtime classes in the application will be scanned and each class annotated with spring annotations will be instantiated as beans and put into a global context (Spring applicationcontext).
- Entities are no beans
- You can autowire only those beans whose life-cycle are managed by Spring IoC container.
- Spring support @Autowire only for Spring Beans
Security
adding to pom.xml:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
and update the project automatically sets up form-based authentication with a generated session cookie generated on the server or basic authentication with a header sent along with every request
- user='user
- pwd=see console output of server start
or set it in application.properties
spring.security.user.name=uwe spring.security.user.password=uwe
This has to be entered just once.
Testing
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
This integrates the frameworks JUnit, Hamcrest, Mockito,
Configuration
Spring Boot allows you to externalize your configuration. You can use properties files, YAML files, environment variables and command-line arguments to externalize configuration which are evaluated in a specific order (see here).
Application Properties
in \<Project>\src\main\resources\application.properties
logging.level.org.springframework = debug #security configuration see here #H2 database configuration see here #logging configuration see here
Logging
A good description is here. The default log output is
<DATE>
To implement logging
import org.slf4j.Logger; import org.slf4j.LoggerFactory; final static Logger logger = LoggerFactory.getLogger(BookmarksRestController.class); // is the LOGGER_NAME BookmarksRestController.logger.trace(...
The general configuration in application.properties:
# a selection of core loggers (embedded container, Hibernate, and Spring Boot) are configured to output more information
debug=true
# enables trace logging for a selection of core loggers (embedded container, Hibernate schema generation, and the whole Spring portfolio)
trace=true
logging.file.name=./log/bookmarks.log
logging.logback.rollingpolicy.max-history=5
# double backslash quote for policy and logback
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{1}.%M{}\\(\\) - %L: %m%n
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{1}.%M{}\\(\\) - %L: %m%n
The specific configuration can be set according to package/class hierachy:
logging.level.<PACKAGE_NAMEn>=<LEVEL> logging.level.<PACKAGE_NAME1.PACKAGE_NAME2>=<LEVEL> logging.level.<PACKAGE_NAME1.PACKAGE_NAME2.CLASSNAME>=<LEVEL> // e.g. logging.level.com.uweheuer=INFO logging.level.com.uweheuer.bookmarks=TRACE logging.level.com.uweheuer.bookmarks.entities=INFO
Implementation
Package Structure
There are two main approaches: structure by layer or structure by feature. It seems that a structure by feature is the most commonly used.
Main Application
see /test1/src/main/java/com/uweheuer/springboot/test1/Test1Application.java/
@SpringBootApplication
public class Test1Application {
...
public static void main(String[] args) {
SpringApplication.run(Test1Application.class, args);
}
...
@SpringBootApplication
is a convience annotation that adds @Configuration, @EnableAutoConfiguration, @EnableWebMvc and @ComponentScan which enables e.g. Auto-Configuration
Rest Controller
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController @CrossOrigin(origins="http://localhost:4200") // avoid cross origin errors in browser public class HelloWorldController { // @RequestMapping(method=RequestMethod.GET, path="/hello-world") @GetMapping(path="/hello-world") @JsonView(MenuView.NodeView.class) // tells Jackson to propagate the view class to the entities for json-fication the return value // the same annotation has to be used at attributes in the JPA entities, which should be used for this view public <METHOD>() { ... }
@RequestMapping
@RequestMapping("/") // by default it maps HTTP operations
JPA
- Spring Boot does not need persistence.xml
Repository
JpaRepository extends PagingAndSortingRepository which in turn extends CrudRepository. Their main functions are:
- CrudRepository mainly provides CRUD functions.
- PagingAndSortingRepository provides methods to do pagination and sorting records.
- JpaRepository provides some JPA-related methods such as flushing the persistence context and deleting records in a batch.
Because of the inheritance mentioned above, JpaRepository will have all the functions of CrudRepository and PagingAndSortingRepository. So if you don't need the repository to have the functions provided by JpaRepository and PagingAndSortingRepository, use CrudRepository.
save()
- can be called on new or existing entities
- in case of new entities the id is available only via the returned object
General Configuration
- configuration in application.properties
spring.jpa.hibernate.ddl-auto=[none|update|create|create-drop] // none: nothing is changed in the DB, default for MySQL // update: DB structure updated according to the entities // create: DB is created on startup // create-drop: creates DB on startup, drops it on closing, default for H2
MySQL
- in pom.xml
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
- configuration in application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/mysql506 spring.datasource.username=root spring.datasource.password=mHalloo0@1m
Command Line Runner
CommandLineRunner is a simple Spring Boot interface with a run method. Spring Boot will automatically call the run method of all beans implementing this interface after the application context has been loaded.
Integration Test
@SpringBootTest
class BookmarksApplicationTests {
@Test
void contextLoads() {
}
}
Resources
Hosting
Heroku
- https://devcenter.heroku.com/articles/deploying-spring-boot-apps-to-heroku
- https://www.codejava.net/heroku/deploy-spring-boot-app-with-mysql
- https://roytuts.com/how-to-deploy-spring-boot-data-jpa-application-to-heroku-cloud/
- https://www.youtube.com/watch?v=TixLbON3TR8
Examples
Test1
- for Raspberry 4
- create app with Sprint Initialzr
- copy test1.zip to
C:\Uwes\eclipse\workspace_2020-12\SpringBoot - extract it, which creates a test1 directory
- import as Maven project and select root directory
Test2
- for Raspberry
- export productive DB content of DB mysql506 via https://uweheuer.spdns.de/phpxmyadmin to C:\Uwes\Backup\Raspberry (incl. drop statements)
- import after starting xampp via http://localhost:8090/phpmyadmin
Then
- use wizzard of Eclipse Spring Tools
- File -> New -> Other -> Spring Starter Project
- in order to use JPA Tools (according to here) right click project -> Configure -> Convert to JPA Project
- RC project -> JAP Tools -> Generate entities from tables
- Run As 'Spring Boot App'
Test3
- creation with eclipse wizzard like Test 2
- identified
- not encrypted urls in productive DB
- change to menu can be null, because urls can exist w/o menu (set by PHPAdmin in DB)
Udemy Course
Bookmarks
- start eclipse
- File -> Import -> Maven -> Existing Maven Projects
- select
C:\Uwes\eclipse\workspace_2020-12\SpringBoot\bookmarks
Database Configuration
The default is that the datasource url is generated randomly and printed to the console. The default user is 'sa', default password is empty.
spring.profiles.active=[dev|laptopmysql|raspberry]
- and created in
\bookmarks\src\main\resources\dedicated property filesapplication-[dev|laptopmysql|raspberry].properties
H2 Database Configuration
- see
application-dev.properties
# to make the h2 database url constant, otherwise it is a random url spring.datasource.url=jdbc:h2:mem:bookmarksdb # user and password for H2 console spring.datasource.username=uwe spring.datasource.password=uwe
Test Data for Startup
- in
<PROJECT_DIR>/src/main/resources/data.sql
Links
- see My Bookmarks -> Web-Präsenz -> localhost -> SpringBoot -> Bookmarks
ToDos
- JSON rest APIs
- adjust maven build
- build entities
- The @ManyToOne association uses FetchType.LAZY because, otherwise, we’d fall back to EAGER fetching which is bad for performance.
- https://thorben-janssen.com/ultimate-guide-derived-queries-with-spring-data-jpa/ Query Documentation]
- Sorted Lists
- http://assarconsulting.blogspot.com/2009/08/why-hibernate-does-delete-all-then-re.html
- https://stackoverflow.com/questions/13101882/jpa-onetomany-list-vs-set/29562678
- https://www.google.com/search?q=jpa+onetomany+list+or+set&rlz=1C1GCEU_deDE848DE867&ei=-iFTYO3XHJWj1fAPw5mgqAM&oq=JPA+%40one2many+list&gs_lcp=Cgdnd3Mtd2l6EAEYATIGCAAQFhAeMgYIABAWEB4yBggAEBYQHjIGCAAQFhAeMgYIABAWEB4yBggAEBYQHjIGCAAQFhAeMgYIABAWEB4yBggAEBYQHjIGCAAQFhAeOgcIABBHELADOggIABAWEAoQHlDLIViCJWC1UmgCcAJ4AIABhgGIAdkDkgEDNC4xmAEAoAEBqgEHZ3dzLXdpesgBCMABAQ&sclient=gws-wiz
- Sorted Lists