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


