spring

Spring snips

Docker

local

docker run -v ./app.jar:/app/app.jar \
-e DB_USERNAME='admin' -e DB_PASSWORD='password123' \
-p 8080:8080 \
amazoncorretto:21 \
java -jar /app/app.jar --spring.profiles.active=prod

start met .properties file

DB_USERNAME=user java -jar target/app.jar --spring.profiles.active=prod

Application properties

in application.prod.properties

spring.application.version=@project.version@

// h2
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}
spring.datasource.url=jdbc:h2:mem:contactdb
spring.h2.console.enabled=true

// MySQL
spring.datasource.url=jdbc:mysql://localhost:3306/tempdb?useUnicode=true&useLegacyDatetimeCode=false&serverTimezone=UTC&createDatabaseIfNotExist=true&allowPublicKeyRetrieval=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=<YOURPASS>
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# Hibernate JPA settings
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

# Logging level for debugging
logging.level.org.hibernate=DEBUG

logging.level.root=debug

actuator

voor in dev:

management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
management.server.port=9090

Intellij Endpoint POST Request

POST http://localhost:8080/players
Accept: */*
Accept-Encoding: gzip, deflate
Content-Type: application/json
Accept-Language: en-us

{
 "role" : "value3",
 "name": "value4"
}

Lombok

Log4j2 Pattern Layout Alternative

configure Log4j2 to automatically include the class and method names in log messages by setting up a custom pattern in log4j2.xml:

<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %-5p [%t] %C{1}.%M - %msg%n"/>

Swagger

`` org.springdoc springdoc-openapi-starter-webmvc-ui 2.6.0 ```

http://localhost:8080/swagger-ui/index.html

en json format
http://localhost:8080/v3/api-docs

Profiles

in yaml -- maakt er feitelijk 2 yaml docs van

in .properties:

spring.profiles.active=sql
spring.config.activate.on-profile=sql

Kafka

https://kafka.apache.org/quickstart

// download
10015  tar -xzf kafka_2.13-3.8.0.tgz
// unpack and start
10016  cd kafka_2.13-3.8.0
10019  cd ~/Downloads/kafka_2.13-3.8.0
10020  bin/kafka-server-start.sh config/server.properties
10022  bin/kafka-topics.sh --create --topic quickstart-events --bootstrap-server localhost:9092
10023  bin/kafka-topics.sh --describe --topic quickstart-events --bootstrap-server localhost:9092
10024  bin/kafka-console-producer.sh --topic quickstart-events --bootstrap-server localhost:9092
10026  bin/kafka-console-consumer.sh --topic quickstart-events --from-beginning --bootstrap-server localhost:9092
10027  bin/kafka-server-start.sh config/server.properties
// consume
10029  bin/kafka-console-producer.sh --topic quickstart-events --bootstrap-server localhost:9092
10030  bin/kafka-console-consumer.sh --topic quickstart-events --from-beginning --bootstrap-server localhost:9092
10032  bin/kafka-topics.sh --describe --topic cab-location --bootstrap-server localhost:9092
10033  bin/kafka-console-consumer.sh --topic cab-location --from-beginning --bootstrap-server localhost:9092

application properties Driver

spring.application.name=kafkaBookingDriver
spring.kafka.producer.bootstrap-servers=localhost:9092
spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer
server.port=8082

application properties User

spring.application.name=kafkaBookingUser

spring.kafka.consumer.bootstrap-servers=localhost:9092
spring.kafka.consumer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
spring.kafka.consumer.value-serializer=org.apache.kafka.common.serialization.StringSerializer
spring.kafka.consumer.auto-offset-reset=earliest
server.port=8081

spring.kafka.consumer.group-id=user-group

Driver

needs: - config

  • Controller

  • service

config:

package nl.appall.java.spring.kafkabookingdriver.config;

import org.apache.kafka.clients.admin.NewTopic;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.config.TopicBuilder;

import static nl.appall.java.spring.kafkabookingdriver.constant.AppConstant.CAB_LOCATION;

@Configuration
public class KafkaConfig {


    @Bean
    public NewTopic topic() {
        return TopicBuilder
                .name(CAB_LOCATION)
                .build();
    }
}

controller:

package nl.appall.java.spring.kafkabookingdriver.controller;

import nl.appall.java.spring.kafkabookingdriver.service.CabLocationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
@RequestMapping("/location")
public class CabLocationController {

    @Autowired private CabLocationService cabLocationService;

    @PutMapping
    public ResponseEntity updateLaction() throws InterruptedException {

        int range = 100;
        while(range > 0) {
            cabLocationService.updateLocation(Math.random() + " , "+ Math.random());
            Thread.sleep(1000);
            range--;
        }
        return new ResponseEntity<>(Map.of("message","Location Updated"), HttpStatus.OK);
    }
}

service:

package nl.appall.java.spring.kafkabookingdriver.service;

import nl.appall.java.spring.kafkabookingdriver.constant.AppConstant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

@Service
public class CabLocationService {

    @Autowired private KafkaTemplate<String,Object> kafkaTemplate;

    public boolean updateLocation(String location){
        kafkaTemplate.send(AppConstant.CAB_LOCATION, location);
        return true;
    }
}

User

needs only service

package nl.appall.java.spring.kafkabookinguser;

import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Service;

@Service
public class LocationService {

    @KafkaListener(
            topics = "cab-location",
            groupId = "user-group"
    )
    public void cabLocation(String location){
        System.out.println(location);

    }
}

Tags: 

Spring + Angular in one jar

based on:
Webapp with Create React App

  • create spring app
  • prevent cors
@Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedOrigins("http://localhost:4200")
                        .allowedHeaders("application/json", "text/plain", "*/*",
                                "Access-Control-Allow-Headers",
                                "Access-Control-Allow-Origin",
                                "Origin", "Accept", "X-Requested-With, Content-Type",
                                "Access-Control-Request-Method",
                                "Access-Control-Request-Headers")
                        .allowedMethods("GET", "PUT", "POST", "PATCH", "DELETE", "OPTIONS")
                        .maxAge(3600)
                ;
            }
        };

  • in root create new ng app
  • create proxy.conf.json in root frontend app
{
  "/api/*": {
    "target": "http://localhost:8080",
    "secure": false,
    "logLevel": "debug",
    "changeOrigin": true
  }
}
  • change angular.json:
            "development": {
              "browserTarget": "frontend:build:development",
              "proxyConfig": "proxy.conf.json"
            }
  • add plugin for building the frontend:
    note: version!!!
    note: npmVersion!!!
    note: nodeVersion!!!
<plugin>
                <groupId>com.github.eirslett</groupId>
                <artifactId>frontend-maven-plugin</artifactId>
                <version>1.9.1</version>
                <configuration>
                    <workingDirectory>frontend</workingDirectory>
                    <installDirectory>target</installDirectory>
                </configuration>
                <executions>
                    <execution>
                        <id>install node and npm</id>
                        <goals>
                            <goal>install-node-and-npm</goal>
                        </goals>
                        <configuration>
                            <nodeVersion>v14.15.4</nodeVersion>
                            <npmVersion>7.17.0</npmVersion>
                        </configuration>
                    </execution>
                    <execution>
                        <id>npm install</id>
                        <goals>
                            <goal>npm</goal>
                        </goals>
                        <configuration>
                            <arguments>install</arguments>
                        </configuration>
                    </execution>
                    <execution>
                        <id>npm run build</id>
                        <goals>
                            <goal>npm</goal>
                        </goals>
                        <configuration>
                            <arguments>run build</arguments>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

  • copy the dist version to target:
    note double check location where the build is located
    note mvn clean package
<plugin>
                <artifactId>maven-antrun-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>generate-resources</phase>
                        <configuration>
                            <target>
                                <copy todir="${project.build.directory}/classes/public">
                                    <fileset dir="${project.basedir}/frontend/dist"/>
                                </copy>
                            </target>
                        </configuration>
                        <goals>
                            <goal>run</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

Spring Mysql One to Many....

pom.xml
- lombok
- spring-boot-starter-data-jpa
- mysql-connector-java

application.properties

# MySQL connection properties
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.url=jdbc:mysql://localhost:3306/testspring

# Log JPA queries
# Comment this in production
spring.jpa.show-sql=true

# Drop and create new tables (create, create-drop, validate, update)
# Only for testing purpose - comment this in production
spring.jpa.hibernate.ddl-auto=create-drop

# Hibernate SQL dialect
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

ResApplication.java

public class RestApplication {

    public static void main(String[] args) {
        SpringApplication.run(RestApplication.class, args);
    }

    @Bean
    public CommandLineRunner mappingDemo(BookRepository bookRepository,
                                         PageRepository pageRepository) {
        return args -> {

            // create a new book
            Book book = new Book("Java 101", "John Doe", "123456");

            // save the book
            bookRepository.save(book);
            pageRepository.save(new Page(65, "Java 8 contents", "Java 8", book));
            pageRepository.save(new Page(95, "Concurrency contents", "Concurrency", book));
        };
    }
}

Book.java


@Entity @Table(name = "books") @Getter @Setter public class Book implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String title; private String author; @Column(unique = true) private String isbn; ```**```@JsonManagedReference```**``` @OneToMany(mappedBy = "book", fetch = FetchType.LAZY, cascade = CascadeType.ALL) private List<Page> pages = new ArrayList<Page>(); public Book() { } public Book(String title, String author, String isbn) { this.title = title; this.author = author; this.isbn = isbn; } // getters and setters, equals(), toString() .... (omitted for brevity) @Override public String toString() { return "Book{" + "id=" + id + ", title='" + title + '\'' + ", author='" + author + '\'' + ", isbn='" + isbn + '\'' + ", number of pages=" + pages.size() + '}'; } }

Pages.java


@Entity @Table(name = "pages") @Setter @Getter public class Page implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private int number; private String content; private String chapter; @JsonBackReference @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "book_id", nullable = false) private Book book; public Page() { } public Page(int number, String content, String chapter, Book book) { this.number = number; this.content = content; this.chapter = chapter; this.book = book; } // getters and setters, equals(), toString() .... (omitted for brevity) @Override public String toString() { return "Page{" + "id=" + id + ", number=" + number + ", content='" + content + '\'' + ", chapter='" + chapter + '\'' + ", book=" + book.toString() + '}'; } }

BookRepository.java

public interface BookRepository extends CrudRepository<Book, Long> {

    Book findByIsbn(String isbn);
}

PageRepository.java

public interface PageRepository extends CrudRepository<Page, Long> {

    List<Page> findByBook(Book book, Sort sort);
}

BooksController.java


@RestController @RequestMapping(value = "/books", produces = MediaType.APPLICATION_JSON_VALUE) public class BooksController { private final BookRepository bookRepository; private final PageRepository pageRepository; public BooksController(BookRepository bookRepository, PageRepository pageRepository) { this.bookRepository = bookRepository; this.pageRepository = pageRepository; } @GetMapping(value = "/pages", produces = MediaType.APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) public List<Page> pages(){ List<Page> result = (List<Page>) pageRepository.findAll(); System.out.println(result); System.out.println(result.get(0)); return result; } @GetMapping("/") public List<Book> books(){ return (List<Book>)bookRepository.findAll(); } }

http://localhost:8080/books/

[
{
"id": 1,
"title": "Java 101",
"author": "John Doe",
"isbn": "123456",
"pages": [
{
"id": 1,
"number": 1,
"content": "Introduction contents",
"chapter": "Introduction"
},
{
"id": 2,
"number": 65,
"content": "Java 8 contents",
"chapter": "Java 8"
},
{
"id": 3,
"number": 95,
"content": "Concurrency contents",
"chapter": "Concurrency"
}
]
}
]

http://localhost:8080/books/pages

[
{
"id": 1,
"number": 1,
"content": "Introduction contents",
"chapter": "Introduction"
},
{
"id": 2,
"number": 65,
"content": "Java 8 contents",
"chapter": "Java 8"
},
{
"id": 3,
"number": 95,
"content": "Concurrency contents",
"chapter": "Concurrency"
}
]
Subscribe to RSS - spring