# allgemeine Datenbankschnittstelle für Webservice



## snoopy007 (22. Okt 2007)

Hallo,

vielleicht hat ja schon jemand eine Lösung für die Fragestellung.

Realisieren gerade eine Schnittstelle per Webservice. Serverseitig hängt eine Datenbank dran.
Client soll nun in der Lage sein, die DB per Webservice abzufragen. 

Stelle mir das ganze vor:
getDatas (tabelle, spalte, typ)
setDatas (tabelle,dpalte,typ).

Problem ist nun der Rückgabewert. Mal ist es ein Integer, mal ein String, dann wieder bool ...
Wie könnte man das realisieren.

Schonmal merci,
snoopy007


----------



## Niki (22. Okt 2007)

Ich hätte zwei Ansätze.
1.) Voraussetzungen der Client läuft unter Java und hat die selbe Runtime Version:
Du baust als return-Wert einen ComplexType mit der Information um welchen Typ es sich handelt. Der Wert selbst wird als byte[] serialisiert zurück geliefert (primitive Typen sollten gewrappt werden):


```
<complexType name="ReturnType">
    <sequence>
     <element name="object" nillable="true" type="xsd:base64Binary"/>
     <element name="type" nillable="true" type="xsd:string"/>
    </sequence>
   </complexType>
```

2.) Du baust einen ComplexType der den Typ zurück liefert und für jeden möglichen Typ ein eigenes Feld:


```
<complexType name="ReturnType">
    <sequence>
     <element name="intVal" nillable="true" type="xsd:int"/>
     <element name="longVal" nillable="true" type="xsd:long"/>
     <element name="stringVal" nillable="true" type="xsd:string"/>
     <element name="type" nillable="true" type="xsd:string"/>
    </sequence>
   </complexType>
```


----------



## snoopy007 (23. Okt 2007)

Hallo,


erstmal Dank für Deine Antwort. Bin aber leider nicht so der Freak  :wink: .
Kannst Du es mit Javacode ein wenig mehr auffüllen ? :applaus: 

Schonmal Danke,
snoopy007


----------



## Niki (23. Okt 2007)

Ok, ich mache das ganze mit axis und ant. Hier die notwendigen files:

Interface MyWebService

```
public interface MyWebService extends java.rmi.Remote {
    public service.ReturnType foh() throws java.rmi.RemoteException;
    public service._ReturnType _foh() throws java.rmi.RemoteException;
}
```

Implementierung MyWebServiceImpl

```
public class MyWebServiceImpl implements MyWebService {

	public _ReturnType _foh() throws RemoteException {
		// Query...
		_ReturnType rt = null;
		try {
			String s = "Result";
			rt = new _ReturnType();
			rt.setType("java.lang.String");
			rt.setObject(getObjectAsBytes(s));
		} catch (Exception ex) {
			throw new RemoteException("object cannot get serialized", ex);
		}

		return rt;

	}

	public ReturnType foh() throws RemoteException {
		ReturnType rt = new ReturnType();
		rt.setStringVal("Result");
		rt.setType("java.lang.String");
		return rt;
	}

	private byte[] getObjectAsBytes(Object o) throws Exception {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(bos);
		oos.writeObject(o);
		oos.flush();
		oos.close();
		return bos.toByteArray();
	}

}
```

ReturnType Möglichkeit1

```
public class ReturnType  implements java.io.Serializable {
    private java.lang.Integer intVal;

    private java.lang.Long longVal;

    private java.lang.String stringVal;

    private java.lang.String type;

  //getter und setter
```

Return Type Möglichkeit2

```
public class _ReturnType  implements java.io.Serializable {
    private byte[] object;

    private java.lang.String type;

  //getter und setter
```

build.xml für ant

```
<?xml version="1.0"?>
<project name="WebService" default="java2wsdl" basedir=".">

	<property name="sys.dir" value="C:/Allg/_system" />
	<property name="src.dir" value="${basedir}/src" />
	<property name="classes.dir" value="${basedir}/classes" />

	<property name="axis.home" value="${sys.dir}/axis/1.4" />


	<path id="axis.classpath">
		<fileset dir="${axis.home}/lib">
			<include name="**/*.jar" />
		</fileset>
	</path>

	<taskdef resource="axis-tasks.properties" classpathref="axis.classpath" />

	<target name="prepare">
		<mkdir dir="${classes.dir}" />
		<mkdir dir="${lib.dir}" />
	</target>

	<target name="clean">
		<delete dir="${classes.dir}" failonerror="false" />
		<delete dir="${lib.dir}" failonerror="false" />
	</target>

	<target name="compile" depends="prepare">
		<javac srcdir="${src.dir}" destdir="${classes.dir}">
			<classpath refid="axis.classpath" />
		</javac>
	</target>

	<target name="java2wsdl">
		<axis-java2wsdl classname="service.MyWebService"
		                location="http://localhost:8080/myapp/services/mywebservice"
		                namespace="urn:mywebservice"
		                output="myservice.wsdl"
		                style="RPC">
			<classpath path="${basedir}/classes" />
		</axis-java2wsdl>
	</target>

	<target name="wsdl2java">
		<axis-wsdl2java output="${src.dir}"
		                testcase="false"
		                serverside="true"
		                verbose="true"
		                url="myservice.wsdl"
		                implementationclassname="service.MyWebServiceImpl">
			<mapping namespace="urn:mywebservice" package="service" />
		</axis-wsdl2java>
	</target>


</project>
```

Bekommst du eigentlich immer nur einen Wert zurück oder ganze ResultSets? Wenn es viele Zeilen und Spalten sind muss man natürlich das ganze ResultSet als Liste von Object-Arrays zurück liefern. Am besten auch ein eigenes kleines ResultSetMetaData Object erzeugen, welche die Spaltennamen und Typen beinhaltet


----------



## Niki (23. Okt 2007)

Soda, habs verbessert:

Interface:

```
public interface MyWebService extends java.rmi.Remote {
    public service.Result select(java.lang.String in0) throws java.rmi.RemoteException;
}
```

Implementierung WebService:

```
public class MyWebServiceImpl implements MyWebService {

	public Result select(String query) throws RemoteException {
		Result result = new Result();
		// Connection sollte aus einem Pool geholt werden
		Connection con = null;
		Statement stmt = null;
		java.sql.ResultSet rs = null;
		try {
			stmt = con.createStatement();
			rs = stmt.executeQuery(query);
			java.sql.ResultSetMetaData rsMeta = rs.getMetaData();
			result.setMetaData(getMetaData(rsMeta));
			List tmp = new ArrayList();
			while (rs.next()) {

				Row row = new Row();
				ColumnValue[] cvs = new ColumnValue[rsMeta.getColumnCount()];
				for (int i = 1; i <= rsMeta.getColumnCount(); i++) {
					ColumnValue cv = new ColumnValue();
					switch (rsMeta.getColumnType(i)) {
					case Types.INTEGER:
						cv
								.setValue(getObjectAsBytes(new Integer(rs
										.getInt(i))));
						break;

					case Types.VARCHAR:
						cv.setValue(getObjectAsBytes(rs.getString(i)));
						break;

					case Types.TIMESTAMP:
						cv.setValue(getObjectAsBytes(rs.getTimestamp(i)));
						break;
					// alle möglichen Type abfragen
					}
					cvs[i - 1] = cv;
				}
				row.setValues(cvs);
				tmp.add(row);
			}

			Row[] rows = new Row[tmp.size()];
			tmp.toArray(rows);
			ResultSet resultSet = new ResultSet();
			resultSet.setRows(rows);
			result.setResultSet(resultSet);
		} catch (Exception ex) {
			throw new RemoteException(
					"Statement konnte nicht durchgeführt werden", ex);
		} finally {
			try {
				if (rs != null)
					rs.close();
				if (stmt != null)
					stmt.close();
				// Connection sollte hier in den Pool zurück gelegt werden
			} catch (Exception ex) {

			}
		}

		return result;
	}

	private ResultSetMetaData getMetaData(java.sql.ResultSetMetaData rsMeta)
			throws SQLException {
		ResultSetMetaData meta = new ResultSetMetaData();
		Column[] cols = new Column[rsMeta.getColumnCount()];
		for (int i = 0; i < cols.length; i++) {
			Column col = new Column();
			String name = rsMeta.getColumnName((i + 1));
			String type = rsMeta.getColumnTypeName((i + 1));
			col.setName(name);
			col.setType(type);
			cols[i] = col;
		}
		meta.setColumns(cols);

		return meta;
	}

	private byte[] getObjectAsBytes(Object o) throws Exception {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(bos);
		oos.writeObject(o);
		oos.flush();
		oos.close();
		return bos.toByteArray();
	}

}
```

ResultSetMetaData:

```
public class ResultSetMetaData  implements java.io.Serializable {
    private service.Column[] columns;

//getter und setter
}
```

ResultSet:


```
public class ResultSet  implements java.io.Serializable {
    private service.Row[] rows;

    public ResultSet() {
    }

//getter und setter
}
```

Result:

```
public class Result  implements java.io.Serializable {
    private service.ResultSetMetaData metaData;

    private service.ResultSet resultSet;

//getter und setter
}
```

Column:

```
public class ColumnValue  implements java.io.Serializable {
    private byte[] value;

    public ColumnValue() {
    }

//getter und setter
}
```

ColumnValue:

```
public class Column  implements java.io.Serializable {
    private java.lang.String name;

    private java.lang.String type;

//getter und setter
}
```


----------



## JavaLearn (11. Dez 2007)

muss man die build.xml mitrealisieren ...?! muss diese selbst erzeugt werden oder kann das der Axis2 automatisch erstellen?!


----------



## Niki (11. Dez 2007)

bei axis1.x musst du das build.xml selber schreiben, bei axis2 wird dir zwar ein build.xml generiert, du musst aber trotzdem ein .xml für ant schreiben


----------



## JavaLearn (13. Dez 2007)

hierzu müssen doch noch setter und getter implementiert werden, damit das ganze funktioniert ?

habe das mal so realisert bei mir tritt ein Fehler hier auf:


```
row.setValues(cvs);
```

muss ich die setValues Methode selbst in eine Klasse setzen?


----------



## Niki (13. Dez 2007)

Die Klasse Row sollte so aussehen:

```
public class Row  implements java.io.Serializable {
    private service.ColumnValue[] values;

    public Row() {
    }

    public Row(
           service.ColumnValue[] values) {
           this.values = values;
    }


    /**
     * Gets the values value for this Row.
     * 
     * @return values
     */
    public service.ColumnValue[] getValues() {
        return values;
    }


    /**
     * Sets the values value for this Row.
     * 
     * @param values
     */
    public void setValues(service.ColumnValue[] values) {
        this.values = values;
    }
}
```


----------



## JavaLearn (13. Dez 2007)

danke, werde das gleich mal mit implementieren ...

hier habe ich die setter und getter so gesetzt?


```
public class Result  implements java.io.Serializable { 
    private ResultSetMetaData metaData; 

    private ResultSet resultSet;

	public void setMetaData(telekom.ResultSetMetaData metaData) {
		this.metaData = (ResultSetMetaData) metaData;
		// TODO Auto-generated method stub
	}
	
	public ResultSetMetaData getMetaData() {
		return metaData;
	}

	public void setResultSet(ResultSet resultSet2) {
		this.resultSet = resultSet;
		// TODO Auto-generated method stub
		
	}
    
	public ResultSet getResultSet() {
		return resultSet;
}	}
```

ist das ok so?!


----------



## Niki (13. Dez 2007)

Ja, schaut richtig aus. Die getter und setter kannst du dir genereiren lassen. In Eclipse mit Strg + Shift + G
oder mit Rechts klick -> Source -> Generate Getters and Setters


----------



## Niki (13. Dez 2007)

JavaLearn hat gesagt.:
			
		

> ```
> public void setResultSet(ResultSet resultSet2) {
> this.resultSet = resultSet;
> // TODO Auto-generated method stub
> ...



mach aus resultSet2 nur resultSet oder this.resultSet = resultSet2; sonst hat das Statement keinen Sinn


----------



## JavaLearn (13. Dez 2007)

danke, oh stimmt habe ich selbst übersehen kriege wenn ich ein Statement ausführen will diese Fehelermeldung:


```
Exception in thread "main" java.rmi.RemoteException: Statement konnte nicht durchgeführt werden; nested exception is: 
	java.lang.ClassCastException: telekom.ResultSetMetaData
	at service.MyWebServiceImpl.select(MyWebServiceImpl.java:73)
	at service.Ausfuhren.main(Ausfuhren.java:25)
```

der service ist doch das Package ?!


----------



## Guest (14. Dez 2007)

habe mal die setter und getter so gesetzt stimmt das so, kannst du mal bitte nachschauen?!

Column:
	
	
	
	





```
public class Column  implements java.io.Serializable { 
    private java.lang.String name; 

    private java.lang.String type;

	public void setName(String name) {
		// TODO Auto-generated method stub
		this.name = name;
	}

	public void setType(String type) {
		// TODO Auto-generated method stub
		this.type = type;
	} 

//getter und setter 
}
```

ColumValue:

```
public class ColumnValue  implements java.io.Serializable { 
    private byte[] value; 

    public ColumnValue() { 
    }

	public void setValue(byte[] objectAsBytes) {
		this.value = objectAsBytes;
		// TODO Auto-generated method stub
		
	}

	public byte[] getValue() {
		return value;
	}

//getter und setter 
}
```


Result:

```
public class Result  implements java.io.Serializable { 
    private ResultSetMetaData metaData; 

    private ResultSet resultSet;

	public void setMetaData(telekom.ResultSetMetaData metaData) {
		this.metaData = (ResultSetMetaData) metaData;
		// TODO Auto-generated method stub
	}
	
	public ResultSetMetaData getMetaData() {
		return metaData;
	}

	public void setResultSet(ResultSet resultSet2) {
		this.resultSet = resultSet2;
		// TODO Auto-generated method stub
		
	}
    
	public ResultSet getResultSet() {
		return resultSet;
	}


//getter und setter 
}
```

ResultSet:

```
public class ResultSet  implements java.io.Serializable { 
    private Row[] rows; 

    public ResultSet() { 
    } 

    public void setRows(Row[] rows) {
    	this.rows = rows;
    }
    
    public Row[] getRows() {
    	return rows;
    }
}
```


ResultSetMetaData

```
public class ResultSetMetaData  implements java.io.Serializable { 
    private Column[] columns; 

    
	public void setColumns(Column[] columns) {
		// TODO Auto-generated method stub
		this.columns = columns;
	}

	public Column[] getColumns() {
		// TODO Auto-generated method stub
		return columns;
	} 
    
//getter und setter 
}
```


----------



## JavaLearn (14. Dez 2007)

wäre dir sehr dankbar wenn du mal drüber schauen könntest , dank dir...



			
				Anonymous hat gesagt.:
			
		

> habe mal die setter und getter so gesetzt stimmt das so, kannst du mal bitte nachschauen?!


----------



## Niki (16. Dez 2007)

Ja, schaut ja recht vernünfig aus, hast du jetzt auch schon das webservice generieren lassen?


----------



## JavaLearn (17. Dez 2007)

Ich habe das ganz normal als Java Code erstmal realisert und da tritt wenn ich das ausführe folgender fehler auf...


```
Exception in thread "main" java.rmi.RemoteException: Statement konnte nicht durchgeführt werden; nested exception is: 
	java.lang.ClassCastException: service.ResultSetMetaData
	at service.MyWebServiceImpl.select(MyWebServiceImpl.java:73)
	at service.Ausfuhren.main(Ausfuhren.java:25)
Caused by: java.lang.ClassCastException: service.ResultSetMetaData
	at service.Result.setMetaData(Result.java:11)
	at service.MyWebServiceImpl.select(MyWebServiceImpl.java:38)
	... 1 more
```


das sql kommando wird nicht ausgeführt...


----------



## JavaLearn (18. Dez 2007)

Ich hätte da noch eine Frage. Die build.xml, wenn ich die schreibe wohin muss die abgelegt werden, zum Service oder auf die Client Seite?

Denn wenn ich ein Dynamic Web Projekt realisiere und das alles generiere, erzeugt mir der Axis2 eine build.xml auf der Client Seite.


----------



## Niki (18. Dez 2007)

die build.xml brauchst du nirgends, die ist zum erzeugen des aar files mittels ant. mach mal einen rechts klick auf das build.xml und sag Run As... Ant Build...
Dort kannst du dann sagen jar.server und dann wird das aar file erstellt


----------



## JavaLearn (18. Dez 2007)

dank dir, hätte noch eine Frage, was ich nicht ganz verstehe für was dient dann dieses build.xml? Ist dieses build.xml unbedingt nötig?

Wäre dankbar wenn du mir hierzu eine Antowort geben könntest. Danke


----------



## Niki (18. Dez 2007)

Die build.xml Datei ist eine art batch-Datei und kann mittels ant übersetzt werden. Darin werden einige Targets definiert die man ausführen kann. Wenn du z.B. das Target jar.server auswählst wird die aar Datei erstellt. Ant ist ein nettes Tool um deployn von Applikationen. Es kann nicht schaden wenn du dich ein bisschen einliest...


----------



## JavaLearn (18. Dez 2007)

ah ok interessant d.h man kann so gut wie ein build.xml erstellen und diese fast für jeden Service benutzen?!

Dank dir nochmal, werde mich dann mal einlesen und ein build.xml erstellen.


----------



## Niki (18. Dez 2007)

ja genau, wenn du in der build.xml properties für serviceinterface, implemtierung, namespace, location.... erstellst, brauchst du nur die properties ändern und kann sehr schnell services generieren lassen


----------



## JavaLearn (18. Dez 2007)

Hi, 

kannst du mal bitte hier drüber schauen?! 
Danke

habe folgendes Problem soll den Inhalt einer tabelle z.B. "select last_name, first_name, geb_date from employees where employee_id = ?" ausgeben können als java Objekt..

Wie muss ich ncoh meine Methode getPerson füllen damit ich das als Java Objekt "retun" kann.
Habe nun folgendes gemacht:
das Hauptproblem die Mehtode zum eingeben der Employee_id:

```
public Person getPerson(int Id) {
		Person person = null;
		//TODO
		
		Connection conn = null;
		ResultSet  rs   = null;
		PreparedStatement  stmt = null;
		
		String Sql = "Select last_name, first_name, geb_id from employees where employee_id = ?"; 
		try
		{
			Class.forName(DbDrv);
			conn = DriverManager.getConnection( DbUrl, User, Pwd );
			stmt = conn.prepareStatement(Sql);
			stmt.setInt(1, Id);
			
			rs = stmt.executeQuery();
		}catch (Exception ex) {
			ex.printStackTrace();
		}
		
		
		return person;
	
	}
```


----------



## Niki (18. Dez 2007)

füge folgendes nach rs = stmt.executeQuery() ein:


```
if(rs.next()){
  person = new Person();
  person.setNachname(rs.getString("last_name"));
  person.setVorname(rs.getString("first_name"));
  person.setGebDatum(rs.getDate("geb_id"));
}
rs.close();
stmt.close();
conn.close();
```

nur so ein Tipp. Du solltest nicht für jedes Statement eine neue Connection aufmachen, da das sehr Ressourcen-fressend ist. Bau die Connection einmal auf und halte sie irgendwo in einem statischen Kontext. Am Ende von jedem Datenbankzugriff solltest du deine Resourcen schließen:


```
rs.close();
stmt.close();
```

die Connection sollte erst am Ende der Applikation geschlossen werden, bzw. verwende einen ConnectionPool


----------



## JavaLearn (19. Dez 2007)

Hi, erstmal danke für deine Hilfe, habe die Veränderungen vorgenommen...

Nun wollte ich das ganze ausführen dies habe ich auch gemacht nur wird mir nach meiner Eingabe der Employee_id folgendes ausgegeben:

```
package_name.TestStub$Person@1632847
```

Mmh hast du vielleicht eine Idee woran das liegen kann?! Danke


----------



## Murray (19. Dez 2007)

Sieht nach dem Resultat von Object#toString aus - überschreibe doch in der Klasse Person die Methode toString mit einem anderen Verhalten, z.B. so:


```
public String toString() {
  return super.toString() + 
            "[Nachame=" + getNachname() + 
            ",Vorname=" + getVorname() + 
            ",GebDatum=" + getGebDatum() + "]";
}
```


----------



## JavaLearn (19. Dez 2007)

MMh das habe ich nicht ganz verstanden meinst du ich soll eine Methode toString erstellen und diese in der Methode Person aufrufen?!


----------



## Murray (19. Dez 2007)

Nur in der Klasse Person die Methode überschreiben, aufgerufen wird die offenbar schon irgendwo (denn irgendwie muss die gepostete Ausgabe ja zustandekommen).


----------



## Niki (19. Dez 2007)

Nein, schreib einfach eine Methode 

```
public String toString(){
  return vorname + " " + nachname + ", " + gebDatum;
}
```
in deiner Klasse Person, sonst brauchst du nichts zu machen!


----------



## JavaLearn (19. Dez 2007)

ja ok, und muss ich dann vorname, nachname, geb_datum hier noch als lokale variable definieren?

und wie kann nun der Client somit die Richtige Antwort bekommen, denn ich setze im Client in der Methode Person die id damit die ausgabe erfolgen kann?


----------



## Murray (19. Dez 2007)

Nein, das sind doch schon Member der Klasse Person.


----------



## JavaLearn (19. Dez 2007)

ja stimmt stand eben völlig auf dem schlauch... 
ok habe die Methode eingefügt und alles nochmal generieren lassen und es wird immer noch dasselbe ausgegeben...


----------



## JavaLearn (19. Dez 2007)

Ok die Ausgabe erfolgt nun nur habe ich jetzt das Problem, dass das Datum nicht angezeigt wird da tritt dies hier auf:

```
java.util.GregorianCalendar[time=156034800000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/Berlin",offset=3600000,dstSavings=3600000,useDaylight=true,transitions=143,lastRule=java.util.SimpleTimeZone[id=Europe/Berlin,offset=3600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=1974,MONTH=11,WEEK_OF_YEAR=50,WEEK_OF_MONTH=2,DAY_OF_MONTH=12,DAY_OF_YEAR=346,DAY_OF_WEEK=5,DAY_OF_WEEK_IN_MONTH=2,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=3600000,DST_OFFSET=0]
```


----------



## Niki (19. Dez 2007)

Wenn du ein Calendar Objekt hast kannst du das mit getTime zu einem Datum umwandeln. Das Datum kann man dann schön ausgeben lassen (mittels SimpleDateFormat):

```
Calendar cal = ....
Date d = cal.getTime();
SimpleDateFormat format = new SimpleDateFormat("dd.MM.yyyy");
String dateAsString = format.format(d);
```


----------



## JavaLearn (19. Dez 2007)

Soll ich das als Methode erstellen?! 
Und ich müsste irgendwie die ColumnNamen darstellen das ist nur mit ResultSetMetaData möglich?


----------



## Niki (19. Dez 2007)

Genau, im ResultSetMetaData stehen die Spaltennamen und Typen drinnen. Obigen Code kannst du einbauen wo immer du das Datum formatiert ausgeben möchtest. Ich kann dir nicht genau sagen wo das bei dir Sinn macht. Du kannst aber in der Person eine Methode getGebDatumAsString implementieren:

```
private static final SimpleDateFormat DATEFORMAT = new SimpleDateFormat("dd.MM.yyyy");

  public String getGebDatumAsString(){
    return DATEFORMAT.format(gebDatum);
  }
```


----------



## JavaLearn (19. Dez 2007)

Das mit dem Datum hab ich auch hinbekommen, dank dir...

habe mal für das ResultSetMetaData folgendes gemacht: Könnte man dies so realisieren oder müsste ich mehrere setter und getter in diesem Fall 3 von denen definieren?


```
ResultSetMetaData rsmd = rs.getMetaData();
	int i, n =rsmd.getColumnCount();
	for (i=1; i<=n; i++) {
	               	person = new Person();
		person.setColumn(rsmd.getColumnName(i));
			}
```


----------



## Niki (19. Dez 2007)

So wird das nicht funktionieren. Was willst du genau machen? Du wirst schon auf die Spaltennamen abfragen müssen.
Der index beginnt bei ResultSetMetaData bei 0, nicht bei 1


----------



## JavaLearn (19. Dez 2007)

ich würde sehr gerne die drei Spaltennamen hier ausgeben können auf der Client Seite, somit ist klar welcher Inhalt zu wem gehört...


----------



## Niki (19. Dez 2007)

Probiers mal so:

```
MyWebService service = locator.getmywebservice();
		Result res = service.select("select * from person");
		service.ResultSetMetaData meta = res.getMetaData();
		for (Column c : meta.getColumns()) {
			System.out.print(c.getName() + " (" + c.getType() + ")\t");
		}
		System.out.println();
		for (Row row : res.getResultSet().getRows()) {
			for (ColumnValue cv : row.getValues()) {
				System.out.print(deserializeObject(cv.getValue()) + "\t");
			}
			System.out.println();
		}
```


----------



## JavaLearn (19. Dez 2007)

soll das ganze in die klasse Test also nicht in die Klasse Person?

und hierzu muss ich doch noch setter und getter setzen ?


----------



## Niki (19. Dez 2007)

Das hat nichts mit der Klasse Person zu tun. Diesen Code kannst du in eine main Methode geben. Hast du das WebService genauso implementiert wie ich es gepostet habe? Wenn ja sollte der Code so funktionieren. Bei mir tut er das


----------



## JavaLearn (19. Dez 2007)

Ich habe als Webservice dies hier gemacht deins hat bei mir nicht ganz geklappt...

Klasse Person

```
ok
```

Klasse Test:

```
ok
```


----------



## Niki (19. Dez 2007)

Das ist ja noch kein WebService. Ist das alles was du hast?


----------



## JavaLearn (19. Dez 2007)

ja dann gibts noch die Client seite, die das ganze ausführt, dass ist aber der  Service an sich


----------



## Niki (19. Dez 2007)

Ich glaube dir ist nicht ganz bewusst was ein WebService ist. Läuft das ganze bei dir in einem WebContainer wie z.B. Tomcat?


----------



## JavaLearn (19. Dez 2007)

ja genau mit Apache Tomcat und Axis2...
ich erstelle bei eclipse ein dynamic web project und generiere diesen als Webservice, anschlißend erstelle ich den client ebenso und schreibe dazu eine Klasse mit einem main z.b so:

```
public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		BufferedReader in = new BufferedReader
			(new InputStreamReader (System.in));
		
		try {
			TestStub stub = new TestStub();
			TestStub.GetPerson request = new TestStub.GetPerson();
			TestStub.GetPersonResponse resp = null;
			
			String statement = "";
			System.out.println("Eingabe des Statementnamen: ");
			statement= in.readLine();
			request.setStatement(statement);			
			
			String s_id = "";
			System.out.println("Eingabe der Employee_id: ");
			s_id = in.readLine();
			int id = Integer.valueOf(s_id);
			request.setId(id);
			
			resp = stub.getPerson(request);
			
			System.out.println(resp.get_return().getNachname() + "     " + resp.get_return().getVorname() 
					+ "     " + resp.get_return().getGebDatumAsString());
			
			
		} catch (AxisFault e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
```
 

habe auch eine build.xml


----------



## Niki (19. Dez 2007)

Alles klar, dann weißt du eh was du tust 
Poste mal den relevanten Code und beschreibe nochmal dein Problem!


----------



## JavaLearn (19. Dez 2007)

Also mein Problem zur Zeit ist es, dass bei der Ausgabe die Spaltennamen noch nicht mithineinbezogen wurden, außerdem würde ich sehr gerne wissen, was wäre wenn ich mehrere Nachnamen, Vornamen, und Geburtsdaten ausgeben will wie etwa so:


```
Select last_name, first_name, geb_id from employees Where employee_id Between ? And ?
```

habe zur Zeit folgendes in meinem Service:
Klasse Test: hier befinden sich zwei Methoden einmal für das setzen einer Id und des weiteren für das setzen von zwei ids ...


----------



## Niki (19. Dez 2007)

Wenn du mehrere Personen zurück geben möchtest musst du das mit einer Collection oder einem Array machen:


```
rs = stmt.executeQuery....
List erg = new ArrayList();
while(rs.next()){
  Person p = new Person();
  p.setZuname(rs.getString("last_name"));
.....
  erg.add(p);

}


return erg;
```

Wozu benötigst du die Spalten informationen in deinem Person Objekt? Beim befüllen der Daten weißt du ja welche Spalte der Tabelle du auf welches Attribut mappen musst. Wozu also die Spaltennamen mit speichern?


----------



## JavaLearn (19. Dez 2007)

Ja stimmt eigentlich mir ist das mit dem füllen von mehreren Spalten eigentlich wichtiger...

Habe nun die while schleife mit eingefügt aber das mit dem return erg java zeigt da ein Fehler an da es nicht vom Objekt Person ist ...


----------



## Niki (19. Dez 2007)

Ja ist ja klar, dann musst du die Methode halt so deklarieren:


```
public List listPersonen(String idFrom, String idTo){
  List erg = new ArrayList();
  //Hier sql Code, Objekte befüllen und in Liste einfügen....
  return erg;
}
```

WebServices kennen keine generischen Typen, eventuell musst du es auch so machen:

```
public Person[] listPersonen(String idFrom, String idTo){
  List erg = new ArrayList();
  //Hier sql Code, Objekte befüllen und in Liste einfügen....
  Person[] pArr = new Person[erg.size()];
  erg.toArray(pArr);
  return pArr;
}
```


----------



## JavaLearn (19. Dez 2007)

Meinst du das ungefähr so, habe das mal so abgeändert ...


```
while(rs.next()){ 
			  person = new Person(); 
			  person.setNachname(rs.getString("last_name")); 
			  person.setVorname(rs.getString("first_name")); 
			  person.setGebDatum(rs.getDate("geb_id")); 
			  erg.toArray(pArr);
			}
```


----------



## Niki (19. Dez 2007)

nicht ganz, der Teil der Schleife muss so aussehen:

```
public Person[] listPersonen(int Id, int Ids) {
      Person person = null;
      List erg = new ArrayList();
//du weißt die Größe hier noch nicht!
      Person[] pArr = null;
   
      String Sql = "Select last_name, first_name, geb_id from employees where employee_id = ?";
      try
      {
         Class.forName(DbDrv);
         conn = DriverManager.getConnection( DbUrl, User, Pwd );
         stmt = conn.prepareStatement(Sql);
         stmt.setInt(1, Id);
         stmt.setInt(2, Ids);
         
         rs = stmt.executeQuery();

          
         while(rs.next()){
           person = new Person();
           person.setNachname(rs.getString("last_name"));
           person.setVorname(rs.getString("first_name"));
           person.setGebDatum(rs.getDate("geb_id"));
          
         }
         //hier wissen wir die Größe!
         pArr = new Person[erg.size()];
         erg.toArray(pArr);
         
         
         rs.close();
         stmt.close();
         conn.close();
         

      }catch (Exception ex) {
         ex.printStackTrace();
      }
      
      
   return pArr;
   
   }
```


----------



## JavaLearn (19. Dez 2007)

dank dir nochmal viels, das auslesen des ganzen auf der Client Seite muss das auch nacheinander folgen...?!

Denn ich will ja, dass die Nachnamen , Vornamen und Geburtstage alle untereinander stehen.


----------



## Niki (19. Dez 2007)

Sicher, du bekommst vom Server ein Array zurück:


```
Person[] pArr = service.getPersonen(fromID, toID);
for(Person p : pArr){
  System.out.println(p.toString());
//oder
  System.out.println(p.getZuname() + " " + p.getVorname() + ", " + p.getGebDatumAsString());
}
```

Wie auch immer du halt deine Daten aufbereiten möchtest


----------



## JavaLearn (19. Dez 2007)

mmh das verstehe ich nicht so ganz denn mein Client bestitzt doch nicht die klasse Person wie soll dann das ganze hier erfolgen mit diesem sourcecode?


----------



## Niki (19. Dez 2007)

Was soll dein Client machen? Ich vermute Personen mittels id auslesen, oder?
Dann sollte der Client ja die Liste der Personen zurück bekommen.


----------



## JavaLearn (19. Dez 2007)

ja genau das sollte er machen es werden die beiden ids eingegeben und dann soll eine ausgabe erzeugt werden...

jep genau die liste wie kann ich die im client laden damit diese ausgegeben werden kann..?


----------



## Niki (19. Dez 2007)

Wie ist dein Service definiert? Dein Service sollte halt die Methode 

```
public Person[] getPersonen(int idFrom, int idto);
```
haben.
Diese kann dein Client dann aufrufen und die Personen ausgeben


----------



## JavaLearn (19. Dez 2007)

ja genau so sieht die aus aber wie kann nun der client diese hier aufrufen das klappt irgendwie nicht so ganz...

Kriege das mit der Ausgabe so nicht hin...


```
System.out.println(resp.get_return());        //wird "null" ausgegeben
```
[/quote]


----------



## Niki (19. Dez 2007)

Der Aufruf des WebServices muss irgendow so ausschaun:


```
MyWebServiceServiceLocator locator = new MyWebServiceServiceLocator();
		MyWebService service = locator.getmywebservice();
		Person[] pArr = service.getPersonen(1, 10);
```

Zuerst erstellst du den locator, dem musst du eventuell den Endpoint setzen, danach holst du dir vom Locator das Service selbst. Von dem Service-Objekt kannst du dann die definierte Methode aufrufen. Diese wird dann am Server ausgeführt und du bekommst deine Liste von Personen zurück.


----------



## JavaLearn (19. Dez 2007)

mmh muss das muss alles auf die ServiceSeite?


----------



## Niki (19. Dez 2007)

Langsam wird es anstrengend, ich bin mir nicht sicher ob du wirklich weißt was du willst oder tust, vielleicht solltest du mal ein bisschen was über soap, wsdls und webservices im allgemeinen lesen.
Kurz dir Vorgehensweise:
du erstellst ein ServiceInterface bzw. eine ServiceKlasse mit der Implementierung, du solltest auch schon alle Objekte, die du für das Service benötigst definieren und ausimplementieren (Person in deinem Fall)
von dieser Klasse lässt du dir eine wsdl Datei generieren (über eclipse plugin oder ant). Diese wsdl Datei beschreibt dir dein WebService.
Anhand der WSDL-Datei kannst du dir deine Klassen neu generieren lassen (dabei nicht die Implementierungsklasse überschreiben, das kann man aber alles angeben)
Nachdem die WebService Klassen generiert wurden kannst du mittels build.xml das WebService deployen (aar Datei erzeugen lassen und in deine WebApp kopieren - Konfiguration nicht vergessen: web.xml, libs...)
Jetzt ist das WebService fertig und kann mit einem Client angesprochen werden. Der obige Code ist der Code auf client Seite!


----------



## JavaLearn (19. Dez 2007)

doch im großen und ganzen ist mir bewusst was ich machen will nur die Umsetzung klappt nicht so ganz.
Muss den z.b für ein Webservice dieser ServiceInterface unbedingt bereitgestellt werden ist es ohne nicht möglich denn habe bis jetzt noch nie ein ServiceInterface genutzt in den Webservices...

Axis2 generiert die build.xml und auch die wsdl datei. Bei mir ist halt das Problem auf der ClientSeite wie dieser das Objekt "Person" zu kennen weiss... 

du hast irgendwie auch kein response bei dir, ich habe bei meinen clients immer am ende ein 



```
System.out.println(response.get_return()) 
//oder
        System.out.println(response.get_return().getNachname() + " " + response.get_return.getVoraname() + ...);
```

Ausserdem besitze ich auf der Clientseite zwei java sourcen die wären...
"CallbackHandler.java" und "Stub.java" die automatisch generiert werden zu dem erstelle ich noch eine Klasse namens Client...


----------



## Niki (19. Dez 2007)

So wie das ausschaut hast du ein asynchrones Service gebaut. Da kann ich dir nicht weiter helfen da ich selber bis jetzt nur synchrone gebaut habe. Schau nochmal nach wie du das Service generieren hast lassen. Es sollte wahrscheinlich synchron sein.
Das Interface brauchst du nicht umbedingt. Ich erstell meistens eins, find es irgendwie schöner.


----------



## JavaLearn (19. Dez 2007)

ja zuerst habe ich ein Projekt mit Dynamic WebProjekt erstellt ...
habe das eigenlich nach diesem link gemacht...

www.eclipse.org/webtools/community/tutorials/BottomUpAxis2WebService/bu_tutorial.html

hast du das noch nie so realisiert?


----------



## Niki (19. Dez 2007)

Nein, ich schreibe die Files die ich für das Service brauche selber, damit ich IDE-unabhängig bleibe und die Kontrolle nicht aus der Hand gebe. Schau dir mal diesen Thread an: webservice_mit_axis2


----------



## JavaLearn (19. Dez 2007)

aha ok du machst eigentlich alles wenn man das so haben will von der hand...

mmh dann muss ich mal schauen wie ich das mit dem client bei mir hinkriege damit da eine vernünftige Ausgabe zustande kommt zurzeit gibt er nur null aus...


----------



## Niki (19. Dez 2007)

Viel Erfolg!


----------



## JavaLearn (21. Dez 2007)

hi, 
hab das mit dem Client nun auch hinbekommen, wollte mich nochmals bei dir bedanken...

Ich wünsch dir noch frohe Weihnachten und einen guten Rutsch ins neue Jahr


----------



## Niki (21. Dez 2007)

Danke, wünsch ich Dir auch!


----------

