From: Joerg H. <joe...@gm...> - 2007-05-19 22:50:26
|
Hello, in my habit to use libs/frameworks as best as possible I often drive them to their extremes and come across some issues in them or at least questions others might not have had and can't answer me. That's the case at the moment with Spring Portlet MVC. I have posted them in the forum [1, 2, 3], but nobody could really give answers to them. And since Spring developers were rarely seen in the forum I decided to ask those questions here again. :-) All the questions are related and result from a feature I implemented in the last two weeks: a generic table view. That means you have a search form, this fills a criteria and the result is shown as table. Since this is very common functionality I built an abstraction of it. There is a TableViewConfig configuring the final result table (columns to view, order of columns, order of rows). There is an object the form is bound to and with which the result is retrieved using criteria by example. The last part is done by a CriteriaProvider (creating Hibernate's DetachedCriteria for example) and a DAO. The Portlet MVC part consists of two controllers: TableViewController for displaying the search form and the result. And TableViewConfigController for displaying a form for configuring the TableViewConfig, i.e. where you can change the order of the columns or switch on or off the one or the other column. The default view (actually view mode) is the TableViewController, you put your criteria into the search form and get the result. If you want to change the TableViewConfig you can switch to the edit mode and the TableViewConfigController comes into play. On saving the TableViewConfig I want to switch back to the view mode and show the new result according to the new TableViewConfig. ===== Issue 1 [1] I have (which is also not much related to my particular use case) is the usage of two different controllers for action and render phase. This is made easy by Spring since the HandlerMapping is executed for each phase. Unfortunately it seems not well-supported since you are more or less forced to use the same command object for both controllers. In the use case on saving the TableViewConfig (action request and form submit) I want to switch to TableViewController and render the result as it were a form submit in the same controller (isFormSubmission() returning true). But that's not possible since I need a different form backing object for this controller. In the case of isFormSubmission() returning true Spring Portlet MVC expects the form backing object to be found in the PortletSession (getRenderCommand(RenderRequest)). Only when isFormSubmission() does not return true a new form backing object is created. So with response_.setRenderParameter(getFormSubmitParameterName(), "false"); in the TableViewConfigController I force the TableViewController to create its own form backing object, but can't display the search result immediately since I'm no longer in form submission rendering. ===== The second issue is about missing value change listeners [2] or something like this. On changing the order of the columns (TableViewConfigController) I want to redisplay the form, i.e. go into form change processing. But it seems impossible to determine changes to the form backing object in Spring MVC. I worked around it by setting a parameter on such form submits on the client with Javascript and trigger on this one in isFormChangeRequest(). A better solution is welcome. ===== The third issue consists of multiple parts. It comes with using selects in the search from and not only plain text inputs. My TableViewConfig actually has a list of TableViewColumns, of which each has for example a property "path", "name", "type" ("input", "select"). For selects there is additionally "optionsPath", "itemValue" and "itemLabel" matching the attribute names of Spring's form taglib. Normally it would look like <form:select path="company"> <form:options items="${companies}" itemValue="id" itemLabel="name"/> </form:select> With my abstraction it would be <!-- context set to tableView.columns[i] via spring:nestedPath --> <form:select path="${path}"> <form:options items="${${optionsPath}}" itemValue="${itemValue}" itemLabel="${itemLabel}"/> </form:select> First problem with it is ${${, so nested property evaluation, which is not supported by JSTL. Lucky me, Spring's OptionsTag allows to pass an expression, so that I only need to prevent JSTL from interpreting the nested expression. I do it with something like (don't have access to the code at the moment) <c:set var="optionsPathExpr" value="${'${'}${optionsPath}${'}'}"/> <form:options items="${optionsPathExpr}" itemValue="${itemValue}" itemLabel="${itemLabel}"/> This works due to Spring's resolving of the "optionsPathExpr". But it's awkward and nicer solutions are welcome. I'll also come back to it later since it gets an issue again ... Now there is the requirement to style the item labels and I'm at [3] or [4]. <form:select> and <form:options> only allow to set plain itemLabel and itemValue. It can again be an expression, but the result of it is interpreted as property of the bean. I can not construct complex labels, while a kind of a template would be nice as shown in [4] and [5]. Workaround up to now, e.g. for i18n, is to use <c:forEach> and <form:option> as shown in [3] since <form:option> can be any JSP stuff. I COULD use it, it would stay as generic as the other solution, it's only a bit longer. BUT (coming back to the nested expression evaluation) I lose Spring's resolving of the "optionsPathExpr". I don't see a way to rewrite <form:select path="${path}"> <c:forEach items="${${optionsPath}}"> <form:option value="${item}"><!--complex label--></form:option> </c:forEach> </form:select> Nested expressions don't work and using the "workaround" from above <c:forEach> would try to iterate on the string "${optionsPathExpr}". That problem is not related to Spring directly, but if anybody knows a solution I'll be happy. While [4] for others is just a shorter way of writing for me it's the only option I see at the moment. ===== Thank you for still reading this lengthy post. I appreciate any input and help on my problems. Regards Joerg [1] http://forum.springframework.org/showthread.php?t=38451 [2] http://forum.springframework.org/showthread.php?t=38499 [3] http://forum.springframework.org/showthread.php?t=38795 [4] http://opensource.atlassian.com/projects/spring/browse/SPR-3484 [5] http://opensource.atlassian.com/projects/spring/browse/SPR-2659 |