views:

3546

answers:

1

UPDATE 1/31/10: Since this thread continues to get a lot of views...I am curious if it has been of help to anyone recently? Feel free to leave comments/feedback, thanks.


I have a Spring form where I would like to reuse the search page to include the results under the search form. Currently when I do this I get the following error on loading the success view:

java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'searchAccounts' available as request attribute

Here is my bean configuration:

<bean name="/search.html" class="myapp.web.AccountSearchController">
        <property name="sessionForm" value="true"/>
    <property name="commandName" value="searchAccounts"/>
    <property name="commandClass" value="myapp.service.AccountSearch"/>
    <property name="validator">
        <bean class="myapp.service.AccountSearchValidator"/>
    </property>
    <property name="formView" value="accountSearch"/>
    <property name="successView" value="accountSearchResults"/>
</bean>

Here is the snippet of JSP that includes the search form:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

<form:form method="post" commandName="searchAccounts">

<table valign="top" cellspacing="0" cellpadding="0" width="500" border="0">

    <tr>
        <td valign="top">

        <div class="border-title">Account Search</div>

        <div id="navhome">
        <div class="border">
        <div id="sidebarhome">


        <table id="form">
            <tr>
                <td colspan="2">Search by Account ID or Domain Name. If
                values are provided for both, only accounts matching both values
                will be returned.</td>
            </tr>

            <tr>
                <td colspan="2">&nbsp;</td>
            </tr>

            <tr>
                <td align="right" valign="top"><form:label path="accountId">Account ID</form:label>:</td>
                <td><form:input path="accountId" size="30"/></td>
            </tr>
            <c:set var="accountIdErrors"><form:errors path="accountId"/></c:set>
            <c:if test="${not empty accountIdErrors}">
            <tr>
                 <td>&nbsp;</td>
                 <td>${accountIdErrors}</td>
            </tr>
            </c:if>
            <tr>
                <td align="right" valign="top"><form:label path="domainName">Domain Name</form:label>:</td>
                <td><form:input path="domainName" size="30"/></td>
            </tr>
            <c:set var="domainNameErrors"><form:errors path="domainName"/></c:set>
            <c:if test="${not empty domainNameErrors}">
            <tr>
                 <td>&nbsp;</td>
                 <td>${domainNameErrors}</td>
            </tr>
            </c:if>
            <tr>
                <td colspan="2">&nbsp;</td>
            </tr>
            <tr>
                <td>&nbsp;</td>
                <td><input type="submit" name="submit" value="Search">
                </td>
            </tr>
        </table>

        </div>
        </div>
        </div>

        </td>
    </tr>
</table>
</form:form>

And...here is my form controller class (less the imports):

    public class AccountSearchController  extends SimpleFormController {

    protected final Log logger = LogFactory.getLog(getClass());

    public ModelAndView onSubmit(Object command, BindException errors) throws ServletException {
        String accountId = ((AccountSearch) command).getAccountId();
        String domainName = ((AccountSearch) command).getDomainName();

        logger.info("User provided search criteria...\n\tDomain Name: " + domainName + "\n\tAccountId: " + accountId);

        //TODO do search

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

        return new ModelAndView(getSuccessView());
    }

    protected Object formBackingObject(HttpServletRequest request) throws ServletException {
        AccountSearch accountSearch = new AccountSearch();
        return accountSearch;
    }
}

Thanks in advance for your help!

-aj

UPDATE:

I ported this to an annotated controller per answer below. Here is the new/working code:

@Controller
@RequestMapping("/search.html")
public class AccountSearchController {

    // note: this method does not have to be called setupForm
    @RequestMapping(method = RequestMethod.GET)
    public String setupForm(Model model) {
        AccountSearchCriteria accountSearchCriteria = new AccountSearchCriteria();
        model.addAttribute("accountSearchCriteria", accountSearchCriteria);
        model.addAttribute("title", "Account Search");
        return "accountSearch";
    }

    // note: this method does not have to be called onSubmit
    @RequestMapping(method = RequestMethod.POST)
    public String onSubmit(@ModelAttribute("accountSearchCriteria") AccountSearchCriteria accountSearchCriteria, BindingResult result, SessionStatus status, Model model) {
        new AccountSearchValidator().validate(accountSearchCriteria, result);
        if (result.hasErrors()) {
            return "accountSearch";

        } else {
            ArrayList<AccountSearchCriteria> accountSearchResults = new ArrayList<AccountSearchCriteria>();

            AccountSearchCriteria rec = new AccountSearchCriteria();
            rec.setDomainName("ajcoon.com");
            accountSearchResults.add(rec);

            AccountSearchCriteria rec2 = new AccountSearchCriteria();
            rec2.setDomainName("ajcoon2.com");
            accountSearchResults.add(rec2);

            //TODO do search
            //ArrayList<HashMap<String,String>> accountSearchResults = new AccountSearchService().search(accountId,domainName);

            if( accountSearchResults.size() < 1 ){
                result.rejectValue("domainName", "error.accountSearch.noMatchesFound", "No matching records were found.");
                return "accountSearch";

            } else if(accountSearchResults.size() > 1){
                model.addAttribute("accountSearchResults", accountSearchResults);
                return "accountSearch";

            } else {
                status.setComplete();
                return "redirect:viewAccount?accountId=";
                //return "redirect:viewAccount?accountId=" + accountSearchResults.get(0).getAccountId();
            }
        }
    }   
}
+1  A: 

try to use (throws Exception instead of ..)

protected Object formBackingObject(HttpServletRequest request)
                            throws Exception {
        AccountSearch accountSearch = new AccountSearch();
        System.out.println("inside formBackingObject");
        return accountSearch;
}

It looks like your formBackingObject Method is not executed. rerun the code with the above change and see log console to see if the method is executed.

--

You should be using annotation instead of extending controller. Spring 3.0 will deprecate the controller hierarchy.

surajz
Thanks surajz...I went ahead and ported this over to an annotated controller and managed to fix the issue. I'll post the new controller to an edit. +1 for the suggestion!
AJ