Nachdem wir im ersten Teil die Basisanwendung und erste Webhooks integriert haben, folgen in diesem zweiten Teil nun weitere Integrationen in unsere Confluence-Cloud-Entwicklungsinstanz.
Dynamisch erstellte Seite in Confluence Cloud verlinken und darstellen
Wir erstellen zunächst einen Spring-Controller, der ein einfaches Template mit der Template-Sprache Thymeleaf rendert und einen Parameter zum Render-Kontext beisteuert:
@Controller public class InfoController { @RequestMapping(value = "/info-page", method = RequestMethod.GET) public String infoPage(@AuthenticationPrincipal AtlassianHostUser hostUser, Model model) { model.addAttribute("userKey", hostUser.getUserKey()); return "info-page"; } }
In unserem Template geben wir den Parameter aus und stellen ebenfalls alle anderen verfügbaren Parameter unseres Render-Kontexts dar:
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <script th:src="@{${atlassianConnectAllJsUrl}}" type="text/javascript"></script> <link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/6.0.0/css/aui.min.css" media="all"/> <link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/6.0.0/css/aui-experimental.min.css" media="all"/> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> </head> <body> <div> <h2>//SEIBERT/MEDIA Cloud Application</h2> <dl> <dt>User-Key</dt> <dd th:text="${userKey}"/> </dl> <hr/> <table class="aui"> <tr th:each="var : ${#vars}"> <td th:text="${var.key}"></td> <td th:text="${var.value}"></td> </tr> </table> </div> </body> </html>
Nun ergänzen wir den Plugin-Descriptor um das folgende Element, um die Darstellung unserer Seite in der Confluence-Cloud-Instanz zu registrieren:
"modules": { "generalPages": [ { "url": "/info-page", "name": { "value": "Seibert Media" }, "key": "sm-info-page" } ] }
Danach ergänzen wir ein weiteres Element im Descriptor, um im Atlassian-Hilfemenü eine Verknüpfung auf unsere dynamische Seite zu erzeugen:
"modules": { "webItems": [ { "key": "info-page-web-item", "location": "system.help", "weight": 200, "url": "/info-page", "name": { "value": "Seibert Media" } } ] }
Dann müssen wir (wie im ersten Teil des Tutorial demonstriert) unseren Plugin-Descriptor erneut hochladen.
Im Anschluss daran können wir über das Hilfemenü unsere dynamisch und Server-seitig erzeugte Seite aufrufen:
Confluence-Cloud-Daten per REST-Client abrufen
Im nächsten Beispiel möchten wir Build-Informationen, die Confluence Cloud über eine REST-Ressource bereitstellt, abrufen.
Dazu werden wir aus unserer Spring-Boot-Anwendung heraus eine OAuth2-authentifizierte Client-Verbindung zu den RESTful Webservices unserer Confluence-Cloud-Instanz aufbauen und die abgerufenen Build-Informationen wiederum unter einer URL verfügbar machen.
Dies ist unser Datentransferobjekt (DTO), das einige der Build-Informationen kapselt:
public class BuildInformation { private String versionNumber; private String buildTimestamp; private String buildNumber; private String revisionNumber; // getter, setter, tostring... }
Hier ist unser beispielhafter REST-Client, der mittels AtlassianHostRestClients
eine authentifizierte Verbindung zur Confluence-Cloud-Instanz aufbaut:
@Service public class ConfluenceClientService { [..] @Autowired private AtlassianHostRestClients atlassianHostRestClients; public BuildInformation getBuildInformation(String baseUrl) { String url = baseUrl + "/rest/prototype/latest/buildInfo"; log.info("calling confluence host with api-url: {}", url); return atlassianHostRestClients.authenticatedAsAddon() .getForObject(url, BuildInformation.class); } }
Dies ist ein vereinfachter Controller, der von der ersten ihm bekannten Confluence-Cloud-Instanz die URL ermittelt, sie an den REST-Client übergibt und dann die Ansicht der Build-Informationen darstellt.
In einem Produktivszenario müssten wir natürlich die Tatsache berücksichtigen, dass 0..n Confluence-Cloud-Instanzen mit unserer Spring-Boot-Anwendung verbunden sein können.
@Controller public class ConnectedHostsAudit { @Autowired ConfluenceClientService confluenceClientService; @Autowired AtlassianHostRepository atlassianHostRepository; @RequestMapping("/build-info") public String buildInformationPage(Model model) { AtlassianHost host = atlassianHostRepository.findAll().iterator().next(); String baseUrl = host.getBaseUrl(); BuildInformation buildInformation = confluenceClientService.getBuildInformation(baseUrl); model.addAttribute("buildInformation", buildInformation); model.addAttribute("host", host); return "build-info"; } }
Das folgende Thymeleaf-Template stellt die abgerufenen Build-Informationen dar:
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <script th:src="@{${atlassianConnectAllJsUrl}}" type="text/javascript"></script> <link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/6.0.0/css/aui.min.css" media="all"/> <link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/6.0.0/css/aui-experimental.min.css" media="all"/> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> <script src="https:///aui-cdn.atlassian.com/aui-adg/6.0.0/js/aui.min.js"></script> </head> <body> <div> <h2>//SEIBERT/MEDIA Cloud Application - Build Information for Host '<span th:text="${host.baseUrl}"/>'</h2> <table class="aui"> <tr> <td>versionNumber</td> <td th:text="${buildInformation.versionNumber}"></td> </tr> <tr> <td>buildTimestamp</td> <td th:text="${buildInformation.buildTimestamp}"></td> </tr> <tr> <td>buildNumber</td> <td th:text="${buildInformation.buildNumber}"></td> </tr> <tr> <td>revisionNumber</td> <td th:text="${buildInformation.revisionNumber}"></td> </tr> </table> </div> </body> </html>
Nun lassen sich die Build-Informationen unter der konfigurierten Adresse abrufen, wie im folgenden Screenshot zu sehen ist:
Soweit dieses zweiteilige Tutorial zu Confluence-Cloud-Apps mit Spring Boot und Atlassian Connect. Haben Sie Fragen oder Anmerkungen? Gibt es spezifische Anwendungsfälle oder Herausforderungen im Zusammenhang mit Ihren Atlassian-Systemen, die durch individuelle Add-ons oder Integrationen gelöst werden könnten? Melden Sie sich bei uns: Wir freuen uns darauf, mit Ihnen ins Gespräch zu kommen!
Mehr über die Creative-Commons-Lizenz erfahren