JAX-RS Restful-Service

  • Antworten:12
Uf Fe
  • Forum-Beiträge: 22

19.03.2014, 07:24:59 via Website

Hallo miteinander,

bin gerade dabei mir einen Webservice zum Upload von Daten einzurichten. Client-Server Kommunikation funktioniert schon.
Ich habe bis jetzt folgenden Code:

Webservice:

1@POST
2 @Path("/upload/")
3 @Consumes(MediaType.MULTIPART_FORM_DATA)
4 public Response uploadFile(@FormDataParam("file") final InputStream uploadedInputStream,
5 @FormDataParam("filename") final String name)
6 {
7
8 String uploadedFileLocation = "d://uploaded/" + name;
9
10 // save it
11 writeToFile(uploadedInputStream, uploadedFileLocation);
12
13 String output = "File uploaded to : " + uploadedFileLocation;
14
15 return Response.status(200).entity(output).build();
16
17 }

Und Handyseite:

1// will post our text file
2 private void postFile(final String uploadFilePath)
3 {
4 try
5 {
6 // the file to be posted
7 // String uploadFilePath = Environment.getExternalStorageDirectory() + "/sample.txt";
8 Log.v(TAG, "textFile: " + uploadFilePath);
9
10 // the URL where the file will be posted
11 String postReceiverUrl = "<URLzuWebservice/restful/upload>";
12 Log.v(TAG, "postURL: " + postReceiverUrl);
13
14 // new HttpClient
15 HttpClient httpClient = new DefaultHttpClient();
16
17 // post header
18
19 File file = new File(uploadFilePath);
20 FileBody fileBody = new FileBody(file, file.getName(), "text/plain", "UTF-8");
21
22 HttpPost httpPost = new HttpPost(postReceiverUrl);
23
24 MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
25 reqEntity.addPart("filename", new StringBody(file.getName()));
26 reqEntity.addPart("file", fileBody);
27 System.out.println(reqEntity.toString());
28 // System.out.println(file.get);
29
30 httpPost.setEntity(reqEntity);
31
32 // execute HTTP post request
33 HttpResponse response = httpClient.execute(httpPost);
34
35 HttpEntity resEntity = response.getEntity();
36
37 httpClient.getConnectionManager().shutdown();
38
39 if(resEntity != null)
40 {
41
42 String responseStr = EntityUtils.toString(resEntity).trim();
43 Log.v(TAG, "Response: " + responseStr);
44
45 // you can add an if statement here and do other actions based on the response
46 }
47
48 }
49 catch(NullPointerException e)
50 {
51 e.printStackTrace();
52 }
53 catch(Exception e)
54 {
55 e.printStackTrace();
56 }
57 }

Dies funktioniert auch wunderbar. Jedoch an der Stelle reqEntity.addPart wird immer nur der erste Befehl abgesetzt, sobald ich mehr Infos hinzufügen möchte, wird immer nur das Erste übertragen. Was mache ich falsch?
Und noch eine Frage, ich habe praktisch mehrere Daten, wie Vorname, Nachname.... zu übergeben, um diese in eine DB zu speichern. Zusätzlich kann man mehrere Bilder mit übergeben. Soll das alles mit einem Aufruf wie in diesem Beispiel geschehen? Ist das die richtige Vorgehensweise?

Danke schon mal für die Antworten

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

19.03.2014, 12:06:19 via Website

zumindest für die vornamen nachnamen sachen würde ich eher json verwenden, selbst images könntest du als Base64 String in json packen.
Damit hättest du einen langen json string. Das wäre auch ein simplet HTTP Post bzw Put in REST

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Uf Fe
  • Forum-Beiträge: 22

24.03.2014, 11:52:11 via Website

Danke für die Antwort, aber mit dem BASE64 String im JSON-Objekt habe ich Probleme.
Das funktioniert nur bis zu einer gewissen Größe.
Wie könnte man das noch anders hochladen?

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

24.03.2014, 12:07:23 via Website

Hmm,

evtl sagt man einfach nur dem Server das es ein Bild gibt, und er gibt einem eine ID dazu zurück, diese Synct man dann im Hintergrund mit der ID vom Server.
Am ehesten ist da sicher ein SyncAdapter für geeignet. Allerdings sind jetzt recht viele schritte dazwischen, was meist Fehleranfällig ist. Ich bin auch kein großer Freund davon Zig HTTP Calls zu machen für eine Resource.

In deinem Provider der den (REST)State der Images hält müsstest du halt entsprechend sowas abbilden.

Aber das weicht alles sehr von dem ab was du gerade machst, daher würde Ich erstmal versuchen damit ein wenig weiter zu kommen.
Wenn Sich das als eher unbrauchbar rausstellt würde Ich evtl diesen Ansatz wählen.

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Uf Fe
  • Forum-Beiträge: 22

25.03.2014, 10:29:07 via Website

So habe mich dazu entschlossen mit Sync Adapter zu arbeiten, und wollte jetzt nachfragen, ob jemand ein gutes Tutorial dazu kennt?

Antworten
Uf Fe
  • Forum-Beiträge: 22

25.03.2014, 15:41:04 via Website

Ok, danke für die Hilfe.
Kämpfe mich den ganzen Tag schon durch diverse Tutorials, aber komm einfach nicht weiter.
Weiß irgendjemand ein gutes Tutorial auf Deutsch?

Antworten
Uf Fe
  • Forum-Beiträge: 22

01.04.2014, 11:53:37 via Website

So habe jetzt den SyncService zum laufen gebracht. Jetzt noch ein Frage, wenn z.B. Daten aus ListFragment hochgeladen wurde, und jetzt das ListFragment aktualisiert werden muss. Da im Cursor noch die alten Daten drin sind. Wir benachrichtige ich am besten das Fragment, dass der Upload erfolgreich war? Mit einem BroadcastReciever oder gibt es da auch andere Varianten?

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

01.04.2014, 12:50:54 via Website

Hi,

du kannst über die URI einen Notification an den Cursor (z.b den Observer der URI) machen.

Dafür musst du in deinem ContentProvider beim #query deine URI registrieren z.b
1@Override
2 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
3 {
4 final SQLiteQueryBuilder query = new SQLiteQueryBuilder();
5 final SQLiteDatabase db = database.getReadableDatabase();
6
7
8 switch (URI_MATCHER.match(uri))
9 {
10 ......
11 ......
12 default:
13 throw new IllegalArgumentException("Unsupported Uri:" + uri);
14
15 }
16
17 final Cursor cursor = query.query(db, projection, selection, selectionArgs, null, null, sortOrder);
18 cursor.setNotificationUri(getContext().getContentResolver(), uri);
19 return cursor;
20 }

Sobald du also die DB änderst musst du den Cursor benachrichtigen, also insert update delete

1getContext().
2 getContentResolver().
3 notifyChange(itemUri, null);

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Uf Fe
  • Forum-Beiträge: 22

02.04.2014, 11:15:10 via Website

Habe mich jetzt für BroadcastReciever entschieden, dieser wird jedes mal angestoßen, wenn er mit syncen fertig ist.

Nochmal eine Frage wegen des Base64 String. Da ich immer OutOfMemory Exceptions bekomme, bin ich jetzt schon am verzweifeln. Und den Ansatz mit der Id die der Server zurückgibt, hab ich nicht ganz verstanden

Antworten
Uf Fe
  • Forum-Beiträge: 22

02.04.2014, 11:16:54 via Website

Hilt es mit Gson oder Jackson zu arbeiten?

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

03.04.2014, 17:40:20 via Website

kA, wieso da jetzt eine OOME fliegt. Base64 vergrößert die Daten erheblich. Wenn du Megabyte weise Bild Daten als Base64 codierst kann das schon sein. Jackson etc sind gute parser, hab damit vieles schon gemacht. Du musst halt zusehen das du evtl nur ein Bild codierst um RAM zu sparen, je mach Device/Android Version kann der RAM den eine APP zur Verfügung hat variieren, gewöhnlich sind heute 16mb oder mehr. Prüfe auch mal ob du referenzen wieder freigibst...

Zur Uri Notification:
Angenommen du hast einen ListView der per Cursor Daten auf der Liste anzeigt. Dieser Cursor kann über die URI mitbekommen das Daten in der Datenbank
geändert wurden, was einen "requery" auslöst. Ist also ein Software Pattern: MVP/MVC
So was kann man auch selbst programmieren, ist aber in der Regel großer Unsinn.

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Uf Fe
  • Forum-Beiträge: 22

15.04.2014, 09:32:33 via Website

So habe noch eine Frage und zwar habe ich jetzt immer so gearbeitet, dass bei mir jede Tabelle eine Spalte mit dem SyncState synced oder notsynced hatte. Aber jetzt habe ich gelesen, dass anscheinend der contentprovider automatisch ein create flag setzt, und dieses nach erfolgreicherer Synchronisation verschwindet. Aber wie funktioniert das? Bzw. wie kann ich auf dieses create flag abfragen?

Antworten