<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Spring Boot &#8211; Pauls Blog</title>
	<atom:link href="https://sterl.org/tag/spring-boot/feed/" rel="self" type="application/rss+xml" />
	<link>https://sterl.org</link>
	<description></description>
	<lastBuildDate>Tue, 12 Aug 2025 10:45:50 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.3</generator>
	<item>
		<title>Spring Persistent Tasks</title>
		<link>https://sterl.org/2025/04/spring-persistent-tasks/</link>
					<comments>https://sterl.org/2025/04/spring-persistent-tasks/#respond</comments>
		
		<dc:creator><![CDATA[Paul Sterl]]></dc:creator>
		<pubDate>Sun, 20 Apr 2025 07:16:43 +0000</pubDate>
				<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[dashboard]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Inbound Pattern]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JPA]]></category>
		<category><![CDATA[Outbound Pattern]]></category>
		<category><![CDATA[Quartz]]></category>
		<category><![CDATA[quartz daschboard]]></category>
		<category><![CDATA[scheduled]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[task ui]]></category>
		<category><![CDATA[task-scheduling]]></category>
		<category><![CDATA[Transaction]]></category>
		<category><![CDATA[trigger]]></category>
		<guid isPermaLink="false">https://sterl.org/?p=1116</guid>

					<description><![CDATA[A simple task management framework designed to queue and execute asynchronous tasks with support for database persistence and a user-friendly interface. It can be used to implement scheduling patterns or outbound patterns. Focus is the usage with spring boot and JPA. https://github.com/sterlp/spring-persistent-tasks Key Features]]></description>
										<content:encoded><![CDATA[
<p>A simple task management framework designed to queue and execute asynchronous tasks with support for database persistence and a user-friendly interface. It can be used to implement scheduling patterns or outbound patterns.</p>



<p>Focus is the usage with spring boot and JPA.</p>



<p><a href="https://github.com/sterlp/spring-persistent-tasks">https://github.com/sterlp/spring-persistent-tasks</a></p>



<h2 class="wp-block-heading">Key Features</h2>



<ol class="wp-block-list">
<li><strong>JPA-Powered Persistence</strong>&nbsp;&#8211; Automatically persists tasks to your database</li>



<li><strong>Spring Boot Auto-Configuration</strong>&nbsp;&#8211; Simple setup with @EnableSpringPersistentTasks</li>



<li><strong>Clustering Support</strong>&nbsp;&#8211; Built-in lock management for distributed environments</li>



<li><strong>Type-Safe Tasks</strong>&nbsp;&#8211; Generic task definitions with state objects</li>



<li><strong>Retry Mechanisms</strong>&nbsp;&#8211; Automatic retry policies for failed executions</li>



<li><strong>Transactional Integration</strong>&nbsp;&#8211; Works with Spring&#8217;s transaction management</li>



<li><strong>Queue Management</strong> &#8211; Intelligent task queuing and prioritization</li>



<li><strong>Different DB Supports</strong> 
<ul class="wp-block-list">
<li>MsSQL</li>



<li>MariaDB</li>



<li>Postgres</li>
</ul>
</li>
</ol>
]]></content:encoded>
					
					<wfw:commentRss>https://sterl.org/2025/04/spring-persistent-tasks/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Propagation REQUIRES_NEW &#038; NEVER &#124; Transaktionsmanagement mit Spring Boot, JPA &#038; Hibernate</title>
		<link>https://sterl.org/2025/01/propagation-requires_new-never-transaktionsmanagement-mit-spring-boot-jpa-hibernate/</link>
					<comments>https://sterl.org/2025/01/propagation-requires_new-never-transaktionsmanagement-mit-spring-boot-jpa-hibernate/#respond</comments>
		
		<dc:creator><![CDATA[Paul Sterl]]></dc:creator>
		<pubDate>Sun, 19 Jan 2025 20:17:00 +0000</pubDate>
				<category><![CDATA[YouTube]]></category>
		<category><![CDATA[@Transactional]]></category>
		<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[JPA]]></category>
		<category><![CDATA[NEVER]]></category>
		<category><![CDATA[propagation]]></category>
		<category><![CDATA[REQUIRES_NEW]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<guid isPermaLink="false">https://sterl.org/?p=1119</guid>

					<description><![CDATA[In diesem Video tauchen wir tiefer in die Welt des Transaktionsmanagements ein und erklären die Unterschiede zwischen den Propagation-Einstellungen REQUIRES_NEW und NEVER in Spring Boot. Erfahre, wie du mit Spring Boot, Spring Data, JPA und Hibernate effektive Transaktionen in modernen Datenbanken steuerst. Lerne, wann und warum du REQUIRES_NEW nutzen solltest, um eine neue Transaktion zu&#8230;]]></description>
										<content:encoded><![CDATA[
<p>In diesem Video tauchen wir tiefer in die Welt des Transaktionsmanagements ein und erklären die Unterschiede zwischen den Propagation-Einstellungen <code>REQUIRES_NEW</code> und <code>NEVER</code> in Spring Boot. Erfahre, wie du mit Spring Boot, Spring Data, JPA und Hibernate effektive Transaktionen in modernen Datenbanken steuerst.</p>



<p>Lerne, wann und warum du <code>REQUIRES_NEW</code> nutzen solltest, um eine neue Transaktion zu starten, und warum <code>NEVER</code> nützlich ist, um sicherzustellen, dass kein bestehender Transaktionskontext verwendet wird. Dieses Tutorial ist ideal für Entwickler, die fortgeschrittene Techniken des Transaktionsmanagements verstehen und in ihren Anwendungen umsetzen möchten.</p>



<p><a rel="noreferrer noopener" href="https://github.com/sterlp/youtube/blob/main/db-grundlagen/src/test/java/org/sterl/db_grundlagen/transaction/AuditServiceTest.java" target="_blank">Github</a></p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="Propagation REQUIRES_NEW &amp; NEVER | Transaktionsmanagement mit Spring Boot, JPA &amp; Hibernate" width="640" height="360" src="https://www.youtube.com/embed/_5JAer04v9M?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://sterl.org/2025/01/propagation-requires_new-never-transaktionsmanagement-mit-spring-boot-jpa-hibernate/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>React &#038; Spring Boot</title>
		<link>https://sterl.org/2024/12/react-spring-boot/</link>
					<comments>https://sterl.org/2024/12/react-spring-boot/#respond</comments>
		
		<dc:creator><![CDATA[Paul Sterl]]></dc:creator>
		<pubDate>Wed, 11 Dec 2024 18:36:41 +0000</pubDate>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[React]]></category>
		<category><![CDATA[TypeScript]]></category>
		<category><![CDATA[ReactJs]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[vite]]></category>
		<guid isPermaLink="false">https://sterl.org/?p=1095</guid>

					<description><![CDATA[Problem We want to combine Spring Boot with a simple React frontend. Use the React development features but also be able to use the Spring IDE. In the end, everything should be built using Maven and nicely packed into a JAR, just like any other Microservice. Let’s get started. Multi-Module project First we create a&#8230;]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Problem</h2>



<p>We want to combine Spring Boot with a simple React frontend. Use the React development features but also be able to use the Spring IDE. In the end, everything should be built using Maven and nicely packed into a JAR, just like any other Microservice. Let’s get started.</p>



<h2 class="wp-block-heading">Multi-Module project</h2>



<p>First we create a spring project here <code>backend</code> folder and a react project in the <code>frontend</code> folder. The root pom should help us to build both projects in one run:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><a href="https://sterl.org/wp-content/uploads/2024/12/image.png"><img fetchpriority="high" decoding="async" width="294" height="211" src="https://sterl.org/wp-content/uploads/2024/12/image.png" alt="" class="wp-image-1096"/></a></figure></div>


<h3 class="wp-block-heading">Root pom.xml</h3>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;xml&quot;,&quot;mime&quot;:&quot;application/xml&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;XML&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;xml&quot;}">&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;

    &lt;groupId&gt;org.foo.bar&lt;/groupId&gt;
    &lt;artifactId&gt;project-root&lt;/artifactId&gt;
    &lt;version&gt;0.1.0-SNAPSHOT&lt;/version&gt;
    &lt;packaging&gt;pom&lt;/packaging&gt;

    &lt;properties&gt;
        &lt;java.version&gt;21&lt;/java.version&gt;
        &lt;maven.compiler.source&gt;${java.version}&lt;/maven.compiler.source&gt;
        &lt;maven.compiler.target&gt;${java.version}&lt;/maven.compiler.target&gt;
        &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;
        &lt;project.reporting.outputEncoding&gt;UTF-8&lt;/project.reporting.outputEncoding&gt;
    &lt;/properties&gt;

    &lt;modules&gt;
        &lt;module&gt;frontend&lt;/module&gt;
        &lt;module&gt;backend&lt;/module&gt;
    &lt;/modules&gt;

  	&lt;!-- feel free to use spring as root instead of this --&gt;
    &lt;dependencyManagement&gt;
        &lt;dependencies&gt;
            &lt;dependency&gt;
                &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
                &lt;artifactId&gt;spring-boot-dependencies&lt;/artifactId&gt;
                &lt;version&gt;3.3.6&lt;/version&gt;
                &lt;type&gt;pom&lt;/type&gt;
                &lt;scope&gt;import&lt;/scope&gt;
            &lt;/dependency&gt;
        &lt;/dependencies&gt;
    &lt;/dependencyManagement&gt;
&lt;/project&gt;</pre></div>



<h3 class="wp-block-heading">Backend pom.xml</h3>



<p>This is straight forward the generated pom from spring with just the dependency to the <code>frontend </code>project.</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;xml&quot;,&quot;mime&quot;:&quot;application/xml&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;XML&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;xml&quot;}">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
    &lt;parent&gt;
        &lt;groupId&gt;org.foo.bar&lt;/groupId&gt;
        &lt;artifactId&gt;project-root&lt;/artifactId&gt;
        &lt;version&gt;0.1.0-SNAPSHOT&lt;/version&gt;
        &lt;relativePath&gt;../pom.xml&lt;/relativePath&gt;
    &lt;/parent&gt;

    &lt;artifactId&gt;project-backend&lt;/artifactId&gt;

    &lt;dependencies&gt;
      	&lt;!-- thats the important part --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.foo.bar&lt;/groupId&gt;
            &lt;artifactId&gt;project-frontend&lt;/artifactId&gt;
            &lt;version&gt;${project.version}&lt;/version&gt;
        &lt;/dependency&gt;
      	&lt;!-- thats the important part end --&gt;
      
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
            &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
        &lt;/dependency&gt;  
        &lt;dependency&gt;
            &lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
            &lt;artifactId&gt;lombok&lt;/artifactId&gt;
            &lt;optional&gt;true&lt;/optional&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
            &lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
            &lt;scope&gt;test&lt;/scope&gt;
        &lt;/dependency&gt;
    &lt;/dependencies&gt;
    &lt;build&gt;
        &lt;plugins&gt;
            &lt;plugin&gt;
                &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
                &lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
            &lt;/plugin&gt;
        &lt;/plugins&gt;
    &lt;/build&gt;

&lt;/project&gt;</pre></div>



<h3 class="wp-block-heading">Frontend pom.xml</h3>



<p>Now we have todo more stuff:</p>



<ol class="wp-block-list">
<li>Ensure the <code>dist</code> result is added to the JAR</li>



<li>Generate during the <code>generate-resources</code> phase also the content for the <code>dist</code> folder</li>



<li>Ensure that during a <code>mvn clean</code> all gets deleted</li>
</ol>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;xml&quot;,&quot;mime&quot;:&quot;application/xml&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;XML&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;xml&quot;}">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
    &lt;parent&gt;
        &lt;groupId&gt;org.foo.bar&lt;/groupId&gt;
        &lt;artifactId&gt;project-root&lt;/artifactId&gt;
        &lt;version&gt;0.1.0-SNAPSHOT&lt;/version&gt;
        &lt;relativePath&gt;../pom.xml&lt;/relativePath&gt;
    &lt;/parent&gt;

    &lt;artifactId&gt;project-frontend&lt;/artifactId&gt;
    
    &lt;dependencies&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
            &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
            &lt;scope&gt;provided&lt;/scope&gt;
        &lt;/dependency&gt;
    &lt;/dependencies&gt;
    
    &lt;build&gt;
        &lt;!-- Ensure the dist result is added to the JAR --&gt;
        &lt;resources&gt;
            &lt;resource&gt;
                &lt;directory&gt;dist&lt;/directory&gt;
            &lt;/resource&gt;
        &lt;/resources&gt;

        &lt;plugins&gt;
          	&lt;!--
                Generate during the generate-resources phase 
                also the content for the dist folder 
            --&gt;
            &lt;plugin&gt;
                &lt;groupId&gt;org.codehaus.mojo&lt;/groupId&gt;
                &lt;artifactId&gt;exec-maven-plugin&lt;/artifactId&gt;
                &lt;version&gt;3.5.0&lt;/version&gt;
                &lt;executions&gt;
                    &lt;execution&gt;
                        &lt;id&gt;npm install&lt;/id&gt;
                        &lt;goals&gt;
                            &lt;goal&gt;exec&lt;/goal&gt;
                        &lt;/goals&gt;
                        &lt;phase&gt;generate-resources&lt;/phase&gt;
                        &lt;configuration&gt;
                            &lt;executable&gt;npm&lt;/executable&gt;
                            &lt;arguments&gt;
                                &lt;argument&gt;install&lt;/argument&gt;
                                &lt;argument&gt;--prefer-offline&lt;/argument&gt;
                                &lt;argument&gt;--no-audit&lt;/argument&gt;
                                &lt;argument&gt;--progress=false&lt;/argument&gt;
                            &lt;/arguments&gt;
                        &lt;/configuration&gt;
                    &lt;/execution&gt;

                    &lt;execution&gt;
                        &lt;id&gt;npm build&lt;/id&gt;
                        &lt;goals&gt;
                            &lt;goal&gt;exec&lt;/goal&gt;
                        &lt;/goals&gt;
                        &lt;phase&gt;generate-resources&lt;/phase&gt;
                        &lt;configuration&gt;
                            &lt;executable&gt;npm&lt;/executable&gt;
                            &lt;arguments&gt;
                                &lt;argument&gt;run&lt;/argument&gt;
                                &lt;argument&gt;build&lt;/argument&gt;
                            &lt;/arguments&gt;
                        &lt;/configuration&gt;
                    &lt;/execution&gt;
                &lt;/executions&gt;
            &lt;/plugin&gt;
            &lt;!-- Ensure that during a mvn clean all gets deleted --&gt;
            &lt;plugin&gt;
                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
                &lt;artifactId&gt;maven-clean-plugin&lt;/artifactId&gt;
                &lt;version&gt;3.4.0&lt;/version&gt;
                &lt;configuration&gt;
                    &lt;filesets&gt;
                        &lt;fileset&gt;
                            &lt;directory&gt;node_modules&lt;/directory&gt;
                        &lt;/fileset&gt;
                        &lt;fileset&gt;
                            &lt;directory&gt;dist&lt;/directory&gt;
                        &lt;/fileset&gt;
                    &lt;/filesets&gt;
                &lt;/configuration&gt;
            &lt;/plugin&gt;
        &lt;/plugins&gt;
    &lt;/build&gt;

&lt;/project&gt;</pre></div>



<h3 class="wp-block-heading">Ensure the result in the dist folder is compatible to Spring</h3>



<p>Spring will pick up automatically any static resources which are placed in the <code>static</code> folder. Here is an example for <a rel="noreferrer noopener" href="https://vite.dev/guide/" target="_blank">vite</a> to do so in the <code>vite.config.js</code>:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;javascript&quot;,&quot;mime&quot;:&quot;application/json&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;JSON&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;json&quot;}">export default defineConfig({
  plugins: [react()],
  build: {
    outDir: './dist/static',
    emptyOutDir: true, // also necessary
  }
})</pre></div>



<h2 class="wp-block-heading">Going beyond</h2>



<p>Sometime it is useful to host the UI in a sub path lets say <code>my-ui</code>, so the url would be <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color"><strong>http://localhost:8080/my-ui</strong></mark></p>



<p>For that we have to adjust the <code>vite.config.js</code>:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;javascript&quot;,&quot;mime&quot;:&quot;application/json&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;JSON&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;json&quot;}">export default defineConfig({
  plugins: [react()],
  base: 'my-ui',
  build: {
    outDir: './dist/static/my-ui',
    emptyOutDir: true,
  }
})</pre></div>



<p>Now it would also be helpful if we don&#8217;t have to directly type the <code>index.html</code> but tell Spring always to re-route.</p>



<p>For that we have to add a Spring Configuration Class:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">package org.foo.bar;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MyFrontedConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController(&quot;/my-ui&quot;).setViewName(&quot;/my-ui/index.html&quot;);
        registry.addRedirectViewController(&quot;/my-ui/&quot;, &quot;/my-ui&quot;);
    }
}
</pre></div>



<h2 class="wp-block-heading">Add cache control to static react assets</h2>



<p>In the end int would also be nice that the generated static resources are cached by the client e.g. for a year. We will extend the <code>MyFrontedConfig</code> class with:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler(&quot;/my-ui/assets/**&quot;) 
                .addResourceLocations(&quot;classpath:/static/my-ui/assets/&quot;) 
                .setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS));
    }</pre></div>
]]></content:encoded>
					
					<wfw:commentRss>https://sterl.org/2024/12/react-spring-boot/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Transaktionsmanagement mit Spring, JPA, Hibernate</title>
		<link>https://sterl.org/2024/08/transaktionsmanagement-mit-spring-jpa-hibernate/</link>
					<comments>https://sterl.org/2024/08/transaktionsmanagement-mit-spring-jpa-hibernate/#respond</comments>
		
		<dc:creator><![CDATA[Paul Sterl]]></dc:creator>
		<pubDate>Sat, 31 Aug 2024 15:02:17 +0000</pubDate>
				<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[YouTube]]></category>
		<category><![CDATA[@Transactional]]></category>
		<category><![CDATA[Datenbank]]></category>
		<category><![CDATA[DB]]></category>
		<category><![CDATA[Grundlagen]]></category>
		<category><![CDATA[Grundlagen Datenbanken]]></category>
		<category><![CDATA[Grundlagen Transaktionen]]></category>
		<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JPA]]></category>
		<category><![CDATA[Mandatory]]></category>
		<category><![CDATA[Read only transaction]]></category>
		<category><![CDATA[Required]]></category>
		<category><![CDATA[Spring Data]]></category>
		<category><![CDATA[Spring TransactionTemplate]]></category>
		<category><![CDATA[Transaction Timeout]]></category>
		<category><![CDATA[Transactions]]></category>
		<category><![CDATA[TransactionTemplate]]></category>
		<category><![CDATA[Transkationen]]></category>
		<guid isPermaLink="false">https://sterl.org/?p=1032</guid>

					<description><![CDATA[Lerne die Grundlagen des Transaktionsmanagements in modernen Datenbanken kennen, und erfahre, wie du mit Spring Boot, Spring Data, JPA und Hibernate effektiv arbeitest. In diesem Tutorial starten wir mit den Grundlagen der Datenbanktransaktionen in deiner Anwendung: &#8211; Transaktionen starten: Dieses Video ist perfekt für Entwickler, die ihre Fähigkeiten in Spring Framework erweitern und transaktionssichere Anwendungen&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Lerne die Grundlagen des Transaktionsmanagements in modernen Datenbanken kennen, und erfahre, wie du mit Spring Boot, Spring Data, JPA und Hibernate effektiv arbeitest.</p>



<p>In diesem Tutorial starten wir mit den Grundlagen der Datenbanktransaktionen in deiner Anwendung: &#8211; Transaktionen starten: </p>



<ul class="wp-block-list">
<li><strong>Transaktion starten</strong>: Verstehe, wie Du Transaktionen in Spring Boot richtig initialisierst.</li>



<li><strong>Rollback-Strategien:</strong> Erlerne die wichtigsten Methoden, um Transaktionen bei Fehlern sicher zurückzusetzen. </li>



<li><strong>Annotations</strong>: Setze Annotations gezielt ein, um Transaktionen zu steuern. </li>



<li><strong>Programmatische Transaktionen</strong>: Implementiere Transaktionen programmatisch und gewinne maximale Kontrolle. </li>



<li><strong>Read Only</strong>: Transaktionen für GET Operationen </li>



<li><strong>Timeouts</strong>: Wie stelle ich bei einer Transaktion einen Timeout ein, was muss ich beachten?</li>
</ul>



<p>Dieses Video ist perfekt für Entwickler, die ihre Fähigkeiten in Spring Framework erweitern und transaktionssichere Anwendungen erstellen möchten.</p>



<ul class="wp-block-list">
<li><a href="https://github.com/sterlp/youtube/commit/24f1d4e1576be803ec32142ffb84f438dcd30623">Git Commit</a></li>



<li><a href="https://github.com/sterlp/youtube/tree/main/db-grundlagen">Git Projekt</a></li>
</ul>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="Transaktionsmanagement | Datenbanken | Spring Boot &amp; Data, JPA &amp; Hibernate | @Transactional" width="640" height="360" src="https://www.youtube.com/embed/9cY73uCj5wA?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://sterl.org/2024/08/transaktionsmanagement-mit-spring-jpa-hibernate/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Setup Spring Boot Azure OAuth2 with CORS</title>
		<link>https://sterl.org/2024/02/setup-spring-boot-azure-oauth2-with-cors/</link>
					<comments>https://sterl.org/2024/02/setup-spring-boot-azure-oauth2-with-cors/#respond</comments>
		
		<dc:creator><![CDATA[Paul Sterl]]></dc:creator>
		<pubDate>Thu, 01 Feb 2024 09:03:03 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[CORS error]]></category>
		<category><![CDATA[oauth2Login]]></category>
		<category><![CDATA[OAuth2UserService]]></category>
		<category><![CDATA[strict-origin-when-cross-origin]]></category>
		<guid isPermaLink="false">https://sterl.org/?p=993</guid>

					<description><![CDATA[What is needed Setup an Azure AAD Application First we need an Azure AAD application which gives us the access to our AD users. The important part are the client id and the tenant id here: Add the web URIs which are allowed to use the OAuth2 login In the next step we have to&#8230;]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">What is needed</h2>



<ol class="wp-block-list">
<li>Setup an Azure AAD Application</li>



<li>Add the web URIs which are allowed to use the OAuth2 login</li>



<li>Add a client secret for your application</li>



<li>Add API Permission to read the profile</li>



<li>Add needed Azure dependencies</li>



<li>Setup Spring OAuth config</li>



<li>Adjust the CORS settings in Spring to ensure token refreshes</li>



<li>Configure spring security</li>
</ol>



<h2 class="wp-block-heading">Setup an Azure AAD Application</h2>



<p>First we need an Azure AAD application which gives us the access to our AD users. The important part are the client id and the tenant id here:</p>



<figure class="wp-block-image size-full is-resized"><a href="https://sterl.org/wp-content/uploads/2024/02/azure-aad-application.png"><img loading="lazy" decoding="async" width="810" height="243" src="https://sterl.org/wp-content/uploads/2024/02/azure-aad-application.png" alt="" class="wp-image-1004" style="aspect-ratio:3.3333333333333335;width:840px;height:auto" srcset="https://sterl.org/wp-content/uploads/2024/02/azure-aad-application.png 810w, https://sterl.org/wp-content/uploads/2024/02/azure-aad-application-300x90.png 300w, https://sterl.org/wp-content/uploads/2024/02/azure-aad-application-768x230.png 768w" sizes="auto, (max-width: 810px) 100vw, 810px" /></a></figure>



<h2 class="wp-block-heading">Add the web URIs which are allowed to use the OAuth2 login</h2>



<p>In the next step we have to allow &#8222;applications&#8220; based on their &#8222;DNS&#8220; name to access and login through this AAD. Ensure to remember the yellow part, which is later needed in the configutation.</p>



<p>The URLs are basically the one you whitelist for a login. If you setup the &#8222;test&#8220; AAD application you may want also add sometimes the localhost for testing. Ensure to remove it again later on.</p>



<figure class="wp-block-image size-large"><a href="https://sterl.org/wp-content/uploads/2024/02/azure-aad-application-autthentication.png"><img loading="lazy" decoding="async" width="1024" height="493" src="https://sterl.org/wp-content/uploads/2024/02/azure-aad-application-autthentication-1024x493.png" alt="" class="wp-image-1006" srcset="https://sterl.org/wp-content/uploads/2024/02/azure-aad-application-autthentication-1024x493.png 1024w, https://sterl.org/wp-content/uploads/2024/02/azure-aad-application-autthentication-300x144.png 300w, https://sterl.org/wp-content/uploads/2024/02/azure-aad-application-autthentication-768x369.png 768w, https://sterl.org/wp-content/uploads/2024/02/azure-aad-application-autthentication.png 1368w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<h2 class="wp-block-heading">Add a client secret for your application</h2>



<p>Next we have to create a secret for our application, we only require later the value of it. Please make sure you provide a new one after the expiration period.</p>



<p>You can have multiple secrets for multiple apps here.</p>



<figure class="wp-block-image size-large"><a href="https://sterl.org/wp-content/uploads/2024/02/azure-aad-application-secret.png"><img loading="lazy" decoding="async" width="1024" height="317" src="https://sterl.org/wp-content/uploads/2024/02/azure-aad-application-secret-1024x317.png" alt="" class="wp-image-1009" srcset="https://sterl.org/wp-content/uploads/2024/02/azure-aad-application-secret-1024x317.png 1024w, https://sterl.org/wp-content/uploads/2024/02/azure-aad-application-secret-300x93.png 300w, https://sterl.org/wp-content/uploads/2024/02/azure-aad-application-secret-768x238.png 768w, https://sterl.org/wp-content/uploads/2024/02/azure-aad-application-secret.png 1439w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<h2 class="wp-block-heading">Setup Spring OAuth config</h2>



<p>In this configuration we have to enter all the collected data <strong>azure-dev</strong> as name is here the suffix provided in the authentication section of the Azure AAD application. You can choose what ever name you like.</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;yaml&quot;,&quot;mime&quot;:&quot;text/x-yaml&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;YAML&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;yaml&quot;}">spring:
  security:
    oauth2:
      client:
        provider:
          azure:
            issuer-uri: https://login.microsoftonline.com/&lt;Directory (tenant) ID&gt;/v2.0
            user-name-attribute: name
        registration:
          azure-dev:
            provider: azure
            client-id: &lt;Application (client) ID&gt;
            client-secret: &lt;the secret value you created for your app&gt;
            client-authentication-method: client_secret_post
            scope:
              - openid
              - email
              - profile</pre></div>



<h2 class="wp-block-heading">Spring Security</h2>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">  @Bean
  SecurityFilterChain filterChain(HttpSecurity http, OptionalYourUserService userService) throws Exception {
    // @formatter:off
    http
      .authorizeHttpRequests(authorizeHttpRequests -&gt;
        authorizeHttpRequests
          // public URLs
          .requestMatchers(antMatcher(&quot;/actuator/health/readiness&quot;)).permitAll()
          // secure actuator
          .requestMatchers(antMatcher(&quot;/actuator/**&quot;)).hasRole(UserGroup.ADMIN)
          // app urls
          .requestMatchers(&quot;/api/**&quot;).authenticated()
          // default; recommended to use .authenticated()
          .anyRequest().permitAll()
      ).headers(headers -&gt; headers.frameOptions(FrameOptionsConfig::sameOrigin))
      .oauth2Login( oauth2 -&gt; oauth2
          .userInfoEndpoint(userInfo -&gt; userInfo
            .oidcUserService(oidcUserService(userService)))
      )
      .headers(headers -&gt; headers.frameOptions(FrameOptionsConfig::sameOrigin));
    // @formatter:on
    return http.build();
  }

  private OAuth2UserService&lt;OidcUserRequest, OidcUser&gt; oidcUserService(
    OptionalYourUserService userService) {
    return userRequest -&gt; {
      var oidcUser = new OidcUserService().loadUser(userRequest); // Delegate to the default
                                                                  // implementation
      
      // add any custom user service integration here, if required.

      return oidcUser;
    };
  }</pre></div>



<h2 class="wp-block-heading">Add CORS Config</h2>



<p>To avoid any <code>CORS error</code> / <code>strict-origin-when-cross-origin</code> in your application we have to whitelist the OAuth2 provider for any redirect, in this example login.microsoft:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">  @Bean
  protected CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(Arrays.asList(&quot;https://login.microsoftonline.com/**&quot;));
    configuration.addAllowedHeader(&quot;*&quot;);
    configuration.addAllowedMethod(&quot;*&quot;);
    configuration.setAllowCredentials(true);
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration(&quot;/**&quot;, configuration);
    return source;
  }</pre></div>



<h2 class="wp-block-heading">Links</h2>



<ul class="wp-block-list">
<li>https://learn.microsoft.com/en-us/azure/developer/java/spring-framework/spring-boot-starter-for-azure-active-directory-developer-guide</li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://sterl.org/2024/02/setup-spring-boot-azure-oauth2-with-cors/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Datenbank&#124; Transaktionen &#124; Isolationlevel &#124; Locks &#124; Hibernate &#124; JPA &#124; Spring Boot</title>
		<link>https://sterl.org/2023/10/datenbank-transaktionen-isolationlevel-locks-hibernate-jpa-spring-boot/</link>
					<comments>https://sterl.org/2023/10/datenbank-transaktionen-isolationlevel-locks-hibernate-jpa-spring-boot/#respond</comments>
		
		<dc:creator><![CDATA[Paul Sterl]]></dc:creator>
		<pubDate>Mon, 02 Oct 2023 11:40:50 +0000</pubDate>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[YouTube]]></category>
		<category><![CDATA[DB Locks]]></category>
		<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Isolationlevel]]></category>
		<category><![CDATA[JPA]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[Transaktionen]]></category>
		<guid isPermaLink="false">https://sterl.org/?p=958</guid>

					<description><![CDATA[Um weiterführende Konzepte besser nachvollziehen zu können, wollen wir uns in den Grundlagen Datenbanken mit Spring Boot, Isolation Level (Isolationsgrad) und Locks beschäftigen.]]></description>
										<content:encoded><![CDATA[
<p>Um weiterführende Konzepte besser nachvollziehen zu können, wollen wir uns in den Grundlagen Datenbanken mit Spring Boot, Isolation Level (Isolationsgrad) und Locks beschäftigen.</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Datenbanken Grundlagen | Transaktionen | Isolation Level | Locks | Hibernate | JPA | Spring Boot" width="640" height="360" src="https://www.youtube.com/embed/6ytlI4Sshjc?start=604&#038;feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://sterl.org/2023/10/datenbank-transaktionen-isolationlevel-locks-hibernate-jpa-spring-boot/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Datenbank Timeouts &#124; Locks &#124; Isonaltionlevel &#124; Transaktionen</title>
		<link>https://sterl.org/2023/10/datenbank-timeouts-locks-isonaltionlevel-transaktionen/</link>
					<comments>https://sterl.org/2023/10/datenbank-timeouts-locks-isonaltionlevel-transaktionen/#respond</comments>
		
		<dc:creator><![CDATA[Paul Sterl]]></dc:creator>
		<pubDate>Mon, 02 Oct 2023 11:15:27 +0000</pubDate>
				<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Pattern & Best Practice]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[YouTube]]></category>
		<category><![CDATA[Datenbanken]]></category>
		<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Isonaltionlevel]]></category>
		<category><![CDATA[Lock]]></category>
		<category><![CDATA[Locks]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[Timeouts]]></category>
		<category><![CDATA[Transaktionen]]></category>
		<guid isPermaLink="false">https://sterl.org/?p=955</guid>

					<description><![CDATA[Häufig vergessen, oder nur teilweise gemacht. Timeouts tragen einen wesentlichen Bestandteil zur Stabilität und dem Ressourcenmanagement von Software bei. Insbesondere bei Microservices sollten diese immer richtig eingestellt sein. Timeouts spielen auch eine wesentliche Rolle in Bezug auf Transaktionen, Locks und Isolationslevel. Sollte man zudem den Zugriff auf die Datenbank auch Dritten gewähren, also nicht nur&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Häufig vergessen, oder nur teilweise gemacht. Timeouts tragen einen wesentlichen Bestandteil zur Stabilität und dem Ressourcenmanagement von Software bei. Insbesondere bei Microservices sollten diese immer richtig eingestellt sein. Timeouts spielen auch eine wesentliche Rolle in Bezug auf Transaktionen, Locks und Isolationslevel. Sollte man zudem den Zugriff auf die Datenbank auch Dritten gewähren, also nicht nur den Services selbst, dann sind diese umso wichtiger, für alle Clients, die auf die Datenbank zugreifen.</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Datenbanken Grundlagen | Timeouts | Locks | Isonaltionlevel | DB | als Architekt | Microservices" width="640" height="360" src="https://www.youtube.com/embed/cW_k_VtOVmQ?start=217&#038;feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://sterl.org/2023/10/datenbank-timeouts-locks-isonaltionlevel-transaktionen/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Quartz integration in Spring</title>
		<link>https://sterl.org/2022/07/quartz-integration-in-spring/</link>
					<comments>https://sterl.org/2022/07/quartz-integration-in-spring/#comments</comments>
		
		<dc:creator><![CDATA[Paul Sterl]]></dc:creator>
		<pubDate>Fri, 01 Jul 2022 19:50:50 +0000</pubDate>
				<category><![CDATA[Quartz]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[quartz-scheduler]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[timer]]></category>
		<guid isPermaLink="false">https://sterl.org/?p=802</guid>

					<description><![CDATA[Why Quartz? motivation Spring comes already with an own timer and this is fine if we have very simple requirements and we don&#8217;t really care about state or on which pod the timer is actually running. To be more precise the timer/ job is running in each of our spring containers independently. Lets be honest,&#8230;]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Why Quartz? <span class="badge badge-pill badge-primary">motivation</span></h2>



<p>Spring comes already with an own <a rel="noreferrer noopener" href="https://spring.io/guides/gs/scheduling-tasks/" target="_blank">timer</a> and this is fine if we have very simple requirements and we don&#8217;t really care about state or on which pod the timer is actually running. To be more precise the timer/ job is running in each of our spring containers independently.</p>



<p>Lets be honest, this is usually never really the case and so it is common to invite <a rel="noreferrer noopener" href="https://github.com/lukas-krecan/ShedLock" target="_blank">ShedLock</a> to the party. Are we done then?</p>



<p>Usually no, honestly we want in the most cases just a bit more:</p>



<ul class="wp-block-list">
<li>Run jobs in the cluster on different nodes simultaneous</li>



<li>Have a kind of state management </li>



<li>The ability to provide some kind of configuration to each run</li>



<li>Have some kind of way for easy retries etc.</li>
</ul>



<p>Hey why don&#8217;t use Spring Batch then? </p>



<p>Because to have just a timer and not really a batch-job it is somehow the wrong tool. Furthermore Spring-Batch is build with a different goal in mind, where we start a container with one job inside to process mass of data. Quartz is more a timer, which we want to use to trigger either smaller task in our application or run kind of repeating small task and are more concerned to orchestrate and Monitor them.</p>



<ul class="wp-block-list">
<li>Spring Batch = Batch Framework to handle large datasets which should be processed, usually in an own container / pod for the duration of the Job</li>



<li>Quartz = Timer which also supports a JDBC/ REDIS store for smaller timer jobs which should run in our app cluster</li>
</ul>



<h2 class="wp-block-heading">Steps for the integration</h2>



<ul class="wp-block-list">
<li>Setup the DB</li>



<li>Configure <a rel="noreferrer noopener" aria-label="Quartz Scheduler (öffnet in neuem Tab)" href="http://www.quartz-scheduler.org" target="_blank">Quartz Scheduler</a></li>



<li>Configure CDI Job Factory</li>



<li>Register our timers</li>



<li>Set a thread priority for our job</li>
</ul>



<p>Setup the DB</p>



<p>Overall quartz comes with <a rel="noreferrer noopener" href="https://github.com/quartz-scheduler/quartz/tree/master/quartz-core/src/main/resources/org/quartz/impl/jdbcjobstore" target="_blank">SQL scripts and liquibase scripts</a> you may just include. <a href="https://sterl.org/2019/09/quartz-scheduler-integration-in-java-jee/#ipt_kb_toc_378_16">Read here</a>. For unit test we can just simply use the build in feature:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;yaml&quot;,&quot;mime&quot;:&quot;text/x-yaml&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;YAML&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;yaml&quot;}">spring:
  quartz:
    jdbc:
      initialize-schema: always</pre></div>



<h3 class="wp-block-heading">Configure Quartz Scheduler</h3>



<p>We will use the CMT Store here, for more details because of the why <a href="https://sterl.org/2019/09/quartz-scheduler-integration-in-java-jee/#ipt_kb_toc_378_3">please read the following tutorial</a>.</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;xml&quot;,&quot;mime&quot;:&quot;application/xml&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;XML&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;xml&quot;}">		&lt;dependency&gt;
			&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
			&lt;artifactId&gt;spring-boot-starter-quartz&lt;/artifactId&gt;
		&lt;/dependency&gt;
</pre></div>



<p>After adding the dependency we have to configure Quartz, in this example we set the thread count to 2, adjust this value based on your needs. The following configuration will usually create a <code>LocalDataSourceJobStore</code> which is an <code>JobStoreCMT</code>.</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;yaml&quot;,&quot;mime&quot;:&quot;text/x-yaml&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;YAML&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;yaml&quot;}">spring:
  quartz:
    wait-for-jobs-to-complete-on-shutdown: false
    job-store-type: jdbc
    overwrite-existing-jobs: true
    jdbc:
      initialize-schema: always
    properties:
      org.quartz.jobStore.isClustered: true
      org.quartz.scheduler.instanceId: AUTO
      org.quartz.scheduler.skipUpdateCheck: true
      org.quartz.threadPool.threadCount: 2
  
  datasource:
    url: jdbc:h2:file:./quartz-db
    username: sa
    password: 
</pre></div>



<div class="bs-callout bs-callout-info"><strong>Note:</strong>
We init the DB just with quartz itself. But quartz contains in the core a liquibase and a SQL file which you may include into your DB update process.
</div>



<p>Yes thats basically it, we will discuss details in further deep dives, but for now lets gets a job running.</p>



<h3 class="wp-block-heading">Create a timer Job</h3>



<p>To setup a timer we have to:</p>



<ol class="wp-block-list">
<li><span style="color: initial; font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Oxygen-Sans, Ubuntu, Cantarell, &quot;Helvetica Neue&quot;, sans-serif;">Add a job class</span></li>



<li>Configure the timer</li>
</ol>



<h4 class="wp-block-heading">Add a Spring configuration</h4>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">// runs only one of these jobs in out cluster
// note we have no spring annotation here, but it contains spring beans
@DisallowConcurrentExecution 
public class QuatzTimerJob implements Job {
	// we can use spring beans, yes we cam
    @Autowired YourService yourService;
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
		yourService.doSomething();
    }

}</pre></div>



<h4 class="wp-block-heading">Configure the timer</h4>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">@Configuration
public class QuartzTimerConfiguration {
	// this registers our job itself
    @Bean
    public JobDetailFactoryBean quatzTimerJob() {
        final var jobDetailFactory = new JobDetailFactoryBean();
        jobDetailFactory.setJobClass(QuatzTimerJob.class);
        jobDetailFactory.setDescription(&quot;Simple timer like @Scheduled - but already like with ShedLock&quot;);
        jobDetailFactory.setDurability(true);
        return jobDetailFactory;
    }
    // here we add the timer, in this case every 30s, with a lower priority as normal for the job
    @Bean
    public SimpleTriggerFactoryBean trigger(JobDetail quatzTimerJob) {
        final var trigger = new SimpleTriggerFactoryBean();
        trigger.setJobDetail(quatzTimerJob);
        trigger.setRepeatInterval(30_000);
        trigger.setPriority(Thread.NORM_PRIORITY - 1);
        trigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
        return trigger;
    }
}</pre></div>



<h3 class="wp-block-heading">Trigger a job</h3>



<p>In difference to a normal Spring timer we may now fire triggers for Quartz Jobs, even add data to the triggers itself, at let Quartz handle the heavy work for us. Handy if we want QUEUE some work, or just distribute the load in our cluster to all available nodes. For this we have to:</p>



<ol class="wp-block-list">
<li>Create a job instance we want to execute</li>



<li>Configure the job &#8211; but now without any default trigger</li>



<li>Create somewhere in our code the triggers, usually with some payload data</li>
</ol>



<h4 class="wp-block-heading">Create a job</h4>



<p>Very simple thing here, just getting one value from the job context and calling out service.</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">public class TriggeredJob implements Job {

    @Autowired YourService yourService;
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        long count = context.getMergedJobDataMap().getLong(&quot;count&quot;));
        yourService.doSomething(count);
    }

}</pre></div>



<h4 class="wp-block-heading">Configure the job</h4>



<p>The only special thing here is that we request a recovery on a different node, should this node for some reason die during the execution of the job.</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">@Configuration
public class QuartzJobConfiguration {
    @Bean
    public JobDetailFactoryBean createStoreItemsJob() {
        final var jobDetailFactory = new JobDetailFactoryBean();
        jobDetailFactory.setJobClass(CreateStoreItemsJob.class);
        jobDetailFactory.setDescription(&quot;Job we directly trigger if we want to run it&quot;);
        jobDetailFactory.setDurability(true);
        jobDetailFactory.setRequestsRecovery(true);
        return jobDetailFactory;
    }
}</pre></div>



<h4 class="wp-block-heading">Trigger the job</h4>



<div class="bs-callout bs-callout-info"><strong>Note:</strong>
The usage of <code>@Transactional</code>, this is by purpose, to ensure the trigger gets removed if we happen to rollback the transaction. If it is missing, quartz will silently create an own one.
</div>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">    @Autowired Scheduler scheduler;
    @Autowired JobDetail createStoreItemsJob;

    @Transactional
    public void triggerStoreItemCreation() throws SchedulerException {
        Trigger t = TriggerBuilder.newTrigger()
            .forJob(createStoreItemsJob)
            .startNow() // run on this node if possible, means we have threads
            .usingJobData(&quot;count&quot;, count)
            .build();
        
        scheduler.scheduleJob(t);
    }</pre></div>



<h2 class="wp-block-heading">Testing it</h2>



<p>You may wonder why we used a file DB in this configuration. Only with a DB which contains the trigger data after a restart you may play around and also kill the running Spring application. After a restart the jobs are triggered again.</p>



<h2 class="wp-block-heading">Alternatives</h2>



<p>We could also go for a command queue using e.g. JMS. This aproach would require  additional infrastructure in form of a persistent broker. Which could be easy in the cloud but rather difficult if you have to operate and maintain it on your own. In the end a data store which have to join our DB transactions in case ACID is an issue and it always is.</p>



<h2 class="wp-block-heading">Links</h2>



<ul class="wp-block-list">
<li><a href="https://github.com/sterlp/training/tree/master/spring-quartz">https://github.com/sterlp/training/tree/master/spring-quartz</a></li>



<li><a href="https://spring.getdocs.org/en-US/spring-boot-docs/boot-features/boot-features-quartz.html">https://spring.getdocs.org/en-US/spring-boot-docs/boot-features/boot-features-quartz.html</a></li>



<li><a href="http://www.quartz-scheduler.org/documentation/quartz-2.3.0/cookbook/">http://www.quartz-scheduler.org/documentation/quartz-2.3.0/cookbook/</a></li>
</ul>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://sterl.org/2022/07/quartz-integration-in-spring/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Disable @Scheduled timers for test in Spring</title>
		<link>https://sterl.org/2022/05/disable-scheduled-timers-for-test-in-spring/</link>
					<comments>https://sterl.org/2022/05/disable-scheduled-timers-for-test-in-spring/#respond</comments>
		
		<dc:creator><![CDATA[Paul Sterl]]></dc:creator>
		<pubDate>Mon, 02 May 2022 09:18:37 +0000</pubDate>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[Testing]]></category>
		<category><![CDATA[@Scheduled]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[timer]]></category>
		<category><![CDATA[Unit Test]]></category>
		<guid isPermaLink="false">https://sterl.org/?p=770</guid>

					<description><![CDATA[Problem As soon we have timers in our project they may cause issues in our integration tests, as they start running in the most undesirable situation. E.g. during the trigger a specific function which would usually be triggered by the timer. Solution 1 If we want to disable the timers even the construction of the&#8230;]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Problem</h2>



<p>As soon we have timers in our project they may cause issues in our integration tests, as they start running in the most undesirable situation. E.g. during the trigger a specific function which would usually be triggered by the timer.</p>



<h2 class="wp-block-heading">Solution 1</h2>



<p>If we want to disable the timers even the construction of the beans we have to tell spring not event to lead the beans. To achieve that we require first some configuration. As we might have more than one timer it is easier to work with an own meta annotaton</p>



<h3 class="wp-block-heading">Own Meta annotation</h3>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Java&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">@ConditionalOnProperty(name = &quot;my-project.timers-enabled&quot;, 
                       havingValue = &quot;true&quot;, 
                       matchIfMissing = true)
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
public @interface TimersEnabled {

}</pre></div>



<h3 class="wp-block-heading">Use the annotation</h3>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Java&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">@TimersEnabled
@Component
@RequiredArgsConstructor
public class MyTimer {
    
    private final MyService service;

    @Scheduled(fixedDelay = 30, timeUnit = TimeUnit.SECONDS)
    void scheduledMethod() {
        service.doStuff();
    }
}</pre></div>



<h3 class="wp-block-heading">Disable the timers</h3>



<p>e.g. in the <code>application.yml</code> of your test resources:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;yaml&quot;,&quot;mime&quot;:&quot;text/x-yaml&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;YAML&quot;,&quot;language&quot;:&quot;YAML&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;yaml&quot;}">my-project:
  timers-enabled: false</pre></div>



<p>The timers will be disabled for any value other then <code>true</code>. </p>



<h2 class="wp-block-heading">Solution 2</h2>



<p>In the easiest scenario if it is a in memory Spring test we can just mock the <code>ScheduledExecutorService</code> and so stop any <code>@Scheduled</code> job executions.</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">    @MockBean
    private ScheduledExecutorService schedulerService;</pre></div>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://sterl.org/2022/05/disable-scheduled-timers-for-test-in-spring/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Spring Boot Redirect to SwaggerUI</title>
		<link>https://sterl.org/2021/05/spring-boot-redirect-to-swaggerui/</link>
					<comments>https://sterl.org/2021/05/spring-boot-redirect-to-swaggerui/#respond</comments>
		
		<dc:creator><![CDATA[Paul Sterl]]></dc:creator>
		<pubDate>Fri, 21 May 2021 13:13:33 +0000</pubDate>
				<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[OpenAPI]]></category>
		<category><![CDATA[Swagger]]></category>
		<category><![CDATA[swagger-ui]]></category>
		<guid isPermaLink="false">https://sterl.org/?p=650</guid>

					<description><![CDATA[Problem Some services don&#8217;t have an UI and the OpenAPI/ Swagger UI should be used as default UI of the service. As so the root should be redirected directly to the SwaggerUI. Solution Just add a WebMvc redirect. Swagger Open API dependencies Spring Boot 2.x Ensure you check the current version: Spring Boot 3.x Ensure&#8230;]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Problem</h2>



<p>Some services don&#8217;t have an UI and the OpenAPI/ Swagger UI should be used as default UI of the service. As so the root should be redirected directly to the SwaggerUI.</p>



<h2 class="wp-block-heading">Solution</h2>



<p>Just add a WebMvc redirect.</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text/x-java&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Java&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;java&quot;}">@Configuration
public class OpenApiConfig implements WebMvcConfigurer {
  @Override
  public void addViewControllers(final ViewControllerRegistry registry) {
    registry.addRedirectViewController(&quot;/&quot;, &quot;/swagger-ui.html&quot;);
    // use setStatusCode(HttpStatus.XYZ) for any custom status code if required, e.g. MOVED_PERMANENTLY
    registry.addRedirectViewController(&quot;/swagger-ui&quot;, &quot;/swagger-ui.html&quot;);
    // any other alias
  }
}</pre></div>



<h3 class="wp-block-heading">Swagger Open API dependencies</h3>



<h4 class="wp-block-heading">Spring Boot 2.x</h4>



<p>Ensure you <a href="https://central.sonatype.com/search?q=springdoc-openapi-ui&amp;namespace=org.springdoc" target="_blank" rel="noreferrer noopener">check the current version</a>: </p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;xml&quot;,&quot;mime&quot;:&quot;application/xml&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;XML&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;xml&quot;}">        &lt;dependency&gt;
            &lt;groupId&gt;org.springdoc&lt;/groupId&gt;
            &lt;artifactId&gt;springdoc-openapi-ui&lt;/artifactId&gt;
            &lt;version&gt;1.7.0&lt;/version&gt;
        &lt;/dependency&gt;
       &lt;!-- if spring security is used --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springdoc&lt;/groupId&gt;
            &lt;artifactId&gt;springdoc-openapi-security&lt;/artifactId&gt;
            &lt;version&gt;1.7.0&lt;/version&gt;
        &lt;/dependency&gt;</pre></div>



<h4 class="wp-block-heading">Spring Boot 3.x</h4>



<p>Ensure you <a href="https://central.sonatype.com/search?q=springdoc-openapi-starter-webmvc-ui&amp;namespace=org.springdoc" target="_blank" rel="noreferrer noopener">check the current version</a>:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;xml&quot;,&quot;mime&quot;:&quot;application/xml&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;XML&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;xml&quot;}">        &lt;dependency&gt;
            &lt;groupId&gt;org.springdoc&lt;/groupId&gt;
            &lt;artifactId&gt;springdoc-openapi-starter-webmvc-ui&lt;/artifactId&gt;
            &lt;version&gt;2.1.0&lt;/version&gt;
        &lt;/dependency&gt;</pre></div>



<p>With the new version you can also use the <code>application.yml</code> to configure the root directory as swagger ui:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;yaml&quot;,&quot;mime&quot;:&quot;text/x-yaml&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;YAML&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;yaml&quot;}">springdoc:
  swagger-ui:
    use-root-path: true</pre></div>



<h2 class="wp-block-heading">Links</h2>



<ul class="wp-block-list">
<li><a rel="noreferrer noopener" href="https://springdoc.org/" target="_blank">https://springdoc.org/</a></li>



<li><a href="https://springdoc.org/v2/">https://springdoc.org/v2/</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://sterl.org/2021/05/spring-boot-redirect-to-swaggerui/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
