Spring: metodo onSubmit() não é chamdo na submissão do formulário

16 respostas
cris.t

Olá,
Estou tentando fazer um simples formulário utilizando Spring, estou me baseando neste exemplo: http://static.springframework.org/docs/Spring-MVC-step-by-step/part4.html.
Pelo que entendi quando eu clico no botão para submeter o formulário é chamado o metodo onSubmit() do SimpleFormController, acontece que quando eu clico para submeter o meu formulário não acontece isso, ele chama o método validate() e referenceData() novamente e nao o onSubmit(). Não sei seestou fazendo algo errado, se alguem puder me ajudar agradeço muito!
Segue o código abaixo:

FormController:

public class CategoryFormController extends SimpleFormController {

    /** Logger for this class and subclasses */
    protected final Log logger = LogFactory.getLog(getClass());
    
    private CategoryDAO categoryDAO;
    
    @Override
    protected ModelAndView onSubmit(Object command, BindException bindException) throws ServletException {
    	System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> onSubit()");
    	Category category = (Category) command;
        categoryDAO.insert(category);

        logger.info("returning from PriceIncreaseForm view to " + getSuccessView());

        return new ModelAndView(getSuccessView());
    }
    
    protected Object formBackingObject(HttpServletRequest request) throws ServletException {
    	Category category = new Category();
    	category.setName("Teste");
    	category.setCategory(this.categoryDAO.findByPK((long) 1));
        return category;
    }
    
    @Override
    protected Map<String, Object> referenceData(HttpServletRequest request) throws Exception {
       	System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> referenceData()");
    	Map<String, Object> referenceData = new HashMap<String, Object>();
        referenceData.put("categories", this.categoryDAO.findAll());
        return referenceData;
    }
    
	public void setCategoryDAO(CategoryDAO categoryDAO) {
	   	System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> setCategory()");
		this.categoryDAO = categoryDAO;
	}
	
	public CategoryDAO getCategoryDAO() {
	   	System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> getCategory()");
		return categoryDAO;
	}
}

formulário:

<h1><fmt:message key="category.heading"/></h1>

	<form:form method="post" commandName="category">
	  <table width="95%" bgcolor="f8f8ff" border="0" cellspacing="0" cellpadding="5">
	    <tr>
	      	<td align="right" width="20%"> <fmt:message key="category.label_name"/></td>
	        <td width="20%">
	          <form:input path="name"/>
	        </td>
	        <td width="60%">
	          <form:errors path="name" cssClass="error"/>
	        </td>
	    </tr>
	    
	     <tr>
	    	<td align="right" width="20%"> <fmt:message key="category.label_mae"/></td>
	        <td width="20%">
              <form:select path="category">  
                <form:option value="" label=""/>  
                <form:options items="${categories}" itemValue="name" itemLabel="name"/>  
             </form:select> 
	        </td>
	    </tr>
	  </table>
	  <br>
	  &lt;input type="submit" name="Cadastrar" align="center" value="submit"&gt;
	&lt;/form:form&gt;
	
	<a hello.htm"/>"&gt;Home</a>

servlet.xml

&lt;bean name="/categoryForm.htm" class="com.braview.sbce.controller.CategoryFormController"&gt;
        &lt;property name="sessionForm" value="true"/&gt;
        &lt;property name="commandName" value="category"/&gt;
        &lt;property name="commandClass" value="com.braview.sbce.dataaccess.entity.Category"/&gt;
        &lt;property name="validator"&gt;
            &lt;bean class="com.braview.sbce.validator.CategoryValidator"/&gt;
        &lt;/property&gt;
        &lt;property name="formView" value="categoryForm"/&gt;
        &lt;property name="successView" value="hello.htm"/&gt;
        &lt;property name="categoryDAO" ref="categoryDAO"/&gt; 
    &lt;/bean&gt;

Gostaria de saber também pra que serve o método formBackingObject, pois não entendi claramente a sua função.

Obrigado!

16 Respostas

quebrado

debuga o bagulho e veja se esta apresentando algum tipo de erro no validate.
o formBackingObject é o metodo que vc prepara o command. Exemplo tenho uma classe carro com a classe motor embutida. tenho que inicializar o motor para que tudo funcione, senão nullpointerexception na cara.

quebrado

use o validate na action.
Assim:

protected void onBindAndValidate(HttpServletRequest request, Object cmd, BindException errors) throws Exception {}
Eu acho mais facil assim.

cris.t

Meu Validator ta desta maneira, porém acho que ele nao está funcionando pois quando deixo o campo nome em branco nao acontece nd:

public class CategoryValidator implements Validator{

	@Override
	public boolean supports(Class clazz) {
		return Category.class.equals(clazz);
	}

	@Override
	public void validate(Object obj, Errors errors) {
	   	System.out.println("&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; validate()");
		Category category = (Category) obj;
        if (category == null) {
            errors.rejectValue("name", "error.not-specified", null, "Value required.");
        }
	}
}

Qual a diferença deste e do método que vc postou acima? Vou testa-lo pra ver se funciona desta maneira.

quebrado

Eu acho mais fácil subscrever este metodo do que colocar um monte de classe de validação! Mas isto é gosto pessoal do desenvolvedor.

cris.t

Precisa fazer algum tipo de confiração na jsp pra usar o onBindAndValidate? Eu o sobrecrevi e implementei e mesmo assim continua acontecendo a mesma coisa o formulario nao submete e qdo eu deixo em branco o campo não aprece nenhuma msgm de validação:

@Override
	protected void onBindAndValidate(HttpServletRequest request,
			Object command, BindException errors) throws Exception {
	 	System.out.println("&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; onBindAndValidate()");
		Category category = (Category) command;
        if (category == null) {
            errors.rejectValue("name", "error.not-specified", null, "Value required.");
        }
	}
cris.t

Mais alguém teria alguma idéia do motivo pelo qual ele não estaria chamando o método onSubimit?

quebrado

o command ta vindo carregado!?

cris.t

Está sim, eu debuguei e quando ele chama o onBindAndValidate() o parametro command dele ta vindo carregado corretamente. Pra utilizar o onBindAndValidate() eu preciso fazer mais alguma configuração ou no form ou em algum bean?

quebrado

se o command tiver carregado no onBindAndValidate e o BindException errors estiver em branco era para funcionar corretamente.

J

Olá

Cara coloca ai o código do seu command, acredito que está ocorrendo um erro ao submeter o formuláriocom erro, pois o seu Command é o pojo Category e no formulário estão mapeados os campos “name” e o auto relacionamento “category”, provavelmente vc precisa de um editor para este auto relacionamento. Somente para ter certeza experimenta retirar esse combo de auto relacionamento.

cris.t

Olá João

Esta é a minha classe Category:

@Entity
@Table(name = "category", schema = "public")
public class Category implements java.io.Serializable {
	private static final long serialVersionUID = -6908769737731206565L;

	private Long id;
	private Category category;
	private String name;
	private Set&lt;Category&gt; categories = new HashSet&lt;Category&gt;(0);
	private Set&lt;Product&gt; products = new HashSet&lt;Product&gt;(0);

	public Category() {
	}

	public Category(String name) {
		this.name = name;
	}

	public Category(Category category, String name, Set&lt;Category&gt; categories,
			Set&lt;Product&gt; products) {
		this.category = category;
		this.name = name;
		this.categories = categories;
		this.products = products;
	}

	@SequenceGenerator(name = "generator", sequenceName = "seq_category", allocationSize=1)
	@Id
	@GeneratedValue(strategy = SEQUENCE, generator = "generator")
	@Column(name = "id", unique = true, nullable = false)
	public Long getId() {
		return this.id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "parent_id")
	public Category getCategory() {
		return this.category;
	}

	public void setCategory(Category category) {
		this.category = category;
	}

	@Column(name = "name", nullable = false, length = 30)
	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@OneToMany(fetch = FetchType.LAZY, mappedBy = "category")
	public Set&lt;Category&gt; getCategories() {
		return this.categories;
	}

	public void setCategories(Set&lt;Category&gt; categories) {
		this.categories = categories;
	}

	@OneToMany(fetch = FetchType.LAZY, mappedBy = "category")
	public Set&lt;Product&gt; getProducts() {
		return this.products;
	}

	public void setProducts(Set&lt;Product&gt; products) {
		this.products = products;
	}

}

O que seria esse editor? vou tirar a combo pra testar.

cris.t

Realmente é essa combo, eu tirei ela e agora o onSubmit() está sendo chamado, mas vou precisar usar, pois uma categoria pode ser filha de outra categoria, como eu devo usar essa combo?

J

Olá

Seguinte leia esse capítulo do spring que vai te ajudar: Validation, Data-binding, the BeanWrapper, and PropertyEditors

Mas de maneira geral é assim: na web, são só trocados texto, então seu combo vai conter o id da categoria selecionada, quando chegar no servidor o id deve ser transformado no pojo Categoria, em meus projetos utilizo da seguinte maneira:

Bean do Controller com editor registrado:

<bean name="/categoryForm.htm" class="com.braview.sbce.controller.CategoryFormController">  
     <property name="sessionForm" value="true"/>  
     <property name="commandName" value="category"/>  
     <property name="commandClass" value="com.braview.sbce.dataaccess.entity.Category"/>  
     <property name="validator">  
         <bean class="com.braview.sbce.validator.CategoryValidator"/>  
     </property>  
     <property name="formView" value="categoryForm"/>  
     <property name="successView" value="hello.htm"/>  
     <property name="categoryDAO" ref="categoryDAO"/>   
     <property name="propertyEditorRegistrars">
         <list>
              <ref bean="categoryEditor"/>
         </list>
     </property>
 </bean>

Bean do Editor:

<bean id="categoryEditor" class="com.sistema.editores.CategoryEditor"/>

Classe do editor:

public class CategoryEditor extends PropertyEditorSupport implements PropertyEditorRegistrar {

    private CategoryDAO categoryDAO; 

    public void setAsText(final String value) {
    	if(	(value == null) ||
    		(value.equals("0"))	){
            super.setValue(null);
    	} else {
            try {
            	Category category = this.categoryDAO.get(value);
                super.setValue(category);
            } catch (final Exception e) {
                super.setValue(null);
            }
    	}

    }

    @Override
    public String getAsText() {
    	Category category = (Category) this.getValue();

    	if(	(category == null) ||
    		(category.getId() == null)	){
    		return super.getAsText();
    	} else {
        	return category.getId().toString();
    	}

    }

	public void registerCustomEditors(PropertyEditorRegistry propertyEditorRegistry) {
		propertyEditorRegistry.registerCustomEditor(Category.class, this);
	}

}
cris.t

Muito Obrigada pela ajuda, agora funcionou, era isto msm, apenas não entendi muito bem td o que vc fez, mas vou ler o tutorial pra ver se consigo entender melhor, valew!!! :slight_smile:

cris.t

A unica coisa é que o id da categoria mae (auto-relacionamento) não está sendo gravado no banco.

cris.t

No metodo setAsTex() o parametro value está vindo com “-”, o que seria essa value?

Criado 26 de maio de 2009
Ultima resposta 28 de mai. de 2009
Respostas 16
Participantes 3