Struts: Reihenfolge validate() und Action

MadM

Mitglied
Moin,

ein neues Problem bei meinem ersten Struts-Projekt:

Ich will einen neuen Datensatz anlegen. Dazu lade ich Formular, das eine ActionForm verwendt. Mein Problem ist nun, dass die validate()-Methode der ActionForm bereits aufgerufen wird, bevor ich die Action zum Speichern auslöse. Es sollte ja aber so sein, dass ich meine Eingaben mache und erst nach drücken des Speichern-Buttons validiert wird. Der Aufruf der Seite zum Erstellen des neuen Datensatzes erfolgt über /editProject.do?do=create.
Ich bekomme dann eine Exception:

java.lang.NullPointerException
de.twinsoft.prototype.struts.form.EditProjectForm.validate(EditProjectForm.java:67)
org.apache.struts.action.RequestProcessor.processValidate(RequestProcessor.java:942)
org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:255)
org.apache.struts.action.ActionServlet.process(ActionServlet.java:1482)
org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:507)


Ich gehe mal davon aus dass es sich um ein Problem handelt, das mit der grundsätzlichen Arbeitsweise von Struts zusammenhängt. Für eine Erläuterung/ Lösung wäre ich sehr dankbar.

Gruß

Matthias

struts-config.xml
Code:
[...]
<action
      attribute="editProjectForm"
      input="/jsp/editProject.jsp"
      name="editProjectForm"
      parameter="do"
      path="/editProject"
      scope="session"
      type="de.twinsoft.prototype.struts.action.EditProjectAction"
      validate="true">      
      
      <forward
        name="projectList"
        path="/listProjects.do"
        redirect="true" />
      <forward
        name="editProject"
        path="/jsp/editProject.jsp" />    
      
    </action>
[...]
editProject.jsp
Code:
<html:form action="/editProject">
    <html:hidden property="project.projektId" />
    <html:hidden property="do" value="saveProject" />

    <TABLE border="1" cellpadding="5" cellspacing="0" bgcolor="#ffffff" width="500">
        <TR>
            <TH>
                Basisnummer:
            </TH>
            <TD>
                <html:text property="project.basisnummer" />
            </TD>
            <TD>
                <html:errors property="basisnummer" />
            </TD>
        </TR>
        <TR>
            <TH>
                Name:
            </TH>
            <TD>
                <html:text property="project.name" />
            </TD>
            <TD>
                <html:errors property="name" />
            </TD>
        </TR>
        <TR>
            <TH>
                Beginn:
            </TH>
            <TD>
                <html:text property="project.beginn" />
            </TD>
            <TD>

            </TD>
        </TR>
        <TR>
            <TH>
                Ende:
            </TH>
            <TD>
                <html:text property="project.ende" />
            </TD>
            <TD>

            </TD>
        </TR>
        <TR>
            <TH>
                Typ:
            </TH>
            <TD>
                <html:select property="project.typ">
                    <html:option key="intern" value="intern" />
                    <html:option key="extern" value="extern" />
                </html:select>
            </TD>
            <TD>

            </TD>
        </TR>
        <TR>
        <TR>
            <TH>
                Beschreibung
            </TH>
            <TD>
                <html:textarea property="project.beschreibung" rows="10" cols="40" />
            </TD>
            <TD>

            </TD>
        </TR>
    </TABLE>  &nbsp;<BR>
    <br />
    <br />
    <html:submit />
    <html:cancel />

</html:form>
EditProjectAction
Code:
public class EditProjectAction extends DispatchAction {
    ProjektDAO projektDAO = new ProjektDAO();

    private static final Log log = LogFactory.getLog(EditProjectForm.class);

    public ActionForward prepareEdit(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) {
        log.info("ACTION: prepareEdit");
        Integer id = Integer.valueOf(request.getParameter("projektId"));
        ((EditProjectForm) form).setProject(projektDAO.findById(id));
        return mapping.findForward("editProject");
    }

    public ActionForward delete(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) {
        log.info("ACTION: delete");
        Integer id = Integer.valueOf(request.getParameter("projektId"));
        projektDAO.delete(projektDAO.findById(id));
        return mapping.findForward("projectList");
    }

    public ActionForward saveProject(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) {
        EditProjectForm editProjectForm = (EditProjectForm) form;
        log.info("ACTION: saveProject");
        projektDAO.save(editProjectForm.getProject());
        return mapping.findForward("projectList");
    }

    public ActionForward create(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) {
        log.info("ACTION: create");
        ((EditProjectForm) form).setProject(new Projekt());
        return mapping.findForward("editProject");
    }

}
editProjectForm
Code:
public class EditProjectForm extends ActionForm {

    // --------------------------------------------------------- Instance
    // Variables
    private Projekt project = new Projekt();    

    private static final Log log = LogFactory.getLog(EditProjectForm.class);

    /**
     * @return Returns the project.
     */
    public Projekt getProject() {

        return project;
    }

    /**
     * @param project
     *            The project to set.
     */
    public void setProject(Projekt project) {
        this.project = project;
        
    }

    public boolean equals(Object obj) {
        return project.equals(obj);
    }

    public void reset(ActionMapping arg0, HttpServletRequest arg1) {
        this.project = new Projekt();
    }

    public int hashCode() {
        return project.hashCode();
    }

    public ActionErrors validate(ActionMapping arg0, HttpServletRequest arg1) {
        log.info("validate");
        ActionErrors errors = null;
        
            errors = new ActionErrors();
            if (project.getBasisnummer().intValue() < 10000000) {
                errors.add("basisnummer", new ActionError("error.basisnummer"));
            }
            if (project.getName().length() < 5) {
                errors.add("name", new ActionError("error.projekt.name"));
            }
            if (project.getBeginn().after(project.getEnde())) {
                errors.add("beginnBeforeEnd", new ActionError("error.projekt.beginnBeforeEnd"));
            }
        
        return errors;

    }
}
 
Zuletzt bearbeitet:
Hi Tom,

dein Vorschlag würde ja bedeuten dass ich auf die XML-Variante der Validierung zurückgreifen würde. Ich will aber die programmatische Lösung mittels validate()-Methode der ActionForm. Oder sehe ich da was falsch?

Gruß

Matthias
 
Hallo,

huch stimmt, du validierst ja von Hand, wieso eigentlich?

Das Problem liegt daran, dass die validate Methode scheinbar auch dann aufgerufen wird,
wenn die FormBean fuer das entsprechende HTML Fomular gesucht wurde oder neu Instanziiert wird. Aendere deinen Check doch so um, dass du zu begin pruefst ob getProject() null zurueck gibt... ist das der Fall gibst fuegst du der ActionErrors Auflistung eben einen "Missing Project Error" mit.

Siehe auch hier:
http://struts.apache.org/struts-action/userGuide/building_view.html

Gruss Tom
 
Hi Tom,

der Gedanke mit der Prüfung auf null bzw. die Verwendung einer boolschen Variable kam mir auch in den Sinn, allerdings scheint mir das eher ein "unsauberer" Workaround zu sein.

Würdest du aufgrund deiner Erfahrungen empfehlen, die XML-Variante der Validierung zu verwenden? Scheint mir auf den ersten Blick etwas umfangreicher/aufwendiger.


Gruß

Matthias
 
Moin,

also ich bin der Meinung, dass Struts genau das tut was es soll. Mir scheint dein Workflow passt nicht so richtig zu dem, was du willst.

Ich gehe jetzt mal davon aus, dass du /editProject.do?do=create aufrufst und dann von der Action einen forward auf dein eigentliches Eingabeformular machst. Da du aber eine FormBean für die Action definiert hast, wird er bevor er die Methode create ausführt eben jene FormBean erzeugen, falls sie noch nicht im Context liegt und sie validieren (das hast du ja so angegeben). Da noch nix drin ist, fliegt er raus.

Du solltest deshalb auch nicht die create() Methode der Action aufrufen, sondern direkt die JSP mit dem Formular. Von dort aus gelangst du dann in die saveProject() Methode. Bevor er diese Methode ausführt, sollte er jetzt automatisch eine neue FormBean erzeugen, diese mit den Werten des Formulars befüllen und dannach erst validate() aufrufen. Wenn deine FormBean ok ist, sollte das auch klappen.

Sollte meine Vermutung über deine Vorgehensweise falsch sein, vergiss alles ab moin ;)

Viele Grüße
THMD
 

Neue Beiträge

Zurück