<?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>INOTEQ GmbH</title>
	<atom:link href="https://www.inoteq.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.inoteq.com/</link>
	<description>IT Unternehmensberatung, Software Entwicklung, IT Infrastruktur aus Karlsruhe</description>
	<lastBuildDate>Thu, 17 Oct 2024 06:32:43 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.4.5</generator>

<image>
	<url>https://www.inoteq.com/wp-content/uploads/2019/12/cropped-Inoteq_Logo_trans_icon-1-32x32.png</url>
	<title>INOTEQ GmbH</title>
	<link>https://www.inoteq.com/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Effiziente Java-Anwendungsentwicklung mit Quarkus und GraalVM</title>
		<link>https://www.inoteq.com/2024/09/30/effiziente-java-anwendungsentwicklung-mit-quarkus-und-graalvm/</link>
					<comments>https://www.inoteq.com/2024/09/30/effiziente-java-anwendungsentwicklung-mit-quarkus-und-graalvm/#respond</comments>
		
		<dc:creator><![CDATA[Alexander Kusmin]]></dc:creator>
		<pubDate>Mon, 30 Sep 2024 09:58:15 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[GraalVM]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Quarkus]]></category>
		<guid isPermaLink="false">https://www.inoteq.com/?p=3276</guid>

					<description><![CDATA[<p>Die fortschreitende Verlagerung von Anwendungen in cloudnative Umgebungen sowie der zunehmende Trend zu Microservices konfrontieren die Java-Entwicklung mit neuen Herausforderungen. Als langjähriger Standard für Unternehmensanwendungen wurde Spring Boot von vielen Entwicklern für seine Flexibilität und umfangreiche Funktionalität geschätzt. Mit steigenden Anforderungen an schnelle Startzeiten, geringen Speicherverbrauch und optimierte Ressourcennutzung, insbesondere in containerbasierten Architekturen, stößt Spring Boot [&#8230;]</p>
<p>Der Beitrag <a href="https://www.inoteq.com/2024/09/30/effiziente-java-anwendungsentwicklung-mit-quarkus-und-graalvm/">Effiziente Java-Anwendungsentwicklung mit Quarkus und GraalVM</a> erschien zuerst auf <a href="https://www.inoteq.com">INOTEQ GmbH</a>.</p>
]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="3276" class="elementor elementor-3276" data-elementor-post-type="post">
						<section class="elementor-section elementor-top-section elementor-element elementor-element-1d309ca elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="1d309ca" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-78d3fa1" data-id="78d3fa1" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-93b5d8d elementor-widget elementor-widget-spacer" data-id="93b5d8d" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-81ef36b elementor-widget elementor-widget-html" data-id="81ef36b" data-element_type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
			<!-- Only for Code Snippet Styles -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/themes/prism-coy.min.css" integrity="sha256-VcuSs+n31yebPlEcehu6PvnidJ808ScFBsK8+tJKX+Q=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/components/prism-core.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/plugins/autoloader/prism-autoloader.min.js"></script>
<style>
    :not(pre) > code[class*=language-].inline {
        padding: 0 0.2rem;
        color: #000;
    }
</style>		</div>
				</div>
				<div class="elementor-element elementor-element-9fb89c5 elementor-widget elementor-widget-theme-post-title elementor-page-title elementor-widget-heading" data-id="9fb89c5" data-element_type="widget" data-widget_type="theme-post-title.default">
				<div class="elementor-widget-container">
			<h1 class="elementor-heading-title elementor-size-default">Effiziente Java-Anwendungsentwicklung mit Quarkus und GraalVM</h1>		</div>
				</div>
				<div class="elementor-element elementor-element-c74a7b9 elementor-widget elementor-widget-post-info" data-id="c74a7b9" data-element_type="widget" data-widget_type="post-info.default">
				<div class="elementor-widget-container">
					<ul class="elementor-inline-items elementor-icon-list-items elementor-post-info">
								<li class="elementor-icon-list-item elementor-repeater-item-5df6a58 elementor-inline-item" itemprop="datePublished">
						<a href="https://www.inoteq.com/2024/09/30/">
											<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="fas fa-calendar"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-date">
										September 30, 2024					</span>
									</a>
				</li>
				<li class="elementor-icon-list-item elementor-repeater-item-df87aa6 elementor-inline-item" itemprop="author">
						<a href="https://www.inoteq.com/author/akusmin/">
											<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="far fa-user-circle"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-author">
										Alexander Kusmin					</span>
									</a>
				</li>
				</ul>
				</div>
				</div>
				<div class="elementor-element elementor-element-7807245 elementor-widget elementor-widget-text-editor" data-id="7807245" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die fortschreitende Verlagerung von Anwendungen in cloudnative Umgebungen sowie der zunehmende Trend zu Microservices konfrontieren die Java-Entwicklung mit neuen Herausforderungen. Als langjähriger Standard für Unternehmensanwendungen wurde <a href="https://spring.io/projects/spring-boot" target="_blank" rel="noopener">Spring Boot</a> von vielen Entwicklern für seine Flexibilität und umfangreiche Funktionalität geschätzt. Mit steigenden Anforderungen an schnelle Startzeiten, geringen Speicherverbrauch und optimierte Ressourcennutzung, insbesondere in containerbasierten Architekturen, stößt Spring Boot jedoch in bestimmten Szenarien an seine Grenzen.</p><p><a href="https://quarkus.io/" target="_blank" rel="noopener">Quarkus</a> präsentiert sich als zeitgenössisches Java-Framework, das eigens für die Erfordernisse cloud-nativer Umgebungen konzipiert wurde. Es verspricht nicht nur kürzere Startzeiten und geringeren Speicherbedarf, sondern besticht insbesondere durch seine enge Integration mit <a href="https://www.graalvm.org/" target="_blank" rel="noopener">GraalVM</a>. Letztere virtuelle Maschine ermöglicht die Erstellung nativer ausführbarer Anwendungen, wodurch sich Java-Anwendungen noch effizienter gestalten lassen.</p><p>Der vorliegende Artikel bietet einen Überblick über die Möglichkeiten und Vorteile der Kombination von Quarkus und GraalVM und zeigt auf, in welchen Bereichen sie sich besonders bewähren. Neben der Betrachtung der nativen Images wird auch der Entwicklungsprozess im Fokus stehen, um zu beleuchten, wie moderne Java-Entwicklung effizient gestaltet werden kann.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-de6d880 elementor-widget elementor-widget-theme-post-featured-image elementor-widget-image" data-id="de6d880" data-element_type="widget" data-widget_type="theme-post-featured-image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img fetchpriority="high" decoding="async" width="2500" height="1500" src="https://www.inoteq.com/wp-content/uploads/2024/09/Untitled.png" class="attachment-full size-full wp-image-3319" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2024/09/Untitled.png 2500w, https://www.inoteq.com/wp-content/uploads/2024/09/Untitled-300x180.png 300w, https://www.inoteq.com/wp-content/uploads/2024/09/Untitled-1024x614.png 1024w, https://www.inoteq.com/wp-content/uploads/2024/09/Untitled-768x461.png 768w, https://www.inoteq.com/wp-content/uploads/2024/09/Untitled-1536x922.png 1536w, https://www.inoteq.com/wp-content/uploads/2024/09/Untitled-2048x1229.png 2048w" sizes="(max-width: 2500px) 100vw, 2500px" />											<figcaption class="widget-image-caption wp-caption-text">KI generiertes Symbolbild: A container on a cloud with a simple background.</figcaption>
										</figure>
							</div>
				</div>
				<div class="elementor-element elementor-element-201d0d5 elementor-toc--minimized-on-tablet elementor-widget elementor-widget-table-of-contents" data-id="201d0d5" data-element_type="widget" data-settings="{&quot;exclude_headings_by_selector&quot;:&quot;.exclude-from-toc&quot;,&quot;headings_by_tags&quot;:[&quot;h2&quot;,&quot;h3&quot;,&quot;h4&quot;,&quot;h5&quot;,&quot;h6&quot;],&quot;marker_view&quot;:&quot;numbers&quot;,&quot;minimize_box&quot;:&quot;yes&quot;,&quot;minimized_on&quot;:&quot;tablet&quot;,&quot;hierarchical_view&quot;:&quot;yes&quot;,&quot;min_height&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;min_height_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;min_height_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}" data-widget_type="table-of-contents.default">
				<div class="elementor-widget-container">
					<div class="elementor-toc__header">
			<h4 class="elementor-toc__header-title">
				Table of Contents			</h4>
							<div class="elementor-toc__toggle-button elementor-toc__toggle-button--expand" role="button" tabindex="0" aria-controls="elementor-toc__201d0d5" aria-expanded="true" aria-label="Open table of contents"><i aria-hidden="true" class="fas fa-chevron-down"></i></div>
				<div class="elementor-toc__toggle-button elementor-toc__toggle-button--collapse" role="button" tabindex="0" aria-controls="elementor-toc__201d0d5" aria-expanded="true" aria-label="Close table of contents"><i aria-hidden="true" class="fas fa-chevron-up"></i></div>
					</div>
		<div id="elementor-toc__201d0d5" class="elementor-toc__body">
			<div class="elementor-toc__spinner-container">
				<i class="elementor-toc__spinner eicon-animation-spin eicon-loading" aria-hidden="true"></i>			</div>
		</div>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-01a996d elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="01a996d" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-6bed0ff" data-id="6bed0ff" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-af482ff elementor-widget elementor-widget-spacer" data-id="af482ff" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-efa6f9b elementor-widget elementor-widget-heading" data-id="efa6f9b" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Quarkus und GraalVM im Überblick</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-ec16476 elementor-widget elementor-widget-heading" data-id="ec16476" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Quarkus: Ein Java-Framework für Cloud-native Workloads</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-eb2ea84 elementor-widget elementor-widget-text-editor" data-id="eb2ea84" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Quarkus ist ein modernes Java-Framework, das speziell für die Anforderungen in <b>Cloud-native</b> Umgebungen und <b>Microservices</b>-Architekturen konzipiert wurde. Es zeichnet sich durch extrem kurze Startzeiten, geringen Speicherbedarf und eine besonders effiziente Nutzung von Ressourcen aus. Diese Eigenschaften machen Quarkus insbesondere für Anwendungen attraktiv, die in <b>containerisierten Umgebungen</b> oder <b>serverlosen Architekturen</b> betrieben werden, da dort Geschwindigkeit und Effizienz von entscheidender Bedeutung sind.</p><p>Im Gegensatz zu traditionellen Java-Frameworks erfolgt bei Quarkus eine Optimierung der Build- und Laufzeitphasen. Dies wird dadurch erreicht, dass Teile der Verarbeitung, welche normalerweise zur Laufzeit stattfinden, bereits zur Build-Zeit durchgeführt werden. Dieser als &#8222;Build Time Boot&#8220; bezeichnete Ansatz resultiert in einer signifikanten Reduktion der Startzeit und des Ressourcenverbrauchs zur Laufzeit.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-e376bda elementor-widget elementor-widget-heading" data-id="e376bda" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">GraalVM: Eine virtuelle Maschine der nächsten Generation</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-714cb3f elementor-widget elementor-widget-text-editor" data-id="714cb3f" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die Erweiterung des Potenzials von Quarkus erfolgt durch GraalVM. Die <b>polyglotte virtuelle Maschine</b> ermöglicht die Ausführung von Anwendungen, die in verschiedenen Programmiersprachen wie Java, JavaScript, Python oder Ruby geschrieben wurden, in einer gemeinsamen Umgebung. GraalVM bietet dabei nicht nur Flexibilität hinsichtlich der Sprache, sondern auch die Möglichkeit, Java-Anwendungen als <b>native Images</b> zu kompilieren. Native Images starten in Millisekunden und benötigen im Vergleich zu herkömmlichen JVM-basierten Anwendungen wesentlich weniger Speicher.</p><p>Die enge Integration von Quarkus und GraalVM ermöglicht es Java-Entwicklern, von den Vorteilen beider Technologien zu profitieren und hochoptimierte Anwendungen zu entwickeln, die sowohl in traditionellen als auch in modernen Umgebungen effizient betrieben werden können.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-01fea60 elementor-widget elementor-widget-heading" data-id="01fea60" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Quarkus und GraalVM gemeinsam: Synergieeffekte</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-1705c0a elementor-widget elementor-widget-text-editor" data-id="1705c0a" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die Kombination von Quarkus und GraalVM eröffnet Entwicklern völlig neue Möglichkeiten, Java-Anwendungen zu erstellen, die die Effizienz moderner Infrastruktur-Architekturen voll ausschöpfen können. Während Quarkus als Framework für die Optimierung von Java-Anwendungen in Cloud- und containerisierten Umgebungen konzipiert wurde, hebt GraalVM diese Optimierungen auf die nächste Ebene, indem es Java-Code in native ausführbare Anwendungen umwandelt.</p><p>Durch die enge Integration profitieren Anwendungen nicht nur von den typischen Vorteilen einer schnellen JVM-Umgebung, sondern auch von der Fähigkeit, als native Images bereitgestellt zu werden. Dies führt zu einer signifikanten Verbesserung der Startzeit, da native Anwendungen ohne die Last einer JVM schneller hochfahren. Gleichzeitig wird der Speicherverbrauch drastisch reduziert, was in Container-Umgebungen oder bei serverlosen Architekturen, wo schnelle Skalierbarkeit und Effizienz entscheidend sind, besonders wichtig ist.</p><p>Ein weiterer Synergieeffekt ergibt sich durch den Build Time Boot Ansatz von Quarkus, der die Anwendungsinitialisierung in die Build-Zeit verlagert. Dies ergänzt sich ideal mit der Native Image Funktion von GraalVM, die darauf abzielt, zur Kompilierzeit so viele Metadaten wie möglich zu generieren. Diese kombinierte Optimierung verringert die Last zur Laufzeit erheblich.</p><p>Zusammen bieten Quarkus und GraalVM Entwicklern die Möglichkeit, Anwendungen zu erstellen, die sich besonders gut für den Betrieb in Cloud-nativen Umgebungen eignen. Durch die geringeren Ressourcenanforderungen und die schnelleren Startzeiten wird die Effizienz bei der Verwaltung von dynamisch skalierbaren Workloads erheblich gesteigert.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-bc97332 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="bc97332" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-2e26e89" data-id="2e26e89" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-0472bb5 elementor-widget elementor-widget-spacer" data-id="0472bb5" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-7f4cf68 elementor-widget elementor-widget-heading" data-id="7f4cf68" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Unterschiede im Entwicklungsprozess</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-c97edd4 elementor-widget elementor-widget-text-editor" data-id="c97edd4" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Der Entwicklungsprozess mit Quarkus in Kombination mit GraalVM unterscheidet sich in wesentlichen Punkten von traditionellen Java-Frameworks wie Spring Boot. Diese Unterschiede betreffen sowohl die Art und Weise, wie Anwendungen entwickelt, getestet und bereitgestellt werden, als auch die damit verbundenen Optimierungen und Anforderungen.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-95def7e elementor-widget elementor-widget-heading" data-id="95def7e" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Build Time Optimierung und Laufzeit-Effizienz</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-3bcf7ff elementor-widget elementor-widget-text-editor" data-id="3bcf7ff" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Ein zentraler Unterschied im Entwicklungsprozess liegt in der Art, wie Quarkus den <b>Build Time Boot Ansatz</b> verfolgt. Im Gegensatz zu herkömmlichen Java-Frameworks wie Spring Boot, das viele Initialisierungsschritte zur Laufzeit durchführt, verschiebt Quarkus diese Schritte in die Build-Zeit. Dadurch wird nicht nur die Startzeit der Anwendung drastisch verkürzt, sondern auch der Speicherverbrauch zur Laufzeit reduziert. Entwickler müssen sich deshalb bereits während der Entwicklung stärker auf den Build-Prozess konzentrieren, da viele Optimierungen und Anwendungslogiken zur Kompilierzeit festgelegt werden. Während der Build-Prozess bei Quarkus gezielt optimiert wird, um Native Images zu erzeugen, nutzt Spring Boot traditionell die HotSpot-JVM. Die daraus resultierende Startzeit für Quarkus-Anwendungen kann bis zu 90 % schneller sein als die von Spring Boot, was insbesondere in Cloud-Umgebungen von großem Vorteil ist.</p><p>In Kombination mit GraalVM bedeutet dies, dass der native Compiler zur Erzeugung von native Images besonders viel Vorarbeit während des Builds leistet. Dies erhöht zwar die Build-Zeit, führt aber zu einer extrem schlanken und effizienten Anwendung zur Laufzeit.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-96b2250 elementor-widget elementor-widget-heading" data-id="96b2250" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Speicherauslastung</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-869ec20 elementor-widget elementor-widget-text-editor" data-id="869ec20" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Ein weiteres wesentliches Merkmal von Quarkus ist die geringe Speicherauslastung. Quarkus-Anwendungen, die als Native Image erstellt werden, benötigen häufig nur 20-50 MB RAM, während Spring Boot-Anwendungen in der Regel zwischen 80 MB und 200 MB RAM verbrauchen. Diese reduzierte Ressourcennutzung führt zu geringeren Betriebskosten und verbessert die Effizienz, besonders in Microservices-Architekturen, wo viele Instanzen gleichzeitig laufen können.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-b642b27 elementor-widget elementor-widget-heading" data-id="b642b27" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Entwicklungsumgebung und Tools</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-96c7468 elementor-widget elementor-widget-text-editor" data-id="96c7468" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Quarkus bietet Entwicklern eine Vielzahl an Tools, die die Produktivität erheblich steigern. Eine der herausragenden Funktionen ist der <b>Dev-Mode</b>, der es ermöglicht, Änderungen im Code live und ohne Neustart der Anwendung zu testen. Diese Live-Coding-Fähigkeit spart nicht nur Entwicklungszeit, sondern sorgt auch für ein schnelles Feedback auf Änderungen, was bei der iterativen Entwicklung von großem Vorteil ist. Zudem ermöglicht Quarkus eine reibungslose Integration in moderne CI/CD-Pipelines, was die gesamte Entwicklungsumgebung benutzerfreundlich und effizient gestaltet.</p><p>Im Vergleich dazu nutzt Spring Boot bereits etablierte Tools und Bibliotheken, die zwar leistungsfähig sind, jedoch in Bezug auf Cloud-native Anwendungen und schnelle Iterationen weniger optimiert sind. Während Spring Boot ebenfalls starke Entwicklungswerkzeuge bereitstellt, kann die mangelnde Flexibilität im Entwicklungsprozess in dynamischen Umgebungen zu längeren Wartezeiten führen. Die Nutzung von GraalVM, die zusätzliche Schritte erfordert, um sicherzustellen, dass die Anwendung zur Kompilierzeit analysiert und optimiert werden kann, bringt ebenfalls Herausforderungen mit sich. Bestimmte Funktionen wie Reflection oder Dynamic Proxies, die in JVM-basierten Anwendungen oft selbstverständlich sind, müssen in GraalVM-konformen Anwendungen explizit konfiguriert werden, was <b>zusätzliche Entwicklungsressourcen</b> in Anspruch nehmen kann.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-49efd3d elementor-widget elementor-widget-heading" data-id="49efd3d" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Testing und Debugging</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-209483c elementor-widget elementor-widget-text-editor" data-id="209483c" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Das Testing und Debugging ist bei der Entwicklung mit Quarkus und GraalVM ebenfalls unterschiedlich im Vergleich zu traditionellen JVM-Anwendungen. Während Spring Boot typischerweise eine JVM-basierte Entwicklungsumgebung nutzt, in der Tests und Debugging-Prozesse direkt in der JVM ausgeführt werden, erlaubt Quarkus die Entwicklung sowohl in der JVM als auch im nativen Modus. Der native Modus bietet zwar bessere Laufzeiteigenschaften, kann jedoch das Debugging erschweren, da es in nativen Anwendungen keine JVM gibt, die typische Werkzeuge wie JVM Debugger oder JMX unterstützt.</p><p>Daher müssen Entwickler beim Einsatz von GraalVM für native Anwendungen auf andere Debugging- und Analysetools zurückgreifen oder den Großteil ihrer Tests in der JVM durchführen, bevor sie die Anwendung als natives Image bereitstellen.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-be8f8fe elementor-widget elementor-widget-heading" data-id="be8f8fe" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Bereitstellung und Skalierung in Cloud-Umgebungen</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-4b9833f elementor-widget elementor-widget-text-editor" data-id="4b9833f" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<div><p>Quarkus in Kombination mit GraalVM bietet klare Vorteile bei der Bereitstellung und Skalierung von Anwendungen, insbesondere in Cloud-Umgebungen. Die schnelleren Startzeiten und der geringere Speicherverbrauch machen Quarkus-Anwendungen besonders geeignet für Microservices-Architekturen und containerisierte Umgebungen wie <a href="https://kubernetes.io/" target="_blank" rel="noopener">Kubernetes</a> oder <a href="https://www.redhat.com/en/technologies/cloud-computing/openshift" target="_blank" rel="noopener">OpenShift</a>. Diese speziellen Optimierungen für containerisierte Workloads ermöglichen es Quarkus, in solchen Einsatzszenarien signifikant zu profitieren.</p><p>In Bezug auf die Leistung zeigt sich, dass Quarkus in containerisierten Umgebungen häufig bessere Ergebnisse erzielt. Die Kombination aus schnellerer Startzeit und optimierter Ressourcennutzung führt dazu, dass Quarkus oft eine überlegene Performance im Vergleich zu Spring Boot bietet, insbesondere in Szenarien, in denen viele kleine Dienste schnell skaliert werden müssen. Während Spring Boot für viele traditionelle Unternehmensanwendungen eine ausreichende Leistung bietet, sind die Vorteile von Quarkus in modernen Architekturen mit hohen Anforderungen an Reaktionsgeschwindigkeit und Ressourcenschonung unbestreitbar.</p></div>						</div>
				</div>
				<div class="elementor-element elementor-element-8425466 elementor-widget elementor-widget-heading" data-id="8425466" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Integration von Spring mit GraalVM</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-27b0830 elementor-widget elementor-widget-text-editor" data-id="27b0830" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die Integration von Spring mit GraalVM ist möglich und bietet sowohl Vor- als auch Nachteile. Einer der Hauptvorteile ist die deutliche Verbesserung der Startzeiten und des Speicherverbrauchs durch die Erstellung nativer Images. Allerdings bringt die Erstellung nativer Images auch Herausforderungen mit sich, wie eine erhöhte Komplexität bei der Konfiguration und die Notwendigkeit, sicherzustellen, dass alle benötigten Ressourcen zur Compile-Zeit vorhanden sind. Darüber hinaus sind nicht alle dynamischen Features von Spring vollständig mit GraalVM kompatibel, was Einschränkungen bei der Nutzung bestimmter Funktionalitäten zur Folge haben kann.</p><p>Insgesamt kann die Kombination von Spring und GraalVM die Leistung und Effizienz von Anwendungen steigern, erfordert jedoch sorgfältige Planung und möglicherweise Anpassungen im Code.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-507d09a elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="507d09a" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-40aee06" data-id="40aee06" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-9e30bb1 elementor-widget elementor-widget-spacer" data-id="9e30bb1" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-f3e1bcc elementor-widget elementor-widget-heading" data-id="f3e1bcc" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Beispiel: Erstellen eines Quarkus-Projekts mit GraalVM</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-1d1224c elementor-widget elementor-widget-text-editor" data-id="1d1224c" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Zur Veranschaulichung wird ein neues Quarkus-Projekt unter Verwendung von IntelliJ erstellt. Dabei ist zu beachten, dass GraalVM auf dem System installiert sein muss und die entsprechende Umgebungsvariable gesetzt werden muss. Für die Konfiguration kann die <a href="https://www.graalvm.org/latest/getting-started/" target="_blank" rel="noopener">offizielle Anleitung</a> herangezogen werden, da die Vorgehensweisen von System zu System variieren können.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-1016602 elementor-widget elementor-widget-image" data-id="1016602" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img decoding="async" width="800" height="739" src="https://www.inoteq.com/wp-content/uploads/2024/09/Screenshot-2024-10-01-at-11.10.31-1024x946.png" class="attachment-large size-large wp-image-3296" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2024/09/Screenshot-2024-10-01-at-11.10.31-1024x946.png 1024w, https://www.inoteq.com/wp-content/uploads/2024/09/Screenshot-2024-10-01-at-11.10.31-300x277.png 300w, https://www.inoteq.com/wp-content/uploads/2024/09/Screenshot-2024-10-01-at-11.10.31-768x709.png 768w, https://www.inoteq.com/wp-content/uploads/2024/09/Screenshot-2024-10-01-at-11.10.31-1536x1419.png 1536w, https://www.inoteq.com/wp-content/uploads/2024/09/Screenshot-2024-10-01-at-11.10.31.png 1702w" sizes="(max-width: 800px) 100vw, 800px" />											<figcaption class="widget-image-caption wp-caption-text">Erstellung und Konfiguration eines neuen Quarkus-Projekts in IntelliJ</figcaption>
										</figure>
							</div>
				</div>
				<div class="elementor-element elementor-element-568cbda elementor-widget elementor-widget-text-editor" data-id="568cbda" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							Die Konfiguration kann nach Belieben angepasst werden. Im vorliegenden Beispiel wird Gradle verwendet, wobei zusätzlich <code class="inline">'io.quarkus:quarkus-rest'</code> als Abhängigkeit hinzugefügt wurde, um einen Beispiel Endpunkt zu verwenden. Von entscheidender Bedeutung ist hierbei die Auswahl von GraalVM als JDK.

Im vorliegenden einfachen Beispiel wurde der Endpunkt auf den Pfad <code class="inline">/hello</code> gelegt, wobei lediglich ein String als Rückgabewert generiert wird.
<pre><code class="language-java">@Path("/hello")
public class ExampleResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "Hello from Quarkus REST";
    }
}</code></pre>
Die Erzeugung eines Native Images erfolgt durch Ausführung des Befehls <code class="inline">./gradlew buildNative</code>. Nach Abschluss des Vorgangs wird im build-Ordner eine ausführbare Datei angelegt. Im vorliegenden Beispiel handelt es sich um die Datei <code class="inline">demo-1.0-SNAPSHOT-runner</code>, welche durch Eingabe von <code class="inline">./build/demo-1.0-SNAPSHOT-runner</code> in das Terminal gestartet werden kann. Die Ausführung von Quarkus ist unmittelbar zu beobachten und der definierte Endpunkt ist aufrufbar.						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-c7a8727 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="c7a8727" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-efc3ae9" data-id="efc3ae9" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-edb4102 elementor-widget elementor-widget-spacer" data-id="edb4102" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-d75b493 elementor-widget elementor-widget-heading" data-id="d75b493" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Native Images von GraalVM</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-c52a648 elementor-widget elementor-widget-text-editor" data-id="c52a648" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>GraalVM ermöglicht die Erstellung von nativen Images, die aus Java-Anwendungen kompiliert werden. Diese nativen Images sind selbstständig ausführbare Dateien, die <b>keine JVM zur Ausführung</b> benötigen. Sie bieten erhebliche Vorteile, darunter verbesserte Startzeiten, geringeren Speicherverbrauch und eine verbesserte Portabilität zwischen verschiedenen Umgebungen. Native Images sind insbesondere in Cloud-nativen und containerisierten Architekturen von Bedeutung, wo schnelle Startzeiten und effiziente Ressourcennutzung entscheidend sind.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-4e33986 elementor-widget elementor-widget-heading" data-id="4e33986" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Erstellung von Native Images</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-5031780 elementor-widget elementor-widget-text-editor" data-id="5031780" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die Erstellung von Native Images erfolgt über den GraalVM-Compiler, welcher die Java-Anwendung zunächst analysiert, um darauf aufbauend die Umwandlung in eine ausführbare Datei vorzunehmen. Der Prozess umfasst mehrere Schritte:</p><ol><li>Im Rahmen der Kompilierung erfolgt die Umwandlung des Quellcodes in Bytecode durch den GraalVM-Compiler. Dabei findet eine Analyse des Codes statt, um die benötigten Klassen, Methoden und Ressourcen zu identifizieren.</li><li>AOT-Kompilierung: Der Compiler erzeugt ein natives Bild der Anwendung, wobei er den Code optimiert und die Ausführung zur Compile-Zeit vorbereitet. Dazu zählt auch die Eliminierung von nicht benötigten Codepfaden.</li><li>Die Vorbereitung von Ressourcen erfolgt durch die Integration aller benötigten Ressourcen, wie etwa Konfigurationsdateien und andere statische Assets, in das native Image, wodurch eine funktionale Unabhängigkeit der Anwendung von externen Dateien sichergestellt wird.</li><li>Des Weiteren werden durch die Anwendung diverse Optimierungsmaßnahmen durchgeführt, welche eine Leistungssteigerung des generierten nativen Images zum Ziel haben. Diesbezüglich ist zunächst die Minimierung des benötigten Speicherplatzes zu nennen. Darüber hinaus erfolgt eine Optimierung der Ausführungszeiten, um die Geschwindigkeit der Anwendung zu erhöhen.</li></ol>						</div>
				</div>
				<div class="elementor-element elementor-element-ad6d642 elementor-widget elementor-widget-heading" data-id="ad6d642" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Vor- und Nachteile von Native Images</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-57a5f81 elementor-widget elementor-widget-text-editor" data-id="57a5f81" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die Verwendung von Native Images ist mit einer Reihe von Vor- und Nachteilen verbunden. Es seien an dieser Stelle einige der bereits genannten Vorteile nochmals aufgeführt, um die nennenswerten Vorteile zu verdeutlichen:</p><ul><li><strong>Schnelle Startzeiten</strong>: Native Images starten in der Regel in wenigen Millisekunden, was sie ideal für serverlose Anwendungen und Microservices macht.</li><li><strong>Geringerer Speicherverbrauch</strong>: Da keine JVM erforderlich ist, benötigen native Images weniger Ressourcen, was die Kosten in Cloud-Umgebungen senkt.</li><li><strong>Portabilität</strong>: Native Images sind plattformunabhängig und können ohne zusätzliche Abhängigkeiten auf verschiedenen Systemen ausgeführt werden.</li></ul><div>Native Images eignen sich hervorragend für Anwendungen, die in containerisierten Umgebungen bereitgestellt werden, wie beispielsweise Microservices, die in Kubernetes laufen. Ein praktisches Beispiel könnte eine REST-API sein, die als Native Image bereitgestellt wird, um die schnelle Reaktionszeit und geringe Speicherauslastung zu demonstrieren.</div><div> </div><div>Es bestehen jedoch auch gewisse Nachteile, die an dieser Stelle nicht unerwähnt bleiben sollten:</div><ul><li><strong>Kompilierungszeit</strong>: Die Erstellung eines nativen Images kann zeitaufwendig sein, insbesondere für große Anwendungen.</li><li><strong>Komplexität</strong>: Die Komplexität bei der Konfiguration und Erstellung von nativen Images kann höher sein als bei der Verwendung einer herkömmlichen JVM.</li><li><strong>Eingeschränkte dynamische Funktionalität</strong>: Einige dynamische Funktionen in Java, wie Reflexion und Proxy-Generierung, sind in nativen Images eingeschränkt oder erfordern zusätzliche Konfigurationen, um ordnungsgemäß zu funktionieren.</li></ul>						</div>
				</div>
				<div class="elementor-element elementor-element-953abe8 elementor-widget elementor-widget-heading" data-id="953abe8" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Best Practices für die Erstellung von Native Images</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-22c85ea elementor-widget elementor-widget-text-editor" data-id="22c85ea" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Um die Vorteile von Native Images optimal zu nutzen, sollten einige Best Practices beachtet werden:</p><ol><li><p><strong>Optimierung des Codes</strong>: Der Code sollte so optimiert werden, dass er wenig dynamische Funktionalität nutzt, um die Komplexität bei der Erstellung des nativen Images zu minimieren.</p></li><li><p><strong>Einsatz von GraalVM-Tools</strong>: Die Nutzung von GraalVM-Tools zur Analyse des Codes kann helfen, Engpässe zu identifizieren und den Prozess der Erstellung von nativen Images zu optimieren.</p></li><li><p><strong>Testen der nativen Images</strong>: Es ist wichtig, nativen Images ausführlich zu testen, um sicherzustellen, dass alle Funktionalitäten korrekt implementiert sind und die Anwendung wie erwartet läuft.</p></li></ol>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-505d35d elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="505d35d" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-de9eb4a" data-id="de9eb4a" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-680c980 elementor-widget elementor-widget-spacer" data-id="680c980" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-ba40305 elementor-widget elementor-widget-heading" data-id="ba40305" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Entwicklungstrends</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-74e51c3 elementor-widget elementor-widget-text-editor" data-id="74e51c3" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die Softwareentwicklung befindet sich in einem kontinuierlichen Wandel, insbesondere im Hinblick auf Cloud-native Architekturen und moderne Frameworks wie Quarkus und GraalVM. Diese Technologien reagieren auf aktuelle Entwicklungen und Trends, die die Anforderungen an Anwendungen und deren Bereitstellung beeinflussen.</p><p>Ein bedeutender Trend ist die steigende Akzeptanz von Cloud-native und Microservices-Architekturen. Unternehmen setzen zunehmend auf flexible, skalierbare Lösungen, die eine schnelle Entwicklung und Bereitstellung von Software ermöglichen. Quarkus ist speziell für diese Anforderungen optimiert und bietet Entwicklern die Werkzeuge, um Microservices effizient zu implementieren.</p><p>Ein weiteres wachsendes Interesse gilt serverlosen Architekturen, die sich durch Effizienz und Kosteneffektivität auszeichnen. Die schnelleren Startzeiten und der geringere Speicherbedarf von Native Images machen Quarkus-Anwendungen besonders geeignet für serverlose Bereitstellungen. In Kombination mit GraalVM können Entwickler die Vorteile dieser Architekturen voll ausschöpfen.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-8960459 elementor-widget elementor-widget-heading" data-id="8960459" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Integration von Künstlicher Intelligenz und Machine Learning</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-c779b63 elementor-widget elementor-widget-text-editor" data-id="c779b63" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die Integration von Künstlicher Intelligenz (KI) und Maschinellem Lernen (ML) in moderne Anwendungen gewinnt zunehmend an Bedeutung. Mit der steigenden Nachfrage nach intelligenten, datengetriebenen Lösungen ist es für Unternehmen unerlässlich, KI-gestützte Funktionen in ihre Software zu integrieren. Quarkus und GraalVM stellen Entwicklern eine leistungsstarke Plattform zur Verfügung, um KI-Modelle effizient zu implementieren.</p><p>Die Vorteile dieser Kombination liegen in der hohen Leistung sowie der Fähigkeit, mehrere Programmiersprachen zu unterstützen. So können Entwickler beispielsweise Python-Bibliotheken für maschinelles Lernen zusammen mit Java nutzen, um innovative Lösungen zu entwickeln. Zudem ermöglichen die Optimierungen von GraalVM in Bezug auf Speicher- und Laufzeiteffizienz, dass KI-Modelle auch in ressourcenbeschränkten Umgebungen effektiv betrieben werden können.w</p>						</div>
				</div>
				<div class="elementor-element elementor-element-b2544a5 elementor-widget elementor-widget-heading" data-id="b2544a5" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Zukunftsausblick</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-5e34dd4 elementor-widget elementor-widget-text-editor" data-id="5e34dd4" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Der Zukunftsausblick für Quarkus und GraalVM sieht vielversprechend aus. Da Unternehmen zunehmend auf Cloud-native Architekturen und Microservices setzen, wird die Nachfrage nach Lösungen, die eine schnelle Entwicklung und Bereitstellung von Anwendungen ermöglichen, weiter steigen. Quarkus und GraalVM sind bestens positioniert, um diesen Anforderungen gerecht zu werden.</p><p>Zudem wird erwartet, dass die Integration von KI und ML in Anwendungen weiter zunehmen wird. Die Möglichkeit, mehrere Programmiersprachen zu kombinieren und gleichzeitig die Vorteile von Native Images zu nutzen, könnte Quarkus und GraalVM zu einer bevorzugten Wahl für Entwickler machen, die innovative und leistungsfähige Lösungen suchen.</p><p>Insgesamt werden Quarkus und GraalVM voraussichtlich eine Schlüsselrolle in der Weiterentwicklung der Softwarelandschaft spielen, insbesondere in der Unterstützung von modernen Architekturen und Technologien, die auf Effizienz und Flexibilität abzielen.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-0fddbc1 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="0fddbc1" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-5bbae19" data-id="5bbae19" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-d112dc0 elementor-widget elementor-widget-spacer" data-id="d112dc0" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-481efe1 elementor-widget elementor-widget-heading" data-id="481efe1" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Fazit</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-168761a elementor-widget elementor-widget-text-editor" data-id="168761a" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die Kombination aus Quarkus und GraalVM stellt eine innovative Lösung für die Herausforderungen der modernen Softwareentwicklung dar. Quarkus bietet Entwicklern eine optimierte Umgebung für Cloud-native Anwendungen, während GraalVM signifikante Leistungssteigerungen durch Native Images und Unterstützung mehrerer Programmiersprachen ermöglicht. Diese Synergien führen zu einer erhöhten Effizienz, verkürzten Entwicklungszyklen und einer verbesserten Skalierbarkeit, die für Microservices-Architekturen entscheidend ist.</p><p>Die Untersuchung der Entwicklungstrends zeigt, dass die Nachfrage nach flexiblen und leistungsstarken Lösungen weiter steigt. Die Integration von KI und ML in Anwendungen wird immer relevanter, und Quarkus sowie GraalVM bieten die erforderliche Basis, um diese Technologien effizient zu implementieren.</p><p>Trotz der zahlreichen Vorteile müssen Entwickler auch die Herausforderungen berücksichtigen, die mit der Nutzung dieser Technologien verbunden sind, insbesondere in Bezug auf Kompatibilität und erforderliche Anpassungen. Die Einarbeitung in die spezifischen Anforderungen und Best Practices ist entscheidend für den erfolgreichen Einsatz von Quarkus und GraalVM.</p><p>Insgesamt wird erwartet, dass die Rolle von Quarkus und GraalVM in der Softwareentwicklung in Zukunft weiter zunehmen wird. Die Kombination aus Geschwindigkeit, Effizienz und Flexibilität wird dazu beitragen, innovative Lösungen zu entwickeln, die den Anforderungen der modernen digitalen Welt gerecht werden.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-8c453f9 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="8c453f9" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-39d38d9" data-id="39d38d9" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-a991c92 elementor-widget elementor-widget-spacer" data-id="a991c92" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				</div>
		<p>Der Beitrag <a href="https://www.inoteq.com/2024/09/30/effiziente-java-anwendungsentwicklung-mit-quarkus-und-graalvm/">Effiziente Java-Anwendungsentwicklung mit Quarkus und GraalVM</a> erschien zuerst auf <a href="https://www.inoteq.com">INOTEQ GmbH</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.inoteq.com/2024/09/30/effiziente-java-anwendungsentwicklung-mit-quarkus-und-graalvm/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Java 21: Ein kurzer Überblick über die wichtigsten Neuerungen</title>
		<link>https://www.inoteq.com/2024/08/03/java-21-ein-kurzer-ueberblick-ueber-die-wichtigsten-neuerungen/</link>
					<comments>https://www.inoteq.com/2024/08/03/java-21-ein-kurzer-ueberblick-ueber-die-wichtigsten-neuerungen/#respond</comments>
		
		<dc:creator><![CDATA[Alexander Kusmin]]></dc:creator>
		<pubDate>Sat, 03 Aug 2024 06:38:00 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Java]]></category>
		<guid isPermaLink="false">https://www.inoteq.com/?p=2956</guid>

					<description><![CDATA[<p>Mit Java 21 steht eine neue Version der Programmiersprache zur Verfügung, die sich durch eine Reihe von bedeutsamen Verbesserungen und Erweiterungen auszeichnet. Die neue Version bietet Entwicklern nicht nur aktualisierte API-Funktionen, sondern auch erweiterte Möglichkeiten im Bereich des Pattern Matchings und innovative Ansätze für die Thread-Verwaltung. Im Folgenden werden die wichtigsten Änderungen detailliert beschrieben. Dazu [&#8230;]</p>
<p>Der Beitrag <a href="https://www.inoteq.com/2024/08/03/java-21-ein-kurzer-ueberblick-ueber-die-wichtigsten-neuerungen/">Java 21: Ein kurzer Überblick über die wichtigsten Neuerungen</a> erschien zuerst auf <a href="https://www.inoteq.com">INOTEQ GmbH</a>.</p>
]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="2956" class="elementor elementor-2956" data-elementor-post-type="post">
						<section class="elementor-section elementor-top-section elementor-element elementor-element-02e3e15 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="02e3e15" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-d924930" data-id="d924930" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-c9bab63 elementor-widget elementor-widget-spacer" data-id="c9bab63" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-da79d1d elementor-widget elementor-widget-html" data-id="da79d1d" data-element_type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
			<!-- Only for Code Snippet Styles -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/themes/prism-coy.min.css" integrity="sha256-VcuSs+n31yebPlEcehu6PvnidJ808ScFBsK8+tJKX+Q=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/components/prism-core.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/plugins/autoloader/prism-autoloader.min.js"></script>
<style>
    :not(pre) > code[class*=language-].inline {
        padding: 0 0.2rem;
        color: #000;
    }
</style>		</div>
				</div>
				<div class="elementor-element elementor-element-46c3870 elementor-widget elementor-widget-theme-post-title elementor-page-title elementor-widget-heading" data-id="46c3870" data-element_type="widget" data-widget_type="theme-post-title.default">
				<div class="elementor-widget-container">
			<h1 class="elementor-heading-title elementor-size-default">Java 21: Ein kurzer Überblick über die wichtigsten Neuerungen</h1>		</div>
				</div>
				<div class="elementor-element elementor-element-322b0b1 elementor-widget elementor-widget-post-info" data-id="322b0b1" data-element_type="widget" data-widget_type="post-info.default">
				<div class="elementor-widget-container">
					<ul class="elementor-inline-items elementor-icon-list-items elementor-post-info">
								<li class="elementor-icon-list-item elementor-repeater-item-5df6a58 elementor-inline-item" itemprop="datePublished">
						<a href="https://www.inoteq.com/2024/08/03/">
											<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="fas fa-calendar"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-date">
										August 3, 2024					</span>
									</a>
				</li>
				<li class="elementor-icon-list-item elementor-repeater-item-df87aa6 elementor-inline-item" itemprop="author">
						<a href="https://www.inoteq.com/author/akusmin/">
											<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="far fa-user-circle"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-author">
										Alexander Kusmin					</span>
									</a>
				</li>
				</ul>
				</div>
				</div>
				<div class="elementor-element elementor-element-3f44608 elementor-widget elementor-widget-text-editor" data-id="3f44608" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Mit Java 21 steht eine neue Version der Programmiersprache zur Verfügung, die sich durch eine Reihe von bedeutsamen Verbesserungen und Erweiterungen auszeichnet. Die neue Version bietet Entwicklern nicht nur aktualisierte API-Funktionen, sondern auch erweiterte Möglichkeiten im Bereich des Pattern Matchings und innovative Ansätze für die Thread-Verwaltung. Im Folgenden werden die wichtigsten Änderungen detailliert beschrieben. Dazu zählen die neuen Math- und String-Methoden, die Erweiterungen bei Sequenced Collections und die Abkehr von bestimmten Methoden (Deprecations). Ein weiterer Punkt sind die Neuerungen im Pattern Matching mit Sealed Interfaces und Record Patterns. Abschließend werden die Vorteile und Best Practices von Virtual Threads erörtert.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-afaa096 elementor-widget elementor-widget-theme-post-featured-image elementor-widget-image" data-id="afaa096" data-element_type="widget" data-widget_type="theme-post-featured-image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img decoding="async" width="2500" height="1500" src="https://www.inoteq.com/wp-content/uploads/2024/06/Untitled.png" class="attachment-full size-full wp-image-3133" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2024/06/Untitled.png 2500w, https://www.inoteq.com/wp-content/uploads/2024/06/Untitled-300x180.png 300w, https://www.inoteq.com/wp-content/uploads/2024/06/Untitled-1024x614.png 1024w, https://www.inoteq.com/wp-content/uploads/2024/06/Untitled-768x461.png 768w, https://www.inoteq.com/wp-content/uploads/2024/06/Untitled-1536x922.png 1536w, https://www.inoteq.com/wp-content/uploads/2024/06/Untitled-2048x1229.png 2048w" sizes="(max-width: 2500px) 100vw, 2500px" />											<figcaption class="widget-image-caption wp-caption-text">KI generiertes Symbolbild: compelling, symbolizing new java 21 as coffee, logo-style, coffee mug, latte art</figcaption>
										</figure>
							</div>
				</div>
				<div class="elementor-element elementor-element-4429dc1 elementor-toc--minimized-on-tablet elementor-widget elementor-widget-table-of-contents" data-id="4429dc1" data-element_type="widget" data-settings="{&quot;exclude_headings_by_selector&quot;:&quot;.exclude-from-toc&quot;,&quot;headings_by_tags&quot;:[&quot;h2&quot;,&quot;h3&quot;,&quot;h4&quot;,&quot;h5&quot;,&quot;h6&quot;],&quot;marker_view&quot;:&quot;numbers&quot;,&quot;minimize_box&quot;:&quot;yes&quot;,&quot;minimized_on&quot;:&quot;tablet&quot;,&quot;hierarchical_view&quot;:&quot;yes&quot;,&quot;min_height&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;min_height_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;min_height_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}" data-widget_type="table-of-contents.default">
				<div class="elementor-widget-container">
					<div class="elementor-toc__header">
			<h4 class="elementor-toc__header-title">
				Table of Contents			</h4>
							<div class="elementor-toc__toggle-button elementor-toc__toggle-button--expand" role="button" tabindex="0" aria-controls="elementor-toc__4429dc1" aria-expanded="true" aria-label="Open table of contents"><i aria-hidden="true" class="fas fa-chevron-down"></i></div>
				<div class="elementor-toc__toggle-button elementor-toc__toggle-button--collapse" role="button" tabindex="0" aria-controls="elementor-toc__4429dc1" aria-expanded="true" aria-label="Close table of contents"><i aria-hidden="true" class="fas fa-chevron-up"></i></div>
					</div>
		<div id="elementor-toc__4429dc1" class="elementor-toc__body">
			<div class="elementor-toc__spinner-container">
				<i class="elementor-toc__spinner eicon-animation-spin eicon-loading" aria-hidden="true"></i>			</div>
		</div>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-8455df0 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="8455df0" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-5c0de59" data-id="5c0de59" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-c2fd228 elementor-widget elementor-widget-spacer" data-id="c2fd228" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-25efaaf elementor-widget elementor-widget-heading" data-id="25efaaf" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">API Updates</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-a103f9e elementor-widget elementor-widget-text-editor" data-id="a103f9e" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Java 21 beinhaltet eine Vielzahl an Optimierungen und Erweiterungen, welche die Arbeitsprozesse für Entwickler vereinfachen und sowohl die Programmiersprache als auch die Laufzeitumgebung beschleunigen sollen. Von besonderer Relevanz sind dabei die Anpassungen an den Application Programming Interfaces (APIs), da sie eine Verbesserung bestehender Funktionen, die Ersetzung veralteter Methoden und die Bereitstellung neuer Optionen zum Ziel haben.</p><p>Eine detaillierte Darstellung aller Änderungen ist im Rahmen dieses Artikels nicht möglich, weshalb für eine vollständige Auflistung aller Änderungen auf die <a href="https://www.oracle.com/java/technologies/javase/21-relnote-issues.html" target="_blank" rel="noopener">Release Notes von Java 21 auf der Website von Oracle</a> verwiesen wird.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-be7ccbd elementor-widget elementor-widget-heading" data-id="be7ccbd" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Math- und String-basierte APIs</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-00bd903 elementor-widget elementor-widget-text-editor" data-id="00bd903" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die neue Version weist praktische Erweiterungen und Verbesserungen auf, wodurch sich Zeichenketten und mathematische Operationen einfacher und effizienter bearbeiten lassen.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-e9d1444 elementor-widget elementor-widget-heading" data-id="e9d1444" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h4 class="elementor-heading-title elementor-size-default">String Methoden</h4>		</div>
				</div>
				<div class="elementor-element elementor-element-9c16e2f elementor-widget elementor-widget-text-editor" data-id="9c16e2f" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die Klassen <code>StringBuilder</code> und <code>StringBuffer</code> wurden um die <code>repeat()</code>-Methode erweitert. Diese ermöglicht die wiederholte Wiedergabe einer Zeichenkette, wodurch sich wiederholende Muster mit geringem Aufwand erstellen lassen.</p><p><strong>Warum ist diese Methode hilfreich?</strong></p><ul><li><strong>Effizienz</strong><br />Die Verwendung der <code>repeat()</code>-Methode anstelle von Schleifen oder manuellen Verkettungen zur Repetition einer Zeichenkette stellt eine grundsätzlich effiziente Lösung dar.</li><li><strong>Lesbarkeit</strong><br />Die Lesbarkeit des Codes wird verbessert, da die Absicht, eine Zeichenkette zu wiederholen, klar und direkt im Code sichtbar ist.</li><li><strong>Wartbarkeit</strong><br />Eine Reduktion der Codezeilen sowie eine klarere Syntax erleichtern die Wartung und die Fehlersuche im Code.</li></ul><p>Es sei angenommen, dass eine Profil-Seite entwickelt wird, wobei eine Teil-Maskierung der hinterlegten Email-Adresse gewünscht wird. In diesem Zusammenhang soll anhand eines Beispiels erörtert werden, wie die Maskierung mit der <code>repeat()</code>-Methode umgesetzt werden kann:</p><pre><code class="language-java">public class EmailMasking {
    public static void main(String[] args) {
        String email = "john.doe@example.com";
        
        // Erstelle eine Maskierung für die EMail
        StringBuilder maskedEmail = new StringBuilder();
        maskedEmail.append(email.substring(0, 3));
        maskedEmail.append("*".repeat(email.length() - 6));
        maskedEmail.append(email.substring(email.length() - 3))
        
        // Maskierte EMail: joh**************com
        System.out.println("Maskierte Email: " + maskedEmail.toString());
    }
}</code></pre><p>Im vorliegenden Beispiel wird die Email-Adresse durch eine Folge von Sternchen der maskiert. Die Verwendung der <code>repeat()</code>-Methode erlaubt die Maskierung mit einem einzigen Aufruf, wodurch der Code klarer und effizienter gestaltet werden kann.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-445658b elementor-widget elementor-widget-heading" data-id="445658b" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h4 class="elementor-heading-title elementor-size-default">Character Methoden</h4>		</div>
				</div>
				<div class="elementor-element elementor-element-26e3d84 elementor-widget elementor-widget-text-editor" data-id="26e3d84" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die neue Methode <code class="language-java inline">Character.isEmoji(int codepoint)</code> erlaubt die Überprüfung, ob ein bestimmtes Zeichen ein Emoji ist. Ein Codepoint ist eine eindeutige Nummer im Unicode-Standard, die jedes Zeichen, einschließlich Emojis, identifiziert. Die Verwendung dieser Methode ist vorteilhaft, da sie die Nutzung von Unicode-Zeichen verbessert und die Arbeit mit modernen Textformaten, die Emojis enthalten, vereinfacht.</p><p><strong>Welcher Nutzen lässt sich aus der Anwendung dieser Methode ableiten?<br /></strong></p><ul><li><strong>Textanalyse und -filterung<br /></strong>In Anwendungen wie sozialen Medien oder Messaging-Diensten kann die Unterscheidung zwischen Emojis und normalem Text von Bedeutung sein. Dies kann beispielsweise durch die Implementierung von Filtern erfolgen, die entweder nur Text ohne Emojis oder nur Nachrichten mit Emojis erlauben.</li><li><strong>Benutzerfreundlichkeit<br /></strong>In zahlreichen modernen Anwendungen, wie beispielsweise Chat-Apps oder Kommentarsystemen, finden Emojis Verwendung. Durch das Erkennen und angemessene Behandeln von Emojis kann die Benutzererfahrung optimiert werden, beispielsweise durch eine grafische Darstellung der Emojis oder eine Hervorhebung in speziellen Kontexten.</li><li><strong>Datenbereinigung</strong><br />Des Weiteren ist bei der Verarbeitung von Textdaten für Analysen oder maschinelles Lernen häufig eine Erkennung von Emojis erforderlich, um diese gegebenenfalls zu entfernen oder durch Platzhalter zu ersetzen.</li></ul><p>Ein exemplarisches Szenario wäre die Entwicklung einer Chat-Anwendung, für die eine Statistik über die Verwendung von Emojis in Nachrichten erstellt werden soll. Die Umsetzung kann mit der Methode <code class="language-java inline">isEmoji()</code> erfolgen, wie im Folgenden dargestellt wird:</p><pre><code class="language-java">public class EmojiUsageAnalyzer {
    public static void main(String[] args) {
        String message = "Hallo 😀! Wie geht's dir heute? 😊";

        int emojiCount = countEmojis(message);

        // Anzahl der Emojis in der Nachricht: 2
        System.out.println("Anzahl der Emojis in der Nachricht: " + emojiCount);
    }

    public static int countEmojis(String text) {
        int count = 0;
        int length = text.length();
        
        for (int i = 0; i &lt; length;) {
            int codePoint = text.codePointAt(i);
            if (Character.isEmoji(codePoint)) {
                count++;
            }
            i += Character.charCount(codePoint);
        }
        
        return count;
    }
}</code></pre><p>Im Folgenden wird der Text einer Nachricht analysiert, um die Anzahl der Emojis zu zählen. Zu diesem Zweck wird die Methode <code class="language-java inline">isEmoji()</code> verwendet, welche es ermöglicht, jedes Zeichen im Text zu überprüfen und festzustellen, ob es sich um ein Emoji handelt. Der Zähler wird entsprechend erhöht. Auf diese Weise kann die Häufigkeit der Emojis in den Nachrichten ermittelt und daraus nützliche Statistiken abgeleitet werden.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-506409a elementor-widget elementor-widget-heading" data-id="506409a" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h4 class="elementor-heading-title elementor-size-default">Math Methoden</h4>		</div>
				</div>
				<div class="elementor-element elementor-element-2c57d1c elementor-widget elementor-widget-text-editor" data-id="2c57d1c" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die in Java eingeführte Methode <code class="language-java inline">Math.clamp(int value, int min, int max)</code> ermöglicht die Begrenzung eines Wertes auf ein bestimmtes Intervall. Dies ist insbesondere dann von Vorteil, wenn sichergestellt werden soll, dass Werte innerhalb eines vorgegebenen Bereichs liegen, ohne dass eine aufwändige Überprüfungslogik erforderlich ist.</p><p><strong>Was bringt diese Methode?</strong></p><ul><li><strong>Einfachheit</strong><br />Die <code class="language-java inline">clamp()</code>-Methode stellt eine einfache und direkte Lösung dar, um sicherzustellen, dass ein Wert innerhalb eines Bereichs liegt, ohne dass manuell eine Überprüfungslogik geschrieben werden muss.</li><li><strong>Lesbarkeit</strong><br />Die Lesbarkeit des Codes wird durch die unmittelbare Erkennbarkeit der Absicht, einen bestimmten Wert zu begrenzen, signifikant verbessert.</li><li><strong>Wartbarkeit</strong><br />Die Wartbarkeit des Codes kann durch eine Reduktion der Codezeilen sowie eine klarere Syntax verbessert werden. Dies erleichtert die Wartung und das Verständnis des Codes.</li></ul><p>Im Folgenden wird die Entwicklung einer Anwendung vorgestellt, welche die Positionierung eines Schiebereglers (Slider) auf einer Benutzeroberfläche steuert. Dabei ist sicherzustellen, dass sich der Schieberegler lediglich innerhalb eines definierten Bereichs bewegt. Zur Veranschaulichung wird ein Beispiel präsentiert, welches die Umsetzung mit der <code class="language-java inline">clamp()</code>-Methode demonstriert:</p><pre><code class="language-java">public class SliderControl {
    public static void main(String[] args) {
        int sliderPosition = 150; // Beispielwert für die Position des Schiebereglers
        int minPosition = 0;
        int maxPosition = 100;
        
        // Begrenze die Position des Schiebereglers auf den Bereich [minPosition, maxPosition]
        int clampedPosition = Math.clamp(sliderPosition, minPosition, maxPosition);
        
        // Begrenzte Position des Schiebereglers: 100
        System.out.println("Begrenzte Position des Schiebereglers: " + clampedPosition);
    }
}</code></pre><p>Die Funktion begrenzt in diesem Beispiel die Position des Schiebereglers auf den Bereich von 0 bis 100. Sollte der ursprüngliche Wert außerhalb dieses Bereichs liegen, erfolgt eine automatische Anpassung auf den nächsten gültigen Wert. Dadurch kann die Position des Schiebereglers ohne weitere Logik innerhalb des erlaubten Bereichs gehalten werden.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-c4cc599 elementor-widget elementor-widget-heading" data-id="c4cc599" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Sequenced Collections</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-d8ea36c elementor-widget elementor-widget-text-editor" data-id="d8ea36c" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die jüngste Erweiterung des Funktionsumfangs ermöglicht eine vereinfachte Handhabung geordneter Datenstrukturen. Die neu implementierten Interfaces und Klassen bieten eine konsistente und intuitive Zugriffsmöglichkeit auf Elemente in geordneten Sammlungen sowie die Möglichkeit ihrer Manipulation.</p><p>In Java-Sammlungen bezeichnet der Begriff <strong>„defined encounter order”</strong> die festgelegte Reihenfolge, in der Elemente verarbeitet oder iteriert werden. Bei Sammlungen wie <code class="language-java inline">ArrayList</code>, <code class="language-java inline">LinkedList</code>, <code class="language-java inline">LinkedHashSet</code> und <code class="language-java inline">LinkedHashMap</code> wird die Reihenfolge, in der Elemente hinzugefügt werden, beibehalten und ist bei der Iteration vorhersehbar. Dies steht im Gegensatz zu Sammlungen wie <code class="language-java inline">HashSet</code> und <code class="language-java inline">HashMap</code>, bei denen die Reihenfolge der Elemente nicht vorhersehbar ist. Eine definierte Begegnungsreihenfolge erweist sich insbesondere dann als vorteilhaft, wenn die Reihenfolge der Elemente für den Algorithmus oder die Logik einer Anwendung von entscheidender Bedeutung ist, da sie eine konsistente und erwartbare Verarbeitung der Elemente gewährleistet.</p>						</div>
				</div>
				<section class="elementor-section elementor-inner-section elementor-element elementor-element-e4fc3c7 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="e4fc3c7" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-d5ebc4f" data-id="d5ebc4f" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-3aa8128 elementor-widget elementor-widget-text-editor" data-id="3aa8128" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<ul>
 	<li><code class="language-java inline">
list.get()
</code></li>
 	<li><code class="language-java inline">
deque.getFirst()
</code></li>
 	<li><code class="language-java inline">
sortedSet.first()
</code></li>
 	<li><code class="language-java inline">
linkedHashSet.iterator().next()
</code></li>
</ul>						</div>
				</div>
					</div>
		</div>
				<div class="elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-5a1b3c9" data-id="5a1b3c9" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-fad288e elementor-widget elementor-widget-text-editor" data-id="fad288e" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<ul>
 	<li><code class="language-java inline">
list.get(list.size()-1)
</code></li>
 	<li><code class="language-java inline">
deque.getLast()
</code></li>
 	<li><code class="language-java inline">
sortedSet.last()
</code></li>
</ul>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<div class="elementor-element elementor-element-3568314 elementor-widget elementor-widget-spacer" data-id="3568314" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-2ced948 elementor-widget elementor-widget-text-editor" data-id="2ced948" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							Diesbezüglich wurden neue gemeinsame Obertypen und Methoden eingeführt, darunter <code class="language-java inline">SequencedCollection&lt;E&gt;</code>, <code class="language-java inline">SequencedSet&lt;E&gt;</code> sowie <code class="language-java inline">SequencedMap&lt;E&gt;</code>.						</div>
				</div>
				<div class="elementor-element elementor-element-9d99ac6 elementor-widget elementor-widget-image" data-id="9d99ac6" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img loading="lazy" decoding="async" width="768" height="545" src="https://www.inoteq.com/wp-content/uploads/2024/06/Java-21-22-Sequenced-Collections-Hierarchy-768x545.png" class="attachment-medium_large size-medium_large wp-image-3014" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2024/06/Java-21-22-Sequenced-Collections-Hierarchy-768x545.png 768w, https://www.inoteq.com/wp-content/uploads/2024/06/Java-21-22-Sequenced-Collections-Hierarchy-300x213.png 300w, https://www.inoteq.com/wp-content/uploads/2024/06/Java-21-22-Sequenced-Collections-Hierarchy-1024x726.png 1024w, https://www.inoteq.com/wp-content/uploads/2024/06/Java-21-22-Sequenced-Collections-Hierarchy-1536x1089.png 1536w, https://www.inoteq.com/wp-content/uploads/2024/06/Java-21-22-Sequenced-Collections-Hierarchy-2048x1453.png 2048w" sizes="(max-width: 768px) 100vw, 768px" />											<figcaption class="widget-image-caption wp-caption-text">Hierarchie der Sequenced Collections</figcaption>
										</figure>
							</div>
				</div>
				<div class="elementor-element elementor-element-a05d849 elementor-widget elementor-widget-text-editor" data-id="a05d849" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Diese Interfaces bringen einheitliche Methoden mit sich:</p><ul><li><code class="language-java inline">E getFirst()</code> und <code class="language-java inline">E getLast()</code>: Gibt das erste bzw. das letzte Element der Sammlung zurück.</li><li><code class="language-java inline">SequencedCollection&lt;E&gt; reversed()</code>: Gibt eine umgekehrte Ansicht der Sammlung zurück.</li><li><code class="language-java inline">void addFirst(E e)</code> und <code class="language-java inline">void addLast(E e)</code>: Fügt ein Element an den Anfang bzw. das Ende der Sammlung hinzu.</li><li><code class="language-java inline">E removeFirst()</code> und <code class="language-java inline">E removeLast()</code>: Entfernt und gibt das erste bzw. letzte Element der Sammlung zurück.</li></ul><p><br />Die Anwendung der genannten Methoden führt zu einer erleichterten Verarbeitung sequenzierter Datenstrukturen. Bei einer Nichtunterstützung einer Methode kann es zu einer sogenannten <code class="language-java inline">UnsupportedOperationException</code> kommen.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-e831275 elementor-widget elementor-widget-heading" data-id="e831275" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Deprecations</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-d8f7664 elementor-widget elementor-widget-text-editor" data-id="d8f7664" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Im Rahmen der vorgenommenen Änderungen wurden einige veraltete Methoden und Konstruktoren entfernt, da sie in der Vergangenheit potenzielle Probleme verursachen konnten. Neben dem Aspekt der erhöhten Sicherheit und Stabilität von Anwendungen zielt die aktuelle Vorgehensweise darauf ab, die Nutzung moderner Alternativen zu fördern.</p><p>In Bezug auf <strong>Threads</strong> sind die Methoden <code class="language-java inline">stop()</code>, <code class="language-java inline">suspend()</code> und <code class="language-java inline">resume()</code> nicht mehr zeitgemäß und führen nun zu einer <code class="language-java inline">UnsupportedOperationException</code>. Diese Methoden waren mit einem gewissen Risiko behaftet, da sie unvorhersehbare Zustände in Threads verursachen konnten. Entwicklerinnen und Entwickler sollten daher sicherere Alternativen wie <code class="language-java inline">interrupt()</code> und andere Steuermechanismen für Threads in Betracht ziehen.</p><p>Des Weiteren sind die älteren <strong>URL-Konstruktoren</strong> veraltet da sie eine höhere Fehleranfälligkeit aufweisen. Stattdessen sollte <code class="language-java inline">URI.create("https://www.example.com/").toURL()</code> verwendet werden, da diese Methode eine höhere Sicherheit und Flexibilität bietet.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-306ad08 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="306ad08" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-5be344d" data-id="5be344d" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-e97c5bd elementor-widget elementor-widget-spacer" data-id="e97c5bd" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-0f2676d elementor-widget elementor-widget-heading" data-id="0f2676d" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Pattern Matching und Record Patterns</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-19521c2 elementor-widget elementor-widget-text-editor" data-id="19521c2" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Java 21 beinhaltet diverse Neuerungen im Bereich Pattern Matching, insbesondere im Hinblick auf Switch-Anweisungen und Record Patterns. Die neuen Möglichkeiten zur Datenanalyse und -verarbeitung erlauben eine elegantere und lesbarere Gestaltung von Code-Strukturen. Zu den wichtigsten Konzepten, welche diese Funktionalitäten unterstützen, zählen Sealed Interfaces und Record Patterns.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-cfc4c64 elementor-widget elementor-widget-heading" data-id="cfc4c64" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Sealed Interfaces</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-939a1ff elementor-widget elementor-widget-text-editor" data-id="939a1ff" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							Sealed Interfaces stellen eine Erweiterung der bereits bekannten Sealed-Klassen dar. Ihr Einsatz erlaubt die Einschränkung der zulässigen Unterklassen einer Klasse auf explizite Weise. Eine Sealed-Klasse kann lediglich durch Klassen oder Schnittstellen erweitert werden, die in der <code class="language-java inline">permit</code>-Klausel der Sealed-Klasse aufgeführt sind. Des Weiteren ist zu beachten, dass sich die Erweiterung in der gleichen Datei befinden muss. Diese Funktion zielt darauf ab, die Kontrolle über die Vererbungshierarchie zu optimieren und sicherzustellen, dass nur bekannte und kontrollierte Erweiterungen einer Klasse existieren. Die Spezifikation von Sealed Interfaces erlaubt die Angabe einer begrenzten Anzahl an Implementierungen, die nach demselben Prinzip erfolgen. Dies impliziert, dass alle zulässigen Unterklassen oder Implementierungen eines Sealed Interfaces in der gleichen Datei enthalten sein müssen, wobei eine Kennzeichnung als <code class="language-java inline">final class</code> oder mit der <code class="language-java inline">permit</code>-Klausel üblich ist. Dies resultiert in sichererem und wartbarerem Code.

Ein weiterer Vorteil ist, dass bei Verwendung von Sealed Interfaces in Switch-Anweisungen der <code class="language-java inline">default</code>-Zweig häufig obsolet wird, da der Compiler mit allen möglichen Fällen vertraut ist und sie entsprechend abdecken kann, was zu klareren und präziseren Codes führt.

Anhand eines konkreten Beispiels soll im Folgenden erörtert werden, wie ein Sealed Interface typischerweise aufgebaut ist:
<pre><code class="language-java">sealed interface Animal {
    String getName();
}

final class Cat implements Animal { /* ... */ }

final class Dog implements Animal { /* ... */ }

// Alternative
sealed interface Animal permits Cat, Dog { ... }
</code></pre>
Die Definition eines Sealed Interfaces kann ebenfalls unter Zuhilfenahme der sogenannten <code class="language-java inline">permits</code>-Klausel erfolgen, um zu spezifizieren, welche Klassen oder Interfaces eine Implementierung vornehmen dürfen. Die <code class="language-java inline">permits</code>-Klausel wird unmittelbar nach dem Namen des Interfaces angegeben und listet alle zulässigen Implementierungen auf.						</div>
				</div>
				<div class="elementor-element elementor-element-57b253c elementor-widget elementor-widget-heading" data-id="57b253c" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Pattern Matching in Switch-Anweisungen</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-a31a6d0 elementor-widget elementor-widget-text-editor" data-id="a31a6d0" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							Pattern Matching in Switch-Anweisungen stellt eine der wesentlichsten Neuerungen in den aktuellen Java-Versionen dar. Ein wesentliches Merkmal von Pattern Matching in Switch besteht darin, dass nicht nur primitive Werte und Enumerationen, sondern auch komplexe Typen und deren Struktur abgefragt werden können. Dadurch wird die Behandlung von Objekten, die unterschiedlichen Klassen oder Hierarchien angehören, deutlich vereinfacht.
<pre><code class="language-java">sealed interface Shape {}

final class Circle implements Shape {
    double radius;
    Circle(double radius) { this.radius = radius; }
}

final class Rectangle implements Shape {
    double length, width;
    Rectangle(double length, double width) {
        this.length = length;
        this.width = width;
    }
}

final class Square implements Shape {
    double side;
    Square(double side) { this.side = side; }
}

public class Main {
    public static void main(String[] args) {
        Shape shape = new Circle(5.0);
        String result = switch (shape) {
            case Circle c -&gt; "Kreis mit Radius " + c.radius;
            case Rectangle r -&gt; "Rechteck mit Länge " + r.length + " und Breite " + r.width;
            case Square s -&gt; "Viereck mit Breite " + s.side;
        };
        // Kreis mit Radius 5
        System.out.println(result);
    }
}</code></pre>
Das vorliegende Beispiel demonstriert die Anwendung von Pattern Matching in Switch-Anweisungen zur Behandlung verschiedener Formen (<code class="language-java inline">Circle</code>, <code class="language-java inline">Rectangle</code>, <code class="language-java inline">Square</code>). Der Compiler überprüft die Abdeckung aller möglichen Formen, wodurch die Verwendung eines <code class="language-java inline">default</code>-Zweigs obsolet wird. Dies ist auf die Nutzung von Sealed Interfaces zurückzuführen, welche zu einer klareren und präziseren Codierung führen.						</div>
				</div>
				<div class="elementor-element elementor-element-62b2921 elementor-widget elementor-widget-heading" data-id="62b2921" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Record Patterns</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-cb6e1b0 elementor-widget__width-initial elementor-widget elementor-widget-text-editor" data-id="cb6e1b0" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							Die Verwendung von Record Patterns trägt zu einer Vereinfachung des Umgangs mit Datensätzen bei. Die Zugriffsmöglichkeit auf die einzelnen Teile eines Records innerhalb von Switch-Anweisungen erlaubt deren Analyse.

In Java stellen Records eine spezielle Art von Klasse dar, welche zur Speicherung unveränderlicher Daten dient. Mithilfe von Record Patterns ist es möglich, in einer Switch-Anweisung direkt auf die verschiedenen Komponenten eines Records zuzugreifen, ohne dass zusätzlicher Code erforderlich ist.
<pre><code class="language-java">public record Point(int x, int y) {}

public class Main {
    public static void main(String[] args) {
        Point point = new Point(10, 20);
        String result = switch (point) {
            case Point(int x, int y) -&gt; "Punkt bei (" + x + ", " + y + ")";
        };
        // Punkt bei (10, 20)
        System.out.println(result);
    }
}</code></pre>
Das vorliegende Beispiel demonstriert die Definition eines Records <code class="language-java inline">Point</code> sowie die Extraktion seiner Koordinaten <code class="language-java inline">x</code> und <code class="language-java inline">y</code> innerhalb einer Switch-Anweisung. Dies erlaubt eine prägnante und direkte Verarbeitung der Daten innerhalb des Records.
<pre><code class="language-java">public record Rectangle(Point topLeft, Point bottomRight) {}

public class Main {
    public static void main(String[] args) {
        Rectangle rectangle = new Rectangle(new Point(0, 0), new Point(10, 20));
        String result = switch (rectangle) {
            case Rectangle(Point(int x1, int y1), Point(int x2, int y2)) -&gt; 
                "Rechteck von (" + x1 + ", " + y1 + ") bis (" + x2 + ", " + y2 + ")";
        };
        // Rechteck von (0, 0) bis (10, 20)
        System.out.println(result);
    }
}</code></pre>
Im vorliegenden Kontext wird ein verschachtelter Record <code class="language-java inline">Rectangle</code> verwendet, der zwei <code class="language-java inline">Point</code>-Records enthält. Die Switch-Anweisung demonstriert die Möglichkeit des Zugriffs auf die Koordinaten dieser verschachtelten Struktur sowie deren Verarbeitung.						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-8b4a8d0 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="8b4a8d0" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-7d3d0f5" data-id="7d3d0f5" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-6ebe788 elementor-widget elementor-widget-spacer" data-id="6ebe788" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-43945e0 elementor-widget elementor-widget-heading" data-id="43945e0" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Virtual Threads</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-cf8c948 elementor-widget elementor-widget-text-editor" data-id="cf8c948" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							Die Virtual Threads stellen eine herausragende Neuerung in Java 21 dar. Die Funktionalität zielt darauf ab, die Skalierbarkeit und Performance von Java-Anwendungen zu optimieren. Während alternative Ansätze wie <code class="language-java inline">HttpClient</code> für <code class="language-java inline">send</code> und <code class="language-java inline">sendAsync</code>, Reactive Programming (beispielsweise Project Reactor und RxJava) sowie asynchrone Programmierung in Kotlin (Coroutines) bereits effiziente Möglichkeiten des Multithreadings bieten, stellt die Einführung von Virtual Threads einen wesentlichen Fortschritt dar. Virtual Threads stellen eine leichtgewichtige und effiziente Thread-API dar, welche die bewährte Thread-API von Java nutzt.						</div>
				</div>
				<div class="elementor-element elementor-element-a98daf8 elementor-widget elementor-widget-heading" data-id="a98daf8" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Grundlagen von Virtual Threads</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-f3f7b33 elementor-widget elementor-widget-text-editor" data-id="f3f7b33" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die Ausführung traditioneller Threads in Java ist durch eine hohe Komplexität sowie einen signifikanten Ressourcenverbrauch gekennzeichnet und die Verwaltung jedes einzelnen Threads obliegt dem Betriebssystem, was zu einem beträchtlichen Overhead führt. Bei Anwendungen, die eine Vielzahl gleichzeitiger Verbindungen oder Aufgaben verwalten müssen, können die klassischen Threads schnell an ihre Grenzen stoßen, was zu erheblichen Skalierungsproblemen führen kann. Der Verwaltungsaufwand für eine große Anzahl von Threads kann die Anwendungsperformance beeinträchtigen.</p><p>Im Gegensatz dazu werden Virtual Threads von der JVM verwaltet, was zu einer signifikanten Reduktion des Overheads führt. Dies ermöglicht die gleichzeitige Ausführung einer deutlich größeren Anzahl von Threads und verbessert die Skalierbarkeit und Nutzung der Hardware-Ressourcen erheblich.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-187b590 elementor-widget elementor-widget-heading" data-id="187b590" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Vergleich von Threads</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-8e7be77 elementor-widget elementor-widget-text-editor" data-id="8e7be77" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Zur Veranschaulichung der Unterschiede zwischen traditionellen Threads und Virtual Threads wird folgendes Beispiel herangezogen:</p><p>Es werden 10.000 Threads erstellt, die jeweils für eine Sekunde schlafen, um eine Netzwerkantwort zu simulieren. Die verstrichene Zeit wird dabei in Millisekunden gemessen.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-c795ab0 elementor-widget elementor-widget-text-editor" data-id="c795ab0" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<pre><code class="language-java">import java.util.ArrayList;
import java.util.List;

public class TraditionalThreadExample {
    public static void main(String[] args) throws InterruptedException {
        int numberOfThreads = 10000;
        List<Thread> threads = new ArrayList<>();

        for (int i = 0; i < numberOfThreads; i++) {
            Thread thread = new Thread(() -> {
                try {
                    // Simuliert eine Netzwerkantwort
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            threads.add(thread);
        }

        long startTime = System.currentTimeMillis();
        for (Thread thread : threads) {
            thread.start();
        }
        for (Thread thread : threads) {
            thread.join();
        }
        long endTime = System.currentTimeMillis();
        
        // Herkömmliche Threads: 5548 ms
        System.out.println("Herkömmliche Threads: " + (endTime - startTime) + " ms");
    }
}
</code></pre>						</div>
				</div>
				<div class="elementor-element elementor-element-af11838 elementor-widget elementor-widget-text-editor" data-id="af11838" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Im Mittel schließt dieses Programm innerhalb von 5.548 Millisekunden ab.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-0911056 elementor-widget elementor-widget-text-editor" data-id="0911056" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<pre><code class="language-java">import java.util.ArrayList;
import java.util.List;

public class VirtualThreadExample {
    public static void main(String[] args) throws InterruptedException {
        int numberOfThreads = 10000;
        List<Thread> threads = new ArrayList<>();

        for (int i = 0; i < numberOfThreads; i++) {
            Thread thread = Thread.ofVirtual().start(() -> {
                try {
                    // Simuliert eine Netzwerkantwort
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            threads.add(thread);
        }

        long startTime = System.currentTimeMillis();
        for (Thread thread : threads) {
            thread.join();
        }
        long endTime = System.currentTimeMillis();
        
        // Virtuelle Threads: 1032 ms
        System.out.println("Virtuelle Threads: " + (endTime - startTime) + " ms");
    }
}
</code></pre>						</div>
				</div>
				<div class="elementor-element elementor-element-f1ddfc3 elementor-widget elementor-widget-text-editor" data-id="f1ddfc3" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die Ausführung von diesem Programm, welches Virtual Threads nutzt, erfolgt mit einer durchschnittlichen Geschwindigkeit von lediglich 1.032 Millisekunden.</p><p>Im Vergleich zu anderen Programmierparadigmen benötigen Virtual Threads deutlich weniger Speicher (lediglich Kilobyte statt Megabyte). Dennoch ist die vertraute Thread-API weiterhin verfügbar. Diese Effizienz ermöglicht die Erstellung von synchronem und blockierendem Code, der dennoch asynchron und nicht blockierend ausgeführt wird. Zudem erleichtert die Debugging-Möglichkeit von Virtual Threads die Fehlersuche.</p><p>Neben der Erstellung von Virtual Threads ist ebenfalls die Generierung von herkömmlichen Threads mittels der Methode <code class="language-java inline">Thread.ofPlatform()</code> möglich. Diese Methode erlaubt die Konstruktion von Threads, welche direkt durch das Betriebssystem administriert werden. Dies kann in spezifischen Szenarien vorteilhaft sein, beispielsweise bei der Notwendigkeit einer hohen Performance von nativen Plattform-Threads.</p><p>Die Erstellung von Virtual Threads kann auch mittels eines <code class="language-java inline">ExecutorService</code> erfolgen, was insbesondere für Anwendungen von Vorteil ist, die eine Vielzahl kurzer, paralleler Aufgaben ausführen müssen. Eine Adaption des Beispiels kann wie folgt vorgenommen werden. Dadurch lässt sich ein direkter Vergleich zu sauberen und besser lesbaren Code durchführen.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-23e4b92 elementor-widget elementor-widget-text-editor" data-id="23e4b92" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<pre><code class="language-java">try (var es = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10000; i++) { es.submit(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
    }
}</code></pre>						</div>
				</div>
				<div class="elementor-element elementor-element-9ff1aaa elementor-widget elementor-widget-heading" data-id="9ff1aaa" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Vorteile und Best Practices</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-5cf7d52 elementor-widget elementor-widget-text-editor" data-id="5cf7d52" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Virtual Threads bieten im Vergleich zu traditionellen Threads signifikante Vorteile, insbesondere hinsichtlich des Ressourcenverbrauchs und der Skalierbarkeit, als auch die Verwaltung, die direkt durch die JVM erfolgt, sodass eine Anwendung eine signifikante Anzahl von Threads effizient erstellen und verwalten kann. Die vertraute Threading-API ermöglicht es Entwicklern, die Vorteile von Virtual Threads zu nutzen, ohne sich mit den Details der leichtgewichtigen Thread-Verwaltung befassen zu müssen, dass es erlaubt synchronem und blockierendem Code zu implementieren, dessen Ausführung jedoch asynchron und nicht blockierend erfolgt.</p><p>Insbesondere für blockierende Arbeitslasten erweisen sich Virtual Threads als besonders geeignet. Die Leichtgewichtigkeit der Virtual Threads eliminiert die Notwendigkeit des Poolings oder der Wiederverwendung, was die Implementierung vereinfacht. Dennoch ist zu berücksichtigen, dass bei der Verwendung synchronisierter Blöcke eine Bindung von Virtual Threads an Plattform-Threads erfolgen kann. Zudem kann es bei blockierenden JDK-APIs, wie beispielsweise File I/O, zu einer suboptimalen Funktionsweise in Verbindung mit Virtual Threads kommen. Daher ist eine Berücksichtigung der spezifischen Anforderungen und Einschränkungen der jeweiligen Anwendung von entscheidender Bedeutung.</p><p>Des Weiteren sind zusätzliche geplante Funktionalitäten wie &#8222;Structured Concurrency&#8220; und &#8222;Scoped Values&#8220; zu erwarten, welche die Arbeit mit Threads und paralleler Ausführung weiter optimieren und vereinfachen werden.</p><p>Die Einführung von Virtual Threads stellt einen signifikanten Fortschritt für die Java-Plattform dar, da sie die Effizienz und Skalierbarkeit von Anwendungen erheblich verbessert. Entwicklerinnen und Entwickler haben nun die Möglichkeit, hochskalierbare Anwendungen mit einer großen Anzahl gleichzeitiger Threads zu erstellen, ohne die mit den klassischen Performance-Problemen traditioneller, vom Betriebssystem verwalteter Threads einhergehenden Nachteile in Kauf nehmen zu müssen.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-a44205d elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="a44205d" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-1de981b" data-id="1de981b" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-89b51f0 elementor-widget elementor-widget-spacer" data-id="89b51f0" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-91c798d elementor-widget elementor-widget-heading" data-id="91c798d" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Zusammenfassung</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-8387aee elementor-widget elementor-widget-text-editor" data-id="8387aee" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Java 21 beinhaltet eine Vielzahl nützlicher und zum Teil lang ersehnter Updates der API. Die Implementierung neuer Methoden innerhalb der Math- und String-Klassen führt zu einer signifikanten Erweiterung der Funktionalität. Zudem erfahren die Sequenced Collections wesentliche Funktionsaktualisierungen. Die Möglichkeit des Pattern Matching erlaubt die Erstellung von deutlich einfacherem und klarer strukturiertem Code, insbesondere durch die Einführung von Sealed Interfaces und Record Patterns. Die Nutzung von Virtual Threads führt zu einer signifikanten Steigerung der Performance, wodurch die Effizienz der Thread-Verwaltung erheblich verbessert wird. Der Artikel beleuchtet diese Aspekte im Detail und zeigt auf, wie sie zur Optimierung moderner Java-Anwendungen beitragen können.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-ffeddce elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="ffeddce" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-d66af2d" data-id="d66af2d" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-0a46019 elementor-widget elementor-widget-spacer" data-id="0a46019" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				</div>
		<p>Der Beitrag <a href="https://www.inoteq.com/2024/08/03/java-21-ein-kurzer-ueberblick-ueber-die-wichtigsten-neuerungen/">Java 21: Ein kurzer Überblick über die wichtigsten Neuerungen</a> erschien zuerst auf <a href="https://www.inoteq.com">INOTEQ GmbH</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.inoteq.com/2024/08/03/java-21-ein-kurzer-ueberblick-ueber-die-wichtigsten-neuerungen/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Automatisches Front-End-Testing einer OAuth 2.0 Spring-Boot Anwendungen</title>
		<link>https://www.inoteq.com/2024/02/08/automatisches-front-end-testing-einer-oauth-2-0-spring-boot-anwendungen/</link>
					<comments>https://www.inoteq.com/2024/02/08/automatisches-front-end-testing-einer-oauth-2-0-spring-boot-anwendungen/#respond</comments>
		
		<dc:creator><![CDATA[Alexander Kusmin]]></dc:creator>
		<pubDate>Thu, 08 Feb 2024 15:09:39 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Keycloak]]></category>
		<category><![CDATA[OAuth2]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[Testing]]></category>
		<guid isPermaLink="false">https://www.inoteq.com/?p=2754</guid>

					<description><![CDATA[<p>Dieser Beitrag vertieft die Thematik des automatischen Front-End-Testings einer OAuth 2.0 Spring Boot-Anwendung. Er fungiert als komplementäre Erweiterung zu unserem vorangegangenen Beitrag über Spring Boot mit OAuth 2.0 und Keycloak. Im Fokus stehen die Integration von Keycloak als zentraler OAuth 2.0 Dienst und die Rolle von Spring Boot als fundamentale Anwendungsplattform. Ein kurzer Rückblick auf [&#8230;]</p>
<p>Der Beitrag <a href="https://www.inoteq.com/2024/02/08/automatisches-front-end-testing-einer-oauth-2-0-spring-boot-anwendungen/">Automatisches Front-End-Testing einer OAuth 2.0 Spring-Boot Anwendungen</a> erschien zuerst auf <a href="https://www.inoteq.com">INOTEQ GmbH</a>.</p>
]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="2754" class="elementor elementor-2754" data-elementor-post-type="post">
						<section class="elementor-section elementor-top-section elementor-element elementor-element-e45a7f1 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="e45a7f1" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-b443f44" data-id="b443f44" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-5ac51a7 elementor-widget elementor-widget-spacer" data-id="5ac51a7" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-d21d227 elementor-widget elementor-widget-html" data-id="d21d227" data-element_type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
			<!-- Only for Code Snippet Styles -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/themes/prism-coy.min.css" integrity="sha256-VcuSs+n31yebPlEcehu6PvnidJ808ScFBsK8+tJKX+Q=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/components/prism-core.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/plugins/autoloader/prism-autoloader.min.js"></script>
<style>
    :not(pre) > code[class*=language-].inline {
        padding: 0 0.2rem;
        color: #000;
    }
</style>		</div>
				</div>
				<div class="elementor-element elementor-element-d6809f5 elementor-widget elementor-widget-theme-post-title elementor-page-title elementor-widget-heading" data-id="d6809f5" data-element_type="widget" data-widget_type="theme-post-title.default">
				<div class="elementor-widget-container">
			<h1 class="elementor-heading-title elementor-size-default">Automatisches Front-End-Testing einer OAuth 2.0 Spring-Boot Anwendungen</h1>		</div>
				</div>
				<div class="elementor-element elementor-element-f62244b elementor-widget elementor-widget-post-info" data-id="f62244b" data-element_type="widget" data-widget_type="post-info.default">
				<div class="elementor-widget-container">
					<ul class="elementor-inline-items elementor-icon-list-items elementor-post-info">
								<li class="elementor-icon-list-item elementor-repeater-item-170d69d elementor-inline-item" itemprop="datePublished">
						<a href="https://www.inoteq.com/2024/02/08/">
											<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="fas fa-calendar"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-date">
										Februar 8, 2024					</span>
									</a>
				</li>
				<li class="elementor-icon-list-item elementor-repeater-item-680cb58 elementor-inline-item" itemprop="author">
						<a href="https://www.inoteq.com/author/akusmin/">
											<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="far fa-user-circle"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-author">
										Alexander Kusmin					</span>
									</a>
				</li>
				<li class="elementor-icon-list-item elementor-repeater-item-0db5256 elementor-inline-item" itemprop="about">
										<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="fas fa-tags"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-terms">
										<span class="elementor-post-info__terms-list">
				<a href="https://www.inoteq.com/tag/keycloak/" class="elementor-post-info__terms-list-item">Keycloak</a>, <a href="https://www.inoteq.com/tag/oauth2/" class="elementor-post-info__terms-list-item">OAuth2</a>, <a href="https://www.inoteq.com/tag/spring/" class="elementor-post-info__terms-list-item">Spring</a>, <a href="https://www.inoteq.com/tag/testing/" class="elementor-post-info__terms-list-item">Testing</a>				</span>
					</span>
								</li>
				</ul>
				</div>
				</div>
				<div class="elementor-element elementor-element-a90db89 elementor-widget elementor-widget-text-editor" data-id="a90db89" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Dieser Beitrag vertieft die Thematik des automatischen Front-End-Testings einer OAuth 2.0 Spring Boot-Anwendung. Er fungiert als komplementäre Erweiterung zu unserem vorangegangenen Beitrag über <a href="https://www.inoteq.com/2023/11/30/oauth2-keycloak-locally/" target="_blank" rel="noopener">Spring Boot mit OAuth 2.0 und Keycloak</a>. Im Fokus stehen die Integration von Keycloak als zentraler OAuth 2.0 Dienst und die Rolle von Spring Boot als fundamentale Anwendungsplattform.</p><p>Ein kurzer Rückblick auf die wesentlichen Konzepte von OAuth 2.0 sowie die spezifische Bedeutung von Keycloak bietet einen soliden Ausgangspunkt. In unserem vorherigen Beitrag haben wir bereits die Integration von Spring Boot und Keycloak beleuchtet, um eine sichere OAuth 2.0-Authentifizierung zu gewährleisten. Falls Sie diesen Beitrag bisher nicht verfolgt haben, empfiehlt es sich, einen Blick darauf zu werfen, da der vorliegende Beitrag nahtlos auf den dort behandelten Grundlagen aufbaut.</p><p>Die Analyse konzentriert sich auf fortgeschrittene Aspekte des automatischen Front-End-Testings. Insbesondere wird die Erstellung einer GitLab Pipeline für automatische Tests auf bewährten Prinzipien von Keycloak und Spring Boot basierend erkundet. Das Ziel ist es, Ihnen Einblicke in die strategischen Schritte zu geben, um eine effiziente und zuverlässige Testumgebung zu schaffen, die sich nahtlos in Ihre Entwicklungsprozesse integrieren lässt.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-8d73400 elementor-widget elementor-widget-theme-post-featured-image elementor-widget-image" data-id="8d73400" data-element_type="widget" data-widget_type="theme-post-featured-image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img loading="lazy" decoding="async" width="2000" height="1200" src="https://www.inoteq.com/wp-content/uploads/2023/11/wp4.png" class="attachment-full size-full wp-image-2920" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2023/11/wp4.png 2000w, https://www.inoteq.com/wp-content/uploads/2023/11/wp4-300x180.png 300w, https://www.inoteq.com/wp-content/uploads/2023/11/wp4-1024x614.png 1024w, https://www.inoteq.com/wp-content/uploads/2023/11/wp4-768x461.png 768w, https://www.inoteq.com/wp-content/uploads/2023/11/wp4-1536x922.png 1536w" sizes="(max-width: 2000px) 100vw, 2000px" />											<figcaption class="widget-image-caption wp-caption-text">KI generiertes Symbolbild: compelling, illustration, symbolizing automated pipeline testing, logo-style, clipboard with test results, pipeline</figcaption>
										</figure>
							</div>
				</div>
				<div class="elementor-element elementor-element-0abacf3 elementor-toc--minimized-on-tablet elementor-widget elementor-widget-table-of-contents" data-id="0abacf3" data-element_type="widget" data-settings="{&quot;exclude_headings_by_selector&quot;:&quot;.exclude-from-toc&quot;,&quot;headings_by_tags&quot;:[&quot;h2&quot;,&quot;h3&quot;,&quot;h4&quot;,&quot;h5&quot;,&quot;h6&quot;],&quot;marker_view&quot;:&quot;numbers&quot;,&quot;minimize_box&quot;:&quot;yes&quot;,&quot;minimized_on&quot;:&quot;tablet&quot;,&quot;hierarchical_view&quot;:&quot;yes&quot;,&quot;min_height&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;min_height_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;min_height_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}" data-widget_type="table-of-contents.default">
				<div class="elementor-widget-container">
					<div class="elementor-toc__header">
			<h4 class="elementor-toc__header-title">
				Table of Contents			</h4>
							<div class="elementor-toc__toggle-button elementor-toc__toggle-button--expand" role="button" tabindex="0" aria-controls="elementor-toc__0abacf3" aria-expanded="true" aria-label="Open table of contents"><i aria-hidden="true" class="fas fa-chevron-down"></i></div>
				<div class="elementor-toc__toggle-button elementor-toc__toggle-button--collapse" role="button" tabindex="0" aria-controls="elementor-toc__0abacf3" aria-expanded="true" aria-label="Close table of contents"><i aria-hidden="true" class="fas fa-chevron-up"></i></div>
					</div>
		<div id="elementor-toc__0abacf3" class="elementor-toc__body">
			<div class="elementor-toc__spinner-container">
				<i class="elementor-toc__spinner eicon-animation-spin eicon-loading" aria-hidden="true"></i>			</div>
		</div>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-247900a elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="247900a" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-daa0597" data-id="daa0597" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-0d03c77 elementor-widget elementor-widget-spacer" data-id="0d03c77" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-a3ebc38 elementor-widget elementor-widget-heading" data-id="a3ebc38" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Keycloak für die Testumgebung</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-0268f17 elementor-widget elementor-widget-text-editor" data-id="0268f17" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Zum Testen der Spring Boot Anwendung ist eine Keycloak Konfiguration für die Testumgebung erforderlich. Später wird mithilfe von Testcontainers eine Keycloak-Instanz mit der gegebenen Konfiguration geladen, um die Authentifizierung in den Tests zu übernehmen. Zu diesem Zweck wird eine Import-Datei im JSON-Format benötigt. Ein einfacher Export der Konfiguration ist über die Keycloak-Benutzeroberfläche zwar möglich, allerdings werden aus Sicherheitsgründen die angelegten Benutzer nicht mit exportiert. Die Testumgebung wäre dann zwar in der Lage, sich mit dem OAuth 2.0 Server zu verbinden und normal zu starten, es stehen anschließend jedoch keine Benutzer für die Authentifizierung zur Verfügung.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-3dd3b3e elementor-widget elementor-widget-heading" data-id="3dd3b3e" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Realm-Export mit Benutzern</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-fc7fb45 elementor-widget elementor-widget-text-editor" data-id="fc7fb45" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Im Folgenden wird erklärt, wie man einen bereits vollständig konfigurierten Realm mit allen Benutzern exportiert, während der Keycloak-Server in einer Docker-Umgebung läuft. Im <a href="https://github.com/inoteq/spring-boot-keycloak-oauth2" target="_blank" rel="noopener">Repository</a> zum letzten Beitrag findet sich bereits eine aus dem vorkonfigurierten Demo-Realm exportierte <strong><i>realm.json</i></strong> Datei, die hier wieder verwendet wird.</p><p>Folgender Befehl wird im Terminal des Systems ausgeführt:</p><p><code class="language-bash inline">docker exec -it keycloak-demo bash</code></p><p>Darüber gelangen wir in das Terminal innerhalb des Containers, auf dem der Keycloak-Server läuft. Dabei wird hier der Container <em><strong>keycloak-demo</strong></em> gewählt. Innerhalb des Containers wird dann folgender Befehl ausgeführt:</p><p><code class="language-bash inline">./opt/keycloak/bin/kc.sh export --dir /tmp/export --realm demo-realm --users realm_file</code></p><p>Damit exportieren wir die Realm-Konfiguration mit allen Benutzerdaten als <strong><i>demo-realm-realm.json</i></strong> in das Verzeichnis <em><strong>/tmp/export</strong></em> innerhalb des Containers. Mit dem Befehl <code class="language-bash inline">exit</code> gelangt man wieder in das Terminal des eigenen Systems zurück. Zuletzt wird die exportierte Datei mit dem folgendem Befehl aus dem Container herauskopiert.</p><p><code class="language-bash inline">docker cp keycloak-demo:/tmp/export/demo-realm-realm.json ~/Desktop/realm.json</code></p><p>In diesem Beispiel wird es einfach auf den Desktop kopiert und gleichzeitig in <strong><i>realm.json</i></strong> umbenannt, später wird diese aber im Spring Boot-Projekt gebraucht.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-b50f9a4 elementor-widget elementor-widget-alert" data-id="b50f9a4" data-element_type="widget" data-widget_type="alert.default">
				<div class="elementor-widget-container">
					<div class="elementor-alert elementor-alert-warning" role="alert">
			<span class="elementor-alert-title">Sensible Daten</span>
							<span class="elementor-alert-description">Die exportierte Realm-Konfiguration kann sensible Daten wie Passwort-Hashes oder E-Mails enthalten. Aus diesem Grund sollte diese Variante ausschließlich für Entwicklungszwecke oder mit Testsysteme mit Testdaten verwendet werden.</span>
								</div>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-1ac0dc1 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="1ac0dc1" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-67a783c" data-id="67a783c" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-8dc0c6a elementor-widget elementor-widget-spacer" data-id="8dc0c6a" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-8c0be78 elementor-widget elementor-widget-heading" data-id="8c0be78" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Playwright Frontend Tests</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-d36b81d elementor-widget elementor-widget-text-editor" data-id="d36b81d" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Um die Benutzeroberfläche der Anwendung zu testen, wird das Testframework <a href="https://playwright.dev/java/" target="_blank" rel="noopener">Playwright</a> verwendet.</p><p>Im Vergleich zu dem bekannteren Selenium bietet Playwright einige Vorteile, wie zum Beispiel eine bessere Performance und weniger erforderlichen Boilerplate-Code beim Schreiben der Tests. Playwright bietet eine verbesserte Browser-Automation und unterstützt mehrere Browser. Außerdem gibt es eine native Unterstützung für den Headless-Modus, bessere Möglichkeiten zur Manipulation von Webseiten und eine einfache Verwendung mit Pipelines für automatische Tests.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-60e90f4 elementor-widget elementor-widget-heading" data-id="60e90f4" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Konfiguration</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-999edee elementor-widget elementor-widget-text-editor" data-id="999edee" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Für die Verwendung von Playwright für Tests muss die <b><i>build.gradle</i></b> angepasst werden. Zunächst sollte sichergestellt werden, dass es eine Test-Task für Gradle existiert und die benötigten Abhängigkeiten für <a href="https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test" target="_blank" rel="noopener">Spring Boot Starter Tests</a> als auch <a href="https://mvnrepository.com/artifact/com.microsoft.playwright/playwright" target="_blank" rel="noopener">Playwright</a> für die Testimplementierung angegeben sind, als auch die Abhängigkeiten für die Verwendung von OAuth 2.0 selbst.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-ae00014 elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="ae00014" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-1821" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1821" aria-expanded="false">build.gradle</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1821" aria-expanded="false">build.gradle</div>
					<div id="elementor-tab-content-1821" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-1821" tabindex="0" hidden="false"><pre><code class="language-groovy">dependencies {
    ...
    testImplementation 'org.springframework.boot:spring-boot-starter-test:3.2.2'
    testImplementation 'com.microsoft.playwright:playwright:1.41.1'
}

...

tasks.named('test') {
    useJUnitPlatform()
}
</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-971daba elementor-widget elementor-widget-text-editor" data-id="971daba" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Eine Testklasse wird erstellt und für die Spring Boot Anwendung sowie für Playwright konfiguriert. Zunächst wird Playwright so konfiguriert, dass der automatische Testprozess beobachtet werden kann, um mögliche Fehler zu sichten. Später sollte diese Option wieder ausgestellt werden, da die Tests so wesentlich schneller laufen.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-948a594 elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="948a594" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-1551" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1551" aria-expanded="false">src/test/kotlin/DemoTest.kt</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1551" aria-expanded="false">src/test/kotlin/DemoTest.kt</div>
					<div id="elementor-tab-content-1551" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-1551" tabindex="0" hidden="false"><pre><code class="language-kotlin">import ...

@SpringBootTest(
    classes = [DemoApplication::class],
    webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT
)
class DemoTest {
    companion object {
        // Playwright setup
        private var playwright: Playwright? = null
        private var browser: Browser? = null
        private var context: BrowserContext? = null
        private var page: Page? = null

        @JvmStatic
        @BeforeAll
        fun launchBrowser() {
            playwright = Playwright.create()
            
            browser = playwright?.chromium()?.launch(
                // Run playwright in headed mode with slow motion to see what's happening
                BrowserType.LaunchOptions().setHeadless(false).setSlowMo(100.0)
            )
        }

        @JvmStatic
        @AfterAll
        fun closeBrowser() {
            playwright?.close()
        }
    }

    @BeforeEach
    fun createContextAndPage() {
        context = browser?.newContext()
        page = context?.newPage()
    }

    @AfterEach
    fun closeContext() {
        context?.close()
    }
}
</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-acca8d1 elementor-widget elementor-widget-text-editor" data-id="acca8d1" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Damit kann Playwright nun für Tests verwendet werden.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-fe028e7 elementor-widget elementor-widget-heading" data-id="fe028e7" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Beispieltests</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-c839f98 elementor-widget elementor-widget-text-editor" data-id="c839f98" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							Wir halten uns bei diesem Beispiel an das Demo-Projekt aus dem letzten Beitrag und wollen die beiden Endpunkte <code class="language-plain inline">/public</code> und <code class="language-plain inline">/private</code> testen. Der <code class="language-plain inline">/public</code> Endpunkt ist immer aufrufbar, aber der <code class="language-plain inline">/private</code> Endpunkt ist erst aufrufbar, nachdem sich der Benutzer erfolgreich authentifiziert hat. Dafür müssen wir Playwright mitteilen, dass er nach dem Aufruf von <code class="language-plain inline">/private</code> auf eine Weiterleitung zum OAuth 2.0 Server warten soll, dort dann Benutzername und Passwort eingibt, bestätigt und zu guter Letzt wieder auf dem erwarteten Endpunkt <code class="language-plain inline">/private</code> landet.						</div>
				</div>
				<div class="elementor-element elementor-element-7391122 elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="7391122" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-1211" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1211" aria-expanded="false">src/test/kotlin/DemoTest.kt</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1211" aria-expanded="false">src/test/kotlin/DemoTest.kt</div>
					<div id="elementor-tab-content-1211" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-1211" tabindex="0" hidden="false"><pre><code class="language-kotlin">@Test
fun publicEndpointTest() {
    page?.navigate("http://localhost:8080/public")
    assertThat(page?.locator("body")).hasText("Hello from a public endpoint!")
}

@Test
fun privateEndpointTest() {
    // Unable to access private endpoint without logging in and redirects to login page
    page?.navigate("http://localhost:8080/private")

    // Login with example user 'John Doe' by filling the login form and submitting it
    page?.fill("#username", "john.doe")
    page?.fill("#password", "password")
    page?.locator("input[type=submit]")?.click()
    // Wait for redirect to previously requested private endpoint
    page?.waitForURL("http://localhost:8080/private?continue")

    // Check for expected content on private endpoint
    assertThat(page?.locator("body")).hasText("Hello from a private endpoint!")
}</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-945f459 elementor-widget elementor-widget-text-editor" data-id="945f459" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Um sicherzustellen, dass unsere Tests korrekt funktionieren, lassen wir den OAuth 2.0 Keycloak-Container im Hintergrund laufen und führen die Tests aus. Dabei wird ein neuer Chromium-Browser geöffnet, den Playwright manipuliert. Für einen kurzen Moment ist auch zu sehen, wie Playwright sich am OAuth 2.0 Server anmeldet.</p><p>Um die Auswirkungen von fehlendem OAuth 2.0 Zugriff zu zeigen, wird der Keycloak-Container gestoppt und die Tests erneut ausgeführt. Dadurch sollten die Tests fehlschlagen. Im nächsten Schritt wird der Zugriff wieder ermöglicht, indem bei den Tests ein Keycloak-Container erstellt und gestartet wird.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-1014992 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="1014992" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-7af1228" data-id="7af1228" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-c29614c elementor-widget elementor-widget-spacer" data-id="c29614c" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-8ab9cf3 elementor-widget elementor-widget-heading" data-id="8ab9cf3" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Keycloak Testcontainer</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-31071f5 elementor-widget elementor-widget-text-editor" data-id="31071f5" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Zunächst benötigen wir die richtige Abhängigkeit, um einen Keycloak-Container für Tests zu starten. Dafür gibt es den <a href="https://github.com/dasniko/testcontainers-keycloak" target="_blank" rel="noopener">Keycloak Testcontainer</a>, eine spezielle Variante des Testcontainers, der für Keycloak angepasst wurde. Dazu wird die folgende Zeile in <b><i>build.gradle</i></b> eingefügt:</p><p><code class="language-gradle inline">testImplementation 'com.github.dasniko:testcontainers-keycloak:3.2.0'</code></p><p>Wichtig ist, dass Docker auf Ihrem System läuft.</p><p>Die Testklasse wird so angepasst, dass unser gewünschter OAuth 2.0 Service wieder erreichbar ist, ohne dass wir den Container dafür erstellen und starten müssen. Dazu wird der Code wie folgt ergänzt:</p>						</div>
				</div>
				<div class="elementor-element elementor-element-99a6d9a elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="99a6d9a" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-1611" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1611" aria-expanded="false">src/test/kotlin/DemoTest.kt</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1611" aria-expanded="false">src/test/kotlin/DemoTest.kt</div>
					<div id="elementor-tab-content-1611" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-1611" tabindex="0" hidden="false"><pre><code class="language-kotlin">companion object {
    // Start a Keycloak instance with an import file for the demo realm
    @JvmStatic
    private val keycloakContainer = KeycloakContainer().apply {
        withRealmImportFile("realm.json")
        portBindings = listOf("8081:8080")
        start()
    }

    // Register the Keycloak issuer URL as a dynamic property for the Spring Boot application
    @JvmStatic
    @DynamicPropertySource
    private fun registerResourceServerIssuerProperty(registry: DynamicPropertyRegistry) {
        registry.add("spring.security.oauth2.client.provider.demo-provider.issuer-uri") {
            "${keycloakContainer.authServerUrl}/realms/demo-realm"
        }
    }

    ...

    @JvmStatic
    @BeforeAll
    fun launchBrowser() {
        playwright = Playwright.create()
        browser = playwright?.chromium()?.launch() // Use headless mode
    }

   ...
}</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-b266315 elementor-widget elementor-widget-text-editor" data-id="b266315" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Es wird ein Keycloak-Container definiert, der die zuvor exportierte <b><i>realm.json</i></b> importiert. Diese Datei muss sich dazu im Verzeichnis <b><i>src/test/resources </i></b>befinden. Zudem wird vor dem Start die Portbindung definiert.</p><p>Testcontainer werden immer mit einem zufälligen Port gestartet. Die Anwendung benötigt jedoch diesen Port, um den OAuth 2.0 Dienst richtig zu konfigurieren. Für diesen Zweck wird im Code die dynamische Eigenschaft für den OAuth 2.0-Dienst angepasst, indem wir die URL des Testcontainers einschließlich des Ports vor dem verwendeten Realm angeben.</p><p>Die Tests sind jetzt unabhängig von der lokalen Umgebung ausführbar. Während des Testprozesses wird ein neuer Container in Docker erstellt und nach Abschluss der Tests wieder gelöscht.</p><p>Es empfiehlt sich, Playwright wieder headless zu benutzen, da dadurch eine wesentlich bessere Performance erreicht wird. Das ist vor allem im nächsten Schritt wichtig.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-2802df5 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="2802df5" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-8cf8bd3" data-id="8cf8bd3" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-9f0c98e elementor-widget elementor-widget-spacer" data-id="9f0c98e" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-b9d6ec9 elementor-widget elementor-widget-heading" data-id="b9d6ec9" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">GitLab Pipeline</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-49b2e44 elementor-widget elementor-widget-text-editor" data-id="49b2e44" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Das Ziel war bisher, die Tests zu automatisieren und für eine GitLab-Pipeline ausführbar zu machen. Dafür ist es wichtig, dass der GitLab-Runner Docker-Container ausführen kann.</p><p>Playwright bietet ein Image an, das für die Zwecke dieses Projekts geeignet ist. Auf der <a href="https://playwright.dev/java/docs/ci#gitlab-ci" target="_blank" rel="noopener">Playwright-Website</a> gibt es genauere Details zur kontinuierlichen Integration, einschließlich GitHub und anderen Plattformen. Auch für Testcontainers werden <a href="https://java.testcontainers.org/supported_docker_environment/continuous_integration/gitlab_ci/" target="_blank" rel="noopener">ausführliche Beispiele</a> gezeict, wie man z.B. eine GitLab Pipeline mit Testcontainers konfiguriert. In unserem Fall orientieren wir uns an der Variante, die Docker-in-Docker verwendet.</p><p>Sobald die benötigten Anpassungen vorgenommen wurden, lassen sich mittels <code class="language-bash inline">./gradlew test</code> die Tests ausführen.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-9069fba elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="9069fba" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-1511" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1511" aria-expanded="false">gitlab-ci.yml</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1511" aria-expanded="false">gitlab-ci.yml</div>
					<div id="elementor-tab-content-1511" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-1511" tabindex="0" hidden="false"><pre><code class="language-yml">image: mcr.microsoft.com/playwright/java:v1.41.0-jammy

services:
  - name: docker:dind
    command: [ "--tls=false" ]

variables:
  DOCKER_HOST: "tcp://docker:2375"
  DOCKER_TLS_CERTDIR: ""
  DOCKER_DRIVER: overlay2

before_script:
  - GRADLE_USER_HOME="$(pwd)/.gradle"
  - export GRADLE_USER_HOME

stages:
  - test

tests:
  stage: test
  script:
    - ./gradlew test
</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-b9bf388 elementor-widget elementor-widget-text-editor" data-id="b9bf388" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Wie man nun sehen kann, läuft die Pipeline erfolgreich durch. Allerdings ist es erwähnenswert, dass sie einige Zeit dafür benötigt. Mit einer größeren Anzahl an Tests steigt auch die Zeit, die die Pipeline benötigt, um diese auszuführen. Dabei sei gesagt, dass die meiste Zeit für die Vorbereitung der Pipeline benötigt wird, einschließlich der größeren Abhängigkeiten wie dem Playwright Browser.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-8b042b4 elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="8b042b4" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-1451" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1451" aria-expanded="false">GitLab Runner</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1451" aria-expanded="false">GitLab Runner</div>
					<div id="elementor-tab-content-1451" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-1451" tabindex="0" hidden="false"><pre><code class="language-log">Running with gitlab-runner 14.7.0 (98daeee0)
  on gitlab-runner-01 y7AkGoZD
Preparing the "docker" executor 00:34
...
Preparing environment 00:00
...
Getting source from Git repository 00:02
...
Executing "step_script" stage of the job script 03:52
Using docker image sha256:df9599e540016f99fbcd1d862224ae9d1cf30df17fa5d367c969ee37cc060afb for mcr.microsoft.com/playwright/java:v1.41.0-jammy with digest mcr.microsoft.com/playwright/java@sha256:390fdf6801be59dd7bc6a3fad6344ae9d795b6585d102af293b57d61076d0824 ...
$ GRADLE_USER_HOME="$(pwd)/.gradle"
$ export GRADLE_USER_HOME
$ ./gradlew test
Downloading https://services.gradle.org/distributions/gradle-8.5-bin.zip
............10%.............20%............30%.............40%.............50%............60%.............70%.............80%............90%.............100%
Welcome to Gradle 8.5!
Here are the highlights of this release:
 - Support for running on Java 21
 - Faster first use with Kotlin DSL
 - Improved error and warning messages
For more details see https://docs.gradle.org/8.5/release-notes.html
Starting a Gradle Daemon (subsequent builds will be faster)
&gt; Task :checkKotlinGradlePluginConfigurationErrors
&gt; Task :processResources
&gt; Task :processTestResources
&gt; Task :compileKotlin
&gt; Task :compileJava NO-SOURCE
&gt; Task :classes
&gt; Task :compileTestKotlin
&gt; Task :compileTestJava NO-SOURCE
&gt; Task :testClasses
&gt; Task :test
OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0.
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
For more on this, please refer to https://docs.gradle.org/8.5/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation.
BUILD SUCCESSFUL in 3m 50s
6 actionable tasks: 6 executed
Cleaning up project directory and file based variables 00:01
Job succeeded</code></pre></div>
							</div>
		</div>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-01f7774 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="01f7774" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-c412524" data-id="c412524" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-9689723 elementor-widget elementor-widget-spacer" data-id="9689723" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-7fdc40d elementor-widget elementor-widget-heading" data-id="7fdc40d" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Fazit</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-d14bd30 elementor-widget elementor-widget-text-editor" data-id="d14bd30" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die vorgestellten Tests zeichnen sich durch ihre hohe Realitätsnähe aus, da sie auf einer dynamischen Keycloak-Testumgebung basieren. Dies vereinfacht die Entwicklung und trägt zur Sicherstellung einer zuverlässigen Authentifizierung bei. Jedoch ist es wichtig zu beachten, dass die GitLab Pipeline, aufgrund ihrer umfassenden Abhängigkeiten wie dem Playwright Browser, eine längere Ausführungszeit aufweisen kann. Trotz dieser potenziellen Einschränkung bieten die realitätsnahen Tests einen unschätzbaren Wert für die Entwicklung von sicheren und zuverlässigen OAuth 2.0 Spring Boot-Anwendungen.</p>
<p>Für weitere Details steht das <a href="https://github.com/inoteq/spring-boot-keycloak-oauth2-testing">GitHub Repository</a> zur Verfügung, das alle im Artikel beschriebenen Schritte und Konfigurationen enthält.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-44c973b elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="44c973b" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-5b14c43" data-id="5b14c43" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-9d09d69 elementor-widget elementor-widget-spacer" data-id="9d09d69" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-354e095 elementor-widget elementor-widget-heading" data-id="354e095" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Referenzierte Artikel</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-98051f8 elementor-grid-1 elementor-grid-tablet-1 elementor-posts--thumbnail-left elementor-hidden-tablet elementor-hidden-mobile elementor-grid-mobile-1 elementor-widget elementor-widget-posts" data-id="98051f8" data-element_type="widget" data-settings="{&quot;classic_columns&quot;:&quot;1&quot;,&quot;classic_columns_tablet&quot;:&quot;1&quot;,&quot;classic_columns_mobile&quot;:&quot;1&quot;,&quot;classic_row_gap&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:35,&quot;sizes&quot;:[]},&quot;classic_row_gap_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;classic_row_gap_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}" data-widget_type="posts.classic">
				<div class="elementor-widget-container">
					<div class="elementor-posts-container elementor-posts elementor-posts--skin-classic elementor-grid">
				<article class="elementor-post elementor-grid-item post-1744 post type-post status-publish format-standard has-post-thumbnail hentry category-blog tag-keycloak tag-oauth-2-0 tag-spring">
				<a class="elementor-post__thumbnail__link" href="https://www.inoteq.com/2023/11/30/oauth2-keycloak-locally/" tabindex="-1" >
			<div class="elementor-post__thumbnail"><img loading="lazy" decoding="async" width="2000" height="1200" src="https://www.inoteq.com/wp-content/uploads/2023/11/wp1.png" class="attachment-full size-full wp-image-2922" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2023/11/wp1.png 2000w, https://www.inoteq.com/wp-content/uploads/2023/11/wp1-300x180.png 300w, https://www.inoteq.com/wp-content/uploads/2023/11/wp1-1024x614.png 1024w, https://www.inoteq.com/wp-content/uploads/2023/11/wp1-768x461.png 768w, https://www.inoteq.com/wp-content/uploads/2023/11/wp1-1536x922.png 1536w" sizes="(max-width: 2000px) 100vw, 2000px" /></div>
		</a>
				<div class="elementor-post__text">
				<p class="elementor-post__title">
			<a href="https://www.inoteq.com/2023/11/30/oauth2-keycloak-locally/" >
				Integration von OAuth 2.0 in Spring Boot mit Keycloak			</a>
		</p>
				<div class="elementor-post__meta-data">
					<span class="elementor-post-author">
			Alexander Kusmin		</span>
				<span class="elementor-post-date">
			30. November 2023		</span>
				</div>
				<div class="elementor-post__excerpt">
			<p>Dieser Leitfaden beschreibt die Integration von OAuth 2.0 in eine Spring Boot Anwendung mit Keycloak. Nach einer kurzen Einführung in die Spring Boot Plattform liegt der Schwerpunkt auf der genauen Konfiguration von Keycloak als vertrauenswürdigen OAuth 2.0 Server und der Absicherung bestimmter Endpunkte in der Anwendung mit Anmeldedaten. Der Beitrag ist dabei so strukturiert, dass Entwickler Schritt für Schritt eine sichere Authentifizierung in einer Spring Boot-Anwendung implementieren können. Inhaltsverzeichnis Spring</p>
		</div>
		
		<a class="elementor-post__read-more" href="https://www.inoteq.com/2023/11/30/oauth2-keycloak-locally/" aria-label="Read more about Integration von OAuth 2.0 in Spring Boot mit Keycloak" tabindex="-1" >
			Weiterlesen »		</a>

				</div>
				</article>
				</div>
		
				</div>
				</div>
				<div class="elementor-element elementor-element-1b24a2c elementor-grid-1 elementor-grid-tablet-1 elementor-posts--thumbnail-left elementor-hidden-desktop elementor-hidden-mobile elementor-grid-mobile-1 elementor-widget elementor-widget-posts" data-id="1b24a2c" data-element_type="widget" data-settings="{&quot;classic_columns&quot;:&quot;1&quot;,&quot;classic_columns_tablet&quot;:&quot;1&quot;,&quot;classic_columns_mobile&quot;:&quot;1&quot;,&quot;classic_row_gap&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:35,&quot;sizes&quot;:[]},&quot;classic_row_gap_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;classic_row_gap_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}" data-widget_type="posts.classic">
				<div class="elementor-widget-container">
					<div class="elementor-posts-container elementor-posts elementor-posts--skin-classic elementor-grid">
				<article class="elementor-post elementor-grid-item post-1744 post type-post status-publish format-standard has-post-thumbnail hentry category-blog tag-keycloak tag-oauth-2-0 tag-spring">
				<a class="elementor-post__thumbnail__link" href="https://www.inoteq.com/2023/11/30/oauth2-keycloak-locally/" tabindex="-1" >
			<div class="elementor-post__thumbnail"><img loading="lazy" decoding="async" width="2000" height="1200" src="https://www.inoteq.com/wp-content/uploads/2023/11/wp1.png" class="attachment-full size-full wp-image-2922" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2023/11/wp1.png 2000w, https://www.inoteq.com/wp-content/uploads/2023/11/wp1-300x180.png 300w, https://www.inoteq.com/wp-content/uploads/2023/11/wp1-1024x614.png 1024w, https://www.inoteq.com/wp-content/uploads/2023/11/wp1-768x461.png 768w, https://www.inoteq.com/wp-content/uploads/2023/11/wp1-1536x922.png 1536w" sizes="(max-width: 2000px) 100vw, 2000px" /></div>
		</a>
				<div class="elementor-post__text">
				<p class="elementor-post__title">
			<a href="https://www.inoteq.com/2023/11/30/oauth2-keycloak-locally/" >
				Integration von OAuth 2.0 in Spring Boot mit Keycloak			</a>
		</p>
				<div class="elementor-post__meta-data">
					<span class="elementor-post-author">
			Alexander Kusmin		</span>
				<span class="elementor-post-date">
			30. November 2023		</span>
				</div>
				<div class="elementor-post__excerpt">
			<p>Dieser Leitfaden beschreibt die Integration von OAuth 2.0 in eine Spring Boot Anwendung mit Keycloak. Nach einer kurzen Einführung in die Spring Boot Plattform liegt der Schwerpunkt auf der genauen Konfiguration von Keycloak als vertrauenswürdigen</p>
		</div>
		
		<a class="elementor-post__read-more" href="https://www.inoteq.com/2023/11/30/oauth2-keycloak-locally/" aria-label="Read more about Integration von OAuth 2.0 in Spring Boot mit Keycloak" tabindex="-1" >
			Weiterlesen »		</a>

				</div>
				</article>
				</div>
		
				</div>
				</div>
				<div class="elementor-element elementor-element-decdf13 elementor-grid-1 elementor-grid-tablet-1 elementor-hidden-desktop elementor-hidden-tablet elementor-grid-mobile-1 elementor-posts--thumbnail-top elementor-widget elementor-widget-posts" data-id="decdf13" data-element_type="widget" data-settings="{&quot;classic_columns&quot;:&quot;1&quot;,&quot;classic_columns_tablet&quot;:&quot;1&quot;,&quot;classic_columns_mobile&quot;:&quot;1&quot;,&quot;classic_row_gap&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:35,&quot;sizes&quot;:[]},&quot;classic_row_gap_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;classic_row_gap_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}" data-widget_type="posts.classic">
				<div class="elementor-widget-container">
					<div class="elementor-posts-container elementor-posts elementor-posts--skin-classic elementor-grid">
				<article class="elementor-post elementor-grid-item post-1744 post type-post status-publish format-standard has-post-thumbnail hentry category-blog tag-keycloak tag-oauth-2-0 tag-spring">
				<a class="elementor-post__thumbnail__link" href="https://www.inoteq.com/2023/11/30/oauth2-keycloak-locally/" tabindex="-1" >
			<div class="elementor-post__thumbnail"><img loading="lazy" decoding="async" width="2000" height="1200" src="https://www.inoteq.com/wp-content/uploads/2023/11/wp1.png" class="attachment-full size-full wp-image-2922" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2023/11/wp1.png 2000w, https://www.inoteq.com/wp-content/uploads/2023/11/wp1-300x180.png 300w, https://www.inoteq.com/wp-content/uploads/2023/11/wp1-1024x614.png 1024w, https://www.inoteq.com/wp-content/uploads/2023/11/wp1-768x461.png 768w, https://www.inoteq.com/wp-content/uploads/2023/11/wp1-1536x922.png 1536w" sizes="(max-width: 2000px) 100vw, 2000px" /></div>
		</a>
				<div class="elementor-post__text">
				<p class="elementor-post__title">
			<a href="https://www.inoteq.com/2023/11/30/oauth2-keycloak-locally/" >
				Integration von OAuth 2.0 in Spring Boot mit Keycloak			</a>
		</p>
				<div class="elementor-post__meta-data">
					<span class="elementor-post-author">
			Alexander Kusmin		</span>
				<span class="elementor-post-date">
			30. November 2023		</span>
				</div>
				<div class="elementor-post__excerpt">
			<p>Dieser Leitfaden beschreibt die Integration von OAuth 2.0 in eine Spring Boot Anwendung mit Keycloak. Nach einer kurzen Einführung in die Spring Boot Plattform liegt der Schwerpunkt auf der genauen Konfiguration von Keycloak als vertrauenswürdigen OAuth 2.0 Server und der Absicherung bestimmter Endpunkte in der Anwendung mit Anmeldedaten. Der Beitrag ist dabei so strukturiert, dass Entwickler Schritt für Schritt eine sichere Authentifizierung in einer Spring Boot-Anwendung implementieren können. Inhaltsverzeichnis Spring Boot: Setup und Grundkonfiguration Konfiguration Die Vorbereitung der Spring Boot</p>
		</div>
		
		<a class="elementor-post__read-more" href="https://www.inoteq.com/2023/11/30/oauth2-keycloak-locally/" aria-label="Read more about Integration von OAuth 2.0 in Spring Boot mit Keycloak" tabindex="-1" >
			Weiterlesen »		</a>

				</div>
				</article>
				</div>
		
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-7c4cd4d elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="7c4cd4d" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-f80ad6a" data-id="f80ad6a" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-e5f9e74 elementor-widget elementor-widget-spacer" data-id="e5f9e74" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				</div>
		<p>Der Beitrag <a href="https://www.inoteq.com/2024/02/08/automatisches-front-end-testing-einer-oauth-2-0-spring-boot-anwendungen/">Automatisches Front-End-Testing einer OAuth 2.0 Spring-Boot Anwendungen</a> erschien zuerst auf <a href="https://www.inoteq.com">INOTEQ GmbH</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.inoteq.com/2024/02/08/automatisches-front-end-testing-einer-oauth-2-0-spring-boot-anwendungen/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Kotlin vs. Java im Praxischeck: Ein Spring Boot Erfahrungsbericht</title>
		<link>https://www.inoteq.com/2024/02/01/kotlin-vs-java-vor-und-nachteile-im-fokus-einer-spring-boot-anwendung/</link>
					<comments>https://www.inoteq.com/2024/02/01/kotlin-vs-java-vor-und-nachteile-im-fokus-einer-spring-boot-anwendung/#respond</comments>
		
		<dc:creator><![CDATA[Alexander Kusmin]]></dc:creator>
		<pubDate>Thu, 01 Feb 2024 14:16:59 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[Spring]]></category>
		<guid isPermaLink="false">https://www.inoteq.com/?p=2000</guid>

					<description><![CDATA[<p>Kürzlich habe ich für einen Kunden ein Fullstack Spring Boot Projekt entwickelt, bei dem ich eine gewisse Freiheit bei der Wahl der Technologie und der Programmiersprache hatte. Es stellte sich rasch die Frage, ob ich Java oder Kotlin verwenden sollte. Ich habe mich bewusst für Kotlin als Programmiersprache entschieden, wobei die Entscheidung nicht nur auf [&#8230;]</p>
<p>Der Beitrag <a href="https://www.inoteq.com/2024/02/01/kotlin-vs-java-vor-und-nachteile-im-fokus-einer-spring-boot-anwendung/">Kotlin vs. Java im Praxischeck: Ein Spring Boot Erfahrungsbericht</a> erschien zuerst auf <a href="https://www.inoteq.com">INOTEQ GmbH</a>.</p>
]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="2000" class="elementor elementor-2000" data-elementor-post-type="post">
						<section class="elementor-section elementor-top-section elementor-element elementor-element-1088501 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="1088501" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-2496c09" data-id="2496c09" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-48d72d0 elementor-widget elementor-widget-spacer" data-id="48d72d0" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-9ba4411 elementor-widget elementor-widget-html" data-id="9ba4411" data-element_type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
			<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/themes/prism-coy.min.css" integrity="sha256-VcuSs+n31yebPlEcehu6PvnidJ808ScFBsK8+tJKX+Q=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/components/prism-core.min.js"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/plugins/autoloader/prism-autoloader.min.js"></script>
<!-- Only for Code Snippet Styles -->		</div>
				</div>
				<div class="elementor-element elementor-element-789a6d3 elementor-widget elementor-widget-theme-post-title elementor-page-title elementor-widget-heading" data-id="789a6d3" data-element_type="widget" data-widget_type="theme-post-title.default">
				<div class="elementor-widget-container">
			<h1 class="elementor-heading-title elementor-size-default">Kotlin vs. Java im Praxischeck: Ein Spring Boot Erfahrungsbericht</h1>		</div>
				</div>
				<div class="elementor-element elementor-element-2dbccee elementor-widget elementor-widget-post-info" data-id="2dbccee" data-element_type="widget" data-widget_type="post-info.default">
				<div class="elementor-widget-container">
					<ul class="elementor-inline-items elementor-icon-list-items elementor-post-info">
								<li class="elementor-icon-list-item elementor-repeater-item-db2a2ac elementor-inline-item" itemprop="datePublished">
						<a href="https://www.inoteq.com/2024/02/01/">
											<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="fas fa-calendar"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-date">
										Februar 1, 2024					</span>
									</a>
				</li>
				<li class="elementor-icon-list-item elementor-repeater-item-7e68cc4 elementor-inline-item" itemprop="author">
						<a href="https://www.inoteq.com/author/akusmin/">
											<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="far fa-user-circle"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-author">
										Alexander Kusmin					</span>
									</a>
				</li>
				<li class="elementor-icon-list-item elementor-repeater-item-40c882e elementor-inline-item" itemprop="about">
										<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="fas fa-tags"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-terms">
										<span class="elementor-post-info__terms-list">
				<a href="https://www.inoteq.com/tag/java/" class="elementor-post-info__terms-list-item">Java</a>, <a href="https://www.inoteq.com/tag/kotlin/" class="elementor-post-info__terms-list-item">Kotlin</a>, <a href="https://www.inoteq.com/tag/spring/" class="elementor-post-info__terms-list-item">Spring</a>				</span>
					</span>
								</li>
				</ul>
				</div>
				</div>
				<div class="elementor-element elementor-element-20a9deb elementor-widget elementor-widget-text-editor" data-id="20a9deb" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Kürzlich habe ich für einen Kunden ein Fullstack Spring Boot Projekt entwickelt, bei dem ich eine gewisse Freiheit bei der Wahl der Technologie und der Programmiersprache hatte. Es stellte sich rasch die Frage, ob ich Java oder Kotlin verwenden sollte. Ich habe mich bewusst für Kotlin als Programmiersprache entschieden, wobei die Entscheidung nicht nur auf technologischer Neugier basierte, sondern auch darauf, die Vor- und Nachteile von Kotlin im Vergleich zu Java in einem realen Projekt zu entdecken. In diesem Beitrag teile ich meine Erfahrungen und Erkenntnisse, während ich einen Blick auf die Unterschiede beider Sprachen werfe.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-5cc3eb0 elementor-widget elementor-widget-theme-post-featured-image elementor-widget-image" data-id="5cc3eb0" data-element_type="widget" data-widget_type="theme-post-featured-image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img loading="lazy" decoding="async" width="2000" height="1200" src="https://www.inoteq.com/wp-content/uploads/2023/11/wp3.png" class="attachment-full size-full wp-image-2919" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2023/11/wp3.png 2000w, https://www.inoteq.com/wp-content/uploads/2023/11/wp3-300x180.png 300w, https://www.inoteq.com/wp-content/uploads/2023/11/wp3-1024x614.png 1024w, https://www.inoteq.com/wp-content/uploads/2023/11/wp3-768x461.png 768w, https://www.inoteq.com/wp-content/uploads/2023/11/wp3-1536x922.png 1536w" sizes="(max-width: 2000px) 100vw, 2000px" />											<figcaption class="widget-image-caption wp-caption-text">KI generiertes Symbolbild: compelling, illustration, symbolizing kotlin and java, logo-style, kotlin as a rocket, java as a locomotive</figcaption>
										</figure>
							</div>
				</div>
				<div class="elementor-element elementor-element-c273fac elementor-toc--minimized-on-tablet elementor-widget elementor-widget-table-of-contents" data-id="c273fac" data-element_type="widget" data-settings="{&quot;exclude_headings_by_selector&quot;:&quot;.exclude-from-toc&quot;,&quot;headings_by_tags&quot;:[&quot;h2&quot;,&quot;h3&quot;,&quot;h4&quot;,&quot;h5&quot;,&quot;h6&quot;],&quot;marker_view&quot;:&quot;numbers&quot;,&quot;minimize_box&quot;:&quot;yes&quot;,&quot;minimized_on&quot;:&quot;tablet&quot;,&quot;hierarchical_view&quot;:&quot;yes&quot;,&quot;min_height&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;min_height_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;min_height_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}" data-widget_type="table-of-contents.default">
				<div class="elementor-widget-container">
					<div class="elementor-toc__header">
			<h4 class="elementor-toc__header-title">
				Table of Contents			</h4>
							<div class="elementor-toc__toggle-button elementor-toc__toggle-button--expand" role="button" tabindex="0" aria-controls="elementor-toc__c273fac" aria-expanded="true" aria-label="Open table of contents"><i aria-hidden="true" class="fas fa-chevron-down"></i></div>
				<div class="elementor-toc__toggle-button elementor-toc__toggle-button--collapse" role="button" tabindex="0" aria-controls="elementor-toc__c273fac" aria-expanded="true" aria-label="Close table of contents"><i aria-hidden="true" class="fas fa-chevron-up"></i></div>
					</div>
		<div id="elementor-toc__c273fac" class="elementor-toc__body">
			<div class="elementor-toc__spinner-container">
				<i class="elementor-toc__spinner eicon-animation-spin eicon-loading" aria-hidden="true"></i>			</div>
		</div>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-946ebcb elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="946ebcb" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-a2c736d" data-id="a2c736d" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-e8d142e elementor-widget elementor-widget-spacer" data-id="e8d142e" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-b5cfe4c elementor-widget elementor-widget-heading" data-id="b5cfe4c" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Grundlegende Unterschiede</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-af6dfcc elementor-widget elementor-widget-text-editor" data-id="af6dfcc" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Java und Kotlin werden beide in der Java Virtual Machine (JVM) ausgeführt, unterscheiden sich jedoch in Syntax, Semantik und Programmierparadigmen. Java wurde 1995 veröffentlicht und ist eine der bekanntesten und etabliertesten Programmiersprachen und folgt dem imperativen, objektorientierten Paradigma. Kotlin hingegen wurde 2011 gezielt entwickelt, um einige der Schwächen von Java zu beheben. </p><p>Die Syntax ist klarer, kompakter und fördert eine höhere Lesbarkeit des Codes. Ein wichtiger Aspekt ist die Reduzierung von Boilerplate-Code, damit sich Entwickler stärker auf die logischen Aspekte ihrer Anwendung konzentrieren können. </p><p>Ein Beispiel für die Vereinfachung der Syntax in Kotlin ist die Deklaration von Datenklassen. In Java müssen Entwickler viel Code für Getter, Setter, Equals, HashCode und ToString schreiben. In Kotlin kann dies mit nur einer Zeile erledigt werden, was zu einer saubereren und wartungsfreundlicheren Codebasis führt. In Java existieren mittlerweile ähnliche Lösungen, wie beispielsweise <a href="https://docs.oracle.com/en/java/javase/14/language/records.html" target="_blank" rel="noopener">Java Records</a>.</p><p>Hier ein Beispiel für den Unterschied von normalen Java-Klassen und Kotlin Daten-Klassen, orientiert nach dem Beispiel von <a href="https://www.baeldung.com/kotlin/data-classes" target="_blank" rel="noopener">Baeldung</a>.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-023c123 elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="023c123" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-2341" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-2341" aria-expanded="false">Java</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-2341" aria-expanded="false">Java</div>
					<div id="elementor-tab-content-2341" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-2341" tabindex="0" hidden="false"><pre><code class="language-java">public class Task {
    private int id;
    private String description;
    private int priority;

    public Task(int id, String description, int priority) {
        this.id = id;
        this.description = description;
        this.priority = priority;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getDescription() {
        return description;
    }

    public void setPriority(int priority) {
        this.priority = priority;
    }

    public float getPriority() {
        return priority;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = Integer.hashCode(this.id) * prime;
        result = prime * result + Integer.hashCode(this.priority);
        result = prime * result + ((this.description == null) ? 0 : this.description.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object var1) {
        if (this != var1) {
            if (var1 instanceof Task) {
                Task var2 = (Task) var1;
                if (this.id == var2.id
                  &amp;&amp; Intrinsics.areEqual(this.description, var2.description)
                  &amp;&amp; this.priority == var2.priority) {
                    return true;
                }
            }
            return false;
        } else {
            return true;
        }
    }

    @Override
    public String toString() {
        return "Task [id=" + id + ", description=" + description + ", priority=" + priority + "]";
    }
}</code></pre>
&nbsp;</div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-50ab037 elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="50ab037" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-8451" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-8451" aria-expanded="false">Kotlin</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-8451" aria-expanded="false">Kotlin</div>
					<div id="elementor-tab-content-8451" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-8451" tabindex="0" hidden="false"><pre><code class="language-kt">data class Task(
    var id: Int,
    var description: String,
    var priority: Int
)</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-8edbaf0 elementor-widget elementor-widget-text-editor" data-id="8edbaf0" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die Syntax von Kotlin ist in einigen Punkten einfacher und intuitiver. Beispielsweise werden Lambda-Ausdrücke als normale Funktionen definiert, während sie in Java als anonyme Klassen definiert werden.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-ef7da52 elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="ef7da52" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-2511" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-2511" aria-expanded="false">Java</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-2511" aria-expanded="false">Java</div>
					<div id="elementor-tab-content-2511" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-2511" tabindex="0" hidden="false"><pre><code class="language-java">public final String[] listOfNames = new String[]{"Alice", "Bob", "Mallory"}
listOfNames.forEach { name -> println(name) }</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-52ec52f elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="52ec52f" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-8691" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-8691" aria-expanded="false">Kotlin</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-8691" aria-expanded="false">Kotlin</div>
					<div id="elementor-tab-content-8691" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-8691" tabindex="0" hidden="false"><pre><code class="language-kt">val listOfNames = listOf("Alice", "Bob", "Mallory")
listOfNames.forEach { println(it) }</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-a4a94de elementor-widget elementor-widget-text-editor" data-id="a4a94de" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die Semantik von Kotlin ist in einigen Punkten strenger als die von Java. Ein entscheidender Unterschied hier ist die Integration von Null-Sicherheit. Im Gegensatz zu Java, das das Arbeiten mit Null-Werten ohne explizite Behandlung erlaubt und häufig zu NullPointerExceptions führt, integriert Kotlin von Haus aus Null-Sicherheit, wodurch unerwünschte Null-Referenzen reduziert werden.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-b5cdd5d elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="b5cdd5d" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-1901" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1901" aria-expanded="false">Java</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1901" aria-expanded="false">Java</div>
					<div id="elementor-tab-content-1901" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-1901" tabindex="0" hidden="false"><pre><code class="language-java">public final String name = null
System.out.println(name.length) // NullPointerException</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-9c82354 elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="9c82354" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-1641" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1641" aria-expanded="false">Kotlin</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1641" aria-expanded="false">Kotlin</div>
					<div id="elementor-tab-content-1641" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-1641" tabindex="0" hidden="false"><pre><code class="language-kt">val name: String? = null
println(name?.length) // null</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-28bac5b elementor-widget elementor-widget-text-editor" data-id="28bac5b" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Kotlin bietet eine umfangreiche Sammlung von Funktionen, die in Java nicht verfügbar sind. Zum Beispiel gibt es die Möglichkeit für Inline-Funktionen oder Erweiterungen von fremden Klassen mit eigenen Methoden. Auf weitere Unterschiede möchte ich hier nicht näher eingehen, diese können auf der <a href="https://kotlinlang.org/docs/comparison-to-java.html" target="_blank" rel="noopener">offiziellen Kotlin-Website</a> eingesehen werden.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-7df93fc elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="7df93fc" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-e286ec7" data-id="e286ec7" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-c263e2e elementor-widget elementor-widget-spacer" data-id="c263e2e" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-22b3ee2 elementor-widget elementor-widget-heading" data-id="22b3ee2" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Kotlin in der Industrie und Community</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-8dce1cb elementor-widget elementor-widget-text-editor" data-id="8dce1cb" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Kotlin ist äußerst relevant und hat in den letzten Jahren erheblich an Bedeutung gewonnen, insbesondere in der Android-Entwicklung. Gründe hierfür sind:</p><ul><li><b>Offizielle Google-Unterstützung</b><br />Google hat Kotlin als offizielle Programmiersprache für die Android-Entwicklung anerkannt. Seit 2017 ist Kotlin eine offizielle Sprache für die Entwicklung von Android-Apps und hat seitdem breite Akzeptanz gefunden.</li><li><b>Interoperabilität mit Java</b><br />Kotlin wurde entwickelt, um nahtlos mit Java zu interagieren. Dadurch können Entwickler bestehenden Java-Code in Kotlin integrieren und umgekehrt.</li><li><b>Moderne Sprachfunktionen</b><br />Kotlin bietet moderne Funktionen wie Null-Sicherheit, Erweiterungsfunktionen, Datenklassen und eine klare Syntax, die die Produktivität von Entwicklern verbessern. Daher ist Kotlin eine attraktive Alternative zu anderen JVM-Sprachen.</li><li><b>Community-Unterstützung</b><br />Die Kotlin-Community wächst kontinuierlich. Es gibt zahlreiche Ressourcen, Bibliotheken und Frameworks, die speziell für Kotlin entwickelt wurden. Die aktive Beteiligung der Entwicklergemeinschaft trägt zur Weiterentwicklung und Verbesserung der Sprache bei.</li><li><b>Branchenakzeptanz</b><br />Viele namhafte Unternehmen wie Google, Netflix, Uber und JetBrains setzen Kotlin erfolgreich in ihren Projekten ein. Dies zeigt, dass Kotlin nicht nur in der Entwicklergemeinschaft, sondern auch in der Industrie an Bedeutung gewinnt.</li><li><b>Plattformunabhängigkeit und -kompatibilität</b><br />Das Kotlin Multiplatform Project ermöglicht es, Code auf mehreren Plattformen zu kompilieren, z. B. auf Android, iOS, Web und Desktop. </li></ul><p> </p><p>Insgesamt ist Kotlin eine leistungsfähige Sprache, die für verschiedene Anwendungsbereiche geeignet ist.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-eddaa71 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="eddaa71" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-1d05640" data-id="1d05640" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-bad4114 elementor-widget elementor-widget-spacer" data-id="bad4114" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-a4a1dbf elementor-widget elementor-widget-heading" data-id="a4a1dbf" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Kotlin in der Praxis</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-801417e elementor-widget elementor-widget-text-editor" data-id="801417e" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die Entscheidung, welche Sprache in einem Projekt verwendet werden soll, hängt wesentlich von den Vorlieben des Entwicklers ab. In meinem Fullstack Spring Boot-Projekt mit Kotlin konnte ich diese Unterschiede aus erster Hand erleben und beurteilen, wie sie sich auf die Entwicklungsdynamik und Codequalität auswirken. </p><p>Um Kotlin zu verstehen, ist es hilfreich, die Herausforderungen zu betrachten, denen Entwickler in der Java-Entwicklung täglich gegenüberstanden. Kotlin ist keine Alternative zu Java, sondern eine moderne Ergänzung, die auf die Schwächen von Java eingeht und neue Ansätze für die Softwareentwicklung bietet. </p><p>Kotlin unterbricht nicht die Verbindung zur etablierten JVM-Welt. Die Zielgruppe für Kotlin umfasst verschiedene Entwicklerprofile und -situationen.</p><ul><li><b>Entwickler, die die Vorteile moderner Sprachen suchen</b><br />Kotlin bietet Funktionen wie Typinferenz, Erweiterungsfunktionen und Datenklassen, die die Entwicklung erleichtern und den Code kompakter und lesbarer machen. Entwickler, die moderne Programmierkonzepte bevorzugen, finden in Kotlin eine zeitgemäße Lösung.</li><li><b>Android Entwickler</b><br />Die offizielle Unterstützung von Kotlin durch Google hat dazu geführt, dass viele Android-Entwickler auf Kotlin umgestiegen sind. Die Sprache integriert sich nahtlos in die Android-Plattform und verbessert die Lesbarkeit und Produktivität.</li><li><b>Unternehmen, die Java-Code weiterentwickeln wollen</b><br />Kotlin ist so konzipiert, dass es mit vorhandenem Java-Code interoperabel ist. Dadurch können Unternehmen schrittweise von Java zu Kotlin wechseln, ohne ihre bestehende Codebase vollständig zu überarbeiten. Kotlin ist somit eine attraktive Option für Organisationen, die ihre Java-Anwendungen modernisieren möchten.</li></ul><p> </p><p>Die Vielseitigkeit von Kotlin macht es zu einer interessanten Wahl für verschiedene Entwicklungsszenarien, sodass ich mich für Kotlin entschied.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-ac7a31c elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="ac7a31c" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-c9eca55" data-id="c9eca55" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-425662d elementor-widget elementor-widget-spacer" data-id="425662d" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-4e3edb1 elementor-widget elementor-widget-heading" data-id="4e3edb1" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Gemeinsamkeiten und Interoperabilität</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-c00d015 elementor-widget elementor-widget-text-editor" data-id="c00d015" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Obwohl Kotlin und Java sich in Syntax und Designphilosophie unterscheiden, teilen sie einige grundlegende Gemeinsamkeiten, die ihre Interoperabilität und Integration ermöglichen.</p><ul><li><b>Lauffähigkeit auf der Java Virtual Machine (JVM)</b><br />Beide Sprachen werden in Bytecode übersetzt und sind daher auf der JVM ausführbar. Diese Kompatibilität ermöglicht es Entwicklern, Kotlin- und Java-Code in derselben Anwendung zu verwenden, was einen schrittweisen Übergang oder die gemeinsame Nutzung von Bibliotheken ermöglicht.</li><li><b>Interoperabilität</b><br />Kotlin ist so konzipiert, dass es nahtlos mit Java interagiert. Das bedeutet, dass bestehende Java-Bibliotheken ohne Probleme in Kotlin-Projekten verwendet werden können und umgekehrt. Dies erleichtert den Übergang von Java zu Kotlin und unterstützt eine schrittweise Migration.</li><li><b>Verwendung des gleichen Bytecodes</b><br />Da beide Sprachen denselben Bytecode erzeugen, können Entwickler von den Vorteilen beider Sprachen profitieren, ohne sich auf eine einzige festlegen zu müssen.</li><li><b>Entwicklungsumgebung und Build-Tools</b><br />Kotlin und Java können mit denselben Entwicklungsumgebungen und Build-Tools verwendet werden. Dies erleichtert die Integration von Kotlin in bestehende Entwicklungsworkflows.</li></ul><p> </p><p>Diese Gemeinsamkeiten erleichtern die Entscheidung für oder gegen Kotlin, insbesondere bei einer schrittweisen Einführung oder Integration in bestehende Java-Projekte.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-7cc80ee elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="7cc80ee" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-bbc5203" data-id="bbc5203" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-b66f8ac elementor-widget elementor-widget-spacer" data-id="b66f8ac" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-6639279 elementor-widget elementor-widget-heading" data-id="6639279" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Nachteile von Kotlin</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-4ad621e elementor-widget elementor-widget-text-editor" data-id="4ad621e" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Trotz der vielen Vorteile von Kotlin gibt es auch einige Nachteile, insbesondere im Kontext von Spring Boot. </p>
<p>Kotlin ist trotz seiner 13 Jahre eine noch relativ neue Sprache, was bedeutet, dass sie noch nicht so weit verbreitet ist wie Java. Es ist wichtig, dass Entwickler, die mit Kotlin arbeiten, Erfahrung mit der Sprache haben oder bereit sind, sie zu erlernen. Dies liegt daran, dass es in Kotlin einige Unterschiede zu Java gibt, die verstanden werden müssen. Zudem kann es zu Problemen bei der Suche nach Dokumentation, Bibliotheken und Unterstützung kommen. Beispielsweise gibt es für Java eine große Auswahl an Bibliotheken, die von einer großen Community von Entwicklern unterstützt werden. </p>
<p>Die Dokumentation von Kotlin erwies sich gelegentlich als weniger hilfreich, insbesondere bei komplexeren Themen oder spezifischen Spring-Anforderungen. Dies führte dazu, dass ich auf eine Kombination aus Trial-and-Error und der Suche nach alternativen Lösungen angewiesen war. Bei einigen Abhängigkeiten, wie zum Beispiel <a href="https://projectlombok.org/" target="_blank" rel="noopener">Lombok</a> oder <a href="https://site.mockito.org/" target="_blank" rel="noopener">Mockito</a> für Tests, traten Probleme auf, die nicht unmittelbar gelöst werden konnten. Die Anpassung an alternative Bibliotheken, wie <a href="https://mockk.io/" target="_blank" rel="noopener">Mockk</a> oder andere, wurde notwendig, um reibungslose Testläufe zu gewährleisten. </p>
<p>Eine der Hürden war die begrenzte Verfügbarkeit von Online-Ressourcen. Oftmals waren die vorhandenen Informationen veraltet oder bezogen sich auf veraltete Versionen, da Kotlin regelmäßig Updates erhält, welche die Sprache auch oft stark verändert. Dies erschwerte die Suche nach aktuellen Lösungen für spezifische Probleme im Spring-Ökosystem. </p>
<p>Kotlin-Code kann in einigen Fällen auch schwieriger zu debuggen sein als Java-Code. Beispielsweise kann ein NullPointerException in Kotlin schwieriger zu finden sein als in Java. Dies liegt daran, dass Kotlin eine Null-safe Sprache ist und daher NullPointerExceptions wesentlich seltener auftreten und im Code daher schwieriger zu finden sind.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-be00bd4 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="be00bd4" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-856ca37" data-id="856ca37" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-11e9e7e elementor-widget elementor-widget-spacer" data-id="11e9e7e" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-c722c41 elementor-widget elementor-widget-heading" data-id="c722c41" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Vorteile von Kotlin</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-548d262 elementor-widget elementor-widget-text-editor" data-id="548d262" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Trotz der genannten Herausforderungen bietet Kotlin zahlreiche Vorteile, die die Entscheidung für diese Sprache rechtfertigen. Ein herausragendes Merkmal von Kotlin ist die Möglichkeit, denselben Funktionalitätsgrad wie in Java mit weniger Code auszudrücken. Dadurch wird der Code lesbarer und wartbarer. </p><p>Die klare und prägnante Syntax, die Integration von Null-Sicherheit, sowie Erweiterungsfunktionen und Datenklassen ermöglichen eine effiziente und wartungsfreundliche Codebasis. Kotlin fördert eine moderne Herangehensweise an die Softwareentwicklung und verbessert die Lesbarkeit des Codes erheblich. </p><p>Die breite Akzeptanz und Unterstützung in der Entwicklergemeinschaft, insbesondere im Android-Bereich, unterstreichen die Relevanz und Zukunftsfähigkeit von Kotlin als Programmiersprache.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-bc6c1d6 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="bc6c1d6" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-e5a55ad" data-id="e5a55ad" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-7c7095c elementor-widget elementor-widget-spacer" data-id="7c7095c" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-3f00418 elementor-widget elementor-widget-heading" data-id="3f00418" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Kotlin im Spring Boot Projekt: Eine strategische Entscheidung</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-10e54fc elementor-widget elementor-widget-text-editor" data-id="10e54fc" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die Entscheidung, Kotlin für ein Spring Boot-Projekt zu wählen, basierte auf überzeugenden Faktoren, die zu einer verbesserten Entwicklungsqualität und Effizienz beitrugen. Die klare und prägnante Syntax von Kotlin trug erheblich zur Lesbarkeit des Codes bei. Durch den Einsatz von Kotlin konnten komplexe Java-Konstruktionen in einfachere und lesbarere Ausdrücke übersetzt werden. </p><p>Dank der statischen Typisierung von Kotlin kann der Compiler viele Fehler bereits während der Entwicklungszeit erkennen. Die Typinferenz von Kotlin ermöglicht es Entwicklern, sichereren Code zu schreiben, indem sie in vielen Fällen auf explizite Typdeklarationen verzichten können.</p><p>Die nahtlose Integration von Kotlin und Java ermöglicht einen schrittweisen Übergang und die Nutzung von bestehendem Java-Code. Besonders in einem Spring-Projekt, in dem viele Bibliotheken und Frameworks in Java geschrieben sind, ist dies von großer Bedeutung. Die Interoperabilität erleichtert die Migration zu Kotlin, ohne dass vorhandene Ressourcen verloren gehen.</p><p>Kotlin bietet außerdem Erweiterungsfunktionen, mit denen Entwickler bestehende Klassen um neue Funktionen erweitern können, ohne den Originalcode zu ändern. Dies trägt zur Modularität des Codes bei und kann auch die Performance optimieren, indem spezifische Funktionen effizienter implementiert werden.</p><p>Bei der Entscheidung sollten vor allem die individuellen Anforderungen berücksichtigt werden. Kotlin kann zum Beispiel eine gute Wahl sein für Anwendungen mit kurzen Entwicklungszeiten und -kosten, Anwendungen, die von Entwicklern mit Erfahrung in anderen objektorientierten Sprachen entwickelt werden, oder Anwendungen, die auf mehreren Plattformen ausgeführt werden sollen.</p><p>Insgesamt trugen diese Aspekte dazu bei, dass die Verwendung von Kotlin in einem Spring-Projekt zu einer angenehmeren und produktiveren Entwicklungszeit führte. Die Entscheidung für Kotlin war eine strategische Wahl, die die Vorteile moderner Sprachen mit der bewährten Stabilität von Spring kombinierte.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-5371329 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="5371329" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-c66ec61" data-id="c66ec61" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-3b3e86d elementor-widget elementor-widget-spacer" data-id="3b3e86d" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-63c5acb elementor-widget elementor-widget-heading" data-id="63c5acb" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Fazit und persönliche Meinung</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-a93a496 elementor-widget elementor-widget-text-editor" data-id="a93a496" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Kotlin hat sich in meinem Fullstack Spring Boot-Projekt als überzeugende Alternative zu Java erwiesen. Die klare Syntax, die Reduzierung von Boilerplate-Code, die Integration von Null-Sicherheit und die nahtlose Interoperabilität mit Java trugen dazu bei, die Entwicklungszeit zu optimieren und die Codequalität zu verbessern.</p><p>Die Entscheidung für Kotlin war nicht nur technologisch, sondern auch strategisch. Kotlin ist aufgrund seiner Vielseitigkeit und modernen Sprachfunktionen eine attraktive Option für verschiedene Entwicklungszenarien. Obwohl Java nach wie vor eine robuste Sprache ist, bietet Kotlin eine zeitgemäße Alternative, insbesondere für Entwickler, die effizienter arbeiten und die Vorteile moderner Programmierkonzepte nutzen möchten.</p><p>In der dynamischen Landschaft der Softwareentwicklung bleibt die Entscheidung zwischen Java und Kotlin letztlich eine Frage der spezifischen Anforderungen und Präferenzen. Kotlin hat sich jedoch als eine Sprache etabliert, die nicht nur die Schwächen von Java adressiert, sondern auch neue Maßstäbe in Bezug auf Effizienz und Lesbarkeit setzt.</p><p>Aus meiner persönlichen Perspektive war die Entscheidung, Kotlin für das Projekt zu wählen, durchweg positiv. Trotz des potenziellen Mangels an Online-Ressourcen und der anfänglichen Lernkurve empfand ich die Vorteile von Kotlin als überzeugend. Die moderne Sprachfunktionalität, die Reduzierung von Boilerplate-Code und die nahtlose Integration mit Java machten den Umstieg lohnenswert. Die Entscheidung, sich auf neue Erfahrungen einzulassen und die Vorteile von Kotlin zu nutzen, trug nicht nur zur erfolgreichen Umsetzung des Projekts bei, sondern erweiterte auch meinen persönlichen Horizont in Bezug auf moderne Programmiersprachen.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-cf22e49 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="cf22e49" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-96a87ad" data-id="96a87ad" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-3019981 elementor-widget elementor-widget-spacer" data-id="3019981" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				</div>
		<p>Der Beitrag <a href="https://www.inoteq.com/2024/02/01/kotlin-vs-java-vor-und-nachteile-im-fokus-einer-spring-boot-anwendung/">Kotlin vs. Java im Praxischeck: Ein Spring Boot Erfahrungsbericht</a> erschien zuerst auf <a href="https://www.inoteq.com">INOTEQ GmbH</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.inoteq.com/2024/02/01/kotlin-vs-java-vor-und-nachteile-im-fokus-einer-spring-boot-anwendung/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Entwicklung einer Spring Boot-Anwendung mit Thymeleaf und Tailwind CSS</title>
		<link>https://www.inoteq.com/2023/12/15/entwicklung-einer-spring-boot-anwendung-mit-thymeleaf-und-tailwind-css/</link>
					<comments>https://www.inoteq.com/2023/12/15/entwicklung-einer-spring-boot-anwendung-mit-thymeleaf-und-tailwind-css/#respond</comments>
		
		<dc:creator><![CDATA[Alexander Kusmin]]></dc:creator>
		<pubDate>Fri, 15 Dec 2023 09:47:55 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[Tailwind CSS]]></category>
		<category><![CDATA[Thymeleaf]]></category>
		<guid isPermaLink="false">https://www.inoteq.com/?p=1918</guid>

					<description><![CDATA[<p>Moderne Webentwicklung erfordert nicht nur eine robuste Backend-Infrastruktur, sondern auch leistungsstarke Werkzeuge für die Gestaltung ansprechender Benutzeroberflächen. Dieser Beitrag enthält eine Schritt-für-Schritt-Anleitung zur Entwicklung einer Web-Anwendung mit Spring Boot mit Thymeleaf und Tailwind CSS via Gradle-Node-Plugin. Diese Kombination ermöglicht die Implementierung dynamischer Inhalte sowie die Erstellung responsiver und modernen Benutzeroberflächen. Inhaltsverzeichnis Setup von Spring Boot Es [&#8230;]</p>
<p>Der Beitrag <a href="https://www.inoteq.com/2023/12/15/entwicklung-einer-spring-boot-anwendung-mit-thymeleaf-und-tailwind-css/">Entwicklung einer Spring Boot-Anwendung mit Thymeleaf und Tailwind CSS</a> erschien zuerst auf <a href="https://www.inoteq.com">INOTEQ GmbH</a>.</p>
]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="1918" class="elementor elementor-1918" data-elementor-post-type="post">
						<section class="elementor-section elementor-top-section elementor-element elementor-element-f66b86b elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="f66b86b" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-8621065" data-id="8621065" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-1519bd7 elementor-widget elementor-widget-spacer" data-id="1519bd7" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-4077a37 elementor-widget elementor-widget-html" data-id="4077a37" data-element_type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
			<!-- Only for Code Snippet Styles -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/themes/prism-coy.min.css" integrity="sha256-VcuSs+n31yebPlEcehu6PvnidJ808ScFBsK8+tJKX+Q=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/components/prism-core.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/plugins/autoloader/prism-autoloader.min.js"></script>
<style>
    :not(pre) > code[class*=language-].inline {
        padding: 0 0.2rem;
        color: #000;
    }
</style>		</div>
				</div>
				<div class="elementor-element elementor-element-364bd83 elementor-widget elementor-widget-theme-post-title elementor-page-title elementor-widget-heading" data-id="364bd83" data-element_type="widget" data-widget_type="theme-post-title.default">
				<div class="elementor-widget-container">
			<h1 class="elementor-heading-title elementor-size-default">Entwicklung einer Spring Boot-Anwendung mit Thymeleaf und Tailwind CSS</h1>		</div>
				</div>
				<div class="elementor-element elementor-element-ee9bfad elementor-widget elementor-widget-post-info" data-id="ee9bfad" data-element_type="widget" data-widget_type="post-info.default">
				<div class="elementor-widget-container">
					<ul class="elementor-inline-items elementor-icon-list-items elementor-post-info">
								<li class="elementor-icon-list-item elementor-repeater-item-251e497 elementor-inline-item" itemprop="datePublished">
						<a href="https://www.inoteq.com/2023/12/15/">
											<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="fas fa-calendar"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-date">
										Dezember 15, 2023					</span>
									</a>
				</li>
				<li class="elementor-icon-list-item elementor-repeater-item-7b70c4e elementor-inline-item" itemprop="author">
						<a href="https://www.inoteq.com/author/akusmin/">
											<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="far fa-user-circle"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-author">
										Alexander Kusmin					</span>
									</a>
				</li>
				<li class="elementor-icon-list-item elementor-repeater-item-42532e0 elementor-inline-item" itemprop="about">
										<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="fas fa-tags"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-terms">
										<span class="elementor-post-info__terms-list">
				<a href="https://www.inoteq.com/tag/spring/" class="elementor-post-info__terms-list-item">Spring</a>, <a href="https://www.inoteq.com/tag/tailwind-css/" class="elementor-post-info__terms-list-item">Tailwind CSS</a>, <a href="https://www.inoteq.com/tag/thymeleaf/" class="elementor-post-info__terms-list-item">Thymeleaf</a>				</span>
					</span>
								</li>
				</ul>
				</div>
				</div>
				<div class="elementor-element elementor-element-f0d808c elementor-widget elementor-widget-text-editor" data-id="f0d808c" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Moderne Webentwicklung erfordert nicht nur eine robuste Backend-Infrastruktur, sondern auch leistungsstarke Werkzeuge für die Gestaltung ansprechender Benutzeroberflächen. Dieser Beitrag enthält eine Schritt-für-Schritt-Anleitung zur Entwicklung einer Web-Anwendung mit Spring Boot mit <a href="https://www.thymeleaf.org/">Thymeleaf</a> und <a href="https://tailwindcss.com/">Tailwind CSS</a> via <span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );"><a href="https://github.com/node-gradle/gradle-node-plugin">Gradle-Node-Plugin</a></span><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );">. Diese Kombination ermöglicht die Implementierung dynamischer Inhalte sowie die Erstellung responsiver und modernen Benutzeroberflächen.</span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-f60e6cf elementor-widget elementor-widget-theme-post-featured-image elementor-widget-image" data-id="f60e6cf" data-element_type="widget" data-widget_type="theme-post-featured-image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img loading="lazy" decoding="async" width="2000" height="1200" src="https://www.inoteq.com/wp-content/uploads/2023/11/wp2.png" class="attachment-full size-full wp-image-2921" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2023/11/wp2.png 2000w, https://www.inoteq.com/wp-content/uploads/2023/11/wp2-300x180.png 300w, https://www.inoteq.com/wp-content/uploads/2023/11/wp2-1024x614.png 1024w, https://www.inoteq.com/wp-content/uploads/2023/11/wp2-768x461.png 768w, https://www.inoteq.com/wp-content/uploads/2023/11/wp2-1536x922.png 1536w" sizes="(max-width: 2000px) 100vw, 2000px" />											<figcaption class="widget-image-caption wp-caption-text">KI generiertes Symbolbild: compelling, light-hearted tone, illustration, logo-style, thymeleaf being painted, symbolizing tailwindcss design</figcaption>
										</figure>
							</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-922a717 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="922a717" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-5858cc2" data-id="5858cc2" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-6ac10c4 elementor-toc--minimized-on-desktop elementor-widget elementor-widget-table-of-contents" data-id="6ac10c4" data-element_type="widget" data-settings="{&quot;exclude_headings_by_selector&quot;:&quot;.exclude-from-toc&quot;,&quot;minimized_on&quot;:&quot;desktop&quot;,&quot;headings_by_tags&quot;:[&quot;h2&quot;,&quot;h3&quot;,&quot;h4&quot;,&quot;h5&quot;,&quot;h6&quot;],&quot;marker_view&quot;:&quot;numbers&quot;,&quot;minimize_box&quot;:&quot;yes&quot;,&quot;hierarchical_view&quot;:&quot;yes&quot;,&quot;min_height&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;min_height_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;min_height_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}" data-widget_type="table-of-contents.default">
				<div class="elementor-widget-container">
					<div class="elementor-toc__header">
			<h4 class="elementor-toc__header-title">
				Inhaltsverzeichnis			</h4>
							<div class="elementor-toc__toggle-button elementor-toc__toggle-button--expand" role="button" tabindex="0" aria-controls="elementor-toc__6ac10c4" aria-expanded="true" aria-label="Open table of contents"><i aria-hidden="true" class="fas fa-chevron-down"></i></div>
				<div class="elementor-toc__toggle-button elementor-toc__toggle-button--collapse" role="button" tabindex="0" aria-controls="elementor-toc__6ac10c4" aria-expanded="true" aria-label="Close table of contents"><i aria-hidden="true" class="fas fa-chevron-up"></i></div>
					</div>
		<div id="elementor-toc__6ac10c4" class="elementor-toc__body">
			<div class="elementor-toc__spinner-container">
				<i class="elementor-toc__spinner eicon-animation-spin eicon-loading" aria-hidden="true"></i>			</div>
		</div>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-9099f1f elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="9099f1f" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-6b9b81a" data-id="6b9b81a" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-3b727c9 elementor-widget elementor-widget-spacer" data-id="3b727c9" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-1c3df64 elementor-widget elementor-widget-heading" data-id="1c3df64" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Setup von Spring Boot</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-1ac048f elementor-widget elementor-widget-text-editor" data-id="1ac048f" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							Es wird eine Spring Boot Anwendung mit folgender Konfiguration benötigt:
<ul>
 	<li>Spring Boot Version 3.2.0</li>
 	<li>Kotlin als Programmiersprache für Spring</li>
 	<li>Kotlin (Groovy) für das Build-Tool</li>
 	<li>Abhängigkeit <a href="https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web/3.2.0" target="_blank" rel="noopener">Spring Web v3.2.0</a></li>
</ul>
Diese Konfiguration kann <a href="https://start.spring.io/#!type=gradle-project&amp;language=kotlin&amp;platformVersion=3.2.1&amp;packaging=jar&amp;jvmVersion=21&amp;groupId=com.example&amp;artifactId=demo&amp;name=demo&amp;description=Demo%20project%20for%20Spring%20Boot&amp;packageName=com.example.demo&amp;dependencies=web" target="_blank" rel="noopener">hier über den Spring Initializr</a> direkt heruntergeladen werden.

Mit dem Befehl <code class="language-bash inline">./gradlew bootRun</code> wird die Anwendung gestartet und anschließend unter der Adresse <a href="http://localhost:8080" target="_blank" rel="noopener">http://localhost:8080</a> erreichbar.						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-05d6dc3 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="05d6dc3" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-9bf3151" data-id="9bf3151" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-7d05a52 elementor-widget elementor-widget-spacer" data-id="7d05a52" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-6211f0b elementor-widget elementor-widget-heading" data-id="6211f0b" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Integration von Thymeleaf</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-0a15ec7 elementor-widget elementor-widget-text-editor" data-id="0a15ec7" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<a href="https://www.thymeleaf.org/">Thymeleaf</a> ist eine leistungsfähige Template-Engine für die Webentwicklung und ermöglicht die Integration dynamischer Inhalte in Seiten.

In der Datei <strong><i>build.gradle</i></strong> wird die Thymeleaf-Abhängigkeit eingebunden:						</div>
				</div>
				<div class="elementor-element elementor-element-8e27b30 elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="8e27b30" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-1491" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1491" aria-expanded="false">./build.gradle</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1491" aria-expanded="false">./build.gradle</div>
					<div id="elementor-tab-content-1491" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-1491" tabindex="0" hidden="false"><pre><code class="“language-groovy”">...
dependencies {
    ...

    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.2.0'
}
...</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-0e46026 elementor-widget elementor-widget-heading" data-id="0e46026" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Thymeleaf-Templates</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-85bc578 elementor-widget elementor-widget-text-editor" data-id="85bc578" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							Zu Beginn wird im Ressourcenverzeichnis ein neues Thymeleaf-Template <em><strong>src/main/resources/templates/index.html</strong></em> erstellt. Dieses Template zeigt einen Text als Überschrift an, der mithilfe von Thymeleaf aus den Ressourcen geladen wird. Dazu legen wir im Ressourcenverzeichnis eine Datei <em><strong>src/main/resources/messages.properties</strong></em> an, in der die Texte definiert werden. An sich mag dies für unser Beispiel etwas umständlich sein, jedoch ermöglicht dieser Ansatz später eine einfachere Übersetzung der Anwendung, indem der Inhalt der <em><strong>messages.properties</strong></em> pro Sprache vorliegt.						</div>
				</div>
				<div class="elementor-element elementor-element-cdae251 elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="cdae251" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-2151" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-2151" aria-expanded="false">index.html</div>
									<div id="elementor-tab-title-2152" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="false" data-tab="2" role="tab" tabindex="-1" aria-controls="elementor-tab-content-2152" aria-expanded="false">messages.properties</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-2151" aria-expanded="false">index.html</div>
					<div id="elementor-tab-content-2151" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-2151" tabindex="0" hidden="false"><pre><code class="“language-html”">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;Index&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1 th:text="#{myIndexText}"&gt;ignored&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre></div>
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="false" data-tab="2" role="tab" tabindex="-1" aria-controls="elementor-tab-content-2152" aria-expanded="false">messages.properties</div>
					<div id="elementor-tab-content-2152" class="elementor-tab-content elementor-clearfix" data-tab="2" role="tabpanel" aria-labelledby="elementor-tab-title-2152" tabindex="0" hidden="hidden"><pre><code class="“language-properties”">myIndexText=This is index!</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-32f0f89 elementor-widget elementor-widget-text-editor" data-id="32f0f89" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							Mit <code class="language-plain inline">th:</code> werden Thymeleaf-Anweisungen eingeleitet. In diesem Fall wird Thymeleaf angewiesen, den Text-Inhalt für das Element zu definieren. Mit <code class="language-plain inline">#{...}</code> werden Ressourcen über einen eindeutigen Schlüssel angefordert, hier der Text <code class="language-plain inline">This is index</code> mit dem Schlüssel <code  class="language-plain inline">myIndexText</code> aus der zuvor definierten <em><strong>messages.properties</strong></em>.

Auf der <a href="https://www.thymeleaf.org/documentation.html" target="_blank" rel="noopener">offiziellen Seite von Thymeleaf</a> sind alle Funktionen ausführlich und mit vielen Beispielen dokumentiert.						</div>
				</div>
				<div class="elementor-element elementor-element-c4eeac8 elementor-widget elementor-widget-heading" data-id="c4eeac8" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Spring Boot Controller</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-95cca38 elementor-widget elementor-widget-text-editor" data-id="95cca38" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Damit die Spring Boot Anwendung auch die Seite anzeigt, muss ein Controller erstellt werden, welcher das Template für den Endpunkt rendert.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-a785e3e elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="a785e3e" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-1751" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1751" aria-expanded="false">./src/main/.../DemoController.kt</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1751" aria-expanded="false">./src/main/.../DemoController.kt</div>
					<div id="elementor-tab-content-1751" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-1751" tabindex="0" hidden="false"><pre><code class="“language-kotlin”">package com.example.demo

import org.springframework.stereotype.Controller
import org.springframework.ui.Model
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping

@Controller
@RequestMapping
class DemoController {
    @GetMapping("/")
    fun myIndexEndpoint(model: Model): String {
        return "index"
    }
}
</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-6ed8b84 elementor-widget elementor-widget-image" data-id="6ed8b84" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img loading="lazy" decoding="async" width="768" height="373" src="https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.17.41-2-1752x2048-1-768x373.png" class="attachment-medium_large size-medium_large wp-image-2631" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.17.41-2-1752x2048-1-768x373.png 768w, https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.17.41-2-1752x2048-1-300x146.png 300w, https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.17.41-2-1752x2048-1-1024x497.png 1024w, https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.17.41-2-1752x2048-1-1536x745.png 1536w, https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.17.41-2-1752x2048-1.png 1752w" sizes="(max-width: 768px) 100vw, 768px" />											<figcaption class="widget-image-caption wp-caption-text">Index-Seite auf http://localhost:8080</figcaption>
										</figure>
							</div>
				</div>
				<div class="elementor-element elementor-element-b48932f elementor-widget elementor-widget-heading" data-id="b48932f" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Erweiterung des Beispiels mit weiteren Thymeleaf Funktionen</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-c1e23e8 elementor-widget elementor-widget-text-editor" data-id="c1e23e8" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							Die Seite unter <a href="http://localhost:8080" target="_blank" rel="noopener">http://localhost:8080</a> wird nun wie folgt erweitert:
<ul>
 	<li>Dem Template wird eine Liste von Strings übergeben. Diese Strings stellen weitere Endpunkte namens <code class="language-plain inline">/foo</code>, <code class="language-plain inline">/bar</code> und <code class="language-plain inline">/baz</code> dar.</li>
 	<li>Der bisherige Controller wird für die weiteren Endpunkte entsprechend erweitert.</li>
 	<li>Die Endpunkte zeigen wie zuvor die Index-Seite nur einen Text an. Es werden dafür Templates erstellt.</li>
 	<li>Das aktuelle Index-Template verweist auf diese Endpunkte mit einer Navigation.</li>
</ul>						</div>
				</div>
				<div class="elementor-element elementor-element-1935e38 elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="1935e38" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-2641" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-2641" aria-expanded="false">DemoController.kt</div>
									<div id="elementor-tab-title-2642" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="false" data-tab="2" role="tab" tabindex="-1" aria-controls="elementor-tab-content-2642" aria-expanded="false">messages.properties</div>
									<div id="elementor-tab-title-2643" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="false" data-tab="3" role="tab" tabindex="-1" aria-controls="elementor-tab-content-2643" aria-expanded="false">index.html</div>
									<div id="elementor-tab-title-2644" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="false" data-tab="4" role="tab" tabindex="-1" aria-controls="elementor-tab-content-2644" aria-expanded="false">foo.html</div>
									<div id="elementor-tab-title-2645" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="false" data-tab="5" role="tab" tabindex="-1" aria-controls="elementor-tab-content-2645" aria-expanded="false">bar.html</div>
									<div id="elementor-tab-title-2646" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="false" data-tab="6" role="tab" tabindex="-1" aria-controls="elementor-tab-content-2646" aria-expanded="false">baz.html</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-2641" aria-expanded="false">DemoController.kt</div>
					<div id="elementor-tab-content-2641" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-2641" tabindex="0" hidden="false"><pre><code class="“language-kotlin”">...
@Controller
@RequestMapping
class DemoController {
    @GetMapping("/")
    fun myIndexEndpoint(model: Model): String {
        model.addAttribute("myEndpoints", listOf("foo", "bar", "baz"))
        return "index"
    }

    @GetMapping("/foo")
    fun fooEndpoint(): String = "foo"

    @GetMapping("/bar")
    fun barEndpoint(): String = "bar"

    @GetMapping("/baz")
    fun bazEndpoint(): String = "baz"
}
</code></pre></div>
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="false" data-tab="2" role="tab" tabindex="-1" aria-controls="elementor-tab-content-2642" aria-expanded="false">messages.properties</div>
					<div id="elementor-tab-content-2642" class="elementor-tab-content elementor-clearfix" data-tab="2" role="tabpanel" aria-labelledby="elementor-tab-title-2642" tabindex="0" hidden="hidden"><pre><code class=“language-properties”>myIndexText=This is index!
myNavigateText=Navigate to {0}
myFooText=This is foo!
myBarText=This is bar!
myBazText=This is baz!
</code></pre></div>
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="false" data-tab="3" role="tab" tabindex="-1" aria-controls="elementor-tab-content-2643" aria-expanded="false">index.html</div>
					<div id="elementor-tab-content-2643" class="elementor-tab-content elementor-clearfix" data-tab="3" role="tabpanel" aria-labelledby="elementor-tab-title-2643" tabindex="0" hidden="hidden"><pre><code class="“language-html”">...
&lt;body&gt;
...
&lt;nav&gt;
    &lt;a th:each="endpoint: ${myEndpoints}"
       th:text="#{myNavigateText(${endpoint})}"
       th:href="@{/{endpoint}(endpoint=${endpoint})}"&gt;ignored&lt;/a&gt;
&lt;/nav&gt;
&lt;/body&gt;
...
</code></pre></div>
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="false" data-tab="4" role="tab" tabindex="-1" aria-controls="elementor-tab-content-2644" aria-expanded="false">foo.html</div>
					<div id="elementor-tab-content-2644" class="elementor-tab-content elementor-clearfix" data-tab="4" role="tabpanel" aria-labelledby="elementor-tab-title-2644" tabindex="0" hidden="hidden"><pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;Foo&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1 th:text="#{myFooText}"&gt;ignored&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre></div>
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="false" data-tab="5" role="tab" tabindex="-1" aria-controls="elementor-tab-content-2645" aria-expanded="false">bar.html</div>
					<div id="elementor-tab-content-2645" class="elementor-tab-content elementor-clearfix" data-tab="5" role="tabpanel" aria-labelledby="elementor-tab-title-2645" tabindex="0" hidden="hidden"><pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;Bar&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1 th:text="#{myBarText}"&gt;ignored&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre></div>
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="false" data-tab="6" role="tab" tabindex="-1" aria-controls="elementor-tab-content-2646" aria-expanded="false">baz.html</div>
					<div id="elementor-tab-content-2646" class="elementor-tab-content elementor-clearfix" data-tab="6" role="tabpanel" aria-labelledby="elementor-tab-title-2646" tabindex="0" hidden="hidden"><pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;Baz&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1 th:text="#{myBazText}"&gt;ignored&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-763986f elementor-widget elementor-widget-text-editor" data-id="763986f" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Unsere Anwendung sieht nun folgendermaßen aus:</p>						</div>
				</div>
				<div class="elementor-element elementor-element-cdf0ee7 elementor-widget elementor-widget-image-carousel" data-id="cdf0ee7" data-element_type="widget" data-settings="{&quot;slides_to_show&quot;:&quot;2&quot;,&quot;autoplay&quot;:&quot;no&quot;,&quot;infinite&quot;:&quot;no&quot;,&quot;slides_to_scroll&quot;:&quot;1&quot;,&quot;navigation&quot;:&quot;none&quot;,&quot;speed&quot;:500}" data-widget_type="image-carousel.default">
				<div class="elementor-widget-container">
					<div class="elementor-image-carousel-wrapper swiper-container" dir="ltr">
			<div class="elementor-image-carousel swiper-wrapper" aria-live="polite">
								<div class="swiper-slide" role="group" aria-roledescription="slide" aria-label="1 von 2"><figure class="swiper-slide-inner"><img decoding="async" class="swiper-slide-image" src="https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-15.17.41-768x391.png" alt="Index-Seite auf http://localhost:8080" /><figcaption class="elementor-image-carousel-caption">Index-Seite auf http://localhost:8080</figcaption></figure></div><div class="swiper-slide" role="group" aria-roledescription="slide" aria-label="2 von 2"><figure class="swiper-slide-inner"><img decoding="async" class="swiper-slide-image" src="https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-15.18.36-1-768x391.png" alt="Seite &quot;foo&quot; auf http://localhost:8080/foo, Seite &quot;bar&quot; und &quot;baz&quot; analog dazu" /><figcaption class="elementor-image-carousel-caption">Seite "foo" auf http://localhost:8080/foo, Seite "bar" und "baz" analog dazu</figcaption></figure></div>			</div>
							
									</div>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-0035aa9 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="0035aa9" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-bd27b30" data-id="bd27b30" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-c60ab59 elementor-widget elementor-widget-spacer" data-id="c60ab59" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-2c14b80 elementor-widget elementor-widget-heading" data-id="2c14b80" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Styling mittels Tailwind CSS</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-a8e32e4 elementor-widget elementor-widget-text-editor" data-id="a8e32e4" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die Integration von Tailwind CSS in die Spring Boot Anwendung bietet eine flexible und leistungsstarke Styling-Option für das Frontend. Dieses Kapitel beschreibt die Integration und Verwendung von Tailwind CSS.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-13810a2 elementor-widget elementor-widget-heading" data-id="13810a2" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Verwendung des Gradle Plugin für Node und Konfiguration von Tailwind CSS<span style="color: var( --e-global-color-primary ); font-family: var( --e-global-typography-primary-font-family ), Sans-serif; font-size: 1.75rem; font-weight: var( --e-global-typography-primary-font-weight );"></span><br></h3>		</div>
				</div>
				<div class="elementor-element elementor-element-0f1455e elementor-widget elementor-widget-text-editor" data-id="0f1455e" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							Für die Integration von Tailwind CSS in die Spring Boot Anwendung wird das <a href="https://github.com/node-gradle/gradle-node-plugin">Gradle Node Plugin</a> verwendet. Dies ermöglicht eine Verwaltung der Node.js-Abhängigkeiten wie z.B. <a href="https://tailwindcss.com/">Tailwind CSS</a> direkt aus Gradle heraus.

Um das Plugin in das Projekt einzubinden, muss die Gradle-Konfiguration folgendermaßen angepasst werden:
<ul>
 	<li>Wir fügen das Plugin <code class="language-plain inline">gradle-node-plugin</code> hinzu.</li>
 	<li>Es wird ein neuer Gradle-Task registriert, die den Tailwind CSS zur Generierung der <em><strong>output.css</strong></em> ausführt.</li>
 	<li>Die Gradle-Task <code class="language-plain inline">npmInstall</code> wird so angepasst, dass npm die benötigten Pakete selbständig installiert.</li>
 	<li>Die Gradle-Task für die Kompilierung mit Kotlin wird so angepasst, dass Tailwind CSS immer vor der Kompilierung ausgeführt wird.</li>
</ul>
Zusätzlich müssen die beiden Dateien <em><strong>tailwind.config.js</strong></em> und <em><strong>package.json</strong></em> entsprechend angelegt werden.						</div>
				</div>
				<div class="elementor-element elementor-element-79ffe51 elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="79ffe51" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-1271" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1271" aria-expanded="false">build.gradle</div>
									<div id="elementor-tab-title-1272" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="false" data-tab="2" role="tab" tabindex="-1" aria-controls="elementor-tab-content-1272" aria-expanded="false">tailwind.config.js</div>
									<div id="elementor-tab-title-1273" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="false" data-tab="3" role="tab" tabindex="-1" aria-controls="elementor-tab-content-1273" aria-expanded="false">package.json</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1271" aria-expanded="false">build.gradle</div>
					<div id="elementor-tab-content-1271" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-1271" tabindex="0" hidden="false"><pre><code class="“language-groovy”">...
plugins {
    ...
    // Gradle plugin for Node
    id 'com.github.node-gradle.node' version '7.0.1'
}
...
// Necessary for node-gradle plugin
node {
    download = true
}

// This task will run `tailwindcss` command and generate the output.css file from styles.css
tasks.register('tailwind', NpxTask) {
    command = 'tailwindcss'
    args = ['-i', './src/main/resources/static/styles.css', '-o', './src/main/resources/static/output.css']

    // This task depends on npmInstall task
    dependsOn(tasks.npmInstall)
}

// Make npmInstall task depend on npmSetup task and adds package.json as input
tasks.npmInstall {
    inputs.file('package.json')
    dependsOn(tasks.npmSetup)
}

tasks.withType(KotlinCompile).configureEach {
    ...
    // Update the output.css file every time after compiling Kotlin code
    dependsOn(tasks.tailwind)
}
...
</code></pre></div>
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="false" data-tab="2" role="tab" tabindex="-1" aria-controls="elementor-tab-content-1272" aria-expanded="false">tailwind.config.js</div>
					<div id="elementor-tab-content-1272" class="elementor-tab-content elementor-clearfix" data-tab="2" role="tabpanel" aria-labelledby="elementor-tab-title-1272" tabindex="0" hidden="hidden"><pre><code class="“language-js”">/** @type {import('tailwindcss').Config} */
module.exports = {
    content: ["./src/**/*.{html,js}"],
}</code></pre></div>
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="false" data-tab="3" role="tab" tabindex="-1" aria-controls="elementor-tab-content-1273" aria-expanded="false">package.json</div>
					<div id="elementor-tab-content-1273" class="elementor-tab-content elementor-clearfix" data-tab="3" role="tabpanel" aria-labelledby="elementor-tab-title-1273" tabindex="0" hidden="hidden"><pre><code class="“language-json”">{
  "devDependencies": {
    "@tailwindcss/forms": "^0.5.7",
    "tailwindcss": "^3.3.6"
  }
}</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-7b6cfc5 elementor-widget elementor-widget-text-editor" data-id="7b6cfc5" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							Der Gradle-Befehl <code class="language-bash inline">./gradlew tailwind</code> ist nun ausführbar und sollte bei korrekter Konfiguration folgende Ausgabe erzeugen:						</div>
				</div>
				<div class="elementor-element elementor-element-7a2e21c elementor-widget elementor-widget-image" data-id="7a2e21c" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img loading="lazy" decoding="async" width="768" height="356" src="https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-15.28.01-768x356.png" class="attachment-medium_large size-medium_large wp-image-2637" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-15.28.01-768x356.png 768w, https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-15.28.01-300x139.png 300w, https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-15.28.01-1024x475.png 1024w, https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-15.28.01-1536x713.png 1536w, https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-15.28.01.png 2026w" sizes="(max-width: 768px) 100vw, 768px" />											<figcaption class="widget-image-caption wp-caption-text">Ausgabe der Gradle-Task für Tailwind</figcaption>
										</figure>
							</div>
				</div>
				<div class="elementor-element elementor-element-d8419a9 elementor-widget elementor-widget-heading" data-id="d8419a9" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Verwendung von Tailwind CSS</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-8d940f7 elementor-widget elementor-widget-text-editor" data-id="8d940f7" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							Unser Beispiel wird nun mit Hilfe von Tailwind CSS erweitert. Dazu können die Tailwind CSS Klassen direkt im Template verwendet oder in der <em><b>styles.css</b></em> unter <strong><i>src/main/resources/static</i></strong> gesammelt werden. Die dort enthaltenen Klassen werden dann von Tailwind CSS in <em><b>output.css</b></em> gebündelt. Für dieses Beispiel wird auch die einfache Unterstützung von Responsive Design durch Tailwind CSS genutzt. So soll die Index-Seite auf einem kleineren Bildschirm die Menüpunkte zeilenweise auflisten, ansonsten spaltenweise. Wichtig ist, dass die <strong><em>output.css</em></strong> in den Thymeleaf-Templates korrekt verlinkt wird.						</div>
				</div>
				<div class="elementor-element elementor-element-a951778 elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="a951778" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-1771" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1771" aria-expanded="false">styles.css</div>
									<div id="elementor-tab-title-1772" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="false" data-tab="2" role="tab" tabindex="-1" aria-controls="elementor-tab-content-1772" aria-expanded="false">index.html</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1771" aria-expanded="false">styles.css</div>
					<div id="elementor-tab-content-1771" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-1771" tabindex="0" hidden="false"><pre><code class=“language-css”>@tailwind base;
@tailwind components;
@tailwind utilities;

body {
    @apply bg-gray-200 w-full p-4 flex flex-col gap-4 items-center justify-center;
}

.headline {
    @apply text-4xl font-extrabold leading-none tracking-tight;
}

.headline-white {
    @apply text-white;
}

.btn {
    @apply font-bold py-2 px-4 rounded;
}
.btn-blue {
    @apply bg-blue-500 text-white;
}
.btn-blue:hover {
    @apply bg-blue-700;
}
</code></pre></div>
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="false" data-tab="2" role="tab" tabindex="-1" aria-controls="elementor-tab-content-1772" aria-expanded="false">index.html</div>
					<div id="elementor-tab-content-1772" class="elementor-tab-content elementor-clearfix" data-tab="2" role="tabpanel" aria-labelledby="elementor-tab-title-1772" tabindex="0" hidden="hidden"><pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;title&gt;Index&lt;/title&gt;
    &lt;link href=&quot;/output.css&quot;
          rel=&quot;stylesheet&quot;&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1 class=&quot;headline&quot;
    th:text=&quot;#{myIndexText}&quot;&gt;ignored&lt;/h1&gt;
&lt;nav class=&quot;flex flex-col sm:flex-row gap-1&quot;&gt;
    &lt;a class=&quot;btn btn-blue&quot;
       th:each=&quot;endpoint: ${myEndpoints}&quot;
       th:text=&quot;#{myNavigateText(${endpoint})}&quot;
       th:href=&quot;@{/{endpoint}(endpoint=${endpoint})}&quot;&gt;ignored&lt;/a&gt;
&lt;/nav&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-271304d elementor-widget elementor-widget-image-carousel" data-id="271304d" data-element_type="widget" data-settings="{&quot;slides_to_show&quot;:&quot;2&quot;,&quot;slides_to_scroll&quot;:&quot;1&quot;,&quot;navigation&quot;:&quot;none&quot;,&quot;autoplay&quot;:&quot;no&quot;,&quot;infinite&quot;:&quot;no&quot;,&quot;speed&quot;:500}" data-widget_type="image-carousel.default">
				<div class="elementor-widget-container">
					<div class="elementor-image-carousel-wrapper swiper-container" dir="ltr">
			<div class="elementor-image-carousel swiper-wrapper" aria-live="polite">
								<div class="swiper-slide" role="group" aria-roledescription="slide" aria-label="1 von 2"><figure class="swiper-slide-inner"><img decoding="async" class="swiper-slide-image" src="https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.15.59-768x475.png" alt="Index-Seite für Anzeigen mit einer horizontalen Auflösung größer als oder gleich 640px." /><figcaption class="elementor-image-carousel-caption">Index-Seite für Anzeigen mit einer horizontalen Auflösung größer als oder gleich 640px.</figcaption></figure></div><div class="swiper-slide" role="group" aria-roledescription="slide" aria-label="2 von 2"><figure class="swiper-slide-inner"><img decoding="async" class="swiper-slide-image" src="https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-15.16.15-768x584.png" alt="Index-Seite für Anzeigen mit einer horizontalen Auflösung kleiner als 640px." /><figcaption class="elementor-image-carousel-caption">Index-Seite für Anzeigen mit einer horizontalen Auflösung kleiner als 640px.</figcaption></figure></div>			</div>
							
									</div>
				</div>
				</div>
				<section class="elementor-section elementor-inner-section elementor-element elementor-element-f1225ad elementor-section-full_width elementor-section-content-middle elementor-section-height-default elementor-section-height-default" data-id="f1225ad" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-66 elementor-inner-column elementor-element elementor-element-100da93" data-id="100da93" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-9282e45 elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="9282e45" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-1531" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1531" aria-expanded="false">foo.html</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1531" aria-expanded="false">foo.html</div>
					<div id="elementor-tab-content-1531" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-1531" tabindex="0" hidden="false"><pre><code class="“language-html”">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;Foo&lt;/title&gt;
    &lt;link href="/output.css"
          rel="stylesheet"&gt;
&lt;/head&gt;
&lt;body class="bg-red-500"&gt;
&lt;h1 class="headline headline-white"
    th:text="#{myFooText}"&gt;ignored&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre></div>
							</div>
		</div>
				</div>
				</div>
					</div>
		</div>
				<div class="elementor-column elementor-col-33 elementor-inner-column elementor-element elementor-element-c717879" data-id="c717879" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-ea3be8f elementor-widget elementor-widget-spacer" data-id="ea3be8f" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-c30791e elementor-widget elementor-widget-image" data-id="c30791e" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
													<img loading="lazy" decoding="async" width="768" height="898" src="https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.16.22-768x898.png" class="attachment-medium_large size-medium_large wp-image-2258" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.16.22-768x898.png 768w, https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.16.22-257x300.png 257w, https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.16.22-876x1024.png 876w, https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.16.22-1314x1536.png 1314w, https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.16.22-1752x2048.png 1752w, https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.16.22.png 2024w" sizes="(max-width: 768px) 100vw, 768px" />													</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-inner-section elementor-element elementor-element-25fb55a elementor-section-full_width elementor-section-content-middle elementor-section-height-default elementor-section-height-default" data-id="25fb55a" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-66 elementor-inner-column elementor-element elementor-element-af1f7b6" data-id="af1f7b6" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-d9174fd elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="d9174fd" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-2271" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-2271" aria-expanded="false">bar.html</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-2271" aria-expanded="false">bar.html</div>
					<div id="elementor-tab-content-2271" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-2271" tabindex="0" hidden="false"><pre><code class="“language-html”">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;Bar&lt;/title&gt;
    &lt;link href="/output.css"
          rel="stylesheet"&gt;
&lt;/head&gt;
&lt;body class="bg-green-500"&gt;
&lt;h1 class="headline headline-white"
    th:text="#{myBarText}"&gt;ignored&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre></div>
							</div>
		</div>
				</div>
				</div>
					</div>
		</div>
				<div class="elementor-column elementor-col-33 elementor-inner-column elementor-element elementor-element-f66614c" data-id="f66614c" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-578ef69 elementor-widget elementor-widget-spacer" data-id="578ef69" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-27b305f elementor-widget elementor-widget-image" data-id="27b305f" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
													<img loading="lazy" decoding="async" width="768" height="898" src="https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.16.30-768x898.png" class="attachment-medium_large size-medium_large wp-image-2259" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.16.30-768x898.png 768w, https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.16.30-257x300.png 257w, https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.16.30-876x1024.png 876w, https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.16.30-1314x1536.png 1314w, https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.16.30-1752x2048.png 1752w, https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.16.30.png 2024w" sizes="(max-width: 768px) 100vw, 768px" />													</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-inner-section elementor-element elementor-element-1a74e9a elementor-section-full_width elementor-section-content-middle elementor-section-height-default elementor-section-height-default" data-id="1a74e9a" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-66 elementor-inner-column elementor-element elementor-element-706dac0" data-id="706dac0" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-8b8b154 elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="8b8b154" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-1461" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1461" aria-expanded="false">baz.html</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1461" aria-expanded="false">baz.html</div>
					<div id="elementor-tab-content-1461" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-1461" tabindex="0" hidden="false"><pre><code class="“language-html”">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;title&gt;Baz&lt;/title&gt;
    &lt;link href=&quot;/output.css&quot;
          rel=&quot;stylesheet&quot;&gt;
&lt;/head&gt;
&lt;body class=&quot;bg-blue-500&quot;&gt;
&lt;h1 class=&quot;headline headline-white&quot;
    th:text=&quot;#{myBazText}&quot;&gt;ignored&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre></div>
							</div>
		</div>
				</div>
				</div>
					</div>
		</div>
				<div class="elementor-column elementor-col-33 elementor-inner-column elementor-element elementor-element-10285ae" data-id="10285ae" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-e571567 elementor-widget elementor-widget-spacer" data-id="e571567" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-e0d3894 elementor-widget elementor-widget-image" data-id="e0d3894" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
													<img loading="lazy" decoding="async" width="768" height="898" src="https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.16.43-768x898.png" class="attachment-medium_large size-medium_large wp-image-2260" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.16.43-768x898.png 768w, https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.16.43-257x300.png 257w, https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.16.43-876x1024.png 876w, https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.16.43-1314x1536.png 1314w, https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.16.43-1752x2048.png 1752w, https://www.inoteq.com/wp-content/uploads/2023/12/Screenshot-2024-01-10-at-15.16.43.png 2024w" sizes="(max-width: 768px) 100vw, 768px" />													</div>
				</div>
					</div>
		</div>
					</div>
		</section>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-2607b93 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="2607b93" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-533c700" data-id="533c700" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-c5994da elementor-widget elementor-widget-spacer" data-id="c5994da" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-30dc1d7 elementor-widget elementor-widget-heading" data-id="30dc1d7" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Schlusswort</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-96fd2c9 elementor-widget elementor-widget-text-editor" data-id="96fd2c9" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Es ist wichtig anzumerken, dass dieser Ansatz, wie jeder andere auch, Vor- und Nachteile hat. Thymeleaf ermöglicht eine nahtlose Integration von Backend- und Frontend-Logik, könnte aber bei komplexeren Frontend-Anforderungen an seine Grenzen stoßen. Tailwind CSS bietet eine unübertroffene Flexibilität beim Styling, aber die umfangreichen Klassen können zu überladenem HTML-Code führen.</p><p>Für weitere Details steht das <a href="https://github.com/inoteq/spring-boot-thymeleaf-tailwind-css" target="_blank" rel="noopener">GitHub Repository</a> zur Verfügung, das alle im Artikel beschriebenen Schritte und Konfigurationen enthält.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-446d063 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="446d063" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-2e6c8af" data-id="2e6c8af" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-d202c85 elementor-widget elementor-widget-spacer" data-id="d202c85" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				</div>
		<p>Der Beitrag <a href="https://www.inoteq.com/2023/12/15/entwicklung-einer-spring-boot-anwendung-mit-thymeleaf-und-tailwind-css/">Entwicklung einer Spring Boot-Anwendung mit Thymeleaf und Tailwind CSS</a> erschien zuerst auf <a href="https://www.inoteq.com">INOTEQ GmbH</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.inoteq.com/2023/12/15/entwicklung-einer-spring-boot-anwendung-mit-thymeleaf-und-tailwind-css/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Integration von OAuth 2.0 in Spring Boot mit Keycloak</title>
		<link>https://www.inoteq.com/2023/11/30/oauth2-keycloak-locally/</link>
					<comments>https://www.inoteq.com/2023/11/30/oauth2-keycloak-locally/#respond</comments>
		
		<dc:creator><![CDATA[Alexander Kusmin]]></dc:creator>
		<pubDate>Thu, 30 Nov 2023 07:00:00 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Keycloak]]></category>
		<category><![CDATA[OAuth 2.0]]></category>
		<category><![CDATA[Spring]]></category>
		<guid isPermaLink="false">https://www.inoteq.com/?p=1744</guid>

					<description><![CDATA[<p>Dieser Leitfaden beschreibt die Integration von OAuth 2.0 in eine Spring Boot Anwendung mit Keycloak. Nach einer kurzen Einführung in die Spring Boot Plattform liegt der Schwerpunkt auf der genauen Konfiguration von Keycloak als vertrauenswürdigen OAuth 2.0 Server und der Absicherung bestimmter Endpunkte in der Anwendung mit Anmeldedaten. Der Beitrag ist dabei so strukturiert, dass [&#8230;]</p>
<p>Der Beitrag <a href="https://www.inoteq.com/2023/11/30/oauth2-keycloak-locally/">Integration von OAuth 2.0 in Spring Boot mit Keycloak</a> erschien zuerst auf <a href="https://www.inoteq.com">INOTEQ GmbH</a>.</p>
]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="1744" class="elementor elementor-1744" data-elementor-post-type="post">
						<section class="elementor-section elementor-top-section elementor-element elementor-element-ec639a5 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="ec639a5" data-element_type="section" data-settings="{&quot;background_background&quot;:&quot;classic&quot;}">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-824d4d9" data-id="824d4d9" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-1f19b9e elementor-widget elementor-widget-spacer" data-id="1f19b9e" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-a029d14 elementor-widget elementor-widget-html" data-id="a029d14" data-element_type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
			<!-- Only for Code Snippet Styles -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/themes/prism-coy.min.css" integrity="sha256-VcuSs+n31yebPlEcehu6PvnidJ808ScFBsK8+tJKX+Q=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/components/prism-core.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/plugins/autoloader/prism-autoloader.min.js"></script>
<style>
    :not(pre) > code[class*=language-].inline {
        padding: 0 0.2rem;
        color: #000;
    }
</style>		</div>
				</div>
				<div class="elementor-element elementor-element-a814a42 elementor-widget elementor-widget-theme-post-title elementor-page-title elementor-widget-heading" data-id="a814a42" data-element_type="widget" data-widget_type="theme-post-title.default">
				<div class="elementor-widget-container">
			<h1 class="elementor-heading-title elementor-size-default">Integration von OAuth 2.0 in Spring Boot mit Keycloak</h1>		</div>
				</div>
				<div class="elementor-element elementor-element-4453699 elementor-widget elementor-widget-post-info" data-id="4453699" data-element_type="widget" data-widget_type="post-info.default">
				<div class="elementor-widget-container">
					<ul class="elementor-inline-items elementor-icon-list-items elementor-post-info">
								<li class="elementor-icon-list-item elementor-repeater-item-265ff67 elementor-inline-item" itemprop="datePublished">
						<a href="https://www.inoteq.com/2023/11/30/">
											<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="fas fa-calendar"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-date">
										November 30, 2023					</span>
									</a>
				</li>
				<li class="elementor-icon-list-item elementor-repeater-item-5924a19 elementor-inline-item" itemprop="author">
						<a href="https://www.inoteq.com/author/akusmin/">
											<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="far fa-user-circle"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-author">
										Alexander Kusmin					</span>
									</a>
				</li>
				<li class="elementor-icon-list-item elementor-repeater-item-2866628 elementor-inline-item" itemprop="about">
										<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="fas fa-tags"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-terms">
										<span class="elementor-post-info__terms-list">
				<a href="https://www.inoteq.com/tag/keycloak/" class="elementor-post-info__terms-list-item">Keycloak</a>, <a href="https://www.inoteq.com/tag/oauth-2-0/" class="elementor-post-info__terms-list-item">OAuth 2.0</a>, <a href="https://www.inoteq.com/tag/spring/" class="elementor-post-info__terms-list-item">Spring</a>				</span>
					</span>
								</li>
				</ul>
				</div>
				</div>
				<div class="elementor-element elementor-element-3fee39a elementor-widget elementor-widget-text-editor" data-id="3fee39a" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Dieser Leitfaden beschreibt die Integration von <a href="https://de.wikipedia.org/wiki/OAuth">OAuth 2.0</a> in eine <a href="https://spring.io/projects/spring-boot/">Spring Boot</a> Anwendung mit <a href="https://www.keycloak.org/" target="_blank" rel="noopener">Keycloak</a>. Nach einer kurzen Einführung in die Spring Boot Plattform liegt der Schwerpunkt auf der genauen Konfiguration von Keycloak als vertrauenswürdigen OAuth 2.0 Server und der Absicherung bestimmter Endpunkte in der Anwendung mit Anmeldedaten.</p><p>Der Beitrag ist dabei so strukturiert, dass Entwickler Schritt für Schritt eine sichere Authentifizierung in einer Spring Boot-Anwendung implementieren können.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-1fddcb6 elementor-widget elementor-widget-theme-post-featured-image elementor-widget-image" data-id="1fddcb6" data-element_type="widget" data-widget_type="theme-post-featured-image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img loading="lazy" decoding="async" width="2000" height="1200" src="https://www.inoteq.com/wp-content/uploads/2023/11/wp1.png" class="attachment-full size-full wp-image-2922" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2023/11/wp1.png 2000w, https://www.inoteq.com/wp-content/uploads/2023/11/wp1-300x180.png 300w, https://www.inoteq.com/wp-content/uploads/2023/11/wp1-1024x614.png 1024w, https://www.inoteq.com/wp-content/uploads/2023/11/wp1-768x461.png 768w, https://www.inoteq.com/wp-content/uploads/2023/11/wp1-1536x922.png 1536w" sizes="(max-width: 2000px) 100vw, 2000px" />											<figcaption class="widget-image-caption wp-caption-text">KI generiertes Symbolbild: compelling, light-hearted tone, humorous, illustration, logo-style, spring boot (footwear), security key, keylock, keycloak oauth2, symbolizing secure access</figcaption>
										</figure>
							</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-38ab89f elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="38ab89f" data-element_type="section">
						<div class="elementor-container elementor-column-gap-no">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-b50792b" data-id="b50792b" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-9ef30cb elementor-toc--minimized-on-desktop elementor-widget elementor-widget-table-of-contents" data-id="9ef30cb" data-element_type="widget" data-settings="{&quot;exclude_headings_by_selector&quot;:&quot;.exclude-from-toc&quot;,&quot;minimized_on&quot;:&quot;desktop&quot;,&quot;headings_by_tags&quot;:[&quot;h2&quot;,&quot;h3&quot;,&quot;h4&quot;,&quot;h5&quot;,&quot;h6&quot;],&quot;marker_view&quot;:&quot;numbers&quot;,&quot;minimize_box&quot;:&quot;yes&quot;,&quot;hierarchical_view&quot;:&quot;yes&quot;,&quot;min_height&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;min_height_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;min_height_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}" data-widget_type="table-of-contents.default">
				<div class="elementor-widget-container">
					<div class="elementor-toc__header">
			<h4 class="elementor-toc__header-title">
				Inhaltsverzeichnis			</h4>
							<div class="elementor-toc__toggle-button elementor-toc__toggle-button--expand" role="button" tabindex="0" aria-controls="elementor-toc__9ef30cb" aria-expanded="true" aria-label="Open table of contents"><i aria-hidden="true" class="fas fa-chevron-down"></i></div>
				<div class="elementor-toc__toggle-button elementor-toc__toggle-button--collapse" role="button" tabindex="0" aria-controls="elementor-toc__9ef30cb" aria-expanded="true" aria-label="Close table of contents"><i aria-hidden="true" class="fas fa-chevron-up"></i></div>
					</div>
		<div id="elementor-toc__9ef30cb" class="elementor-toc__body">
			<div class="elementor-toc__spinner-container">
				<i class="elementor-toc__spinner eicon-animation-spin eicon-loading" aria-hidden="true"></i>			</div>
		</div>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-74fdfab elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="74fdfab" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-3f3966c" data-id="3f3966c" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-96f6788 elementor-widget elementor-widget-spacer" data-id="96f6788" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-820e96a elementor-widget elementor-widget-heading" data-id="820e96a" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Spring Boot: Setup und Grundkonfiguration</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-d1751ae elementor-widget elementor-widget-heading" data-id="d1751ae" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Konfiguration</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-ccc8dbe elementor-widget elementor-widget-text-editor" data-id="ccc8dbe" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die Vorbereitung der Spring Boot Anwendung für die Integration von OAuth 2.0 beginnt mit der Einrichtung des Projektes.</p><p>Für diesen Leitfaden wurde folgende Konfiguration gewählt:</p><ul><li>Spring Boot v3.2.0</li><li>Kotlin als Programmiersprache für Spring</li><li>Gradle (Groovy) für das Build-Tool</li></ul><p>Als Vorbereitung für die spätere Integration von OAuth 2.0 werden zudem noch folgende Abhängigkeiten benötigt:</p><ul><li><a href="https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web/3.2.0" target="_blank" rel="noopener">Spring Web v3.2.0</a></li><li><a href="https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security/3.2.0" target="_blank" rel="noopener">Spring Security v3.2.0</a></li><li><a href="https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-oauth2-client/3.2.0" target="_blank" rel="noopener">OAuth2 Client v3.2.0</a></li></ul><p>Diese Konfiguration bildet die Grundlage für die Entwicklung der Webanwendung mit integriertem OAuth 2.0 als Sicherheitsmechanismus. Die spezifische Konfiguration kann als neues leeres Projekt <a style="font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight ); background-color: #ffffff;" href="https://start.spring.io/#!type=gradle-project&amp;language=kotlin&amp;platformVersion=3.2.0&amp;packaging=jar&amp;jvmVersion=21&amp;groupId=com.example&amp;artifactId=demo&amp;name=demo&amp;description=Demo%20project%20for%20Spring%20Boot&amp;packageName=com.example.demo&amp;dependencies=web,security,oauth2-client" target="_blank" rel="noopener">hier über den Spring Initializr</a> direkt geladen werden.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-ca0c0e8 elementor-widget elementor-widget-heading" data-id="ca0c0e8" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Anwendung für OAuth 2.0 vorbereiten</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-542df6e elementor-widget elementor-widget-text-editor" data-id="542df6e" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Bevor die Anwendung erstmalig gestartet wird, sollten noch die folgenden Anpassungen vorgenommen werden. Durch die Einbindung der Spring Security Abhängigkeit, ist bereits die gesamte Anwendung mit allen Endpunkten standardmäßig mit einer simplen User/Passwort-Authentifizierung abgesichert. Da OAuth 2.0 später nur für bestimmte Endpunkte verwendet werden soll, ist eine entsprechende Konfiguration von Spring Security erforderlich, bei der diese grundlegende Authentifizierung durch eine Annotation in der Datei <b><i>DemoApplication.kt</i></b> vorerst deaktiviert wird. Zu Testzwecken wird ein Endpunkt in einem neuen Controller <b><i>DemoController.kt</i></b> definiert. Der Endpunkt und die Deaktivierung der Authentifizierung werden zu einem späteren Zeitpunkt wieder entfernt, wenn OAuth 2.0 konfiguriert wird.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-9eea9ed elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="9eea9ed" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-1661" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1661" aria-expanded="false">src/main/kotlin/.../DemoApplication.kt</div>
									<div id="elementor-tab-title-1662" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="false" data-tab="2" role="tab" tabindex="-1" aria-controls="elementor-tab-content-1662" aria-expanded="false">src/main/kotlin/.../DemoController.kt</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1661" aria-expanded="false">src/main/kotlin/.../DemoApplication.kt</div>
					<div id="elementor-tab-content-1661" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-1661" tabindex="0" hidden="false"><pre><code class="language-kotlin">package com.example.demo

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
import org.springframework.boot.runApplication

// Deaktivierung der default Authentifizierung von Spring Security
@SpringBootApplication(exclude = [SecurityAutoConfiguration::class])
class DemoApplication

fun main(args: Array) {
    runApplication(*args)
}
</code></pre></div>
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="false" data-tab="2" role="tab" tabindex="-1" aria-controls="elementor-tab-content-1662" aria-expanded="false">src/main/kotlin/.../DemoController.kt</div>
					<div id="elementor-tab-content-1662" class="elementor-tab-content elementor-clearfix" data-tab="2" role="tabpanel" aria-labelledby="elementor-tab-title-1662" tabindex="0" hidden="hidden"><pre><code class="language-kotlin">package com.example.demo

import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@RestController
class DemoController {
    @RequestMapping("/")
    fun helloWorld() = "Hello World!"
}
</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-0c8dbd5 elementor-widget elementor-widget-text-editor" data-id="0c8dbd5" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Mit dem Befehl <code class="language-bash inline">./gradlew bootRun</code> wird die Anwendung über das Terminal gestartet und ist anschließend unter der Adresse <a href="http://localhost:8080" target="_blank" rel="noopener">http://localhost:8080</a> erreichbar.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-825a46a elementor-widget elementor-widget-image" data-id="825a46a" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img loading="lazy" decoding="async" width="768" height="447" src="https://www.inoteq.com/wp-content/uploads/2023/11/Screenshot-2024-01-09-at-12.27.53-768x447.png" class="attachment-medium_large size-medium_large wp-image-2078" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2023/11/Screenshot-2024-01-09-at-12.27.53-768x447.png 768w, https://www.inoteq.com/wp-content/uploads/2023/11/Screenshot-2024-01-09-at-12.27.53-300x175.png 300w, https://www.inoteq.com/wp-content/uploads/2023/11/Screenshot-2024-01-09-at-12.27.53-1024x596.png 1024w, https://www.inoteq.com/wp-content/uploads/2023/11/Screenshot-2024-01-09-at-12.27.53.png 1061w" sizes="(max-width: 768px) 100vw, 768px" />											<figcaption class="widget-image-caption wp-caption-text">Ausgabe von "Hello World!" auf http://localhost:8080</figcaption>
										</figure>
							</div>
				</div>
				<div class="elementor-element elementor-element-f99b2cf elementor-widget elementor-widget-text-editor" data-id="f99b2cf" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Als Vorbereitung für die spätere Integration von OAuth 2.0 werden zwei weitere Endpunkte implementiert — ein öffentlicher Endpunkt <code class="language-plain inline">/public</code> und ein privater Endpunkt <code class="language-plain inline">/private</code>, welcher später nur für authentifizierte Benutzer aufrufbar sein soll. Unser &#8222;Hello World!&#8220; Endpunkt wird wieder entfernt:</p>						</div>
				</div>
				<div class="elementor-element elementor-element-2d26e30 elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="2d26e30" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-4731" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-4731" aria-expanded="false">./src/main/kotlin/.../DemoController.kt</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-4731" aria-expanded="false">./src/main/kotlin/.../DemoController.kt</div>
					<div id="elementor-tab-content-4731" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-4731" tabindex="0" hidden="false"><pre><code class="language-kotlin">package com.example.demo

import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@RestController
class DemoController {
    @RequestMapping("/", "/public")
    fun publicEndpoint() = "Hello from a public endpoint!"

    @RequestMapping("/private")
    fun privateEndpoint() = "Hello from a private endpoint!"
}
</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-41e88b2 elementor-widget elementor-widget-text-editor" data-id="41e88b2" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							Im Folgenden wollen wir mit OAuth 2.0 den Endpunkt <code class="language-plain inline">/private</code> absichern, der in diesem Zustand noch ohne Authentifizierung erreichbar ist.						</div>
				</div>
				<div class="elementor-element elementor-element-ffd0789 elementor-widget elementor-widget-alert" data-id="ffd0789" data-element_type="widget" data-widget_type="alert.default">
				<div class="elementor-widget-container">
					<div class="elementor-alert elementor-alert-warning" role="alert">
			<span class="elementor-alert-title">Mögliche Herrausforderungen</span>
							<span class="elementor-alert-description">Bei der Integration von Spring Security und OAuth 2.0 können Herausforderungen wie Konfigurationskonflikte und unerwartetes Verhalten auftreten. Es ist ratsam sicherzustellen, dass die Versionen der verwendeten Abhängigkeiten konsistent sind. Eine Überprüfung der Logdateien auf mögliche Fehlermeldungen ist ratsam.</span>
								</div>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-8cde8de elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="8cde8de" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-0a9c3ef" data-id="0a9c3ef" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-576ce23 elementor-widget elementor-widget-spacer" data-id="576ce23" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-d5c74ac elementor-widget elementor-widget-heading" data-id="d5c74ac" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Installation &amp; Konfiguration von Keycloak</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-2042828 elementor-widget elementor-widget-text-editor" data-id="2042828" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><a href="https://www.keycloak.org/" target="_blank" rel="noopener">Keycloak</a> ist eine Open-Source-Identitäts- und Zugriffsmanagementlösung. Es fungiert als OAuth 2.0 Server und ermöglicht die Authentifizierung von Benutzern, die Verwaltung von Anwendungs-Berechtigungen und die Bereitstellung von Single Sign-On für Anwendungen.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-42605d9 elementor-widget elementor-widget-heading" data-id="42605d9" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Einrichtung mit Docker</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-d1b28e2 elementor-widget elementor-widget-text-editor" data-id="d1b28e2" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							Die Verwendung von Docker ermöglicht den Betrieb einer konsistente und isolierte Umgebung für Keycloak. Zusätzlich wird die Einrichtung erleichtert und sichergestellt, dass alle erforderlichen Abhängigkeiten vorhanden sind und reibungslos funktionieren. <span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );">Da bereits eine ausführliche Anleitung </span><a style="font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight ); background-color: #ffffff;" href="https://www.keycloak.org/getting-started/getting-started-docker" target="_blank" rel="noopener">auf der offiziellen Keycloak-Seite</a><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );"> zu finden ist, wird im Folgenden nur noch auf die relevanten Punkte eingegangen. Bevor Keycloak in einem Docker-Container gestartet werden kann, sollten sichergestellt werden, dass Docker auf dem System installiert und einsatzbereit ist. Dies kann mit dem Befehl </span><code style="color: var( --e-global-color-text ); font-weight: var( --e-global-typography-text-font-weight ); font-size: 18px;" class="language-plain inline">docker −−version</code><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );"> getestet werden, wobei Die Ausgabe die Installierte Docker-Version anzeigen muss. Eine Installationsanleitung für Docker selbst kann der </span><a style="font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight ); background-color: #ffffff;" href="https://docs.docker.com/engine/install/" target="_blank" rel="noopener">offziellen Seite</a><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );"> entnommen werden.</span>

<span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );">Zur eigentlichen Installation und Starten von Keycloak verwenden wir folgenden Befehl:</span>						</div>
				</div>
				<div class="elementor-element elementor-element-9a02a17 elementor-widget elementor-widget-html" data-id="9a02a17" data-element_type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
			<pre><code style="white-space: normal; word-break: break-word;" class="language-sh">docker run -p 8081:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak start-dev</code></pre>		</div>
				</div>
				<div class="elementor-element elementor-element-64c4573 elementor-widget elementor-widget-text-editor" data-id="64c4573" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Der Befehl setzt sich dabei folgendermaßen zusammen:</p><ul><li><code class="language-plain inline">docker run</code> Anweisung an Docker den Container mit den Parametern zu starten</li><li><code class="language-plain inline">-p 8081:8080</code> Portmapping von 8081 (Container außen) zu 8080 (Container innen)</li><li><code class="language-plain inline">-e KEYCLOAK_ADMIN=admin</code> Benutzername für das Keycloak Webinterface</li><li><code class="language-plain inline">-e KEYCLOAK_ADMIN_PASSWORD=admin</code> Passwort für das Keycloak Webinterface</li><li><code class="language-plain inline">quay.io/keycloak/keycloak</code> URL auf das Docker-Image für Keycloak</li><li><code class="language-plain inline">start-dev</code> Startet Keycloak innerhalb des Docker-Containers</li></ul>						</div>
				</div>
				<div class="elementor-element elementor-element-6413a8e elementor-arrows-position-inside elementor-pagination-position-outside elementor-widget elementor-widget-image-carousel" data-id="6413a8e" data-element_type="widget" data-settings="{&quot;slides_to_show&quot;:&quot;1&quot;,&quot;autoplay&quot;:&quot;no&quot;,&quot;infinite&quot;:&quot;no&quot;,&quot;navigation&quot;:&quot;both&quot;,&quot;effect&quot;:&quot;slide&quot;,&quot;speed&quot;:500}" data-widget_type="image-carousel.default">
				<div class="elementor-widget-container">
					<div class="elementor-image-carousel-wrapper swiper-container" dir="ltr">
			<div class="elementor-image-carousel swiper-wrapper" aria-live="polite">
								<div class="swiper-slide" role="group" aria-roledescription="slide" aria-label="1 von 1"><figure class="swiper-slide-inner"><img decoding="async" class="swiper-slide-image" src="https://www.inoteq.com/wp-content/uploads/2023/11/Screenshot-2024-01-09-at-13.15.49-768x833.png" alt="Ausgabe von Docker für Keycloak" /><figcaption class="elementor-image-carousel-caption">Ausgabe von Docker für Keycloak</figcaption></figure></div>			</div>
					</div>
				</div>
				</div>
				<section class="elementor-section elementor-inner-section elementor-element elementor-element-3c3343d elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="3c3343d" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-66 elementor-inner-column elementor-element elementor-element-a373291" data-id="a373291" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-beb93e5 elementor-widget elementor-widget-text-editor" data-id="beb93e5" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );">Sofern lokal noch kein Keycloak Docker-Image existiert, wird dieses automatisch heruntergeladen. Wenn der Befehl ausgeführt wird, startet ein neuer Keycloak-Container, welcher über </span><a style="font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight ); background-color: #ffffff;" href="http://localhost:8081" target="_blank" rel="noopener">http://localhost:8081</a><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );"> erreichbar ist. In der Administrationskonsole unter </span><a style="font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight ); background-color: #ffffff;" href="http://localhost:8081/admin" target="_blank" rel="noopener">http://localhost:8081/admin</a><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );"> kann sich mit den definierten Benutzerdaten angemeldet werden, um Keycloak für den OAuth 2.0 Server zu konfigurieren.</span></p>						</div>
				</div>
					</div>
		</div>
				<div class="elementor-column elementor-col-33 elementor-inner-column elementor-element elementor-element-7254df5" data-id="7254df5" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-3e5a55c elementor-widget elementor-widget-image" data-id="3e5a55c" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
														<a href="https://www.inoteq.com/wp-content/uploads/2023/11/Screenshot-2024-01-09-at-13.15.54.png" data-elementor-open-lightbox="yes" data-elementor-lightbox-title="Keycloak" data-e-action-hash="#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6MjExMywidXJsIjoiaHR0cHM6XC9cL3d3dy5pbm90ZXEuY29tXC93cC1jb250ZW50XC91cGxvYWRzXC8yMDIzXC8xMVwvU2NyZWVuc2hvdC0yMDI0LTAxLTA5LWF0LTEzLjE1LjU0LnBuZyJ9">
							<img loading="lazy" decoding="async" width="800" height="786" src="https://www.inoteq.com/wp-content/uploads/2023/11/Screenshot-2024-01-09-at-13.15.54-1024x1006.png" class="attachment-large size-large wp-image-2113" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2023/11/Screenshot-2024-01-09-at-13.15.54-1024x1006.png 1024w, https://www.inoteq.com/wp-content/uploads/2023/11/Screenshot-2024-01-09-at-13.15.54-300x295.png 300w, https://www.inoteq.com/wp-content/uploads/2023/11/Screenshot-2024-01-09-at-13.15.54-768x754.png 768w, https://www.inoteq.com/wp-content/uploads/2023/11/Screenshot-2024-01-09-at-13.15.54-1536x1509.png 1536w, https://www.inoteq.com/wp-content/uploads/2023/11/Screenshot-2024-01-09-at-13.15.54.png 2034w" sizes="(max-width: 800px) 100vw, 800px" />								</a>
													</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<div class="elementor-element elementor-element-349897e elementor-widget elementor-widget-heading" data-id="349897e" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">OAuth 2.0 Server Konfiguration</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-98011df elementor-widget elementor-widget-text-editor" data-id="98011df" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>In der Administrationskonsole wird zuerst neuer <em><strong>Realm</strong></em> für die Anwendung erstellt. Bei einem Realm in Keycloak handelt es sich um eine isolierte Sicherheitsdomäne, die Benutzer, Ressourcen und Einstellungen in einem OAuth 2.0 Server organisiert. Auf diese Weise ist eine flexible Verwaltung verschiedener Anwendungen in ein und derselben Keycloak-Instanz möglich. Standardmäßig ist der build-in Realm <code class="language-plain inline">master</code> ausgewählt. Der Reiter wird angeklickt und über die Schaltfläche <em><strong>Create realm</strong></em> wird ein neuer Realm erstellt. Beim Anlegen wird ein Name vergeben <code class="language-plain inline">demo-realm</code> vergeben , und sichergestellt, dass dieser aktiv ist.</p><p><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );">Nun müssen wir für die Anwendung ein </span><em style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );"><strong>Mandant</strong></em><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );"> anlegen. Ein Mandant in Keycloak repräsentiert eine Anwendung, die OAuth 2.0 oder OpenID Connect zur Authentifizierung und Autorisierung verwendet. Jeder Mandant hat eine eindeutige Identität und Konfiguration und kann Ressourcen in einem bestimmten Realm schützen. Beispiele für Mandanten sind Webanwendungen, mobile Anwendungen oder Dienste, die Zugriff auf geschützte Ressourcen benötigen. Zur Erstellung eines neuen Mandanten kann im Menüpunkt </span><strong style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif;"><em>Clients</em></strong><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );"> der Button </span><strong style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif;"><em>Create client </em></strong><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );">angeklickt werden, worauf ein Formular erscheint, das in drei Schritte gegliedert ist:</span></p><ol><li>Schritt: Für den Client wird der Typ <strong><em>OpenID Connect</em></strong> ausgewählt und die Client-ID <code class="language-plain inline">demo-client</code> vergeben .</li><li>Schritt: In diesem Schritt muss sichergestellt werden, dass unter &#8222;<em>Authentication flow</em>&#8220; die Option <strong><em>Standard flow</em></strong> aktiviert ist. Die Aktivierung der Option &#8222;Standard flow&#8220; in Keycloak ist entscheidend, um die Sicherheit zu erhöhen, indem der Authentifizierungsprozess in zwei Schritte aufgeteilt wird: Der Benutzer authentifiziert sich am Autorisierungsserver und tauscht sicher einen temporären Autorisierungscode gegen Zugriffstoken aus. Dies minimiert das Risiko, sensible Informationen am Frontend preiszugeben, insbesondere bei serverseitigen Anwendungen wie Spring Boot.</li><li>Schritt: Hier wird im Feld <em><b>Valid redirect URIs</b></em> die URL <code class="language-plain inline">http://localhost:8080/*</code> eingetragen und alle Eingaben mit einem Klick auf <strong><em>Save</em></strong> bestätigt. Dieser Eintrag ist erforderlich, damit Keycloak nach der Benutzerauthentifizierung die korrekte Rücksendeadresse für den Authorisierungscode erhält. Der Stern ermöglicht die Annahme gültiger Redirect-URIs für alle Pfade unter <code class="language-plain inline">http://localhost:8080/</code>. Dies bietet Flexibilität für verschiedene Endpunkte und unterstützt die sichere Rückgabe von Authentifizierungsantworten.</li></ol><div> </div><p>Damit wäre Keycloak bereits als OAuth 2.0 Server für die Anwendung konfiguriert.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-8450c1a elementor-arrows-position-inside elementor-pagination-position-outside elementor-widget elementor-widget-image-carousel" data-id="8450c1a" data-element_type="widget" data-settings="{&quot;slides_to_show&quot;:&quot;1&quot;,&quot;autoplay&quot;:&quot;no&quot;,&quot;infinite&quot;:&quot;no&quot;,&quot;navigation&quot;:&quot;both&quot;,&quot;effect&quot;:&quot;slide&quot;,&quot;speed&quot;:500}" data-widget_type="image-carousel.default">
				<div class="elementor-widget-container">
					<div class="elementor-image-carousel-wrapper swiper-container" dir="ltr">
			<div class="elementor-image-carousel swiper-wrapper" aria-live="polite">
								<div class="swiper-slide" role="group" aria-roledescription="slide" aria-label="1 von 3"><figure class="swiper-slide-inner"><img decoding="async" class="swiper-slide-image" src="https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-09.38.03-768x755.png" alt="Schritt 1 - Erstellung eines Mandanten in Keycloak" /><figcaption class="elementor-image-carousel-caption">Schritt 1 - Erstellung eines Mandanten in Keycloak</figcaption></figure></div><div class="swiper-slide" role="group" aria-roledescription="slide" aria-label="2 von 3"><figure class="swiper-slide-inner"><img decoding="async" class="swiper-slide-image" src="https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-09.38.33-768x755.png" alt="Schritt 2 - Erstellung eines Mandanten in Keycloak" /><figcaption class="elementor-image-carousel-caption">Schritt 2 - Erstellung eines Mandanten in Keycloak</figcaption></figure></div><div class="swiper-slide" role="group" aria-roledescription="slide" aria-label="3 von 3"><figure class="swiper-slide-inner"><img decoding="async" class="swiper-slide-image" src="https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-09.38.59-768x755.png" alt="Schritt 3 - Erstellung eines Mandanten in Keycloak" /><figcaption class="elementor-image-carousel-caption">Schritt 3 - Erstellung eines Mandanten in Keycloak</figcaption></figure></div>			</div>
												<div class="elementor-swiper-button elementor-swiper-button-prev" role="button" tabindex="0">
						<i aria-hidden="true" class="eicon-chevron-left"></i>					</div>
					<div class="elementor-swiper-button elementor-swiper-button-next" role="button" tabindex="0">
						<i aria-hidden="true" class="eicon-chevron-right"></i>					</div>
				
									<div class="swiper-pagination"></div>
									</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-1b159ff elementor-widget elementor-widget-heading" data-id="1b159ff" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Rollenverwaltung</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-8d6d796 elementor-widget elementor-widget-text-editor" data-id="8d6d796" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die Benutzer müssen mit einem Rollenattribut versehen werden, welches über den Token an die Anwendung weitergegeben werden muss. Zu diesem Zweck muss der Mandant noch weiter konfiguriert werden.</p><p>Um eine neue Rolle anzulegen, wird über den Menüpunkt <strong><em>Clients</em></strong> in den angelegten Mandanten <code class="language-plain inline">demo-client</code> navigiert. Hier wird über den Reiter <strong><em>Roles</em></strong> und den Button <strong><em>Create role</em></strong> eine neue Rolle angelegt. Für die neue Rolle wird der Rollenname <code class="language-plain inline">demo-role</code> gewählt und anschließend mit dem Button <strong><em>Save</em></strong> bestätigt. Der Mandant muss nun so konfiguriert werden, dass diese Rolle im Token enthalten ist. Nach erfolgreicher Authentifizierung generiert Keycloak das Token, welches Informationen über den Benutzer sowie gewährte Berechtigungen enthält. Die Anwendung nutzt das Token zur Identifikation des Benutzers und für entsprechende Aktionen basierend auf den Tokeninformationen. Dazu wird im Reiter &#8222;<em>Client scopes</em>&#8220; zu &#8222;<em>demo-client-dedicated</em>&#8220; navigiert und dort mit &#8222;<em>Add predifined mapper</em>&#8220; ein neuer Token-Mapper für <strong><em>client roles</em></strong> definiert. Das Ganze wird mit &#8222;<em>Add</em>&#8220; bestätigt. Ein Klick auf den neu angelegten Eintrag &#8222;<em>client roles</em>&#8220; öffnet weitere Einstellungen. Hier wird für &#8222;<em>Token Claim Name</em>&#8220; ein Wert festgelegt, z.B. <code class="language-plain inline">roles</code> , die Option &#8222;<em>Add to ID token</em>&#8220; <strong>aktiviert</strong> und die Änderungen mit &#8222;<em>Save</em>&#8220; bestätigt. Nun enthält das Token in der Anwendung über ein Attribut mit dem Schlüssel &#8222;<em>roles</em>&#8220; alle Rollen des Benutzers.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-b800550 elementor-arrows-position-inside elementor-pagination-position-outside elementor-widget elementor-widget-image-carousel" data-id="b800550" data-element_type="widget" data-settings="{&quot;slides_to_show&quot;:&quot;1&quot;,&quot;autoplay&quot;:&quot;no&quot;,&quot;infinite&quot;:&quot;no&quot;,&quot;navigation&quot;:&quot;both&quot;,&quot;effect&quot;:&quot;slide&quot;,&quot;speed&quot;:500}" data-widget_type="image-carousel.default">
				<div class="elementor-widget-container">
					<div class="elementor-image-carousel-wrapper swiper-container" dir="ltr">
			<div class="elementor-image-carousel swiper-wrapper" aria-live="polite">
								<div class="swiper-slide" role="group" aria-roledescription="slide" aria-label="1 von 4"><figure class="swiper-slide-inner"><img decoding="async" class="swiper-slide-image" src="https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-09.39.27-768x755.png" alt="Navigation zum Mandanten-Geltungsbereich" /><figcaption class="elementor-image-carousel-caption">Navigation zum Mandanten-Geltungsbereich</figcaption></figure></div><div class="swiper-slide" role="group" aria-roledescription="slide" aria-label="2 von 4"><figure class="swiper-slide-inner"><img decoding="async" class="swiper-slide-image" src="https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-09.39.39-768x755.png" alt="Ansicht zu Hinzufügen eines neuen Token-Mappers" /><figcaption class="elementor-image-carousel-caption">Ansicht zu Hinzufügen eines neuen Token-Mappers</figcaption></figure></div><div class="swiper-slide" role="group" aria-roledescription="slide" aria-label="3 von 4"><figure class="swiper-slide-inner"><img decoding="async" class="swiper-slide-image" src="https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-09.39.52-768x755.png" alt="Ausgewählter Token-Mapper für Mandanten-Rollen" /><figcaption class="elementor-image-carousel-caption">Ausgewählter Token-Mapper für Mandanten-Rollen</figcaption></figure></div><div class="swiper-slide" role="group" aria-roledescription="slide" aria-label="4 von 4"><figure class="swiper-slide-inner"><img decoding="async" class="swiper-slide-image" src="https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-09.40.31-768x755.png" alt="Konfiguration des Token-Mappers" /><figcaption class="elementor-image-carousel-caption">Konfiguration des Token-Mappers</figcaption></figure></div>			</div>
												<div class="elementor-swiper-button elementor-swiper-button-prev" role="button" tabindex="0">
						<i aria-hidden="true" class="eicon-chevron-left"></i>					</div>
					<div class="elementor-swiper-button elementor-swiper-button-next" role="button" tabindex="0">
						<i aria-hidden="true" class="eicon-chevron-right"></i>					</div>
				
									<div class="swiper-pagination"></div>
									</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-8546b84 elementor-widget elementor-widget-heading" data-id="8546b84" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Benutzerverwaltung</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-c21f7ad elementor-widget elementor-widget-text-editor" data-id="c21f7ad" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Um sich später in der Spring Boot Anwendung anmelden zu können, muss ein Benutzer definiert werden. Dazu wird ein neuer Benutzer im Realm angelegt. Das Formular zur Eingabe der Benutzerdaten wird über den Menüpunkt <strong><em>Users</em></strong> und den Button <strong><em>Add user</em></strong> aufgerufen. Im Rahmen dieses Leitfadens wird ein Benutzer mit dem Benutzernamen <code class="language-plain inline">john.doe</code> , dem Vor- und Nachnamen <code class="language-plain inline">John Doe</code> und der E-Mail-Adresse <code class="language-plain inline">john.doe@example.com</code> angelegt. Es ist nicht erforderlich, weitere Einstellungen zu ändern.</p><p><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );">Für den neu angelegten Benutzer muss noch ein Passwort festgelegt werden. Dazu reicht es zunächst aus, im Benutzer unter dem Reiter </span><strong style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif;"><em>Credentials</em></strong><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );"> und dem Button </span><strong style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif;"><em>Set password</em></strong><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );"> ein neues, nicht temporäres Passwort zu setzen, z.B. </span><code class="language-plain inline" style="font-weight: var( --e-global-typography-text-font-weight ); font-size: 18px;">password</code><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );"> . Unter dem Reiter </span><strong style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif;"><em>Role mapping</em></strong><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );"> wird dem Benutzer die zuvor angelegte Gruppe zugewiesen. Dazu wird auf </span><strong style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif;"><em>Assign role</em></strong><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );"> geklickt und der Filter so eingestellt, dass die Mandantenrollen angezeigt werden. Anschließend wird die Rolle </span><code class="language-plain inline" style="font-weight: var( --e-global-typography-text-font-weight ); font-size: 18px;">(demo-client) demo-role</code><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );"> ausgewählt und mit </span><strong style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif;"><em>Assign</em></strong><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );"> bestätigt.</span></p><p><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );">Unter &#8222;</span><a style="font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight ); background-color: #ffffff;" href="http://localhost:8081/realms/demo-realm/account" target="_blank" rel="noopener">http://localhost:8081/realms/demo-realm/account</a><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );">&#8220; kann durch Anmelden mit dem angelegten Benutzer überprüft werden, ob dieser korrekt angelegt und konfiguriert wurde.</span></p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-4dc4e86 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="4dc4e86" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-7143e2a" data-id="7143e2a" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-2e7c0e2 elementor-widget elementor-widget-spacer" data-id="2e7c0e2" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-af8f6d2 elementor-widget elementor-widget-heading" data-id="af8f6d2" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">OAuth 2.0 Konfiguration in Spring Boot</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-bcb971c elementor-widget elementor-widget-heading" data-id="bcb971c" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Anpassen der Anwendungseigenschaften</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-000c56c elementor-widget elementor-widget-text-editor" data-id="000c56c" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							Der erste Schritt bei der Konfiguration von OAuth 2.0 in der Anwendung ist die Anpassung der Datei <b><em>application.yml</em></b>. Dabei wird ein Provider <code>demo-provider</code> definiert, der auf den Realm verweist, und ein Client <code class="language-plain inline">demo-client</code> registriert:						</div>
				</div>
				<div class="elementor-element elementor-element-27d1fd5 elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="27d1fd5" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-4171" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-4171" aria-expanded="false">./application.yml</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-4171" aria-expanded="false">./application.yml</div>
					<div id="elementor-tab-content-4171" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-4171" tabindex="0" hidden="false"><pre><code class="language-yml">spring:
  security:
    oauth2:
      client:
        provider:
          # provider name used for registration
          demo-provider:
            # Keycloak realm URL: "{keycloak-url}/realms/{realm-name}"
            issuer-uri: http://localhost:8081/realms/demo-realm
        registration:
          # client-id from Keycloak client configuration
          demo-client:
            # provider from above
            provider: demo-provider
            # client-id from Keycloak client configuration
            client-id: demo-client
            scope: openid
            # default redirect URI: "{baseUrl}/login/oauth2/code/{registrationId}"
            redirect-uri: http://localhost:8080/login/oauth2/code/demo-client
</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-96d20f7 elementor-widget elementor-widget-heading" data-id="96d20f7" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Spring Security Konfiguration</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-11e3031 elementor-widget elementor-widget-text-editor" data-id="11e3031" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							Zusätzlich muss noch eine Konfiguration für Spring Security erstellt werden. Dazu wird eine neue Klasse <em><strong>SecurityConfiguration.kt</strong></em> erstellt, in der die Filterkette so konfiguriert wird, dass für den Endpunkt <code class="language-plain inline">/private</code> ein Benutzer mit OAuth 2.0 erfolgreich angemeldet sein muss. Mit der Syntax <code class="language-plain inline">/private/**</code> werden alle Endpunkte gesichert. Es müssen nicht alle einzeln angegeben werden.						</div>
				</div>
				<div class="elementor-element elementor-element-b677605 elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="b677605" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-1911" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1911" aria-expanded="false">./src/main/kotlin/.../SecurityConfiguration.kt</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1911" aria-expanded="false">./src/main/kotlin/.../SecurityConfiguration.kt</div>
					<div id="elementor-tab-content-1911" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-1911" tabindex="0" hidden="false"><pre><code class="language-kotlin">package com.example.demo

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.Customizer
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.web.SecurityFilterChain

@Configuration
@EnableWebSecurity
class SecurityConfiguration {
    @Bean
    fun securityFilterChain(http: HttpSecurity): SecurityFilterChain =
        http
            .authorizeHttpRequests {
                it
                    // Only allow authenticated users here
                    .requestMatchers("/private/**")
                    .fullyAuthenticated()
                    // Allow all other requests
                    .anyRequest()
                    .permitAll()
            }
            // Use OAuth 2.0 Login to handle authentication
            .oauth2Login(Customizer.withDefaults())
            .build()
}
</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-5fca981 elementor-widget elementor-widget-text-editor" data-id="5fca981" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							Wurde die automatische Konfiguration von Spring Security per Annotation deaktiviert, wie wir es anfangs zu Testzwecken gemacht haben, muss sichergestellt werden, dass sie wieder aktiviert wird. Um dies zu erreichen, muss der Parameter aus der <code class="language-plain inline">@SpringBootApplication()</code> Annotation in der Datei <strong><b><i>DemoApplication.kt</i></b></strong> entfernt werden. Die Annotation selbst muss bestehen bleiben.

<span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );">Die Anwendung kann nun gestartet werden. Unter dem Endpunkt </span><code class="language-plain inline" style="font-weight: var( --e-global-typography-text-font-weight ); font-size: 18px;">/public</code><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );"> sollte keine Authentifizierung abgefragt werden und es wird lediglich &#8222;Hello from a public endpoint!&#8220; angezeigt. Wird zum Endpunkt </span><code class="language-plain inline" style="font-weight: var( --e-global-typography-text-font-weight ); font-size: 18px;">/private</code><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );"> navigiert, so navigiert die Anwendung zunächst zum OAuth 2.0 Server. Hier kann eine Anmeldung mit dem Benutzer </span><code class="language-plain inline" style="font-weight: var( --e-global-typography-text-font-weight ); font-size: 18px;">john.doe</code><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );"> und dem Passwort </span><code class="language-plain inline" style="font-weight: var( --e-global-typography-text-font-weight ); font-size: 18px;">password</code><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );"> erfolgen. Anschließend sollte eine automatische Weiterleitung zurück zur urpsürnglichen Seite erfolgen. Nun wird der Text &#8222;Hello from a private endpoint!&#8220; angezeigt.</span>						</div>
				</div>
				<div class="elementor-element elementor-element-a714aad elementor-arrows-position-inside elementor-pagination-position-outside elementor-widget elementor-widget-image-carousel" data-id="a714aad" data-element_type="widget" data-settings="{&quot;slides_to_show&quot;:&quot;1&quot;,&quot;autoplay&quot;:&quot;no&quot;,&quot;infinite&quot;:&quot;no&quot;,&quot;navigation&quot;:&quot;both&quot;,&quot;effect&quot;:&quot;slide&quot;,&quot;speed&quot;:500}" data-widget_type="image-carousel.default">
				<div class="elementor-widget-container">
					<div class="elementor-image-carousel-wrapper swiper-container" dir="ltr">
			<div class="elementor-image-carousel swiper-wrapper" aria-live="polite">
								<div class="swiper-slide" role="group" aria-roledescription="slide" aria-label="1 von 3"><figure class="swiper-slide-inner"><img decoding="async" class="swiper-slide-image" src="https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-10.10.25-768x606.png" alt="Ausgabe auf http://localhost:8080/ bzw. http://localhost:8080/public" /><figcaption class="elementor-image-carousel-caption">Ausgabe auf http://localhost:8080/ bzw. http://localhost:8080/public</figcaption></figure></div><div class="swiper-slide" role="group" aria-roledescription="slide" aria-label="2 von 3"><figure class="swiper-slide-inner"><img decoding="async" class="swiper-slide-image" src="https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-10.11.03-768x606.png" alt="Anmeldung beim Versuch den privaten Endpunkt aufzurufen" /><figcaption class="elementor-image-carousel-caption">Anmeldung beim Versuch den privaten Endpunkt aufzurufen</figcaption></figure></div><div class="swiper-slide" role="group" aria-roledescription="slide" aria-label="3 von 3"><figure class="swiper-slide-inner"><img decoding="async" class="swiper-slide-image" src="https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-10.11.11-768x606.png" alt="Ausgabe auf http://localhost:8080/private, wenn sich erfolgreich angemeldet wurde" /><figcaption class="elementor-image-carousel-caption">Ausgabe auf http://localhost:8080/private, wenn sich erfolgreich angemeldet wurde</figcaption></figure></div>			</div>
												<div class="elementor-swiper-button elementor-swiper-button-prev" role="button" tabindex="0">
						<i aria-hidden="true" class="eicon-chevron-left"></i>					</div>
					<div class="elementor-swiper-button elementor-swiper-button-next" role="button" tabindex="0">
						<i aria-hidden="true" class="eicon-chevron-right"></i>					</div>
				
									<div class="swiper-pagination"></div>
									</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-5cf4d5d elementor-widget elementor-widget-heading" data-id="5cf4d5d" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Ausgabe der Informationen vom Token</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-7c24d5f elementor-widget elementor-widget-text-editor" data-id="7c24d5f" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Sobald ein Benutzer die Anwendung aufruft, wird in der Anwendung ein Benutzerobjekt erzeugt. Wenn der Benutzer sich nicht authentifiziert hat, z.B. am öffentlichen Endpunkt, wird der Benutzer als <b><i>anonym</i></b> behandelt. Sobald jedoch eine erfolgreiche Anmeldung über OAuth 2.0 erfolgt ist, wird ein entsprechendes Objekt mit dem erhaltenen Token erzeugt. Aus diesem Objekt können die Benutzerinformationen ausgelesen und für die Anwendung verwendet werden.<br></p>
<p><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );">Ein wird nun ein weiterer Endpunkt zur Ausgabe dieser Daten hinzugefügt. Da alle Endpunkte bereits unter </span><code class="language-plain inline" style="font-weight: var( --e-global-typography-text-font-weight ); font-size: 18px;">/private</code><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );"> abgesichert sind, wird der neue Endpunkt unter &#8222;</span><a style="font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight ); background-color: #ffffff;" href="http://localhost:8080/private/user">http://localhost:8080/private/user</a><span style="color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight );">&#8220; abgelegt. Die Benutzerinformationen können über den Kontext geladen werden. Dabei ist zu beachten, dass eine Konvertierung in einen OAuth2User vorgenommen wird. Die Umwandlung eines Principal-Objekts in ein OAuth2User-Objekt in Spring Boot ist sinnvoll, wenn erweiterte Benutzerinformationen aus dem OAuth 2.0-Token benötigt werden. Das OAuth2User-Objekt stellt standardisierte Methoden für den Zugriff auf diese Informationen bereit und erleichtert somit eine einheitliche Verarbeitung von OAuth 2.0-basierten Benutzerdaten in Spring-Boot-Anwendungen. Nach der Umwandlung kann auf die Attribute des Benutzers zugegriffen werden. In diesem Fall werden Name, E-Mail-Adresse und alle zugehörigen Rollen ausgegeben.</span></p>						</div>
				</div>
				<div class="elementor-element elementor-element-5b630ef elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="5b630ef" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-9581" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-9581" aria-expanded="false">./src/main/kotlin/.../DemoController.kt</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-9581" aria-expanded="false">./src/main/kotlin/.../DemoController.kt</div>
					<div id="elementor-tab-content-9581" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-9581" tabindex="0" hidden="false"><pre><code class="language-kotlin">...
@RequestMapping("/private/user")
    fun userEndpoint(): String {
        val user = SecurityContextHolder.getContext().authentication.principal as OAuth2User
        return "Name: ${user.attributes["name"]}, " +
            "Email: ${user.attributes["email"]}, " +
            "Roles: ${user.attributes["roles"]}"
    }
...</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-57361db elementor-widget elementor-widget-text-editor" data-id="57361db" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							Die Anwendung kann neu gestartet und der neue Endpunkt getestet werden. Wird zum Endpunkt <code class="language-plain inline">/private/user</code> navigiert, findet eine erneute Authentifizierung statt. Möglicherweise geschieht dies automatisch, da das Cookie vom OAuth-Server noch gespeichert ist. Auf der Seite wird dann folgendes angezeigt:						</div>
				</div>
				<div class="elementor-element elementor-element-d2a8e52 elementor-widget elementor-widget-image" data-id="d2a8e52" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img loading="lazy" decoding="async" width="768" height="606" src="https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-10.11.23-768x606.png" class="attachment-medium_large size-medium_large wp-image-2168" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-10.11.23-768x606.png 768w, https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-10.11.23-300x237.png 300w, https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-10.11.23-1024x808.png 1024w, https://www.inoteq.com/wp-content/uploads/2024/01/Screenshot-2024-01-10-at-10.11.23.png 1061w" sizes="(max-width: 768px) 100vw, 768px" />											<figcaption class="widget-image-caption wp-caption-text">Ausgabe auf http://localhost:8080/private/user</figcaption>
										</figure>
							</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-f4bb66e elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="f4bb66e" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-f95c884" data-id="f95c884" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-7d593ee elementor-widget elementor-widget-spacer" data-id="7d593ee" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-b2e76de elementor-widget elementor-widget-heading" data-id="b2e76de" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Entwicklungsperspektiven</h2>		</div>
				</div>
				<section class="elementor-section elementor-inner-section elementor-element elementor-element-6a99a63 elementor-section-full_width elementor-section-content-top elementor-section-height-default elementor-section-height-default" data-id="6a99a63" data-element_type="section">
						<div class="elementor-container elementor-column-gap-no">
					<div class="elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-4f32b32" data-id="4f32b32" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-0cba619 elementor-widget elementor-widget-text-editor" data-id="0cba619" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die Integration von Keycloak in Spring Boot ermöglicht eine effiziente und sichere Authentifizierung. Entwickler profitieren vom externen Authentifizierungsmanagement, können sich auf Kernfunktionen konzentrieren und Sicherheitsaspekte einfach implementieren. Die Flexibilität durch die Konfigurierbarkeit von Keycloak erlaubt die Anpassung an spezifische Anforderungen. Die Basis von Keycloak legt zudem den Grundstein für zukünftige Erweiterungen, ohne die Anwendungslogik stark verändern zu müssen. Die Flexibilität von Spring Boot ermöglicht es, auch andere OAuth 2.0 Server wie Azure, ADFS und mehr zu integrieren. Dadurch können Entwickler die Authentifizierungslösung an die spezifischen Anforderungen ihrer Anwendung anpassen.</p><p>Für weitere Details steht das <a href="https://github.com/inoteq/spring-boot-keycloak-oauth2" target="_blank" rel="noopener">GitHub Repository</a> zur Verfügung, das alle im Artikel beschriebenen Schritte und Konfigurationen enthält, einschließlich eines vorkonfigurierten Keycloak Containers mit Docker.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-4582ebd elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="4582ebd" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-5c48a3f" data-id="5c48a3f" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-7c6e6ad elementor-widget elementor-widget-text-editor" data-id="7c6e6ad" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Eine detaillierte Beschreibung der Funktionsweise von OAuth 2.0 und dem Zusammenspiel der verschiedenen Komponenten findet sich in dem verlinkten Artikel.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-985898c elementor-grid-1 elementor-grid-tablet-1 elementor-posts--thumbnail-left elementor-hidden-tablet elementor-hidden-mobile elementor-grid-mobile-1 elementor-widget elementor-widget-posts" data-id="985898c" data-element_type="widget" data-settings="{&quot;classic_columns&quot;:&quot;1&quot;,&quot;classic_columns_tablet&quot;:&quot;1&quot;,&quot;classic_columns_mobile&quot;:&quot;1&quot;,&quot;classic_row_gap&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:35,&quot;sizes&quot;:[]},&quot;classic_row_gap_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;classic_row_gap_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}" data-widget_type="posts.classic">
				<div class="elementor-widget-container">
					<div class="elementor-posts-container elementor-posts elementor-posts--skin-classic elementor-grid">
				<article class="elementor-post elementor-grid-item post-1479 post type-post status-publish format-standard has-post-thumbnail hentry category-blog">
				<a class="elementor-post__thumbnail__link" href="https://www.inoteq.com/2021/05/06/springboot-authentifizierung/" tabindex="-1" >
			<div class="elementor-post__thumbnail"><img loading="lazy" decoding="async" width="574" height="400" src="https://www.inoteq.com/wp-content/uploads/2021/04/inoteq-polygon-background.png" class="attachment-full size-full wp-image-1391" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2021/04/inoteq-polygon-background.png 574w, https://www.inoteq.com/wp-content/uploads/2021/04/inoteq-polygon-background-300x209.png 300w" sizes="(max-width: 574px) 100vw, 574px" /></div>
		</a>
				<div class="elementor-post__text">
				<p class="elementor-post__title">
			<a href="https://www.inoteq.com/2021/05/06/springboot-authentifizierung/" >
				Sichern einer Spring Boot WebApp mit OAuth 2.0​			</a>
		</p>
				<div class="elementor-post__meta-data">
					<span class="elementor-post-author">
			Aymen Khalki		</span>
				<span class="elementor-post-date">
			6. Mai 2021		</span>
				</div>
				<div class="elementor-post__excerpt">
			<p>Authentifizierung ist der erste Schritt in jedem Sicherheitssystem. Es ist der Prozess mit dem die Identität eines Clients verifiziert wird. Ob der Client Zugriff auf bestimmte Ressourcen erhält, wird allerdings durch den Autorisierungsprozess festgestellt. In diesem Artikel werden wir eine API mit Spring Boot erstellen und das OAuth 2.0 Authentifizierungsprotokoll verwenden, um diese API abzusichern. Table of Contents Eingehende Erläuterungen und Definitionen OAuth 2.0 OAuth 2.0 (Open Authentication) ist ein</p>
		</div>
		
		<a class="elementor-post__read-more" href="https://www.inoteq.com/2021/05/06/springboot-authentifizierung/" aria-label="Read more about Sichern einer Spring Boot WebApp mit OAuth 2.0​" tabindex="-1" >
			Weiterlesen »		</a>

				</div>
				</article>
				</div>
		
				</div>
				</div>
				<div class="elementor-element elementor-element-cdf4163 elementor-grid-1 elementor-grid-tablet-1 elementor-posts--thumbnail-left elementor-hidden-desktop elementor-hidden-mobile elementor-grid-mobile-1 elementor-widget elementor-widget-posts" data-id="cdf4163" data-element_type="widget" data-settings="{&quot;classic_columns&quot;:&quot;1&quot;,&quot;classic_columns_tablet&quot;:&quot;1&quot;,&quot;classic_columns_mobile&quot;:&quot;1&quot;,&quot;classic_row_gap&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:35,&quot;sizes&quot;:[]},&quot;classic_row_gap_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;classic_row_gap_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}" data-widget_type="posts.classic">
				<div class="elementor-widget-container">
					<div class="elementor-posts-container elementor-posts elementor-posts--skin-classic elementor-grid">
				<article class="elementor-post elementor-grid-item post-1479 post type-post status-publish format-standard has-post-thumbnail hentry category-blog">
				<a class="elementor-post__thumbnail__link" href="https://www.inoteq.com/2021/05/06/springboot-authentifizierung/" tabindex="-1" >
			<div class="elementor-post__thumbnail"><img loading="lazy" decoding="async" width="300" height="209" src="https://www.inoteq.com/wp-content/uploads/2021/04/inoteq-polygon-background-300x209.png" class="attachment-medium size-medium wp-image-1391" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2021/04/inoteq-polygon-background-300x209.png 300w, https://www.inoteq.com/wp-content/uploads/2021/04/inoteq-polygon-background.png 574w" sizes="(max-width: 300px) 100vw, 300px" /></div>
		</a>
				<div class="elementor-post__text">
				<p class="elementor-post__title">
			<a href="https://www.inoteq.com/2021/05/06/springboot-authentifizierung/" >
				Sichern einer Spring Boot WebApp mit OAuth 2.0​			</a>
		</p>
				<div class="elementor-post__meta-data">
					<span class="elementor-post-author">
			Aymen Khalki		</span>
				<span class="elementor-post-date">
			6. Mai 2021		</span>
				</div>
				<div class="elementor-post__excerpt">
			<p>Authentifizierung ist der erste Schritt in jedem Sicherheitssystem. Es ist der Prozess mit dem die Identität eines Clients verifiziert wird. Ob der Client Zugriff auf bestimmte Ressourcen erhält, wird allerdings durch den Autorisierungsprozess festgestellt. In</p>
		</div>
		
		<a class="elementor-post__read-more" href="https://www.inoteq.com/2021/05/06/springboot-authentifizierung/" aria-label="Read more about Sichern einer Spring Boot WebApp mit OAuth 2.0​" tabindex="-1" >
			Weiterlesen »		</a>

				</div>
				</article>
				</div>
		
				</div>
				</div>
				<div class="elementor-element elementor-element-81ae1bc elementor-grid-1 elementor-grid-tablet-1 elementor-hidden-desktop elementor-hidden-tablet elementor-grid-mobile-1 elementor-posts--thumbnail-top elementor-widget elementor-widget-posts" data-id="81ae1bc" data-element_type="widget" data-settings="{&quot;classic_columns&quot;:&quot;1&quot;,&quot;classic_columns_tablet&quot;:&quot;1&quot;,&quot;classic_columns_mobile&quot;:&quot;1&quot;,&quot;classic_row_gap&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:35,&quot;sizes&quot;:[]},&quot;classic_row_gap_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;classic_row_gap_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}" data-widget_type="posts.classic">
				<div class="elementor-widget-container">
					<div class="elementor-posts-container elementor-posts elementor-posts--skin-classic elementor-grid">
				<article class="elementor-post elementor-grid-item post-1479 post type-post status-publish format-standard has-post-thumbnail hentry category-blog">
				<a class="elementor-post__thumbnail__link" href="https://www.inoteq.com/2021/05/06/springboot-authentifizierung/" tabindex="-1" >
			<div class="elementor-post__thumbnail"><img loading="lazy" decoding="async" width="300" height="209" src="https://www.inoteq.com/wp-content/uploads/2021/04/inoteq-polygon-background-300x209.png" class="attachment-medium size-medium wp-image-1391" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2021/04/inoteq-polygon-background-300x209.png 300w, https://www.inoteq.com/wp-content/uploads/2021/04/inoteq-polygon-background.png 574w" sizes="(max-width: 300px) 100vw, 300px" /></div>
		</a>
				<div class="elementor-post__text">
				<p class="elementor-post__title">
			<a href="https://www.inoteq.com/2021/05/06/springboot-authentifizierung/" >
				Sichern einer Spring Boot WebApp mit OAuth 2.0​			</a>
		</p>
				<div class="elementor-post__meta-data">
					<span class="elementor-post-author">
			Aymen Khalki		</span>
				<span class="elementor-post-date">
			6. Mai 2021		</span>
				</div>
				<div class="elementor-post__excerpt">
			<p>Authentifizierung ist der erste Schritt in jedem Sicherheitssystem. Es ist der Prozess mit dem die Identität eines Clients verifiziert wird. Ob der Client Zugriff auf bestimmte Ressourcen erhält, wird allerdings durch den Autorisierungsprozess festgestellt. In diesem Artikel werden wir eine API mit Spring Boot erstellen und das OAuth 2.0 Authentifizierungsprotokoll verwenden, um diese API abzusichern. Table of Contents Eingehende Erläuterungen und Definitionen OAuth 2.0 OAuth 2.0 (Open Authentication) ist ein von der IETF entwickeltes Standardprotokoll, das die Authentifizierung und Autorisierung von</p>
		</div>
		
		<a class="elementor-post__read-more" href="https://www.inoteq.com/2021/05/06/springboot-authentifizierung/" aria-label="Read more about Sichern einer Spring Boot WebApp mit OAuth 2.0​" tabindex="-1" >
			Weiterlesen »		</a>

				</div>
				</article>
				</div>
		
				</div>
				</div>
				<div class="elementor-element elementor-element-34f4387 elementor-widget elementor-widget-spacer" data-id="34f4387" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				</div>
		<p>Der Beitrag <a href="https://www.inoteq.com/2023/11/30/oauth2-keycloak-locally/">Integration von OAuth 2.0 in Spring Boot mit Keycloak</a> erschien zuerst auf <a href="https://www.inoteq.com">INOTEQ GmbH</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.inoteq.com/2023/11/30/oauth2-keycloak-locally/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Skalierbare und moderne Web-Frontends mit Angular</title>
		<link>https://www.inoteq.com/2021/06/18/skalierbare-angular-frontends/</link>
					<comments>https://www.inoteq.com/2021/06/18/skalierbare-angular-frontends/#respond</comments>
		
		<dc:creator><![CDATA[Steffen Seeger]]></dc:creator>
		<pubDate>Fri, 18 Jun 2021 08:21:10 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[TechStack]]></category>
		<category><![CDATA[Tech-Stack]]></category>
		<guid isPermaLink="false">https://www.inoteq.com/?p=1611</guid>

					<description><![CDATA[<p>Nachdem wir für unsere Anwendung das Backend implementiert haben, widmet sich dieser Artikel der Erstellung eines Frontends. Hierzu verwenden wir das Framework Angular und erstellen eine Single-Page Application &#8211; SPA. Eine Single-Page Application wird wie eine klassische Website von einem Server ausgeliefert. Dabei wird jedoch nicht nur eine Seite ausgeliefert, sondern die komplette Anwendung, welche [&#8230;]</p>
<p>Der Beitrag <a href="https://www.inoteq.com/2021/06/18/skalierbare-angular-frontends/">Skalierbare und moderne Web-Frontends mit Angular</a> erschien zuerst auf <a href="https://www.inoteq.com">INOTEQ GmbH</a>.</p>
]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="1611" class="elementor elementor-1611" data-elementor-post-type="post">
						<section class="elementor-section elementor-top-section elementor-element elementor-element-3f56aa0 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="3f56aa0" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-3656221" data-id="3656221" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-5141813 elementor-widget elementor-widget-spacer" data-id="5141813" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-ed801e5 elementor-widget elementor-widget-theme-post-title elementor-page-title elementor-widget-heading" data-id="ed801e5" data-element_type="widget" data-widget_type="theme-post-title.default">
				<div class="elementor-widget-container">
			<h1 class="elementor-heading-title elementor-size-default">Skalierbare und moderne Web-Frontends mit Angular</h1>		</div>
				</div>
				<div class="elementor-element elementor-element-d920c18 elementor-widget elementor-widget-post-info" data-id="d920c18" data-element_type="widget" data-widget_type="post-info.default">
				<div class="elementor-widget-container">
					<ul class="elementor-inline-items elementor-icon-list-items elementor-post-info">
								<li class="elementor-icon-list-item elementor-repeater-item-3dcdd3d elementor-inline-item" itemprop="datePublished">
						<a href="https://www.inoteq.com/2021/06/18/">
											<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="fas fa-calendar"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-date">
										Juni 18, 2021					</span>
									</a>
				</li>
				<li class="elementor-icon-list-item elementor-repeater-item-09a1e4d elementor-inline-item" itemprop="author">
						<a href="https://www.inoteq.com/author/sdumjahn/">
											<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="far fa-user-circle"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-author">
										Steffen Seeger					</span>
									</a>
				</li>
				<li class="elementor-icon-list-item elementor-repeater-item-fee817f elementor-inline-item" itemprop="about">
										<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="fas fa-tags"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-terms">
										<span class="elementor-post-info__terms-list">
				<a href="https://www.inoteq.com/tag/tech-stack/" class="elementor-post-info__terms-list-item">Tech-Stack</a>				</span>
					</span>
								</li>
				</ul>
				</div>
				</div>
				<div class="elementor-element elementor-element-b3d67b9 elementor-widget elementor-widget-html" data-id="b3d67b9" data-element_type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
			<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/themes/prism-coy.min.css" integrity="sha256-VcuSs+n31yebPlEcehu6PvnidJ808ScFBsK8+tJKX+Q=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/components/prism-core.min.js"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/plugins/autoloader/prism-autoloader.min.js"></script>
<!-- Only for Code Snippet Styles -->		</div>
				</div>
				<div class="elementor-element elementor-element-5566856 elementor-widget elementor-widget-text-editor" data-id="5566856" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Nachdem wir für unsere Anwendung das Backend implementiert haben, widmet sich dieser Artikel der Erstellung eines Frontends. Hierzu verwenden wir das Framework <b>Angular</b> und erstellen eine <b>S</b>ingle-<b>P</b>age <b>A</b>pplication &#8211; SPA.</p><p>Eine Single-Page Application wird wie eine klassische Website von einem Server ausgeliefert. Dabei wird jedoch nicht nur eine Seite ausgeliefert, sondern die komplette Anwendung, welche meist aus viel JavaScript-Logik besteht. Nach dem Laden läuft die Anwendung anschließend vollständig im Browser des Anwenders. Die von der Anwendung benötigten Daten werden anschließend von einer REST-API geladen und dargestellt. Die Erstellung so einer API haben wir uns mit <a href="https://www.inoteq.com/2020/05/27/backend-mit-azure-cloud/">Azure</a> und <a href="https://www.inoteq.com/2020/06/01/backend-mit-aws/">AWS</a> bereits angeschaut.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-d06cbb7 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="d06cbb7" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-6709856" data-id="6709856" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-8bfeda7 elementor-widget elementor-widget-heading" data-id="8bfeda7" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Aufsetzen der Entwicklungsumgebung</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-a095755 elementor-widget elementor-widget-text-editor" data-id="a095755" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Angular ist ein Framework, welches selber auf Node.js aufsetzt. Aus diesem Grund müssen wir zuerst Node.js installieren. In diesem Beispiel installieren wie Node.js über Brew auf einem Mac. Über die <a href="https://nodejs.org/en/download/">offizielle WebSite</a> stehen auch für andere Betriebssysteme Installationsdateien zur Verfügung.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-5ac5c66 elementor-widget elementor-widget-text-editor" data-id="5ac5c66" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<pre><code class="language-bash">&gt; brew install node
&gt; npm install -g @angular/cli
&gt; ng version
     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/
     
 
Angular CLI: 9.1.0
Node: 12.16.1
OS: win32 x64
</code></pre>						</div>
				</div>
				<div class="elementor-element elementor-element-4e5f299 elementor-widget elementor-widget-text-editor" data-id="4e5f299" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Nachdem wir nun Angular installiert haben, können wir unser Projekt anlegen. Dazu benutzen wir ein Befehl von Angular, welcher uns ein funktionsfähiges leeres Projekt erstellt.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-12b7043 elementor-widget elementor-widget-text-editor" data-id="12b7043" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<pre><code class="language-bash">&gt; ng new todo-app
? Would you like to add Angular routing? Yes
? Which stylesheet format would you like to use? CSS
...
</code></pre>						</div>
				</div>
				<div class="elementor-element elementor-element-d226168 elementor-widget elementor-widget-text-editor" data-id="d226168" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Wichtig ist hier, dass die Frage nach <i><b>Angular routing</b></i> mit <b><i>Yes</i></b> beantwortet wird, da die App später den Anwender auf verschiedene Seiten leiten wird. Durch diese Option wird das Projekt für die Verwendung dieses Features bereits vorbereitet. Die Auswahl nach dem CSS-Format kann nach persönlichen Vorlieben entschieden werden.</p><p>Anschließend erhalten wir folgende Projektstruktur:</p>						</div>
				</div>
				<div class="elementor-element elementor-element-4b2f525 elementor-widget elementor-widget-text-editor" data-id="4b2f525" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<pre><code class="language-bash">todo-app/                               # App-Verzeichnis
├── e2e/                                # Hier werden End-to-End-Tests implementiert
├── node_modules/                       # Beinhaltet alle installierten Node.js-Module für das Projekt
├── src/                                # Beinhaltet die Implementierung der App
│   ├── app/                            # In diesem Ordner werden die Komponente, Services, etc, abgelegt
│   │   ├── app-routin.module.ts        # Konfiguration der Navigationsrouten innerhalb der App (welche Komponente ist für welche URL zuständig)
│   │   ├── app.component.css           # CSS-Styles, welche ausschließlich für die aktuelle Komponente gültig sind
│   │   ├── app.component.html          # HTML-Template-Code, welche beim Ausführen der Komponente angezeigt wird
│   │   ├── app.component.spec.ts       # Unit-Tests für die Komponente
│   │   ├── app.component.ts            # "Code-Behind"-Datei, welche die Business-Logik der Komponente beinhaltet
│   │   └── app.module.ts               # Root-Konfigurations-Datei der App, in welcher alle verwendeten Node.js-Module, App-Komponente, etc. registriert werden
│   ├── assets/                         # Beinhaltet Dateien wie Bilder
│   ├── environments/
│   │   ├── environment.prod.ts         # Konfigurationsdatei für den produktiven Betrieb
│   │   └── environment.ts              # Konfigurationsdatei für das Entwickeln
│   ├── ...
│   ├── index.html                      # Root-Datei, welche Aufgerufen wird, wenn der Anwender die SAP aufruft
│   ├── main.ts                         # Einstiegspunkt für die App (Muss in der Regel nicht geändert werden)
│   └── styles.css                      # Datei für globale CSS-Regeln, welche für die gesamte App gelten
├── ...
├── angular.json                        # Konfiguration des Projektes, welche u.a. z.B. die Build-Konfigurationen beinhaltet
└── package.json                        # Konfigurationsdatei, welche angibt, welche Node.js-Module in welcher Version verwendetet werden
</code></pre>						</div>
				</div>
				<div class="elementor-element elementor-element-983d879 elementor-widget elementor-widget-text-editor" data-id="983d879" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Zu guter letzt installieren wir noch ein paar weitere Packete, welche wir im Verlauf der Implementierung verwenden werden &#8230;</p>						</div>
				</div>
				<div class="elementor-element elementor-element-5a1e2f1 elementor-widget elementor-widget-text-editor" data-id="5a1e2f1" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<pre><code class="language-bash">&gt; npm install --save bootstrap jquery popper.js
</code></pre>						</div>
				</div>
				<div class="elementor-element elementor-element-64f473a elementor-widget elementor-widget-text-editor" data-id="64f473a" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>&#8230; und referenzieren anschließend  noch die entsprechenden CSS-Dateien.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-766c372 elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="766c372" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-1241" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1241" aria-expanded="false">/angular.json</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1241" aria-expanded="false">/angular.json</div>
					<div id="elementor-tab-content-1241" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-1241" tabindex="0" hidden="false"><pre><code class="language-json">{
  "projects": {
    "todo-app": {
      "architect": {
        "build": {
          "options": {
            "styles": [
              "src/styles.css",
              "node_modules/bootstrap/dist/css/bootstrap.min.css"
            ],
            "scripts": [
              "node_modules/jquery/dist/jquery.min.js",
              "node_modules/popper.js/dist/umd/popper.min.js",
              "node_modules/bootstrap/dist/js/bootstrap.min.js"
            ]
          }
        }
      }
    }
  }
}
</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-f7c4940 elementor-widget elementor-widget-text-editor" data-id="f7c4940" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Nun können wir das Projekt starten und im WebBrowser die generierte Start-Seite sehen. Das leicht defekte Design liegt an der Einbindung von Bootstrap und kann ignoriert werden, da wir die Seite im nächsten Schritt ersetzen werden.</p>						</div>
				</div>
				<section class="elementor-section elementor-inner-section elementor-element elementor-element-a2b1bec elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="a2b1bec" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-8538e2e" data-id="8538e2e" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-93ebd72 elementor-widget elementor-widget-text-editor" data-id="93ebd72" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<pre><code class="language-bash">&gt; ng serve --open
</code></pre>						</div>
				</div>
					</div>
		</div>
				<div class="elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-48850cd" data-id="48850cd" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-bf43f70 elementor-widget elementor-widget-image" data-id="bf43f70" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
													<img loading="lazy" decoding="async" width="425" height="277" src="https://www.inoteq.com/wp-content/uploads/2021/06/image2020-4-15_10-28-54.png" class="attachment-large size-large wp-image-1636" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2021/06/image2020-4-15_10-28-54.png 425w, https://www.inoteq.com/wp-content/uploads/2021/06/image2020-4-15_10-28-54-300x196.png 300w" sizes="(max-width: 425px) 100vw, 425px" />													</div>
				</div>
					</div>
		</div>
					</div>
		</section>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-dd9fa64 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="dd9fa64" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-5fd8300" data-id="5fd8300" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-1c27df3 elementor-widget elementor-widget-heading" data-id="1c27df3" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Anzeige einer Liste von Tasks</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-1791209 elementor-widget elementor-widget-text-editor" data-id="1791209" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Als erstes implementieren wir die Start-Seite unser Anwendung. Diese soll eine Liste aller vorhandenen TODO-Aufgaben anzeigen. Dabei können die benötigten Dateien manuell per Hand angelegt werden oder wir nutzen Angular und lassen uns die Dateien generieren.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-f5d71c6 elementor-widget elementor-widget-text-editor" data-id="f5d71c6" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<pre><code class="language-bash">&gt; ng generate component task-list
 
CREATE src/app/task-list/task-list.component.html (24 bytes)
CREATE src/app/task-list/task-list.component.spec.ts (643 bytes)
CREATE src/app/task-list/task-list.component.ts (286 bytes)
CREATE src/app/task-list/task-list.component.css (0 bytes)
UPDATE src/app/app.module.ts (485 bytes)
</code></pre>						</div>
				</div>
				<div class="elementor-element elementor-element-d250420 elementor-widget elementor-widget-text-editor" data-id="d250420" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die generierten Dateien haben dabei folgenden Nutzen:</p><ul><li><b>task-list.component.html</b>: Hier wird der HTML-Code, also die Anzeige der Liste implementiert.</li><li><b>task-list.component.ts</b>: Hier wird die Logik zum Laden der Tasks implementiert, damit diese anschließend zur Anzeige zur Verfügung stehen.</li><li><b>task-list.component.spec.ts</b>: Hier können Unit-Tests implementiert werden, welche die Korrektheit der Logik prüft.</li><li><b>task-list.component.css</b>: Hier können Komponenten-spezifische Style-Regeln hinterlegt werden, welche nur für diese Komponente gelten.</li></ul>						</div>
				</div>
				<div class="elementor-element elementor-element-9709703 elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="9709703" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-1581" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1581" aria-expanded="false">/src/app/task-list/task-list.component.html</div>
									<div id="elementor-tab-title-1582" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="false" data-tab="2" role="tab" tabindex="-1" aria-controls="elementor-tab-content-1582" aria-expanded="false">/src/app/task-list/task-list.component.ts</div>
									<div id="elementor-tab-title-1583" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="false" data-tab="3" role="tab" tabindex="-1" aria-controls="elementor-tab-content-1583" aria-expanded="false">/src/app/app.module.ts</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-1581" aria-expanded="false">/src/app/task-list/task-list.component.html</div>
					<div id="elementor-tab-content-1581" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-1581" tabindex="0" hidden="false"><pre><code class="language-html">&lt;ul class="list-group"&gt;
    &lt;li class="list-group-item text-nowrap" *ngFor="let task of tasks"&gt;
        &lt;a [title]="'Details für ' + task.name"&gt;
            &lt;strong&gt;{{ task.name }}&lt;/strong&gt;
        &lt;/a&gt;
          
        &lt;span *ngIf="task.priority === 1" class="badge badge-danger"&gt;High&lt;/span&gt;
        &lt;span *ngIf="task.priority === 2" class="badge badge-info"&gt;Middle&lt;/span&gt;
        &lt;span *ngIf="task.priority === 3" class="badge badge-light"&gt;Low&lt;/span&gt;
    &lt;/li&gt;
&lt;/ul&gt;
</code></pre></div>
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="false" data-tab="2" role="tab" tabindex="-1" aria-controls="elementor-tab-content-1582" aria-expanded="false">/src/app/task-list/task-list.component.ts</div>
					<div id="elementor-tab-content-1582" class="elementor-tab-content elementor-clearfix" data-tab="2" role="tabpanel" aria-labelledby="elementor-tab-title-1582" tabindex="0" hidden="hidden"><pre><code class="language-js">import { Component, OnInit } from '@angular/core';
 
import { TaskService } from '../task.service';
 
@Component({
  selector: 'app-task-list',
  templateUrl: './task-list.component.html',
  styleUrls: ['./task-list.component.css']
})
export class TaskListComponent implements OnInit {
  tasks;
 
  constructor(private taskService: TaskService) { }
 
  ngOnInit(): void {
    this.taskService.getTasks()
      .subscribe(tasks => (this.tasks = tasks));
  }
}
</code></pre></div>
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="false" data-tab="3" role="tab" tabindex="-1" aria-controls="elementor-tab-content-1583" aria-expanded="false">/src/app/app.module.ts</div>
					<div id="elementor-tab-content-1583" class="elementor-tab-content elementor-clearfix" data-tab="3" role="tabpanel" aria-labelledby="elementor-tab-title-1583" tabindex="0" hidden="hidden"><pre><code class="language-js">// ...
 
import { RouterModule } from '@angular/router';
 
// ...
 
@NgModule({
  // ...
  imports: [
 
    // ...   
 
    RouterModule.forRoot([
      { path: '', component: TaskListComponent }
    ])
  ],
  // ... 
})
// ...
</code></pre></div>
							</div>
		</div>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-1f18cd1 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="1f18cd1" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-8dbc763" data-id="8dbc763" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-c0e940a elementor-widget elementor-widget-heading" data-id="c0e940a" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Implementierung der Kommunikation mit REST-API</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-1ef27e1 elementor-widget elementor-widget-text-editor" data-id="1ef27e1" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Durch durch die Art und Weise, dass die SPA im Browser des Anwenders ausgeführt wird, kann sie nicht direkt auf die Datenbank zugreifen. Aus diesem Grund wird eine SPA fast immer in Verbindung mit einer REST-API verwendet, welche einen kontrollierten Zugriff auf die Daten bereitstellt.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-3566e34 elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="3566e34" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-5591" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-5591" aria-expanded="false">/src/app/task.service.ts</div>
									<div id="elementor-tab-title-5592" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="false" data-tab="2" role="tab" tabindex="-1" aria-controls="elementor-tab-content-5592" aria-expanded="false">/src/app/app.module.ts</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-5591" aria-expanded="false">/src/app/task.service.ts</div>
					<div id="elementor-tab-content-5591" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-5591" tabindex="0" hidden="false"><pre><code class="language-js">import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
 
import { Observable } from 'rxjs';
 
import { Task } from './task';
 
@Injectable({
  providedIn: 'root'
})
export class TaskService {
 
  baseUrl = 'https://exmaple.com/api';  // URL to web api
 
  constructor(
    private http: HttpClient) {}
 
  /** GET tasks from the server */
  getTasks (): Observable<Task[]> {
    return this.http.get<Task[]>(`${this.baseUrl}/task`);
  }
 
}</code></pre></div>
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="false" data-tab="2" role="tab" tabindex="-1" aria-controls="elementor-tab-content-5592" aria-expanded="false">/src/app/app.module.ts</div>
					<div id="elementor-tab-content-5592" class="elementor-tab-content elementor-clearfix" data-tab="2" role="tabpanel" aria-labelledby="elementor-tab-title-5592" tabindex="0" hidden="hidden"><pre><code class="language-js">// ...
import { HttpClientModule } from '@angular/common/http';
 
// ...
 
@NgModule({
  // ...
  imports: [
    // ...   
    BrowserModule,
    AppRoutingModule,
    ReactiveFormsModule,
    FormsModule,
    HttpClientModule,
    // ...   
  ],
  // ... 
})
// ...
</code></pre></div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-5e30383 elementor-widget elementor-widget-text-editor" data-id="5e30383" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die Implementiert der zugehörige API kann in den anderen beiden Artikeln nachgelesen werden, wo diese einmal mit <a href="https://www.inoteq.com/2020/06/01/backend-mit-aws/">Azure Web Service</a> und einmal mit <a href="https://www.inoteq.com/2020/05/27/backend-mit-azure-cloud/">Amazon AWS</a> implementiert wurde.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-0bf0220 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="0bf0220" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-f9a3b87" data-id="f9a3b87" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-d27f504 elementor-widget elementor-widget-heading" data-id="d27f504" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Deployment der SPA als Azure App-Service</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-f8dc2dc elementor-widget elementor-widget-text-editor" data-id="f8dc2dc" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Auch für das Bauen einer veröffentlichbaren App bringt Angular fertige Befehle mit. Dieser kompiliert und komprimiert den Code, sodass beim späteren deployen nur wenige kleine Dateien hochgeladen werden müssen. Dies hat zusätzlich den Vorteil, dass die Anwendung beim Anwender schneller lädt, da der Browser ebenfalls nur wenige kleine Dateien herunterladen muss um die Anwendung zu starten.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-88eaa2a elementor-widget elementor-widget-text-editor" data-id="88eaa2a" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<pre><code class="language-bash">&gt; ng build --prod
 
Generating ES5 bundles for differential loading...
ES5 bundle generation complete.
 
chunk {0} runtime-es2015.1eba213af0b233498d9d.js (runtime) 1.45 kB [entry] [rendered]
chunk {0} runtime-es5.1eba213af0b233498d9d.js (runtime) 1.45 kB [entry] [rendered]
chunk {2} polyfills-es2015.690002c25ea8557bb4b0.js (polyfills) 36.1 kB [initial] [rendered]
chunk {3} polyfills-es5.9e286f6d9247438cbb02.js (polyfills-es5) 129 kB [initial] [rendered]
chunk {1} main-es2015.af5b6cb4ca52ef1efbf6.js (main) 376 kB [initial] [rendered]
chunk {1} main-es5.af5b6cb4ca52ef1efbf6.js (main) 456 kB [initial] [rendered]
chunk {4} styles.66057ddcee1a0c134465.css (styles) 146 kB [initial] [rendered]
chunk {scripts} scripts.4f7d6bdd9aa2a2ef7f2f.js (scripts) 165 kB [entry] [rendered]
Date: 2020-04-16T13:22:11.289Z - Hash: c755857ecfed044fd8c0 - Time: 43419ms
</code></pre>						</div>
				</div>
				<div class="elementor-element elementor-element-6028975 elementor-widget elementor-widget-text-editor" data-id="6028975" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Als nächstes können wir die App nach Azure deployen. Sofern <a style="background-color: #ffffff;" href="https://code.visualstudio.com/">Visual Studio Code</a> verwendet wird, geschieht dies über das Azure Plugin recht einfach. Dazu auf dem entsprechenden AppService mit der rechten Maus klicken und <b><i>Deploy to Web App&#8230;</i></b> auswählen.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-596146b elementor-widget elementor-widget-image" data-id="596146b" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
													<img loading="lazy" decoding="async" width="421" height="582" src="https://www.inoteq.com/wp-content/uploads/2021/06/image2020-5-13_14-47-44.png" class="attachment-large size-large wp-image-1648" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2021/06/image2020-5-13_14-47-44.png 421w, https://www.inoteq.com/wp-content/uploads/2021/06/image2020-5-13_14-47-44-217x300.png 217w" sizes="(max-width: 421px) 100vw, 421px" />													</div>
				</div>
				<div class="elementor-element elementor-element-4e3db84 elementor-widget elementor-widget-image" data-id="4e3db84" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
													<img loading="lazy" decoding="async" width="608" height="99" src="https://www.inoteq.com/wp-content/uploads/2021/06/image2020-5-13_14-49-6.png" class="attachment-large size-large wp-image-1649" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2021/06/image2020-5-13_14-49-6.png 608w, https://www.inoteq.com/wp-content/uploads/2021/06/image2020-5-13_14-49-6-300x49.png 300w" sizes="(max-width: 608px) 100vw, 608px" />													</div>
				</div>
				<div class="elementor-element elementor-element-f51f031 elementor-widget elementor-widget-text-editor" data-id="f51f031" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>In dem nun erscheinenden Dialog navigieren wir zu dem <b><i>dist</i></b>-Ordner in unserem Projekt und laden diesen hoch.</p><p>Die Anwendung kann nun über die URL der Azure Wep App aufgerufen werden.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-a4fa29f elementor-widget elementor-widget-image" data-id="a4fa29f" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img loading="lazy" decoding="async" width="519" height="400" src="https://www.inoteq.com/wp-content/uploads/2021/06/image2020-4-15_15-17-36.jpg" class="attachment-large size-large wp-image-1671" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2021/06/image2020-4-15_15-17-36.jpg 519w, https://www.inoteq.com/wp-content/uploads/2021/06/image2020-4-15_15-17-36-300x231.jpg 300w" sizes="(max-width: 519px) 100vw, 519px" />											<figcaption class="widget-image-caption wp-caption-text">Anzeige der Aufgaben in einer ToDo Liste</figcaption>
										</figure>
							</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-b185f98 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="b185f98" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-c9c18c0" data-id="c9c18c0" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
							</div>
		</div>
					</div>
		</section>
				</div>
		<p>Der Beitrag <a href="https://www.inoteq.com/2021/06/18/skalierbare-angular-frontends/">Skalierbare und moderne Web-Frontends mit Angular</a> erschien zuerst auf <a href="https://www.inoteq.com">INOTEQ GmbH</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.inoteq.com/2021/06/18/skalierbare-angular-frontends/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Eventarchitektur für Microservices mit dem Saga Pattern</title>
		<link>https://www.inoteq.com/2021/05/18/event-driven-architecture-saga-pattern/</link>
					<comments>https://www.inoteq.com/2021/05/18/event-driven-architecture-saga-pattern/#respond</comments>
		
		<dc:creator><![CDATA[Aymen Khalki]]></dc:creator>
		<pubDate>Tue, 18 May 2021 14:36:43 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<guid isPermaLink="false">https://www.inoteq.com/?p=1527</guid>

					<description><![CDATA[<p>Table of Contents Was sind Microservices? Microservices sind heutzutage eine sehr populäre Architektur für Software, bei der die Anwendung in kleinere Komponenten (Services) unterteilt wird. Jeder Service soll dabei eine bestimmte Aufgabe erledigen und kommuniziert mit den anderen Services über Schnittstellen. Microservices bringen viele Vorteile. Aufgrund des Designs der Architektur (leicht gekoppelte Komponenten), können die [&#8230;]</p>
<p>Der Beitrag <a href="https://www.inoteq.com/2021/05/18/event-driven-architecture-saga-pattern/">Eventarchitektur für Microservices mit dem Saga Pattern</a> erschien zuerst auf <a href="https://www.inoteq.com">INOTEQ GmbH</a>.</p>
]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="1527" class="elementor elementor-1527" data-elementor-post-type="post">
						<section class="elementor-section elementor-top-section elementor-element elementor-element-a718b23 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="a718b23" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-c11ee92" data-id="c11ee92" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-3fc28fc elementor-widget elementor-widget-spacer" data-id="3fc28fc" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-eebc1b5 elementor-widget elementor-widget-theme-post-title elementor-page-title elementor-widget-heading" data-id="eebc1b5" data-element_type="widget" data-widget_type="theme-post-title.default">
				<div class="elementor-widget-container">
			<h1 class="elementor-heading-title elementor-size-default">Eventarchitektur für Microservices mit dem Saga Pattern</h1>		</div>
				</div>
				<div class="elementor-element elementor-element-5a7ce88 elementor-widget elementor-widget-post-info" data-id="5a7ce88" data-element_type="widget" data-widget_type="post-info.default">
				<div class="elementor-widget-container">
					<ul class="elementor-inline-items elementor-icon-list-items elementor-post-info">
								<li class="elementor-icon-list-item elementor-repeater-item-4896e09 elementor-inline-item" itemprop="datePublished">
						<a href="https://www.inoteq.com/2021/05/18/">
											<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="fas fa-calendar"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-date">
										Mai 18, 2021					</span>
									</a>
				</li>
				<li class="elementor-icon-list-item elementor-repeater-item-5ef2576 elementor-inline-item" itemprop="author">
						<a href="https://www.inoteq.com/author/akhalki/">
											<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="far fa-user-circle"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-author">
										Aymen Khalki					</span>
									</a>
				</li>
				</ul>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-ec5a8fc elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="ec5a8fc" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-2f6c43d" data-id="2f6c43d" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-21a11a9 elementor-toc--minimized-on-tablet elementor-widget elementor-widget-table-of-contents" data-id="21a11a9" data-element_type="widget" data-settings="{&quot;exclude_headings_by_selector&quot;:[],&quot;headings_by_tags&quot;:[&quot;h2&quot;,&quot;h3&quot;,&quot;h4&quot;,&quot;h5&quot;,&quot;h6&quot;],&quot;marker_view&quot;:&quot;numbers&quot;,&quot;minimize_box&quot;:&quot;yes&quot;,&quot;minimized_on&quot;:&quot;tablet&quot;,&quot;hierarchical_view&quot;:&quot;yes&quot;,&quot;min_height&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;min_height_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;min_height_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}" data-widget_type="table-of-contents.default">
				<div class="elementor-widget-container">
					<div class="elementor-toc__header">
			<h4 class="elementor-toc__header-title">
				Table of Contents			</h4>
							<div class="elementor-toc__toggle-button elementor-toc__toggle-button--expand" role="button" tabindex="0" aria-controls="elementor-toc__21a11a9" aria-expanded="true" aria-label="Open table of contents"><i aria-hidden="true" class="fas fa-chevron-down"></i></div>
				<div class="elementor-toc__toggle-button elementor-toc__toggle-button--collapse" role="button" tabindex="0" aria-controls="elementor-toc__21a11a9" aria-expanded="true" aria-label="Close table of contents"><i aria-hidden="true" class="fas fa-chevron-up"></i></div>
					</div>
		<div id="elementor-toc__21a11a9" class="elementor-toc__body">
			<div class="elementor-toc__spinner-container">
				<i class="elementor-toc__spinner eicon-animation-spin eicon-loading" aria-hidden="true"></i>			</div>
		</div>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-d025abc elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="d025abc" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-a98741b" data-id="a98741b" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-6480dd6 elementor-widget elementor-widget-heading" data-id="6480dd6" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Was sind Microservices?</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-e7fae96 elementor-widget elementor-widget-text-editor" data-id="e7fae96" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Microservices sind heutzutage eine sehr populäre Architektur für Software, bei der die Anwendung in kleinere Komponenten (Services) unterteilt wird. Jeder Service soll dabei eine bestimmte Aufgabe erledigen und kommuniziert mit den anderen Services über Schnittstellen. Microservices bringen viele Vorteile. Aufgrund des Designs der Architektur (leicht gekoppelte Komponenten), können die einzelnen Services separat gewartet, getestet und deployed werden. Das bedeutet, dass wir Services ersetzen können, ohne die Prozesse der Anwendung zu beeinträchtigen. Der Preis dafür ist eine hohe Komplexität in der Kommunikation zwischen den Services und der Definition ihrer Schnittstellen. In diesem Artikel werden wir zwei Patterns vorstellen, die in der Microservice Architektur oft eingesetzt werden, um diese Komplexität zu reduzieren und eine konsistente funktionsfähige Infrastruktur zu erhalten.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-a887025 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="a887025" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-6ef8de8" data-id="6ef8de8" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-d3ef874 elementor-widget elementor-widget-heading" data-id="d3ef874" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Motivation für SAGA</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-223307c elementor-widget elementor-widget-heading" data-id="223307c" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h4 class="elementor-heading-title elementor-size-default">ACID</h4>		</div>
				</div>
				<div class="elementor-element elementor-element-fb07761 elementor-widget elementor-widget-text-editor" data-id="fb07761" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Die &#8222;<strong>ACID-</strong>ity&#8220; einer Transaktion beschreibt vier Eigenschaften der Transaktion, die die Validität und Konsistenz der Daten in einer Datenbank garantieren:</p><ul><li><strong>A</strong>tomicity: Eine Transaktion kann entweder komplett fehlschlagen oder komplett erfolgen</li><li><strong>C</strong>onsistency: Alle Integritätsprüfungen sind vor dem Abschluss der Transaktion überprüft</li><li><strong>I</strong>solation:  Transaktion die nebenläufig ausgeführt werden dürfen sich nicht gegenseitig beeinflussen</li><li><strong>D</strong>urability: Die Auswirkungen einer erfolgreich ausgeführten Transaktion persistieren.</li></ul>						</div>
				</div>
				<div class="elementor-element elementor-element-e7fdbd0 elementor-widget elementor-widget-heading" data-id="e7fdbd0" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h4 class="elementor-heading-title elementor-size-default">Local Transaction</h4>		</div>
				</div>
				<div class="elementor-element elementor-element-0cf0adc elementor-widget elementor-widget-image" data-id="0cf0adc" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img loading="lazy" decoding="async" width="343" height="333" src="https://www.inoteq.com/wp-content/uploads/2021/05/monolithic_transaction.png" class="attachment-large size-large wp-image-1530" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2021/05/monolithic_transaction.png 343w, https://www.inoteq.com/wp-content/uploads/2021/05/monolithic_transaction-300x291.png 300w" sizes="(max-width: 343px) 100vw, 343px" />											<figcaption class="widget-image-caption wp-caption-text">locale Transaktion</figcaption>
										</figure>
							</div>
				</div>
				<div class="elementor-element elementor-element-66787a6 elementor-widget elementor-widget-text-editor" data-id="66787a6" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Das obige Bild beschreibt eine Transaktion in einem monolithischen System. Wenn ein beliebiger Schritt fehlschlägt, wird die ganze Transaktion rückgängig gemacht. Alle Änderungen bisheriger Schritte werden abgebrochen und damit die ACID-ity der Transaktion garantiert.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-141991d elementor-widget elementor-widget-heading" data-id="141991d" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h4 class="elementor-heading-title elementor-size-default">Distributed Transaction</h4>		</div>
				</div>
				<div class="elementor-element elementor-element-625f503 elementor-widget elementor-widget-image" data-id="625f503" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
													<img loading="lazy" decoding="async" width="524" height="260" src="https://www.inoteq.com/wp-content/uploads/2021/05/distributed_transaction.png" class="attachment-large size-large wp-image-1529" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2021/05/distributed_transaction.png 524w, https://www.inoteq.com/wp-content/uploads/2021/05/distributed_transaction-300x149.png 300w" sizes="(max-width: 524px) 100vw, 524px" />													</div>
				</div>
				<div class="elementor-element elementor-element-72f0e7c elementor-widget elementor-widget-text-editor" data-id="72f0e7c" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>In einer Microservices Architektur soll jeder Service seine eigene Datenbank haben und darf nur mit dieser Datenbank kommunizieren. Was passiert wenn Transaktionen mehrere Services überbrücken?</p><p>Das obige Bild stellt einen PlaceOrder Transaktion bzw. Prozess dar, die den CustomerService und den OrderService einbezieht.</p><ol><li>Der Benutzer gibt eine neue Bestellung auf</li><li>Der <em>Conductor</em> weiß, dass sowohl die CustomerTable als auch die OrderTable aktualisiert werden müssen und beauftragt dafür die Customer- und Order-Service.</li><li>Wenn beide Services mit der Transaktion durch sind, sendet der Conductor eine OK Antwort zurück.</li></ol><div> </div><p>Soweit so gut. Allerdings müssen wir das Szenario betrachten, bei dem der CustomerService seine Datenbank aktualisiert hat und aus irgendeinem Grund der OrderService fehlschlägt. Wir kommen in einen invaliden Zustand, da die Transaktion nicht atomar ist. Welchen Zustand soll zurückgegeben werden, wenn während eine Transaktion, die ein Objekt ändert, eine Anfrage zum Lesen des Objekts ankommt? Im nächsten Abschnitt stellen wir zwei Alternativen dar, um dieses Problem zu bewältigen. </p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-1cdbc69 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="1cdbc69" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-41d623b" data-id="41d623b" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-c860abb elementor-widget elementor-widget-heading" data-id="c860abb" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Lösungen</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-3f06d53 elementor-widget elementor-widget-heading" data-id="3f06d53" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h4 class="elementor-heading-title elementor-size-default">2pc</h4>		</div>
				</div>
				<div class="elementor-element elementor-element-d18d3b2 elementor-widget elementor-widget-image" data-id="d18d3b2" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img loading="lazy" decoding="async" width="432" height="433" src="https://www.inoteq.com/wp-content/uploads/2021/05/2pc_transaction.png" class="attachment-large size-large wp-image-1534" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2021/05/2pc_transaction.png 432w, https://www.inoteq.com/wp-content/uploads/2021/05/2pc_transaction-300x300.png 300w, https://www.inoteq.com/wp-content/uploads/2021/05/2pc_transaction-150x150.png 150w" sizes="(max-width: 432px) 100vw, 432px" />											<figcaption class="widget-image-caption wp-caption-text">2pc - Transaktion</figcaption>
										</figure>
							</div>
				</div>
				<div class="elementor-element elementor-element-6d847d2 elementor-widget elementor-widget-text-editor" data-id="6d847d2" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>2pc, Two Phase Commit besteht aus zwei Phasen:</p><ol><li><em><strong>Prepare:</strong></em> Alle beteiligten Microservices werden in dieser Phase ein Signal vom Coordinator erhalten, sich für eine lokale Datenänderung vorzubereiten.</li><li><em><strong>Commit: </strong></em>Diese Phase beginnt, wenn alle Services bereit sind. Die Änderungen werden in jedem Service angewendet (committed), bevor der Coordinator die Transaktion beendet. </li></ol><div> </div><div>Dieses Pattern garantiert uns, dass die Transaktion atomar ist. Das Protokoll sperrt das Objekt, das die Transaktion ändern wird und ist erst verfügbar wenn die Transaktion beendet ist, mit oder ohne Erfolg. Das Problem ist allerdings die Synchronität. Andere Transaktionen, die dieses Objekt brauchen müssen warten bis die aktuelle Transaktion fertig ist. Dies könnte ein Bottleneck für unser System sein. Es ist auch möglich, dass zwei Transaktionen sich gegenseitig blockieren, wenn jede Transaktion ein Objekt braucht, das der andere sperrt. Dies nennt man einen Deadlock. Dies gilt es jedoch zu vermeiden.</div>						</div>
				</div>
				<div class="elementor-element elementor-element-425dbbe elementor-widget elementor-widget-heading" data-id="425dbbe" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h4 class="elementor-heading-title elementor-size-default">Was bedeutet Saga?</h4>		</div>
				</div>
				<div class="elementor-element elementor-element-cb86140 elementor-widget elementor-widget-text-editor" data-id="cb86140" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Der <a href="https://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf">Saga Pattern</a> ist eins der prominentesten Patterns, die in einer Microservice Architektur eingesetzt werden. Ein Saga ist eine Sequenz von lokalen Transaktionen, bei der jede Transaktion die Daten eines einzigen Service ändern kann. Ein externer Trigger (z.B. Aufruf eines API Endpunktes) startet die erste Transaktion, dessen Ende die nächste Transaktion bis die letzte Transaktion zum Ende kommt.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-099650c elementor-widget elementor-widget-text-editor" data-id="099650c" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Man das Saga Pattern auf verschiedene Arten implementieren</p><ul><li><strong>Choreography</strong>: jede lokale Transaktion publiziert ein Event welches andere lokale Transaktionen in einem anderen Services triggert.</li><li><strong>Orchestration</strong>: Ein Orchestrator kontrolliert, wann die Transaktion in welchem Service ausgeführt werden muss.</li></ul><div> </div><p>Die folgende Bilder beschreiben eine Choreography zwischen dem <em>Order-</em> und dem Customer-Service:</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-f53d781 elementor-section-content-middle elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="f53d781" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-562ec0e" data-id="562ec0e" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<section class="elementor-section elementor-inner-section elementor-element elementor-element-6431a52 elementor-section-content-middle elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="6431a52" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-311c631" data-id="311c631" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-88a411a elementor-widget elementor-widget-image" data-id="88a411a" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img loading="lazy" decoding="async" width="402" height="296" src="https://www.inoteq.com/wp-content/uploads/2021/05/saga_success.png" class="attachment-large size-large wp-image-1532" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2021/05/saga_success.png 402w, https://www.inoteq.com/wp-content/uploads/2021/05/saga_success-300x221.png 300w" sizes="(max-width: 402px) 100vw, 402px" />											<figcaption class="widget-image-caption wp-caption-text">Saga - erfolgreiche Transaktion</figcaption>
										</figure>
							</div>
				</div>
				<div class="elementor-element elementor-element-39cf7e7 elementor-widget elementor-widget-text-editor" data-id="39cf7e7" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<ol><li><em>CreateOrder </em>gestartet: Eine Bestellung wurde aufgegeben.</li><li>Daten im OrderService werden aktualisiert.</li><li> Das Order Created Event wird gesendet.</li><li>CustomerService reagiert auf dieses Event und aktualisiert entsprechend seine Daten.</li><li>Das Ende des Sagas ist mit dem Customer Updated Event signalisiert.</li></ol>						</div>
				</div>
					</div>
		</div>
				<div class="elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-7b1fc2f" data-id="7b1fc2f" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-1d72e95 elementor-widget elementor-widget-image" data-id="1d72e95" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img loading="lazy" decoding="async" width="429" height="346" src="https://www.inoteq.com/wp-content/uploads/2021/05/saga_failed.png" class="attachment-large size-large wp-image-1531" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2021/05/saga_failed.png 429w, https://www.inoteq.com/wp-content/uploads/2021/05/saga_failed-300x242.png 300w" sizes="(max-width: 429px) 100vw, 429px" />											<figcaption class="widget-image-caption wp-caption-text">Saga - fehlerhafte Transaktion</figcaption>
										</figure>
							</div>
				</div>
				<div class="elementor-element elementor-element-4c1fc36 elementor-widget elementor-widget-text-editor" data-id="4c1fc36" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<ol>
 	<li><em>CreateOrder </em>gestartet: Eine Bestellung wurde aufgegeben.</li>
 	<li>Daten im OrderService werden aktualisiert.</li>
 	<li>Das Order Created Event wird gesendet.</li>
 	<li>CustomerService reagiert auf dieses Event und aktualisiert entsprechend seine Daten.</li>
 	<li>Die Transaktion ist fehlgeschlagen. Der CustomerService sendet ein Customer Update Failed Event, damit Änderungen im OrderService zurückgesetzt werden</li>
 	<li>Das Ende des Sagas ist mit dem Order Creation Compensated Event signalisiert.</li>
</ol>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-62c950b elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="62c950b" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-6e78121" data-id="6e78121" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
							</div>
		</div>
					</div>
		</section>
				</div>
		<p>Der Beitrag <a href="https://www.inoteq.com/2021/05/18/event-driven-architecture-saga-pattern/">Eventarchitektur für Microservices mit dem Saga Pattern</a> erschien zuerst auf <a href="https://www.inoteq.com">INOTEQ GmbH</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.inoteq.com/2021/05/18/event-driven-architecture-saga-pattern/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Sichern einer Spring Boot WebApp mit OAuth 2.0​</title>
		<link>https://www.inoteq.com/2021/05/06/springboot-authentifizierung/</link>
					<comments>https://www.inoteq.com/2021/05/06/springboot-authentifizierung/#respond</comments>
		
		<dc:creator><![CDATA[Aymen Khalki]]></dc:creator>
		<pubDate>Thu, 06 May 2021 14:48:34 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<guid isPermaLink="false">https://www.inoteq.com/?p=1479</guid>

					<description><![CDATA[<p>Authentifizierung ist der erste Schritt in jedem Sicherheitssystem. Es ist der Prozess mit dem die Identität eines Clients verifiziert wird. Ob der Client Zugriff auf bestimmte Ressourcen erhält, wird allerdings durch den Autorisierungsprozess festgestellt. In diesem Artikel werden wir eine API mit Spring Boot erstellen und das OAuth 2.0 Authentifizierungsprotokoll verwenden, um diese API abzusichern. [&#8230;]</p>
<p>Der Beitrag <a href="https://www.inoteq.com/2021/05/06/springboot-authentifizierung/">Sichern einer Spring Boot WebApp mit OAuth 2.0​</a> erschien zuerst auf <a href="https://www.inoteq.com">INOTEQ GmbH</a>.</p>
]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="1479" class="elementor elementor-1479" data-elementor-post-type="post">
						<section class="elementor-section elementor-top-section elementor-element elementor-element-d7239d4 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="d7239d4" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-0b86a2d" data-id="0b86a2d" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-31f8182 elementor-widget elementor-widget-spacer" data-id="31f8182" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-8a4da57 elementor-widget elementor-widget-theme-post-title elementor-page-title elementor-widget-heading" data-id="8a4da57" data-element_type="widget" data-widget_type="theme-post-title.default">
				<div class="elementor-widget-container">
			<h1 class="elementor-heading-title elementor-size-default">Sichern einer Spring Boot WebApp mit OAuth 2.0​</h1>		</div>
				</div>
				<div class="elementor-element elementor-element-5928c89 elementor-widget elementor-widget-post-info" data-id="5928c89" data-element_type="widget" data-widget_type="post-info.default">
				<div class="elementor-widget-container">
					<ul class="elementor-inline-items elementor-icon-list-items elementor-post-info">
								<li class="elementor-icon-list-item elementor-repeater-item-9ac6b47 elementor-inline-item" itemprop="datePublished">
						<a href="https://www.inoteq.com/2021/05/06/">
											<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="fas fa-calendar"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-date">
										Mai 6, 2021					</span>
									</a>
				</li>
				<li class="elementor-icon-list-item elementor-repeater-item-fae3c22 elementor-inline-item" itemprop="author">
						<a href="https://www.inoteq.com/author/akhalki/">
											<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="far fa-user-circle"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-author">
										Aymen Khalki					</span>
									</a>
				</li>
				</ul>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-15d35fc elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="15d35fc" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-07f960e" data-id="07f960e" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-d038ccf elementor-widget elementor-widget-text-editor" data-id="d038ccf" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Authentifizierung ist der erste Schritt in jedem Sicherheitssystem. Es ist der Prozess mit dem die Identität eines Clients verifiziert wird. Ob der Client Zugriff auf bestimmte Ressourcen erhält, wird allerdings durch den Autorisierungsprozess festgestellt. In diesem Artikel werden wir eine API mit Spring Boot erstellen und das OAuth 2.0 Authentifizierungsprotokoll verwenden, um diese API abzusichern.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-cbbbe31 elementor-toc--minimized-on-tablet elementor-widget elementor-widget-table-of-contents" data-id="cbbbe31" data-element_type="widget" data-settings="{&quot;exclude_headings_by_selector&quot;:[],&quot;headings_by_tags&quot;:[&quot;h2&quot;,&quot;h3&quot;,&quot;h4&quot;,&quot;h5&quot;,&quot;h6&quot;],&quot;marker_view&quot;:&quot;numbers&quot;,&quot;minimize_box&quot;:&quot;yes&quot;,&quot;minimized_on&quot;:&quot;tablet&quot;,&quot;hierarchical_view&quot;:&quot;yes&quot;,&quot;min_height&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;min_height_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;min_height_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}" data-widget_type="table-of-contents.default">
				<div class="elementor-widget-container">
					<div class="elementor-toc__header">
			<h4 class="elementor-toc__header-title">
				Table of Contents			</h4>
							<div class="elementor-toc__toggle-button elementor-toc__toggle-button--expand" role="button" tabindex="0" aria-controls="elementor-toc__cbbbe31" aria-expanded="true" aria-label="Open table of contents"><i aria-hidden="true" class="fas fa-chevron-down"></i></div>
				<div class="elementor-toc__toggle-button elementor-toc__toggle-button--collapse" role="button" tabindex="0" aria-controls="elementor-toc__cbbbe31" aria-expanded="true" aria-label="Close table of contents"><i aria-hidden="true" class="fas fa-chevron-up"></i></div>
					</div>
		<div id="elementor-toc__cbbbe31" class="elementor-toc__body">
			<div class="elementor-toc__spinner-container">
				<i class="elementor-toc__spinner eicon-animation-spin eicon-loading" aria-hidden="true"></i>			</div>
		</div>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-0c2e257 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="0c2e257" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-c3a4390" data-id="c3a4390" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-29cf541 elementor-widget elementor-widget-spacer" data-id="29cf541" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-d1dcbb6 elementor-widget elementor-widget-heading" data-id="d1dcbb6" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Eingehende Erläuterungen und Definitionen</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-f1f267d elementor-widget elementor-widget-heading" data-id="f1f267d" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h5 class="elementor-heading-title elementor-size-default">OAuth 2.0</h5>		</div>
				</div>
				<div class="elementor-element elementor-element-ad32853 elementor-widget elementor-widget-text-editor" data-id="ad32853" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>OAuth 2.0 (Open Authentication) ist ein von der <a href="https://www.ietf.org/mailman/listinfo/oauth">IETF</a> entwickeltes Standardprotokoll, das die Authentifizierung und Autorisierung von Desktop- und Mobile-Anwendungen gegen eine API ermöglicht. Ein Benutzer kann mittels dieses Protokolls einer Client Anwendung den Zugriff auf seine Daten geben, ohne der Anwendung seine Credentials preiszugeben. Der Resource Server, der die Nutzerdaten bereitstellt entscheidet anhand des sogenannten JWT Token, ob die Anwendung autorisierten Zugriff auf die Daten hat. </p>						</div>
				</div>
				<div class="elementor-element elementor-element-80bbd0e elementor-widget elementor-widget-heading" data-id="80bbd0e" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h5 class="elementor-heading-title elementor-size-default">JSON Web Tokens (JWT)</h5>		</div>
				</div>
				<div class="elementor-element elementor-element-a5518ab elementor-widget elementor-widget-text-editor" data-id="a5518ab" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Ein JSON Web Token ist ein Base64 verschlüsseltes JSON Objekt mit einem bestimmten <a href="https://de.wikipedia.org/wiki/JSON_Web_Token">Format</a>, das zum Austauschen von Claims über einen Benutzer zwischen einem Identity Provider und einem Service Provider verwendet wird. Claims sind in diesem Context authentifizierungsrelevante Informationen, die den Benutzer und seinen Zugriff definieren. </p>						</div>
				</div>
				<div class="elementor-element elementor-element-4a0b815 elementor-widget elementor-widget-heading" data-id="4a0b815" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h5 class="elementor-heading-title elementor-size-default">Authorization Server</h5>		</div>
				</div>
				<div class="elementor-element elementor-element-243752b elementor-widget elementor-widget-text-editor" data-id="243752b" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Ein Server, der den Resource Owner authentifiziert und einen zeitlich begrenzten Access-Token für einen von ihm definierten Scope ausstellt.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-c1527e4 elementor-widget elementor-widget-heading" data-id="c1527e4" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h5 class="elementor-heading-title elementor-size-default">Resource Server</h5>		</div>
				</div>
				<div class="elementor-element elementor-element-20898ac elementor-widget elementor-widget-text-editor" data-id="20898ac" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Im OAuth 2.0 Protokoll fungiert der <a href="https://tools.ietf.org/html/rfc6749#section-1.1">Resource Server</a> als der API Server, der authentifizierte Anfragen verarbeitet, wenn ein gültiges Access Token vorliegt. Bei autorisierten Anfragen werden die Daten bereitgestellt und zurückgegeben.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-d1ba0a9 elementor-widget elementor-widget-text-editor" data-id="d1ba0a9" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Das folgende Diagramm veranschaulicht den Ablauf des <em>Authorization Code Flow</em> und die Rollen der beteiligten Komponenten:</p>						</div>
				</div>
				<div class="elementor-element elementor-element-c507112 elementor-widget elementor-widget-image" data-id="c507112" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img loading="lazy" decoding="async" width="768" height="643" src="https://www.inoteq.com/wp-content/uploads/2021/05/AuthCodeFlowSequenceDiagram-1-e1620399929854-768x643.png" class="attachment-medium_large size-medium_large wp-image-1481" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2021/05/AuthCodeFlowSequenceDiagram-1-e1620399929854-768x643.png 768w, https://www.inoteq.com/wp-content/uploads/2021/05/AuthCodeFlowSequenceDiagram-1-e1620399929854-300x251.png 300w, https://www.inoteq.com/wp-content/uploads/2021/05/AuthCodeFlowSequenceDiagram-1-e1620399929854-1024x857.png 1024w, https://www.inoteq.com/wp-content/uploads/2021/05/AuthCodeFlowSequenceDiagram-1-e1620399929854.png 1291w" sizes="(max-width: 768px) 100vw, 768px" />											<figcaption class="widget-image-caption wp-caption-text">OAuth 2.0: Authorization Code Flow</figcaption>
										</figure>
							</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-b119b62 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="b119b62" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-a57b081" data-id="a57b081" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-70dd815 elementor-widget elementor-widget-spacer" data-id="70dd815" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-d9bbd4b elementor-widget elementor-widget-heading" data-id="d9bbd4b" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Einrichten des Authorization Servers</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-d086ba0 elementor-widget elementor-widget-text-editor" data-id="d086ba0" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Wir werden Azure B2C als Authorization Server verwenden. Dafür brauchen wir einen Mandant (Tenant). Der Tenant ist eine Gruppe von Identitäten, die eine Organisation repräsentieren.  Jede Identität hat bestimmte Attribute und Berechtigungen, die ihre Zugriffe bestimmen. Damit eine Client Anwendung Access Tokens für unsere API von Azure AD B2C ausstellen kann, müssen wir sowohl die Client App als auch die API im Tenant registrieren.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-fd9e9c1 elementor-skin-carousel elementor-arrows-yes elementor-pagination-type-bullets elementor-pagination-position-outside elementor-widget elementor-widget-media-carousel" data-id="fd9e9c1" data-element_type="widget" data-settings="{&quot;slides_per_view&quot;:&quot;1&quot;,&quot;slides_to_scroll&quot;:&quot;1&quot;,&quot;skin&quot;:&quot;carousel&quot;,&quot;effect&quot;:&quot;slide&quot;,&quot;show_arrows&quot;:&quot;yes&quot;,&quot;pagination&quot;:&quot;bullets&quot;,&quot;speed&quot;:500,&quot;autoplay&quot;:&quot;yes&quot;,&quot;autoplay_speed&quot;:5000,&quot;loop&quot;:&quot;yes&quot;,&quot;pause_on_hover&quot;:&quot;yes&quot;,&quot;pause_on_interaction&quot;:&quot;yes&quot;,&quot;space_between&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:10,&quot;sizes&quot;:[]},&quot;space_between_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:10,&quot;sizes&quot;:[]},&quot;space_between_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:10,&quot;sizes&quot;:[]}}" data-widget_type="media-carousel.default">
				<div class="elementor-widget-container">
					<div class="elementor-swiper">
			<div class="elementor-main-swiper swiper-container">
				<div class="swiper-wrapper">
											<div class="swiper-slide">
									<div class="elementor-carousel-image" role="img" aria-label="1. Registrierung der App" style="background-image: url(&#039;https://www.inoteq.com/wp-content/uploads/2021/05/Screenshot-2021-05-19-at-11.25.11.png&#039;)">

			
					</div>
								</div>
											<div class="swiper-slide">
									<div class="elementor-carousel-image" role="img" aria-label="2. Erstellung der App ID" style="background-image: url(&#039;https://www.inoteq.com/wp-content/uploads/2021/05/Screenshot-2021-05-19-at-11.44.05.png&#039;)">

			
					</div>
								</div>
											<div class="swiper-slide">
									<div class="elementor-carousel-image" role="img" aria-label="Hinzufügen von Scopes" style="background-image: url(&#039;https://www.inoteq.com/wp-content/uploads/2021/05/Screenshot-2021-05-19-at-11.27.30.png&#039;)">

			
					</div>
								</div>
									</div>
															<div class="swiper-pagination"></div>
																<div class="elementor-swiper-button elementor-swiper-button-prev" role="button" tabindex="0">
							<i aria-hidden="true" class="eicon-chevron-left"></i>							<span class="elementor-screen-only">Voriger</span>
						</div>
						<div class="elementor-swiper-button elementor-swiper-button-next" role="button" tabindex="0">
							<i aria-hidden="true" class="eicon-chevron-right"></i>							<span class="elementor-screen-only">Nächster</span>
						</div>
												</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-1da1f5f elementor-widget elementor-widget-text-editor" data-id="1da1f5f" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<ol><li>Im Azure AD B2C (in dem neu angelegten Tenant) unter <strong><em>App Registrations</em></strong> auf <em><strong>New Registration</strong></em><em> </em>klicken</li><li>Das Formular ausfüllen (name, supported account types) und auf <em><strong>Register</strong></em><em> </em>klicken, um die Anwendung zu erstellen.</li><li>Die Anwendung muss als API definiert werden und muss außerdem eine eindeutige URI haben. Nach der Definition der API, selektieren wir die Anwendung aus der Liste der registrierten Apps und beenden den Vorgang mit einem Klick<em><strong> </strong></em>auf <em><strong>Set</strong></em><em> in </em><em><span style="font-weight: bolder;">Expose an API</span></em>. Es wird daraufhin eine neue URI generiert, die wir mit einem Klick auf <em><strong>Save </strong></em>speichern können<em>.</em></li><li>APIs müssen auf jeden Fall einen Scope publizieren, damit Client Apps einen gültigen Access Token erhalten können.</li></ol>						</div>
				</div>
				<div class="elementor-element elementor-element-34a81f7 elementor-widget elementor-widget-spacer" data-id="34a81f7" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-ea55ce9 elementor-widget elementor-widget-heading" data-id="ea55ce9" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Anwendungsbeispiel für JAVA Spring Boot</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-c7407e7 elementor-widget elementor-widget-heading" data-id="c7407e7" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h4 class="elementor-heading-title elementor-size-default">Notwendige Dependencies definieren</h4>		</div>
				</div>
				<div class="elementor-element elementor-element-7872921 elementor-widget elementor-widget-text-editor" data-id="7872921" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Wir brauchen <a href="https://search.maven.org/search?q=spring-boot-starter-oauth2-resource-server"><em>spring-boot-starter-oauth2-resource-server</em></a>, mit dem wir unsere Sicherheitskonfiguration definieren. </p>						</div>
				</div>
				<div class="elementor-element elementor-element-e885f9c elementor-tabs-view-horizontal elementor-widget elementor-widget-tabs" data-id="e885f9c" data-element_type="widget" data-widget_type="tabs.default">
				<div class="elementor-widget-container">
					<div class="elementor-tabs">
			<div class="elementor-tabs-wrapper" role="tablist" >
									<div id="elementor-tab-title-2431" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-2431" aria-expanded="false">Maven</div>
									<div id="elementor-tab-title-2432" class="elementor-tab-title elementor-tab-desktop-title" aria-selected="false" data-tab="2" role="tab" tabindex="-1" aria-controls="elementor-tab-content-2432" aria-expanded="false">Gradle</div>
							</div>
			<div class="elementor-tabs-content-wrapper" role="tablist" aria-orientation="vertical">
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="true" data-tab="1" role="tab" tabindex="0" aria-controls="elementor-tab-content-2431" aria-expanded="false">Maven</div>
					<div id="elementor-tab-content-2431" class="elementor-tab-content elementor-clearfix" data-tab="1" role="tabpanel" aria-labelledby="elementor-tab-title-2431" tabindex="0" hidden="false"><!-- HTML generated using hilite.me --><div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%"> <span style="color: #007700">&lt;dependency&gt;</span>
      <span style="color: #007700">&lt;groupId&gt;</span>org.springframework.boot<span style="color: #007700">&lt;/groupId&gt;</span>
      <span style="color: #007700">&lt;artifactId&gt;</span>spring-boot-starter-oauth2-resource-server<span style="color: #007700">&lt;/artifactId&gt;</span>
 <span style="color: #007700">&lt;/dependency&gt;</span>
</pre></div>
</div>
									<div class="elementor-tab-title elementor-tab-mobile-title" aria-selected="false" data-tab="2" role="tab" tabindex="-1" aria-controls="elementor-tab-content-2432" aria-expanded="false">Gradle</div>
					<div id="elementor-tab-content-2432" class="elementor-tab-content elementor-clearfix" data-tab="2" role="tabpanel" aria-labelledby="elementor-tab-title-2432" tabindex="0" hidden="hidden"><!-- HTML generated using hilite.me --><div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%">    <span style="color: #0066BB; font-weight: bold">implementation</span> <span style="color: #FF0000; background-color: #FFAAAA">&#39;</span><span style="color: #003366; font-weight: bold">org.springframework.boot</span>:<span style="color: #003366; font-weight: bold">spring-boot-starter-oauth2-resource-server</span><span style="color: #FF0000; background-color: #FFAAAA">&#39;</span>
</pre></div>

</div>
							</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-5db3c81 elementor-widget elementor-widget-heading" data-id="5db3c81" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h4 class="elementor-heading-title elementor-size-default">Modell</h4>		</div>
				</div>
				<div class="elementor-element elementor-element-96ac138 elementor-widget elementor-widget-text-editor" data-id="96ac138" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Definition des POJO Person.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-61eb369 elementor-widget elementor-widget-html" data-id="61eb369" data-element_type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
			<div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%"><span style="color: #008800; font-weight: bold">public</span> <span style="color: #008800; font-weight: bold">class</span> <span style="color: #BB0066; font-weight: bold">Person</span> <span style="color: #333333">{</span>
    <span style="color: #008800; font-weight: bold">public</span> String name<span style="color: #333333">;</span>
    <span style="color: #008800; font-weight: bold">public</span> String lastName<span style="color: #333333">;</span>
    
   <span style="color: #888888">// ... constructor, getters and setters</span>
<span style="color: #333333">}</span>
</pre></div>

		</div>
				</div>
				<div class="elementor-element elementor-element-593533a elementor-widget elementor-widget-heading" data-id="593533a" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h4 class="elementor-heading-title elementor-size-default">Controller</h4>		</div>
				</div>
				<div class="elementor-element elementor-element-023146b elementor-widget elementor-widget-text-editor" data-id="023146b" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Hier definieren wir den <em>PeopleController, der die API beschreibt</em>. Der Controller soll die zwei folgende Operationen implementieren:</p><ul><li>Abfrage der Liste der Personen: GET</li><li>Hinzufügen einer Person in der List: POST</li></ul><p>Anhand der Spring Annotationen <em><strong>@GetMapping</strong> </em>und <em><strong>@PostMapping</strong> (usw&#8230;) können wir die einzelnen Endpunkte der API definieren.</em></p>						</div>
				</div>
				<div class="elementor-element elementor-element-bdaed8a elementor-widget elementor-widget-html" data-id="bdaed8a" data-element_type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
			<div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%"><span style="color: #555555; font-weight: bold">@RestController</span>
<span style="color: #555555; font-weight: bold">@RequestMapping</span><span style="color: #333333">(</span><span style="background-color: #fff0f0">&quot;/people&quot;</span><span style="color: #333333">)</span>
<span style="color: #008800; font-weight: bold">public</span> <span style="color: #008800; font-weight: bold">class</span> <span style="color: #BB0066; font-weight: bold">PeopleController</span> <span style="color: #333333">{</span>
    <span style="color: #008800; font-weight: bold">private</span> List<span style="color: #333333">&lt;</span>Person<span style="color: #333333">&gt;</span> people <span style="color: #333333">=</span> Arrays<span style="color: #333333">.</span><span style="color: #0000CC">asList</span><span style="color: #333333">(</span>Person<span style="color: #333333">(</span><span style="background-color: #fff0f0">&quot;foo&quot;</span><span style="color: #333333">,</span> <span style="background-color: #fff0f0">&quot;bar&quot;</span><span style="color: #333333">),</span> Person<span style="color: #333333">(</span><span style="background-color: #fff0f0">&quot;baz&quot;</span><span style="color: #333333">,</span> <span style="background-color: #fff0f0">&quot;bar&quot;</span><span style="color: #333333">));</span>

    <span style="color: #555555; font-weight: bold">@GetMapping</span><span style="color: #333333">(</span><span style="background-color: #fff0f0">&quot;/&quot;</span><span style="color: #333333">)</span>
    <span style="color: #008800; font-weight: bold">public</span> ResponseEntity<span style="color: #333333">&lt;</span>List<span style="color: #333333">&lt;</span>Person<span style="color: #333333">&gt;&gt;</span> <span style="color: #0066BB; font-weight: bold">getAllPeople</span><span style="color: #333333">()</span> <span style="color: #333333">{</span>
        <span style="color: #008800; font-weight: bold">return</span> <span style="color: #008800; font-weight: bold">new</span> <span style="color: #0066BB; font-weight: bold">ResponseEntity</span><span style="color: #333333">(</span>people<span style="color: #333333">,</span> HttpStatus<span style="color: #333333">.</span><span style="color: #0000CC">OK</span><span style="color: #333333">);</span>
    <span style="color: #333333">}</span> 
    
    <span style="color: #555555; font-weight: bold">@PostMapping</span>
    <span style="color: #008800; font-weight: bold">public</span> ResponseEntity <span style="color: #0066BB; font-weight: bold">addPerson</span><span style="color: #333333">(</span><span style="color: #555555; font-weight: bold">@RequestBody</span> person<span style="color: #333333">)</span> <span style="color: #333333">{</span>
        people<span style="color: #333333">.</span><span style="color: #0000CC">add</span><span style="color: #333333">(</span>person<span style="color: #333333">);</span>
        <span style="color: #008800; font-weight: bold">return</span> <span style="color: #008800; font-weight: bold">new</span> <span style="color: #0066BB; font-weight: bold">ResponseEntity</span><span style="color: #333333">(</span>HttpStatus<span style="color: #333333">.</span><span style="color: #0000CC">OK</span><span style="color: #333333">);</span>
    <span style="color: #333333">}</span>
<span style="color: #333333">}</span>
</pre></div>

		</div>
				</div>
				<div class="elementor-element elementor-element-f25f41a elementor-widget elementor-widget-heading" data-id="f25f41a" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h4 class="elementor-heading-title elementor-size-default">CORS</h4>		</div>
				</div>
				<div class="elementor-element elementor-element-019687d elementor-widget elementor-widget-text-editor" data-id="019687d" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Wir konfigurieren CORS, um Ressourcen außerhalb der Domain der Resource Servers abfragen zu können. </p>						</div>
				</div>
				<div class="elementor-element elementor-element-0173e3d elementor-widget elementor-widget-html" data-id="0173e3d" data-element_type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
			<div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%"><span style="color: #555555; font-weight: bold">@Configuration</span>
<span style="color: #008800; font-weight: bold">public</span> <span style="color: #008800; font-weight: bold">class</span> <span style="color: #BB0066; font-weight: bold">AppConf</span> <span style="color: #008800; font-weight: bold">implements</span> WebMvcConfigurer <span style="color: #333333">{</span>

    <span style="color: #555555; font-weight: bold">@Override</span>
    <span style="color: #008800; font-weight: bold">public</span> <span style="color: #333399; font-weight: bold">void</span> <span style="color: #0066BB; font-weight: bold">addCorsMappings</span><span style="color: #333333">(</span>CorsRegistry registry<span style="color: #333333">)</span> <span style="color: #333333">{</span>
        registry<span style="color: #333333">.</span><span style="color: #0000CC">addMapping</span><span style="color: #333333">(</span><span style="background-color: #fff0f0">&quot;/**&quot;</span><span style="color: #333333">)</span>
                <span style="color: #333333">.</span><span style="color: #0000CC">allowedOrigins</span><span style="color: #333333">(</span><span style="background-color: #fff0f0">&quot;http://example.com&quot;</span><span style="color: #333333">)</span>
                <span style="color: #333333">.</span><span style="color: #0000CC">allowedMethods</span><span style="color: #333333">(</span><span style="background-color: #fff0f0">&quot;GET&quot;</span><span style="color: #333333">,</span> <span style="background-color: #fff0f0">&quot;POST&quot;</span><span style="color: #333333">,</span> <span style="background-color: #fff0f0">&quot;PUT&quot;</span><span style="color: #333333">,</span> <span style="background-color: #fff0f0">&quot;DELETE&quot;</span><span style="color: #333333">);</span>
    <span style="color: #333333">}</span>
<span style="color: #333333">}</span>
</pre></div>

		</div>
				</div>
				<div class="elementor-element elementor-element-e5058dd elementor-widget elementor-widget-heading" data-id="e5058dd" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h4 class="elementor-heading-title elementor-size-default">Security Configuration</h4>		</div>
				</div>
				<div class="elementor-element elementor-element-49361e7 elementor-widget elementor-widget-text-editor" data-id="49361e7" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Zunächst müssen wir den Endpunkt des Authorization Servers setzen, gegen den unsere API die Access Tokens validieren wird. Dies können wir in der <strong><em>application.yml </em></strong>Datei definieren.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-8b7b5e4 elementor-widget elementor-widget-html" data-id="8b7b5e4" data-element_type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
			<div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%">spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: http://example-authorization-server.com/keys
</pre></div>

		</div>
				</div>
				<div class="elementor-element elementor-element-360789f elementor-widget elementor-widget-text-editor" data-id="360789f" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Bisher ist unsere API noch nicht gesichert, da alle Anfragen die den <em>&#8222;/people&#8220;</em> Endpunkt treffen durchgelassen werden.</p><p>Spring Security bietet uns die Möglichkeit, verschiedene Access Levels anhand der Eigenschaften (URL, Headers,&#8230;) der Anfragen zu konfigurieren.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-52e8fcf elementor-widget elementor-widget-html" data-id="52e8fcf" data-element_type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
			<div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%"><span style="color: #555555; font-weight: bold">@Configuration</span>
<span style="color: #008800; font-weight: bold">public</span> <span style="color: #008800; font-weight: bold">class</span> <span style="color: #BB0066; font-weight: bold">SecurityConfig</span> <span style="color: #008800; font-weight: bold">extends</span> WebSecurityConfigurerAdapter <span style="color: #333333">{</span>
    <span style="color: #555555; font-weight: bold">@Override</span>
    <span style="color: #008800; font-weight: bold">protected</span> <span style="color: #333399; font-weight: bold">void</span> <span style="color: #0066BB; font-weight: bold">configure</span><span style="color: #333333">(</span>HttpSecurity http<span style="color: #333333">)</span> <span style="color: #008800; font-weight: bold">throws</span> Exception <span style="color: #333333">{</span>
        <span style="color: #888888">// allows CORS preflight checks to succeed</span>
        http<span style="color: #333333">.</span><span style="color: #0000CC">cors</span><span style="color: #333333">()</span>

            <span style="color: #333333">.</span><span style="color: #0000CC">and</span><span style="color: #333333">()</span>
                <span style="color: #333333">.</span><span style="color: #0000CC">authorizeRequests</span><span style="color: #333333">()</span>
                <span style="color: #333333">.</span><span style="color: #0000CC">antMatchers</span><span style="color: #333333">(</span><span style="background-color: #fff0f0">&quot;/admin/*&quot;</span><span style="color: #333333">)</span>
                <span style="color: #333333">.</span><span style="color: #0000CC">hasRole</span><span style="color: #333333">(</span><span style="background-color: #fff0f0">&quot;ADMIN&quot;</span><span style="color: #333333">)</span>
            <span style="color: #333333">.</span><span style="color: #0000CC">and</span><span style="color: #333333">()</span>
                <span style="color: #333333">.</span><span style="color: #0000CC">authorizeRequests</span><span style="color: #333333">()</span>
                <span style="color: #333333">.</span><span style="color: #0000CC">anyRequest</span><span style="color: #333333">()</span>
                <span style="color: #333333">.</span><span style="color: #0000CC">authenticated</span><span style="color: #333333">()</span>
            <span style="color: #333333">.</span><span style="color: #0000CC">and</span><span style="color: #333333">()</span>               
                <span style="color: #333333">.</span><span style="color: #0000CC">sessionManagement</span><span style="color: #333333">()</span>
                <span style="color: #333333">.</span><span style="color: #0000CC">sessionCreationPolicy</span><span style="color: #333333">(</span>SessionCreationPolicy<span style="color: #333333">.</span><span style="color: #0000CC">STATELESS</span><span style="color: #333333">)</span>
            <span style="color: #333333">.</span><span style="color: #0000CC">and</span><span style="color: #333333">()</span>
                <span style="color: #333333">.</span><span style="color: #0000CC">oauth2ResourceServer</span><span style="color: #333333">()</span>
                <span style="color: #333333">.</span><span style="color: #0000CC">jwt</span><span style="color: #333333">();</span>
    <span style="color: #333333">}</span>
<span style="color: #333333">}</span>
</pre></div>

		</div>
				</div>
				<div class="elementor-element elementor-element-6c89d33 elementor-widget elementor-widget-text-editor" data-id="6c89d33" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>In dieser Konfiguration werden:</p><ol><li>Anfragen zum <em>&#8222;/admin&#8220; </em>Endpunkt nur erlauben, wenn in den Claims die Rolle &#8222;Admin&#8220; vorhanden ist.</li><li>Sonst alle authentifizierte Anfragen</li></ol><p>Die Authentifizierung in unserer Anwendung ist zustandslos, weshalb wir keinen Session Kontext benötigen.</p><p>Die zwei letzen Zeilen der Konfiguration stellen sicher, dass die Resource Server Funktionalitäten bereitgestellt werden (Abfangen der HTTP Anfragen, Extraktion des Tokens aus dem <em>&#8222;Authorization&#8220;</em> Header und die Authentifizierung an sich&#8230;) . <em>jwt()</em> spezifiziert den Typen der Tokens, die die API erwarten soll.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-b32e097 elementor-widget elementor-widget-heading" data-id="b32e097" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h4 class="elementor-heading-title elementor-size-default">Tests</h4>		</div>
				</div>
				<div class="elementor-element elementor-element-e37b4ed elementor-widget elementor-widget-text-editor" data-id="e37b4ed" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Um unsere Konfiguration programmatisch zu testen, erstellen wir zwei Unit Tests &#8211; ein Test für den positiven Fall der Authentifizierung und ein Test für den negativen Fall.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-a12dad4 elementor-widget elementor-widget-html" data-id="a12dad4" data-element_type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
			<div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%">   <span style="color: #555555; font-weight: bold">@Test</span>
    <span style="color: #333399; font-weight: bold">void</span> <span style="color: #0066BB; font-weight: bold">userIsNotAuthenticated_whenGetPeople_thenFail</span><span style="color: #333333">()</span> <span style="color: #333333">{</span>
        String token <span style="color: #333333">=</span> getToken<span style="color: #333333">();</span>

        Response response <span style="color: #333333">=</span> RestAssured<span style="color: #333333">.</span><span style="color: #0000CC">given</span><span style="color: #333333">()</span>
                <span style="color: #333333">.</span><span style="color: #0000CC">header</span><span style="color: #333333">(</span>HttpHeaders<span style="color: #333333">.</span><span style="color: #0000CC">AUTHORIZATION</span><span style="color: #333333">,</span> <span style="background-color: #fff0f0">&quot;Bearer &quot;</span> <span style="color: #333333">+</span> token<span style="color: #333333">)</span>
                <span style="color: #333333">.</span><span style="color: #0000CC">get</span><span style="color: #333333">(</span><span style="background-color: #fff0f0">&quot;http://localhost:8081/people/&quot;</span><span style="color: #333333">);</span>

        assertThat<span style="color: #333333">(</span>response<span style="color: #333333">.</span><span style="color: #0000CC">statusCode</span><span style="color: #333333">()).</span><span style="color: #0000CC">isEqualTo</span><span style="color: #333333">(</span>HttpStatus<span style="color: #333333">.</span><span style="color: #0000CC">SC_UNAUTHORIZED</span><span style="color: #333333">);</span>
    <span style="color: #333333">}</span>

    <span style="color: #555555; font-weight: bold">@Test</span>
    <span style="color: #333399; font-weight: bold">void</span> <span style="color: #0066BB; font-weight: bold">userIsAuthenticated_whenGetPeople_thenSucceed</span><span style="color: #333333">()</span> <span style="color: #333333">{</span>
        String token <span style="color: #333333">=</span> getToken<span style="color: #333333">();</span>

        Response response <span style="color: #333333">=</span> RestAssured<span style="color: #333333">.</span><span style="color: #0000CC">given</span><span style="color: #333333">()</span>
                <span style="color: #333333">.</span><span style="color: #0000CC">header</span><span style="color: #333333">(</span>HttpHeaders<span style="color: #333333">.</span><span style="color: #0000CC">AUTHORIZATION</span><span style="color: #333333">,</span> <span style="background-color: #fff0f0">&quot;Bearer &quot;</span> <span style="color: #333333">+</span> token<span style="color: #333333">)</span>
                <span style="color: #333333">.</span><span style="color: #0000CC">get</span><span style="color: #333333">(</span><span style="background-color: #fff0f0">&quot;http://localhost:8081/people/&quot;</span><span style="color: #333333">);</span>

        assertThat<span style="color: #333333">(</span>response<span style="color: #333333">.</span><span style="color: #0000CC">as</span><span style="color: #333333">(</span>List<span style="color: #333333">.</span><span style="color: #0000CC">class</span><span style="color: #333333">).</span><span style="color: #0000CC">isEmpty</span><span style="color: #333333">()).</span><span style="color: #0000CC">isFalse</span><span style="color: #333333">();</span>
    <span style="color: #333333">}</span>
</pre></div>

		</div>
				</div>
				<div class="elementor-element elementor-element-d6907a2 elementor-widget elementor-widget-spacer" data-id="d6907a2" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-10b8c24 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="10b8c24" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-4cebb4d" data-id="4cebb4d" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<section class="elementor-section elementor-inner-section elementor-element elementor-element-0521f6c elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="0521f6c" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-4c36754" data-id="4c36754" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-c168a0b elementor-widget elementor-widget-heading" data-id="c168a0b" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h4 class="elementor-heading-title elementor-size-default">Method Security</h4>		</div>
				</div>
				<div class="elementor-element elementor-element-577649a elementor-widget elementor-widget-text-editor" data-id="577649a" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Spring Boot unterstützt das Konfigurieren der Sicherheit der API auf Methodenebene mittels drei Annotationen:</p><ul><li><em><strong>@Secured</strong></em>: definiert eine Liste von Rollen. Die annotierte Methode wird nur ausgeführt, für Clients die mindestens eine dieser Rollen besitzt.</li><li><em><strong>@PreAuthorize</strong></em> &amp; <em><strong>@PostAuthorize </strong></em>: definieren Zugriffskontrolle anhand <em>Predicates, </em>die in <a href="https://www.baeldung.com/spring-expression-language">SpEL</a> geschrieben sind.</li></ul>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<div class="elementor-element elementor-element-116d7d7 elementor-widget elementor-widget-text-editor" data-id="116d7d7" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Bevor wir die Annotationen benutzen können, müssen wir die MethodSecurity einstellen.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-1b7f061 elementor-widget elementor-widget-html" data-id="1b7f061" data-element_type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
			<div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%"><span style="color: #555555; font-weight: bold">@Configuration</span>
<span style="color: #555555; font-weight: bold">@EnableGlobalMethodSecurity</span><span style="color: #333333">(</span>
        prePostEnabled <span style="color: #333333">=</span> <span style="color: #008800; font-weight: bold">true</span><span style="color: #333333">,</span>
        securedEnabled <span style="color: #333333">=</span> <span style="color: #008800; font-weight: bold">true</span><span style="color: #333333">,</span>
        jsr250Enabled <span style="color: #333333">=</span> <span style="color: #008800; font-weight: bold">true</span><span style="color: #333333">)</span>
<span style="color: #008800; font-weight: bold">public</span> <span style="color: #008800; font-weight: bold">class</span> <span style="color: #BB0066; font-weight: bold">MethodSecurityConfig</span>
        <span style="color: #008800; font-weight: bold">extends</span> GlobalMethodSecurityConfiguration <span style="color: #333333">{</span>
<span style="color: #333333">}</span>
</pre></div>

		</div>
				</div>
				<div class="elementor-element elementor-element-7d04238 elementor-widget elementor-widget-text-editor" data-id="7d04238" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>In unserem Controller, können wir nun die Methoden wie folgend annotieren</p>						</div>
				</div>
				<section class="elementor-section elementor-inner-section elementor-element elementor-element-285186c elementor-section-content-space-evenly elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="285186c" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-289b32f" data-id="289b32f" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-4959d8e elementor-widget elementor-widget-html" data-id="4959d8e" data-element_type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
			<div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%"><span style="color: #555555; font-weight: bold">@Secured</span><span style="color: #333333">({</span> <span style="background-color: #fff0f0">&quot;ROLE_ADMIN&quot;</span><span style="color: #333333">,</span> <span style="background-color: #fff0f0">&quot;ROLE_MEMBER&quot;</span> <span style="color: #333333">})</span>
<span style="color: #008800; font-weight: bold">public</span> String <span style="color: #0066BB; font-weight: bold">getMembershipId</span><span style="color: #333333">(</span>String userId<span style="color: #333333">)</span> <span style="color: #333333">{</span>
    <span style="color: #008800; font-weight: bold">return</span> userRepository<span style="color: #333333">.</span><span style="color: #0000CC">getMembershipId</span><span style="color: #333333">(</span>userId<span style="color: #333333">);</span>
<span style="color: #333333">}</span>
</pre></div>

		</div>
				</div>
					</div>
		</div>
				<div class="elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-a41244a" data-id="a41244a" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-db56f7d elementor-widget elementor-widget-html" data-id="db56f7d" data-element_type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
			<div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%"><span style="color: #555555; font-weight: bold">@PreAuthorize</span><span style="color: #333333">(</span><span style="background-color: #fff0f0">&quot;hasRole(&#39;ROLE_ADMIN&#39;) or hasRole(&#39;ROLE_MEMBER&#39;)&quot;</span><span style="color: #333333">)</span>
<span style="color: #008800; font-weight: bold">public</span> String <span style="color: #0066BB; font-weight: bold">getMembershipId</span><span style="color: #333333">(</span>String userId<span style="color: #333333">)</span> <span style="color: #333333">{</span>
     <span style="color: #888888">//...</span>
<span style="color: #333333">}</span>
</pre></div>

		</div>
				</div>
					</div>
		</div>
					</div>
		</section>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-8b0453a elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="8b0453a" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-709d417" data-id="709d417" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-28a9539 elementor-widget elementor-widget-spacer" data-id="28a9539" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				</div>
		<p>Der Beitrag <a href="https://www.inoteq.com/2021/05/06/springboot-authentifizierung/">Sichern einer Spring Boot WebApp mit OAuth 2.0​</a> erschien zuerst auf <a href="https://www.inoteq.com">INOTEQ GmbH</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.inoteq.com/2021/05/06/springboot-authentifizierung/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Container in der AWS Cloud betreiben und überwachen</title>
		<link>https://www.inoteq.com/2021/04/30/containers-in-aws/</link>
					<comments>https://www.inoteq.com/2021/04/30/containers-in-aws/#comments</comments>
		
		<dc:creator><![CDATA[Aymen Khalki]]></dc:creator>
		<pubDate>Fri, 30 Apr 2021 15:12:54 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<guid isPermaLink="false">https://www.inoteq.com/?p=1475</guid>

					<description><![CDATA[<p>Table of Contents Container as a Service (CaaS) ist ein cloudbasierter Service mit dem Container deployed, ausgeführt, skaliert und verwaltet werden können. Im AWS Umfeld finden wir zwei solche Services, nämlich den Elastic Container Service (ECS) und den Elastic Kubernetes Service (EKS). In diesem Artikel, werden wir die zwei Services vorstellen und ihre Eigenschaften und [&#8230;]</p>
<p>Der Beitrag <a href="https://www.inoteq.com/2021/04/30/containers-in-aws/">Container in der AWS Cloud betreiben und überwachen</a> erschien zuerst auf <a href="https://www.inoteq.com">INOTEQ GmbH</a>.</p>
]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="1475" class="elementor elementor-1475" data-elementor-post-type="post">
						<section class="elementor-section elementor-top-section elementor-element elementor-element-4293754 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="4293754" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-9e837e0" data-id="9e837e0" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-671129d elementor-widget elementor-widget-spacer" data-id="671129d" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-96e908f elementor-widget elementor-widget-theme-post-title elementor-page-title elementor-widget-heading" data-id="96e908f" data-element_type="widget" data-widget_type="theme-post-title.default">
				<div class="elementor-widget-container">
			<h1 class="elementor-heading-title elementor-size-default">Container in der AWS Cloud betreiben und überwachen</h1>		</div>
				</div>
				<div class="elementor-element elementor-element-8030d30 elementor-widget elementor-widget-post-info" data-id="8030d30" data-element_type="widget" data-widget_type="post-info.default">
				<div class="elementor-widget-container">
					<ul class="elementor-inline-items elementor-icon-list-items elementor-post-info">
								<li class="elementor-icon-list-item elementor-repeater-item-cd74d0a elementor-inline-item" itemprop="datePublished">
						<a href="https://www.inoteq.com/2021/04/30/">
											<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="fas fa-calendar"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-date">
										April 30, 2021					</span>
									</a>
				</li>
				<li class="elementor-icon-list-item elementor-repeater-item-1d823a0 elementor-inline-item" itemprop="author">
						<a href="https://www.inoteq.com/author/akhalki/">
											<span class="elementor-icon-list-icon">
								<i aria-hidden="true" class="far fa-user-circle"></i>							</span>
									<span class="elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-author">
										Aymen Khalki					</span>
									</a>
				</li>
				</ul>
				</div>
				</div>
				<div class="elementor-element elementor-element-ba1a509 elementor-toc--minimized-on-tablet elementor-widget elementor-widget-table-of-contents" data-id="ba1a509" data-element_type="widget" data-settings="{&quot;headings_by_tags&quot;:[&quot;h2&quot;,&quot;h3&quot;],&quot;exclude_headings_by_selector&quot;:[],&quot;marker_view&quot;:&quot;numbers&quot;,&quot;minimize_box&quot;:&quot;yes&quot;,&quot;minimized_on&quot;:&quot;tablet&quot;,&quot;hierarchical_view&quot;:&quot;yes&quot;,&quot;min_height&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;min_height_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;min_height_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}" data-widget_type="table-of-contents.default">
				<div class="elementor-widget-container">
					<div class="elementor-toc__header">
			<h4 class="elementor-toc__header-title">
				Table of Contents			</h4>
							<div class="elementor-toc__toggle-button elementor-toc__toggle-button--expand" role="button" tabindex="0" aria-controls="elementor-toc__ba1a509" aria-expanded="true" aria-label="Open table of contents"><i aria-hidden="true" class="fas fa-chevron-down"></i></div>
				<div class="elementor-toc__toggle-button elementor-toc__toggle-button--collapse" role="button" tabindex="0" aria-controls="elementor-toc__ba1a509" aria-expanded="true" aria-label="Close table of contents"><i aria-hidden="true" class="fas fa-chevron-up"></i></div>
					</div>
		<div id="elementor-toc__ba1a509" class="elementor-toc__body">
			<div class="elementor-toc__spinner-container">
				<i class="elementor-toc__spinner eicon-animation-spin eicon-loading" aria-hidden="true"></i>			</div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-cb415d5 elementor-widget elementor-widget-text-editor" data-id="cb415d5" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Container as a Service (CaaS) ist ein cloudbasierter Service mit dem Container deployed, ausgeführt, skaliert und verwaltet werden können.</p><p>Im AWS Umfeld finden wir zwei solche Services, nämlich den Elastic Container Service (ECS) und den Elastic Kubernetes Service (EKS). In diesem Artikel, werden wir die zwei Services vorstellen und ihre Eigenschaften und Einsatzzwecke auflisten.</p>						</div>
				</div>
				<section class="elementor-section elementor-inner-section elementor-element elementor-element-90652b0 elementor-section-content-middle elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="90652b0" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-33 elementor-inner-column elementor-element elementor-element-e7a0d67" data-id="e7a0d67" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-b1d0bde elementor-widget elementor-widget-image" data-id="b1d0bde" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
													<img loading="lazy" decoding="async" width="152" height="117" src="https://www.inoteq.com/wp-content/uploads/2021/04/aws-ecs-logo.png" class="attachment-large size-large wp-image-1510" alt="" />													</div>
				</div>
					</div>
		</div>
				<div class="elementor-column elementor-col-33 elementor-inner-column elementor-element elementor-element-13cbe59" data-id="13cbe59" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-ecbb31a elementor-widget elementor-widget-image" data-id="ecbb31a" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
													<img loading="lazy" decoding="async" width="160" height="122" src="https://www.inoteq.com/wp-content/uploads/2021/04/aws-eks-logo.png" class="attachment-large size-large wp-image-1509" alt="" />													</div>
				</div>
					</div>
		</div>
				<div class="elementor-column elementor-col-33 elementor-inner-column elementor-element elementor-element-d23e595" data-id="d23e595" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-bc05270 elementor-widget elementor-widget-image" data-id="bc05270" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
													<img loading="lazy" decoding="async" width="149" height="120" src="https://www.inoteq.com/wp-content/uploads/2021/04/aws-ecr-logo-e1621003842985.png" class="attachment-large size-large wp-image-1511" alt="" />													</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<div class="elementor-element elementor-element-a4abbb5 elementor-widget elementor-widget-spacer" data-id="a4abbb5" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-bb2a77a elementor-widget elementor-widget-heading" data-id="bb2a77a" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Elastic Container Service</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-41222e6 elementor-widget elementor-widget-text-editor" data-id="41222e6" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Ein ECS Cluster beinhaltet alle Services, die  das Verwalten (Scheduling, Load Balancing, Container Lifecycle) der Container ermöglichen.</p><p>Die Container werden auf EC2 Instanzen gehostet, die zum Cluster verbunden sind. Auf jeder Instanz muss die Container Runtime (z.B. Docker) und ein ECS Agent installiert werden, der die Kommunikation zwischen der Control Plane (ECS) und der entsprechenden EC2 Instanz ermöglicht.</p><p>Obwohl wir die Verwaltung der Container dem ECS Service überlassen haben, müssen wir uns um die virtuellen Maschinen (EC2 Instanzen) selbst kümmern. Darunter versteht man z.B. :</p><ul><li>Erstellen der EC2 Instanz</li><li>Verbinden der Instanz zum ECS Cluster</li><li>Sicherstellen, dass genügend Ressourcen verfügbar sind</li><li>Verwalten des Betriebsystems, das auf der Instanz läuft</li><li>Docker &amp; ECS Agents</li></ul>						</div>
				</div>
				<div class="elementor-element elementor-element-f5cb072 elementor-widget elementor-widget-image" data-id="f5cb072" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img loading="lazy" decoding="async" width="652" height="212" src="https://www.inoteq.com/wp-content/uploads/2021/04/ecs-diagramm-2.png" class="attachment-large size-large wp-image-1505" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2021/04/ecs-diagramm-2.png 652w, https://www.inoteq.com/wp-content/uploads/2021/04/ecs-diagramm-2-300x98.png 300w" sizes="(max-width: 652px) 100vw, 652px" />											<figcaption class="widget-image-caption wp-caption-text">ECS - Architektur</figcaption>
										</figure>
							</div>
				</div>
				<div class="elementor-element elementor-element-175e651 elementor-widget elementor-widget-text-editor" data-id="175e651" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>EC2 lässt sich schnell und einfach mit anderen AWS Services integrieren :</p>
<ul>
<li><strong>CloudWatch</strong>&nbsp;für das Monitoring</li>
<li><strong>Elastic Load Balancer&nbsp;</strong>für das Load-balancing</li>
<li><strong>IAM&nbsp;</strong>für Authentifizierung und Autorisierung</li>
</ul>						</div>
				</div>
				<div class="elementor-element elementor-element-8c296e8 elementor-widget elementor-widget-spacer" data-id="8c296e8" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-39275f2 elementor-widget elementor-widget-heading" data-id="39275f2" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Elastic Kubernetes Cluster</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-3e7ff0e elementor-widget elementor-widget-text-editor" data-id="3e7ff0e" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Wenn wir ein EKS Cluster erstellen, werden automatisch die Kubernetes Master Nodes deployed und der Kubernetes Master Service darauf installiert. Diese Master Nodes sowie die Etcd Datei, die den Zustand und Konfiguration des Clusters beschreiben, werden auf alle Availability Zones der ausgewählten AWS Region repliziert.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-9b5a442 elementor-widget elementor-widget-image" data-id="9b5a442" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img loading="lazy" decoding="async" width="622" height="212" src="https://www.inoteq.com/wp-content/uploads/2021/04/eks-diagramm.png" class="attachment-large size-large wp-image-1506" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2021/04/eks-diagramm.png 622w, https://www.inoteq.com/wp-content/uploads/2021/04/eks-diagramm-300x102.png 300w" sizes="(max-width: 622px) 100vw, 622px" />											<figcaption class="widget-image-caption wp-caption-text">EKS - Architektur</figcaption>
										</figure>
							</div>
				</div>
				<div class="elementor-element elementor-element-18a8994 elementor-widget elementor-widget-text-editor" data-id="18a8994" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Für die Worker Nodes können wir, wie bei ECS, EC2 Instanzen benutzen, die wir zu unserem EKS Cluster verbinden. Die Kommunikation zwischen Control Plane (Master Nodes) und den VMs erfolgt über Kubernetes Worker Processes (Analog zum ECS Agent für ECS)</p>						</div>
				</div>
				<div class="elementor-element elementor-element-3942709 elementor-widget elementor-widget-heading" data-id="3942709" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h4 class="elementor-heading-title elementor-size-default">Nodegroups</h4>		</div>
				</div>
				<div class="elementor-element elementor-element-8b2f656 elementor-widget elementor-widget-text-editor" data-id="8b2f656" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Wenn wir uns mehr auf die Entwicklung der Anwendung und weniger auf die Infrastruktur fokussieren wollen, können wir entweder <strong><em>Fargate</em></strong> für eine fully-managed Compute-Fleet oder EC2 Instanzen benutzen. Es gibt allerdings eine dritte semi-managed Option &#8211; <strong>Nodegroups</strong>. <br />Eine Nodegroup (Autoscaling group + zugehörige EC2 Instanzen) übernimmt das Provisioning und die Verwaltung der Lifecycles von Nodes (EC2 Instanzen) für EKS Clusters. Jede Nodegroup benutzt die <a href="https://docs.aws.amazon.com/de_de/eks/latest/userguide/eks-optimized-ami.html">Amazon EKS-optimized Amazon Linux 2 AMI</a>. Außerdem werden alle Nodes einer Nodegroup automatisch markiert (tagged) für die auto-discovery vom Kubernetes Cluster auto-scaler. </p>						</div>
				</div>
				<div class="elementor-element elementor-element-6be3655 elementor-widget elementor-widget-heading" data-id="6be3655" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h4 class="elementor-heading-title elementor-size-default">Fargate</h4>		</div>
				</div>
				<div class="elementor-element elementor-element-3e5c0ab elementor-widget elementor-widget-text-editor" data-id="3e5c0ab" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>AWS Fargate ist ein serverloser Compute Engine Dienst für Container, der uns die oben genannten Verantwortungen übernimmt.</p><p>Wenn wir ein Container an Fargate übergeben, wird der Service Analysen durchführen, um zu schätzen, wie viel Ressourcen (CPU, RAM, &#8230;) dieser Container benötigt. Anhand dieser Informationen wird dann automatisch ein Server instanziiert, worauf der Container letztlich laufen wird. Damit müssen wir uns nicht mehr um die EC2 Instanzen kümmern und werden nur für die Ressourcen bezahlen, die unsere Container auch benötigt.</p><p>Der Nachteil eines solchen Einsatzes ist es, dass wir unflexibel sind, wenn wir mehr Konfiguration und Kontrolle über die VMs brauchen. In diesem Fall sind EC2 Instanzen eher zu empfehlen.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-ac9b016 elementor-widget elementor-widget-spacer" data-id="ac9b016" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-f881c9a elementor-widget elementor-widget-heading" data-id="f881c9a" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">EC2 Spot</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-9678761 elementor-widget elementor-widget-text-editor" data-id="9678761" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Spot Instanzen sind nicht genutzte EC2 Instanzen, die den AWS Kunden als Kaufoption mit erheblichen Ermäßigungen (bis zu 90%) zur Verfügung gestellt werden.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-dfdfc74 elementor-widget elementor-widget-heading" data-id="dfdfc74" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h4 class="elementor-heading-title elementor-size-default">Spot Allocation Strategies</h4>		</div>
				</div>
				<div class="elementor-element elementor-element-496c601 elementor-widget elementor-widget-text-editor" data-id="496c601" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Es gibt zwei Strategien bzw. Möglichkeiten, wie Spot Instanzen bei einer Spot-Anfrage zur Verfügung gestellt werden können.</p>						</div>
				</div>
				<section class="elementor-section elementor-inner-section elementor-element elementor-element-ed7bada elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="ed7bada" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-655e8c4" data-id="655e8c4" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-6de64c6 elementor-widget elementor-widget-heading" data-id="6de64c6" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h4 class="elementor-heading-title elementor-size-default">Lowest-price</h4>		</div>
				</div>
				<div class="elementor-element elementor-element-49777c4 elementor-widget elementor-widget-text-editor" data-id="49777c4" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Nimmt Instanzen aus dem <em>Spot Instance Pool, </em>die den niedrigsten Preis verlangen. Wenn der Preis sich ändert, wird die Instanz terminiert und durch eine billigere (falls vorhanden) ersetzt.</p>						</div>
				</div>
					</div>
		</div>
				<div class="elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-a487658" data-id="a487658" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-33f2cf0 elementor-widget elementor-widget-heading" data-id="33f2cf0" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h4 class="elementor-heading-title elementor-size-default">Capacity-optimized</h4>		</div>
				</div>
				<div class="elementor-element elementor-element-c413f4a elementor-widget elementor-widget-text-editor" data-id="c413f4a" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Nimmt Instanzen aus dem <em>Spot Instance Pool</em> mit optimaler Kapazität, ohne Rücksicht auf den Preis. Im Gegensatz zu der lowest-price Strategie, wird die Änderung des Preises für eine Instanz nicht zu einer Terminierung führen.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<div class="elementor-element elementor-element-9f59838 elementor-widget elementor-widget-heading" data-id="9f59838" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">EKS mit EC2 Spot</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-bb94da1 elementor-widget elementor-widget-text-editor" data-id="bb94da1" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
													</div>
				</div>
				<div class="elementor-element elementor-element-3a93229 elementor-widget elementor-widget-image" data-id="3a93229" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img decoding="async" src="https://www.inoteq.com/wp-content/uploads/2021/04/eks-cluster.png" title="" alt="" loading="lazy" />											<figcaption class="widget-image-caption wp-caption-text"></figcaption>
										</figure>
							</div>
				</div>
				<div class="elementor-element elementor-element-40befcd elementor-widget elementor-widget-spacer" data-id="40befcd" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
				<div class="elementor-element elementor-element-19a2919 elementor-widget elementor-widget-heading" data-id="19a2919" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h2 class="elementor-heading-title elementor-size-default">Container überwachen und beobachten</h2>		</div>
				</div>
				<div class="elementor-element elementor-element-54f72a9 elementor-widget elementor-widget-text-editor" data-id="54f72a9" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>In einer verteilten Architektur (z.B. Microservices) ist es extrem wichtig den Status aller aktiven Komponenten zu überwachen. Hierfür brauchen wir einen komplexeren Monitoring Service als bei einer monolithischen Anwendung, da eine einzige Anomalie einen entscheidenden Prozess beeinträchtigen könnte. In diesem Abschnitt stellen wir AWS Services vor die uns ermöglichen Anomalien auf Komponentenebene zu identifizieren, Metriken von verschiedenen Quellen der Anwendung zu sammeln und daraus Visualisierungen zu erstellen.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-5544620 elementor-widget elementor-widget-spacer" data-id="5544620" data-element_type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
					<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-a0031f2 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="a0031f2" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-4a091eb" data-id="4a091eb" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-288fb6b elementor-widget elementor-widget-heading" data-id="288fb6b" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">CloudWatch Container Insights</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-4f453fd elementor-widget elementor-widget-text-editor" data-id="4f453fd" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Container Insights stellt uns Diagnoseinformationen und Metriken bereit (CPU, Memory, Network, Container Restart Failures, etc&#8230;.). Aus diesen Metriken werden automatische Dashboards generiert, die uns helfen auftretende Probleme zu identifizieren und isoliert zu behandeln. Dieser Service ermöglicht uns auch, Alarme zu definieren, falls bestimmte Metriken definierte Thresholds unter- oder überschreiten. Außerdem können wir eigene Metriken sammeln und persönliche Dashboards einrichten, um diese Metriken zu visualisieren.</p>						</div>
				</div>
				<div class="elementor-element elementor-element-3452425 elementor-widget elementor-widget-image" data-id="3452425" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img loading="lazy" decoding="async" width="768" height="442" src="https://www.inoteq.com/wp-content/uploads/2021/04/container-insights-768x442.png" class="attachment-medium_large size-medium_large wp-image-1554" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2021/04/container-insights-768x442.png 768w, https://www.inoteq.com/wp-content/uploads/2021/04/container-insights-300x173.png 300w, https://www.inoteq.com/wp-content/uploads/2021/04/container-insights-1024x590.png 1024w, https://www.inoteq.com/wp-content/uploads/2021/04/container-insights.png 1434w" sizes="(max-width: 768px) 100vw, 768px" />											<figcaption class="widget-image-caption wp-caption-text">Container Insights - Dashboards</figcaption>
										</figure>
							</div>
				</div>
				<div class="elementor-element elementor-element-83ab749 elementor-widget elementor-widget-heading" data-id="83ab749" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h3 class="elementor-heading-title elementor-size-default">Amazon X-Ray</h3>		</div>
				</div>
				<div class="elementor-element elementor-element-37a5517 elementor-widget elementor-widget-text-editor" data-id="37a5517" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Amazon X-Ray ist ein Service zum Analysieren und Debuggen verteilter Anwendungen, die z.B. über eine Microservice Architektur verfügen.</p><p>Der Service verfolgt ankommende Requests  auf dem Weg durch einzelne Komponenten der Anwendung. An jeder Stelle werden Daten und Ressourcen zusammengefasst, aus denen am Ende eine End-to-End Ansicht der kompletten Anwendung abgebildet werden kann. Dies ermöglicht uns Anomalien schneller und präziser zu identifizieren, dadurch dass wir feststellen können, an welchen Stellen diese Anomalien stattfinden.</p><p>Das folgende Diagramm soll den Prozess und seine einzelne Schritte von X-Ray veranschaulichen </p>						</div>
				</div>
				<div class="elementor-element elementor-element-a1cb762 elementor-widget elementor-widget-image" data-id="a1cb762" data-element_type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
										<figure class="wp-caption">
										<img loading="lazy" decoding="async" width="692" height="292" src="https://www.inoteq.com/wp-content/uploads/2021/04/xray-diagramm-1.png" class="attachment-large size-large wp-image-1503" alt="" srcset="https://www.inoteq.com/wp-content/uploads/2021/04/xray-diagramm-1.png 692w, https://www.inoteq.com/wp-content/uploads/2021/04/xray-diagramm-1-300x127.png 300w" sizes="(max-width: 692px) 100vw, 692px" />											<figcaption class="widget-image-caption wp-caption-text">X-Ray - Flow Diagramm</figcaption>
										</figure>
							</div>
				</div>
				<section class="elementor-section elementor-inner-section elementor-element elementor-element-2679c0c elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="2679c0c" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-c40523d" data-id="c40523d" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-5de3ca4 elementor-widget elementor-widget-heading" data-id="5de3ca4" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h5 class="elementor-heading-title elementor-size-default">1) Collect Traces</h5>		</div>
				</div>
				<div class="elementor-element elementor-element-ccfedc0 elementor-widget elementor-widget-text-editor" data-id="ccfedc0" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Informationen zu einer Webanfrage werden über die Anwendung hinweg von allen Services gesammelt.</p>						</div>
				</div>
					</div>
		</div>
				<div class="elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-3000b36" data-id="3000b36" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-4a104b0 elementor-widget elementor-widget-heading" data-id="4a104b0" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h5 class="elementor-heading-title elementor-size-default">2) Record Traces</h5>		</div>
				</div>
				<div class="elementor-element elementor-element-c775305 elementor-widget elementor-widget-text-editor" data-id="c775305" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Diese Daten werden zu einem sogenannten Trace kombiniert.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-inner-section elementor-element elementor-element-895620b elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="895620b" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-743d7ce" data-id="743d7ce" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-83ed27f elementor-widget elementor-widget-heading" data-id="83ed27f" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h5 class="elementor-heading-title elementor-size-default">3) View Service Map</h5>		</div>
				</div>
				<div class="elementor-element elementor-element-3db2210 elementor-widget elementor-widget-text-editor" data-id="3db2210" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Aus diesen Traces wird eine Service Map erstellt, die die Verknüpfungen der Services darstellt. Zudem stellt uns diese Ansicht ein paar Informationen über die Services zur Verfügung (z.B. HTTP Status Codes, Latenz, andere Metadata, etc..)</p>						</div>
				</div>
					</div>
		</div>
				<div class="elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-879fb14" data-id="879fb14" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-051193f elementor-widget elementor-widget-heading" data-id="051193f" data-element_type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
			<h5 class="elementor-heading-title elementor-size-default">4) Analyze Issues</h5>		</div>
				</div>
				<div class="elementor-element elementor-element-11851e2 elementor-widget elementor-widget-text-editor" data-id="11851e2" data-element_type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
							<p>Der Service, der ein unerwartetes Verhalten zeigt, kann nun anhand geeigneter Tools tiefer analysiert werden.</p>						</div>
				</div>
					</div>
		</div>
					</div>
		</section>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-b47d3c3 elementor-section-boxed elementor-section-height-default elementor-section-height-default" data-id="b47d3c3" data-element_type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-be0fc41" data-id="be0fc41" data-element_type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
							</div>
		</div>
					</div>
		</section>
				</div>
		<p>Der Beitrag <a href="https://www.inoteq.com/2021/04/30/containers-in-aws/">Container in der AWS Cloud betreiben und überwachen</a> erschien zuerst auf <a href="https://www.inoteq.com">INOTEQ GmbH</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.inoteq.com/2021/04/30/containers-in-aws/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>
