SpringBoot
Introduction[edit]
- 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[edit]
Concepts[edit]
- SpringBoot Autoconfiguration: by scanning the classpath
- Dispatcher Servlet
- SpringBoot Actuator (for monitoring)
Architecture[edit]
- Client -> Controller -> Service (Business Logic) -> Model
Rest[edit]
- see here
Application Context[edit]
The ApplicationContext is where Spring holds instances of objects that it has identified to be managed and distributed automatically. These are called Beans. The application context can also be autowired:
@Autowired private ApplicationContext applicationContext;
Dependency Injection[edit]
Beans[edit]
- Beans are specified by class level annotations e.g.
@Component, @Service, @Repositoryetc. or by XML configuration. The annotations are hierachical meaning for example that there are more specialized annotations for@Component. @Beanis a special annotation on method level.- 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
- the default scope is singleton
Security[edit]
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[edit]
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
This integrates the frameworks JUnit, Hamcrest, Mockito,
When you build a Spring boot application using Spring Initializer. It auto creates a @SpringBootTest annotated class for you with contextLoads() empty method. @SpringBootTest by default starts searching in the current package of the test class and then searches upwards through the package structure, looking for a class annotated with @SpringBootConfiguration from which it then reads the configuration to create an application context.
TestRestTemplate[edit]
- TestRestTemplate is part of the Spring Boot Test module and provides a high-level, programmatic way to test RESTful services by making actual HTTP requests to the service. It allows you to send HTTP requests (GET, POST, PUT, DELETE, etc.) to your application's REST endpoints and receive actual HTTP responses.
- It starts an embedded server (typically an embedded Tomcat or Jetty instance) and sends requests to the server as if they were real HTTP requests.
- TestRestTemplate is more suitable for integration testing and end-to-end testing because it interacts with the running server, making actual network calls.
MockMvc[edit]
- MockMvc, on the other hand, is a part of the Spring Test framework and is specifically designed for testing the controllers of your Spring application in isolation.
- It allows you to perform requests against your controller methods without starting a full server.
- With MockMvc, you can simulate HTTP requests and responses without making actual network calls. This makes it a more suitable choice for unit testing and integration testing of your Spring MVC controllers.
- MockMvc provides a fluent and expressive API for setting up requests, sending them to your controllers, and then validating the results.
Configuration[edit]
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[edit]
It is located in \<Project>\src\main\resources\application.properties. In addition to this file profile specific propertiers can be set by the naming convention application-{profile}.properties at the same location. Placeholders can be used to get the value from the environment or properties defined before with x.y.z=${ENV}.
logging.level.org.springframework = debug
# Profile setting
spring.profiles.active=dev // hard coded
spring.profiles.active=@spring.profiles.active@ // the Spring Boot Resources Plugin replaces it during the Maven build
// with the active profile from pom.xml in the \target\classes\ directory.
# security configuration see here
# MySQL configuration see here
# H2 database configuration see here
# logging configuration see here
# actuator see here
Logging[edit]
Spring Boot is using LogBack as a logging proivder by default. It is not totally clear which configuration has which impact (application.properties, log-back-spring.xml).
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
LogBack[edit]
- good description here
/src/main/resource/log-back-spring.xml
Actuator[edit]
- standard monitoring, status information, ...
- add dependency to pom.xml
- configure the available endpoints in application.properties
management.endpoints.web.exposure.include=env,health,info
- example implementation in Heroku Demo Project
Implementation[edit]
The standard implementation is heavily using a starter configuration provided by maven plugins.
Folder Structure[edit]
\target\ // contains the jar file of the Spring Boot application
Package Structure[edit]
There are two main approaches: structure by layer or structure by feature. It seems that a structure by feature is the most commonly used.
Static Content[edit]
\src\main\resources\static\will be used in Spring Boot application by copying to\target\classes\static\- sources which have to be transpiled like Angular apps should not be located here but in a separate directory
\src\main\resources\<APP>\ - for Angular:
- adjust angular.json with
"outputPath": "../../main/resources/static/",
Main Application[edit]
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[edit]
is a convience annotation that adds @Configuration, @EnableAutoConfiguration, @EnableWebMvc and @ComponentScan which enables e.g. Auto-Configuration
Rest Controller[edit]
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 @RequestMapping("xyz") 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[edit]
import org.springframework.web.bind.annotation.RequestMapping;
@RequestMapping("xyz") // no need of backslash, all URLs of the mappings have the prefix 'xyz', method mappings need to include the / after the prefix e.g. http://localhost/xyz/do_something
public class XYZControler {
@GetMapping("/do_something")
public void doSomething() {
...
@ResponseBody[edit]
The @ResponseBody annotation tells a controller that the object returned is automatically serialized into JSON and passed back into the HttpResponse object. There is no need to annotate the @RestController-annotated controllers with the @ResponseBody annotation since Spring does it by default.
Method Return Values[edit]
public User <METHOD> public ResponseEntity<User> <METHOD> // is the same as above
JPA[edit]
- Spring Boot does not need persistence.xml
JPA Repository[edit]
import org.springframework.data.jpa.repository.JpaRepository;
public interface TestRepository extends JpaRepository<E1, Long> {
}
// in controller
@Autowired
TestRepository testRepo;
Repository[edit]
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.
Query Methods[edit]
Define the query methods in a repository interface that extends one of the Spring Data's repositories. Spring Data JPA will create queries automatically by parsing these method names. A derived query method name has two main components separated by the first By keyword:
- The introducer clause like find, read, query, count, or get which tells Spring Data JPA what you want to do with the method. This clause can contain further expressions, such as Distinct to set a distinct flag on the query to be created.
- The criteria clause that starts after the first By keyword. The first By acts as a delimiter to indicate the start of the actual query criteria. The criteria clause is where you define conditions on entity properties and concatenate them with And and Or keywords.
save()[edit]
- can be called on new or existing entities
- returns the entity, if new with the id set
General Configuration[edit]
- 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
MariaDB[edit]
- in pom.xml:
<dependency> <groupId>org.mariadb.jdbc</groupId> <artifactId>mariadb-java-client</artifactId> <scope>runtime</scope> </dependency>
- configuration in application.properties
spring.datasource.url=jdbc:mariadb://localhost:3306/test spring.datasource.username=root spring.datasource.password=
MySQL[edit]
- 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[edit]
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[edit]
@SpringBootTest
class BookmarksApplicationTests {
@Test
void contextLoads() {
}
}
Build[edit]
There are two standard build tools, Maven and Yaml.
mvn package // compile and put jar to target mvn -Dmaven.test.skip package // skip test generation mvn -DskipTests package // skip test execution mvn install // compile, put jar to target and put it to local repository
Resources[edit]
Hosting[edit]
Heroku[edit]
- 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[edit]
Some examples are not available anymore due to the loss of the Eon laptop.
Demo project local and on Heroku[edit]
Test1[edit]
- 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[edit]
- 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[edit]
- 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[edit]
Bookmarks[edit]
- start eclipse
- File -> Import -> Maven -> Existing Maven Projects
- select
C:\Uwes\eclipse\workspace_2020-12\SpringBoot\bookmarks
Database Configuration[edit]
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[edit]
- 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[edit]
- in
<PROJECT_DIR>/src/main/resources/data.sql
Links[edit]
- see My Bookmarks -> Web-Präsenz -> localhost -> SpringBoot -> Bookmarks
ToDos[edit]
- 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