{"id":8528,"date":"2017-07-18T03:33:22","date_gmt":"2017-07-18T01:33:22","guid":{"rendered":"http:\/\/blog.wenzlaff.de\/?p=8528"},"modified":"2020-04-07T08:52:18","modified_gmt":"2020-04-07T06:52:18","slug":"standalone-restful-server-und-client-mit-dem-restlet-framework","status":"publish","type":"post","link":"http:\/\/blog.wenzlaff.de\/?p=8528","title":{"rendered":"Standalone RESTful Server und Client mit dem Restlet Framework"},"content":{"rendered":"<p>Manchmal braucht man in Java einen <a href=\"https:\/\/de.wikipedia.org\/wiki\/Representational_State_Transfer\" target=\"_blank\" rel=\"noopener noreferrer\">REST<\/a> Server oder Client oder beides. Das ist mit dem Restlet Framework schnell implementiert.<\/p>\n<p><a href=\"http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2017\/07\/Rest.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8530\" src=\"http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2017\/07\/Rest.png\" alt=\"\" width=\"2732\" height=\"2048\" srcset=\"http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2017\/07\/Rest.png 2732w, http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2017\/07\/Rest-300x225.png 300w, http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2017\/07\/Rest-768x576.png 768w, http:\/\/blog.wenzlaff.de\/wp-content\/uploads\/2017\/07\/Rest-1024x768.png 1024w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/a><\/p>\n<p>Es kann entweder das ganze Beispielprojekt von <a href=\"https:\/\/github.com\/IT-Berater\/TWRestUmgebung\" target=\"_blank\" rel=\"noopener noreferrer\">Github<\/a> geladen werden oder diese Schritte ausgef\u00fchrt werden:<\/p>\n<p>Zuerst richten wir in Eclipse ein neues Maven Projekt ein und f\u00fcgen der pom.xml diese Eintr\u00e4ge hinzu:<!--more--><\/p>\n<pre class=\"lang:xhtml decode:true \">&lt;project xmlns=\"http:\/\/maven.apache.org\/POM\/4.0.0\" xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\r\n\txsi:schemaLocation=\"http:\/\/maven.apache.org\/POM\/4.0.0 http:\/\/maven.apache.org\/maven-v4_0_0.xsd\"&gt;\r\n\t&lt;modelVersion&gt;4.0.0&lt;\/modelVersion&gt;\r\n\t&lt;groupId&gt;de.wenzlaff.umgebung&lt;\/groupId&gt;\r\n\t&lt;artifactId&gt;de.wenzlaff.umgebung&lt;\/artifactId&gt;\r\n\t&lt;packaging&gt;jar&lt;\/packaging&gt;\r\n\t&lt;version&gt;1.0-SNAPSHOT&lt;\/version&gt;\r\n\t&lt;name&gt;RestUmgebung&lt;\/name&gt;\r\n\t&lt;url&gt;http:\/\/www.wenzlaff.info&lt;\/url&gt;\r\n\r\n\t&lt;repositories&gt;\r\n\t\t&lt;repository&gt;\r\n\t\t\t&lt;id&gt;maven-restlet&lt;\/id&gt;\r\n\t\t\t&lt;name&gt;Public online Restlet repository&lt;\/name&gt;\r\n\t\t\t&lt;url&gt;http:\/\/maven.restlet.org&lt;\/url&gt;\r\n\t\t&lt;\/repository&gt;\r\n\t&lt;\/repositories&gt;\r\n\t&lt;properties&gt;\r\n\t\t&lt;project.build.sourceEncoding&gt;UTF-8&lt;\/project.build.sourceEncoding&gt;\r\n\t\t&lt;restlet-version&gt;2.3.10&lt;\/restlet-version&gt;\r\n\t\t&lt;maven.compiler.source&gt;1.8&lt;\/maven.compiler.source&gt;\r\n\t\t&lt;maven.compiler.target&gt;1.8&lt;\/maven.compiler.target&gt;\r\n\t&lt;\/properties&gt;\r\n\t&lt;build&gt;\r\n\t\t&lt;plugins&gt;\r\n\t\t\t&lt;plugin&gt;\r\n\t\t\t\t&lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;\r\n\t\t\t\t&lt;artifactId&gt;maven-compiler-plugin&lt;\/artifactId&gt;\r\n\t\t\t\t&lt;version&gt;3.6.1&lt;\/version&gt;\r\n\t\t\t\t&lt;configuration&gt;\r\n\t\t\t\t\t&lt;source&gt;1.8&lt;\/source&gt;\r\n\t\t\t\t\t&lt;target&gt;1.8&lt;\/target&gt;\r\n\t\t\t\t&lt;\/configuration&gt;\r\n\t\t\t&lt;\/plugin&gt;\r\n\t\t&lt;\/plugins&gt;\r\n\t&lt;\/build&gt;\r\n\t&lt;dependencies&gt;\r\n\t\t&lt;!-- Java Standalone --&gt;\r\n\t\t&lt;dependency&gt;\t\t\r\n\t\t\t&lt;groupId&gt;org.restlet.jse&lt;\/groupId&gt;\r\n\t\t\t&lt;artifactId&gt;org.restlet&lt;\/artifactId&gt;\r\n\t\t\t&lt;version&gt;${restlet-version}&lt;\/version&gt;\r\n\t\t&lt;\/dependency&gt;\r\n\t\t&lt;dependency&gt;\r\n\t\t\t&lt;groupId&gt;org.restlet.jse&lt;\/groupId&gt;\r\n\t\t\t&lt;artifactId&gt;org.restlet.ext.simple&lt;\/artifactId&gt;\r\n\t\t\t&lt;version&gt;${restlet-version}&lt;\/version&gt;\r\n\t\t&lt;\/dependency&gt;\r\n\t\t&lt;!-- Java Jackson unterst\u00fczung um Objekte zu serialisieren --&gt;\r\n\t\t&lt;dependency&gt;\r\n\t\t\t&lt;groupId&gt;org.restlet.jee&lt;\/groupId&gt;\r\n\t\t\t&lt;artifactId&gt;org.restlet.ext.jackson&lt;\/artifactId&gt;\r\n\t\t\t&lt;version&gt;${restlet-version}&lt;\/version&gt;\r\n\t\t&lt;\/dependency&gt;\r\n\t\t&lt;!-- Testframework JUnit --&gt;\r\n\t\t&lt;dependency&gt;\r\n\t\t\t&lt;groupId&gt;junit&lt;\/groupId&gt;\r\n\t\t\t&lt;artifactId&gt;junit&lt;\/artifactId&gt;\r\n\t\t\t&lt;version&gt;4.12&lt;\/version&gt;\r\n\t\t\t&lt;scope&gt;test&lt;\/scope&gt;\r\n\t\t&lt;\/dependency&gt;\r\n\t&lt;\/dependencies&gt;\r\n&lt;\/project&gt;\r\n<\/pre>\n<p>Den Standalone Server machen wir mit zwei Klassen:<\/p>\n<pre class=\"lang:java decode:true \">\t\r\npackage de.wenzlaff.umgebung;\r\n\r\nimport org.restlet.Component;\r\nimport org.restlet.data.Protocol;\r\n\r\n\/**\r\n * Ein Beispiel Standalone Server.\r\n * \r\n * @author Thomas Wenzlaff\r\n *\r\n *\/\r\npublic class StandaloneServer {\r\n\r\n\tpublic static final Integer PORT = 6969;\r\n\r\n\tpublic static final String HOST = \"http:\/\/localhost:\" + PORT;\r\n\r\n\tpublic static void main(String[] args) throws Exception {\r\n\r\n\t\tThread t = new Thread(new Runnable() {\r\n\t\t\t@Override\r\n\t\t\tpublic void run() {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tStandaloneServer.start();\r\n\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\tSystem.err.println(e.getMessage());\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\t\tt.start();\r\n\t}\r\n\r\n\t\/**\r\n\t * Der Server mit der Hauptanwendung.\r\n\t * \r\n\t * Aufruf \u00fcber\r\n\t * \r\n\t * http:\/\/localhost:9696\/umgebung\/\r\n\t * \r\n\t * http:\/\/localhost:9696\/umgebung\/service\r\n\t * \r\n\t * http:\/\/localhost:9696\/umgebung\/version\r\n\t * \r\n\t * @param args\r\n\t * @throws Exception\r\n\t *\/\r\n\tpublic static void start() throws Exception {\r\n\t\tComponent component = new Component();\r\n\t\tcomponent.getServers().add(Protocol.HTTP, PORT);\r\n\r\n\t\tcomponent.getDefaultHost().attach(\"\/umgebung\", new UmgebungsZiele());\r\n\r\n\t\tcomponent.start();\r\n\t}\r\n}\r\n\r\n<\/pre>\n<p>Und noch eine Klasse von <strong>Application<\/strong> erben und die Routen bzw. die URLs angeben:<\/p>\n<pre class=\"lang:java decode:true \" >package de.wenzlaff.umgebung;\r\n\r\nimport org.restlet.Application;\r\nimport org.restlet.Restlet;\r\nimport org.restlet.routing.Router;\r\n\r\nimport de.wenzlaff.umgebung.resource.InfoResource;\r\nimport de.wenzlaff.umgebung.resource.MindmapResource;\r\nimport de.wenzlaff.umgebung.resource.UmgebungResource;\r\nimport de.wenzlaff.umgebung.resource.VersionResource;\r\n\r\n\/**\r\n * Bearbeitet alle Aufrufe f\u00fcr den Server.\r\n * \r\n * @author Thomas Wenzlaff\r\n *\r\n *\/\r\npublic class UmgebungsZiele extends Application {\r\n\r\n\t\/**\r\n\t * Erzeugt den root Restlet der alle eingehende Aufrufe bearbeitet.\r\n\t * \r\n\t * http:\/\/localhost:9696\/umgebung\/\r\n\t * \r\n\t * http:\/\/localhost:9696\/umgebung\/service\r\n\t * \r\n\t * http:\/\/localhost:9696\/umgebung\/version\r\n\t * \r\n\t *\/\r\n\t@Override\r\n\tpublic synchronized Restlet createInboundRoot() {\r\n\r\n\t\tRouter router = new Router(getContext());\r\n\r\n\t\trouter.attach(\"\/\", InfoResource.class);\r\n\t\trouter.attach(\"\/service\", UmgebungResource.class);\r\n\t\trouter.attach(\"\/version\", VersionResource.class);\r\n\t\trouter.attach(\"\/mindmap\", MindmapResource.class);\r\n\r\n\t\treturn router;\r\n\t}\r\n\r\n}\r\n<\/pre>\n<p>Dann noch eine <strong>UmgebungResource<\/strong> anlegen, die von <strong>ServerResource<\/strong> erbt. <\/p>\n<pre class=\"lang:java decode:true \" >package de.wenzlaff.umgebung.resource;\r\n\r\nimport org.restlet.resource.Get;\r\nimport org.restlet.resource.ServerResource;\r\n\r\n\/**\r\n * Liefert die Systemumgebung.\r\n * \r\n * @author Thomas Wenzlaff\r\n *\r\n *\/\r\npublic class UmgebungResource extends ServerResource implements Umgebung {\r\n\r\n\t@Override\r\n\t@Get\r\n\tpublic String getUmgebung() {\r\n\t\treturn \"Umgebung:\\n\" + System.getProperties().toString().replaceAll(\",\", \"\\n\");\r\n\t}\r\n\r\n}<\/pre>\n<p>Daf\u00fcr auch gleich noch ein Interface mit Klassennamen <strong>Umgebung<\/strong> und der Annotation <strong>@get<\/strong> anlegen:<\/p>\n<pre class=\"lang:java decode:true \" >package de.wenzlaff.umgebung.resource;\r\n\r\nimport org.restlet.resource.Get;\r\n\r\n\/**\r\n * Interface f\u00fcr die Umgebung.\r\n * \r\n * @author Thomas Wenzlaff\r\n *\r\n *\/\r\npublic interface Umgebung {\r\n\r\n\t@Get\r\n\tString getUmgebung();\r\n\r\n}<\/pre>\n<p>Das ist schon alles f\u00fcr den Server. Wir wollen das aber ja nicht nur \u00fcber den Browser testen. Deshalb einen Client in einer JUnit Testklasse verpackt:<\/p>\n<pre class=\"lang:java decode:true \" >package de.wenzlaff.umgebung;\r\n\r\nimport static org.junit.Assert.assertEquals;\r\nimport static org.junit.Assert.assertTrue;\r\n\r\nimport org.junit.BeforeClass;\r\nimport org.junit.Test;\r\nimport org.restlet.resource.ClientResource;\r\n\r\nimport de.wenzlaff.umgebung.resource.Mindmap;\r\nimport de.wenzlaff.umgebung.resource.MindmapModell;\r\nimport de.wenzlaff.umgebung.resource.Umgebung;\r\nimport de.wenzlaff.umgebung.resource.Version;\r\n\r\n\/**\r\n * Testklasse f\u00fcr den Server.\r\n * \r\n * @author Thomas Wenzlaff\r\n *\r\n *\/\r\npublic class ServerAppTest {\r\n\r\n\t@BeforeClass\r\n\tpublic static void startServer() throws Exception {\r\n\t\tStandaloneServer.start();\r\n\t}\r\n\r\n\t@Test\r\n\tpublic void testGetUmgebungVersion() throws Exception {\r\n\r\n\t\tString hostUrl = StandaloneServer.HOST + \"\/umgebung\/version\";\r\n\t\tSystem.out.println(\"Anfrage von: \" + hostUrl);\r\n\r\n\t\tClientResource clientResource = new ClientResource(hostUrl);\r\n\r\n\t\tVersion resource = clientResource.wrap(Version.class);\r\n\r\n\t\tString vers = resource.getVersion();\r\n\r\n\t\tSystem.out.println(vers);\r\n\r\n\t\tassertEquals(\"0.0.1\", vers);\r\n\t}\r\n\r\n\t@Test\r\n\tpublic void testGetUmgebungService() throws Exception {\r\n\r\n\t\tString hostUrl = StandaloneServer.HOST + \"\/umgebung\/service\";\r\n\t\tSystem.out.println(\"Anfrage von: \" + hostUrl);\r\n\r\n\t\tClientResource clientResource = new ClientResource(hostUrl);\r\n\r\n\t\tUmgebung resource = clientResource.wrap(Umgebung.class);\r\n\r\n\t\tString vers = resource.getUmgebung();\r\n\r\n\t\tSystem.out.println(vers);\r\n\t\tassertTrue(vers.length() &gt; 10);\r\n\t}\r\n\r\n\t\/**\r\n\t * Ben\u00f6tigt org.restlet.ext.jackson in der pom.xml\r\n\t * \r\n\t * @throws Exception\r\n\t *\/\r\n\t@Test\r\n\tpublic void testGetUmgebungMindmap() throws Exception {\r\n\r\n\t\tString hostUrl = StandaloneServer.HOST + \"\/umgebung\/mindmap\";\r\n\t\tSystem.out.println(\"Anfrage von: \" + hostUrl);\r\n\r\n\t\tClientResource clientResource = new ClientResource(hostUrl);\r\n\r\n\t\tMindmap resource = clientResource.wrap(Mindmap.class);\r\n\r\n\t\tMindmapModell m = resource.getMindmap();\r\n\r\n\t\tif (m == null) {\r\n\t\t\tSystem.err.println(\"Es fehlt evl. die org.restlet.ext.jackson unterst\u00fczung in der pom.xml\");\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tassertEquals(\"0.0.1\", m.getVersion());\r\n\r\n\t\tSystem.out.println(\"Mindmap Version: \" + m.getVersion());\r\n\t\tSystem.out.println(\"Mindmap Name: \" + m.getName());\r\n\t\tSystem.out.println(\"Erstellungs Datum: \" + m.getErstellungsDatum());\r\n\t\tSystem.out.println(m);\r\n\r\n\t}\r\n\r\n}\r\n<\/pre>\n<p>Ist die Beschreibung ausf\u00fchrlich genug? Weitere Details siehe auch im Beispielprojekt auf <a href=\"https:\/\/github.com\/IT-Berater\/TWRestUmgebung\" target=\"_blank\" rel=\"noopener noreferrer\">Github<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Manchmal braucht man in Java einen REST Server oder Client oder beides. Das ist mit dem Restlet Framework schnell implementiert. Es kann entweder das ganze Beispielprojekt von Github geladen werden oder diese Schritte ausgef\u00fchrt werden: Zuerst richten wir in Eclipse ein neues Maven Projekt ein und f\u00fcgen der pom.xml diese Eintr\u00e4ge hinzu:<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_import_markdown_pro_load_document_selector":0,"_import_markdown_pro_submit_text_textarea":"","footnotes":""},"categories":[3,5,79],"tags":[116,2939,2487,2938,83,2940],"class_list":["post-8528","post","type-post","status-publish","format-standard","hentry","category-allgemein","category-java","category-programmierung","tag-client","tag-get","tag-rest","tag-restful","tag-server","tag-umgebung"],"_links":{"self":[{"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=\/wp\/v2\/posts\/8528","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=8528"}],"version-history":[{"count":0,"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=\/wp\/v2\/posts\/8528\/revisions"}],"wp:attachment":[{"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=8528"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=8528"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.wenzlaff.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=8528"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}