# Struts multibox - dynamische checkboxen



## pusteblume (18. Nov 2008)

hallo zusammen,

zu meiner problematik konnte ich hier im forum noch nichts finden. sollte es dennoch einen thread mit lösungsvorschlägen bereits geben, sag ich schon mal vorab sorry! 

also folgendes: ich habe auf einer jsp-seite ein dropdown-menü mit einer auswahllliste. entsprechend des gewählten eintrages wird aus einer datenbank mir ein vector mit den passenden einträgen zurückgeliefert. das funktioniert alles ganz wunderbar. nun soll es so sein, nachdem der benutzer auf dieser jsp-seite auf submit klickt, eine weiterleitung zu einer neuen jsp-seite erfolgt, auf der eine liste mit checkboxen sind und entsprechend des gelieferten vectors die jeweiligen checkboxen aktiviert sind. 

ich habe jetzt verschiedene tutorials versucht durchzuexerzieren, aber irgendwie komme ich absolut nicht weiter. hier vielleicht einfach mal mein ansatz: was ich gelesen habe, ist, dass man ein String-array verwendet, in dem die zu aktivierenden einträge enthalten sind. d. h. ich müsste die einträge aus meinem vector in dieses String[] packen. 



```
/*form-bean*/

import java.util.Vector;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;

public class ThemaForm extends ActionForm {

	// form-fields
	private String topic_name;
	private int topic_id;
	private String [] allLayers = {};

	//set and get methods
	public int getTopic_id() {
		return topic_id;
	}

	public void setTopic_id(int topic_id) {
		this.topic_id = topic_id;
	}

	public String getTopic_name() {
		return topic_name;
	}

	public void setTopic_name(String topic_name) {
		this.topic_name = topic_name;
	}
	
	public String[] getAllLayers() {
		return allLayers;
	}
	public void setAllLayers(Vector input) {
		input.copyInto(allLayers);
	}
	
	//reset the variables
	
	public void reset(ActionMapping mapping, HttpServletRequest request) {
		topic_name = null;
		topic_id = 0;

		
	}
	
	//validate if the variables are filled
	public ActionErrors validate(HttpServletRequest request) {

		ActionErrors errors = new ActionErrors();
		if (topic_name == null || topic_id == 0) {
			errors.add("thema", new ActionMessage(
					"thema.problem"));
			
		}
		
		return errors;
	}
	
}
```


```
/*action-class*/

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping; 
import java.io.BufferedReader;



import java.io.*;
import java.sql.Connection; 
import java.sql.Statement; 
import de.dlr.ng.nki.layermanagement.forms.*;
i

public class ThemaAction extends Action {

	
	static Connection con; // db-verbindung-variable
	static Statement st; // sql-variable

	public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {

		String topic = request.getParameter("topic_id"); 
		int tid = Integer.parseInt(request.getParameter("topic_id"));
		

		TopicChoice.topicChoice(tid); // calls the method topicChoice which
										// returns the layer-ids for the
										// specified topic-id from the database

		String [] selectedLayers = ((LayerForm)form).getSelectedLayers();
		
		HttpSession session = request.getSession();
		session.setAttribute("layers", selectedLayers);

		return mapping.findForward("layerform"); // weiterleitung zuml ayer-formular
													

	}

	public int compareTo(File arg0) {
		// TODO Auto-generated method stub
		return 0;
	}

}
```

hier die "input-jsp": themaForm.jsp

```
<%@ page language="java"%>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean"%>
<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Thema-Auswahl</title>
</head>

<body>
<h1>Thema Auswahl</h1>
<html:errors></html:errors>

<html:form action="/themaForm">
	<bean:message key="thema.name" />
	<html:select property="topic_id">
		<html:option value="1">grassland</html:option>
		<html:option value="2">water</html:option>
		<html:option value="3">streets</html:option>
		<html:option value="4">sealed_areas</html:option>
		<html:option value="5">trees</html:option>
		<html:option value="6">vegetation</html:option>
	</html:select>


<logic:iterate name="ThemaForm" property="allLayers" id="allLayer" >
<html:multibox property="selectedLayers"> 
<bean:write name="allLayer"/>
</html:multibox>

<bean:write name="allLayer"/>
</logic:iterate>


	<html:submit />
	<html:cancel />
	<html:reset />
</html:form>


</body>
</html>
```

und hier die "output-jsp" mit den checkboxen: layerForm.jsp


```
<%@ page language="java"%>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean"%>
<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic"%>


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html:html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Layer-Auswahl</title>

</head>

<body>
<h1>Layer Auswahl</h1>
<html:errors />

<<logic:iterate id="allLayer" property="allLayers" name="testForm">
<bean:write name="allLayer"/>

</logic:iterate>
<hr size=5 color="black"/>



</body>
</html:html>
```

eintrag in der struts-config.xml:


```
...
<form-beans>
		<form-bean name="ThemaForm" type="de.dlr.ng.nki.layermanagement.forms.ThemaForm" />
		<form-bean name="LayerForm" type="de.dlr.ng.nki.layermanagement.forms.LayerForm" />
</form-beans>

...

<action
			path="/themaForm"
			type="ThemaAction"
			name="ThemaForm"
			validate="true"
			input="/themaForm.jsp">
			<forward name="layerform" path="/layerForm.jsp" />
		</action>
		<action
			path="/layerForm"
			type="LayerAction"
			name="LayerForm"
			validate="true"
			input="/layerForm.jsp">
			<forward name="success" path="/regSuccess.jsp" />
		</action>

...
```

beim ausführen erhalte ich diese meldung:



> exception
> 
> javax.servlet.ServletException: java.lang.ClassCastException: de.dlr.ng.nki.layermanagement.forms.ThemaForm
> org.apache.struts.chain.ComposableRequestProcessor.process(ComposableRequestProcessor.java:286)
> ...



irgendwie habe ich keinen plan, was ich falsch mache. ich hoffe, das war nicht zu viel, was ich gepostet habe.  

für jeden hinweis/tipp/hilfe bin ich sehr dankbar!

gruß pusteblume


----------



## HLX (18. Nov 2008)

Du hast in deiner struts-config.xml festgelegt, dass "ThemaForm" das Formular zu deiner Action "ThemaAction" ist. In der Klasse "ThemaAction" castest du allerdings das Formular der Action zu "LayerForm".


----------



## pusteblume (18. Nov 2008)

hallo hlx,

ich habe jetzt deine anmerkung geändert und noch diverse andere änderungen vorgenommen, so dass ich jetzt aber eine leeres jsp als ergebnis bekomme.  meine änderungen sehen nun wie folgt aus: ich hab in die Action-Klasse ThemaAction.java die Zeilen 




```
Vector lids = TopicChoice.topicChoice(tid); // calls the method topicChoice which
										// returns the layer-ids for the
										// specified topic-id
		int length = lids.size();
		
		String [] selectedLayers = new String[length];
		
		logger.debug("laenge array:" + length);
		
		for (int i=0; i<length; i++) {
			selectedLayers[i]=lids.get(i).toString();
			logger.debug(i+". element im array:"+selectedLayers[i]);
		}
```

Damit befülle ich das Array, in dem steht, welche Checkboxen gerendert werden sollen. 
Aber irgendwie muss ja auch noch das allLayers befüllt werden oder? irgendwie verliere ich so langsam den überblick  und mir ist auch noch nicht so ganz hundertprozentig klar, wodurch jetzt die checkboxen gerendert werden würden (wenn sie es denn mal täten). 

any ideas? 

vielen dank schon mal,

pusteblume


----------



## HLX (18. Nov 2008)

So wie ich das sehe brauchst du die zweite Action-Definition in deiner Struts-Config nicht. Du hast hier im Prinzip nur eine Aktion mit einer Eingabeseite und einer Ausgabeseite. In der Eingabeseite befindet sich ein Formular, dessen Daten in einer Formklasse gehalten werden. Nach dem Absenden befinden sich die gesendeten Daten in deinem Form-Objekt und sind über das in der Struts-Config angegebene Mapping in der entsprechenden Action verfügbar.

Die Ergebnisse für deine Ausgabeseite gehören nicht in die Formularklasse (da kein Formular benötigt) sondern in ein Request-Attribut:

```
request.setAttribute(meinSchluessel, meinObjekt); //wobei meinObjekt z.B ein Array sein könnte
```

Auf deiner Ergebnisseite können verschiedene Struts-Tags über den Schlüssel auf das Objekt zugreifen. Bsp:

```
// Ausgabe von meinObjekt:
<bean:write name="meinSchluessel"/>
// Iteriere über meinObjekt --> muss vom Typ Collection oder Array sein:
<logic:iterate name="meinSchluessel" id="einzelobjektInDerCollection">
```


----------



## pusteblume (18. Nov 2008)

hi hxl,

besten Dank für deine Antwort(en). 



> ```
> // Iteriere über meinObjekt --> muss vom Typ Collection oder Array sein:
> <logic:iterate name="meinSchluessel" id="einzelobjektInDerCollection">
> ```



Was ich hier nicht verstehe: die id des einzelnen Objekts im Array. Wie soll das funkionieren? ???:L 

Nochmal zum Verständnis (vorallem für meins  ): ich habe zwei Formulare:
themaForm.jsp in dem das Thema gewählt wird.  Das dort gewählte Thema wird in einem Objekt der Bean ThemaForm.java gespeichert. Die Speicherung des gewählten Themas erfolgt durch das Ausführen der Action-Klasse ThemaAction.java, in der zum einen die Datenbank-Abfrage angestoßen wird durch den Aufruf der Methode topicChoice()  aus der Klasse TopicChoice.java, welcher Layer zu welchem Thema gehört und dann ... ja und dann? da verliere ich den Faden... 

Mit 
	
	
	
	





```
String [] selectedLayers = ActivateLayer.activateLayer(TopicChoice.topicChoice(tid));
```
 erzeuge ich das String-Array mit den IDs der Layer, für die eine gecheckte Checkbox gerendert werden soll. Das schreibe ich in die Action-Klasse ThemaAction.java hinein. Und mit 
	
	
	
	





```
request.setAttribute("layers",selectedLayers);
```
 passiert was? Das habe ich dann gleich danach in die Action-Klasse geschrieben. Oder ist das falsch? Hä? ??? ???:L 

layerForm.jsp sollte mir eigentlich die Checkboxen ausgeben. Es bekommt die IDs der Checkboxen aus einem Objekt, nämlich dem String-Array namens selectedLayers, dass in der Action-Klasse befüllt wird. Zur Funktionsweise von _iterate _habe ich noch Fragen, die ich nirgends beantwortet finden konnte:

Der Tag 
	
	
	
	





```
<logic:iterate id="selectedLayers" property="?" name="ThemaForm">
```
 durchläuft mein String-Array namens selectedLayers, das aus der Bean ThemaForm.java kommt. Bei property gebe ich dann also nochmal die Bean an oder wie? Ich verstehe nicht, was da in der API gemeint ist:



> property: Name of the property, of the JSP bean specified by name, whose getter returns the collection to be iterated.




```
<bean:write>
```
 würde mir quasi die Strings, die in dem String-Array selectedLayers gespeichert sind, rendern, oder? Mit 
	
	
	
	





```
<html:multibox property="selectedLayers">
```
tut er was? Wird eine gecheckte Checkbox gerendert für die Strings, die in dem Array stehen? Müsste, oder?

Aber irgendwie wird gar nix gerendert. Auf der Konsole lasse ich mir das Array ausgeben und das sieht auch alles richtig aus.  Also leer ist es nicht. 

Ich bin total ratlos. Gibts vielleicht noch eine mailing-Liste oder ist meine Frage dafür zu banal?

Besten Dank + lg
pusteblume


----------



## HLX (19. Nov 2008)

pusteblume hat gesagt.:
			
		

> hi hxl,
> 
> besten Dank für deine Antwort(en).
> 
> ...


Bei dieser Iteration wird über ein Objekt mit dem Schlüssel "meinSchluessel" iteriert. Das jeweils aktuelle Objekt aus dem Iterationsvorgang wird von Struts in einer Variable namens "einzelobjektInDerCollection" gespeichert. In Java sähe das so aus:

```
String[] meinArray = request.getAttribute("meinSchluessel");
for(int i = 0; i < meinArray.length; i++) {
    String einzelobjektInDerCollection = meinArray[i];
    // jetzt kannst du das einzelne Objekt verwenden
}
```



			
				pusteblume hat gesagt.:
			
		

> Nochmal zum Verständnis (vorallem für meins  ): ich habe zwei Formulare:
> themaForm.jsp in dem das Thema gewählt wird.  Das dort gewählte Thema wird in einem Objekt der Bean ThemaForm.java gespeichert. Die Speicherung des gewählten Themas erfolgt durch das Ausführen der Action-Klasse ThemaAction.java, in der zum einen die Datenbank-Abfrage angestoßen wird durch den Aufruf der Methode topicChoice()  aus der Klasse TopicChoice.java, welcher Layer zu welchem Thema gehört und dann ... ja und dann? da verliere ich den Faden...
> 
> Mit
> ...


Dieser Aufruf gehört zu den allgemeinen Java-Web-Grundlagen. 
]java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/ServletRequest.html#setAttribute(java.lang.String,%20java.lang.Object)
Du speicherst ein Attribut an einem Requets-Objekt, so dass es deiner Antwort-JSP-Seite zur Verfügung steht. Dein Struts-Formular ist auch nicht anderes als ein solches Attribut, nur dass Struts den "setAttribute"-Aufruf vor dir verbirgt.


			
				pusteblume hat gesagt.:
			
		

> Das habe ich dann gleich danach in die Action-Klasse geschrieben. Oder ist das falsch? Hä? ??? ???:L


Das ist korrekt. 



			
				pusteblume hat gesagt.:
			
		

> Der Tag
> 
> 
> 
> ...


Bei einer JSP-Bean handelt es sich um eine JavaBean (Objekt mit Gettern und Settern) das an der Seite, dem Request, der Session oder dem SessionContext abgelegt ist. Das Ablegen erfolgt mittels der Methode "setAttribute(key, value)", also z.B. mit

```
request.setAttribute("meinSchluessel", meinObjekt);
```
legst du eine JSPBean am Request unter dem Namen "meinSchluessel" ab.

Property ist das Attribut der Bean, welches über Getter und Setter verfügen muss.

```
public class MeinObjekt {

    private Layer[] selectedLayers; // dieser Attributname wird bei Property verwendet

    public MeinObjekt() {
        super();
    }

    public Layer[] getSelectedLayers() {
        return selectedLayers
    }

    public void setSelectedLayers(Layer[] layers) {
        selectedLayers = layers;    
    }
}
...
// in der Action
MeinObjekt meinObjekt = getObjektIrgendwoher();
request.setAttribute("meinSchluessel", meineObjekt); // Bean MeinObjekt erhält den Namen "meinSchluessel" 

// in der JSP
<logic iterate name="meinSchluessel" property="selectedLayers".../>
```



			
				pusteblume hat gesagt.:
			
		

> Ich bin total ratlos. Gibts vielleicht noch eine mailing-Liste oder ist meine Frage dafür zu banal?


Es gibt ein hilfreiches JSP-Tutorial für Grundlagen. Das dürfte sehr zum Verständnis beitragen:
www.jsptutorial.org/


----------

