Refactoring: Move presentation logic from JSP page to Action and Tiles
Category: Techy
Tags: jsp, refactoring, struts
|
1 2 3 4 5 6 7 |
<logic:equals value="true" name="valid"> <logic:equals value="assigned" name="status"> <logic:equals value="admin" name="access"> Some HTML </logic:equals> </logic:equals> </logic:equals> |
to
|
1 2 3 4 |
<tiles:useattribute name="canShowHtml" /> <logic:equals value="true" name="canShowHtml"> Some HTML </logic:equals> |
Motivation
To prevent too much logic from being placed in the JSP page directly which makes things harder to debug as it will be mixed in with other HTML. One other alternative is to create separate pages for each state. However, to reduce code duplication we can put all of the buttons on the same page just hide or show them as needed.
Mechanics
- Define state subgroupings on paper
- Define state groupings on paper
- Define additional local forwards based on the groupings in struts-config.xml
- Define extensions to the page in your tiles-config.xml
- Convert the single return mappings.findForward("page") to break it up into conditions that will send to the appropriate forward
- Define which sections should be shown and not shown in your tiles-config.xml
- If sub-tiles are used. Rename the tiles defintion for the subtile and make the original definition include the new subtile definition. This is to get around Tiles not passing in context data to its subtiles.
- Add
<tiles:useattribute>for the attributes that define which sections can be seen to the JSP page. - Replace the multiple logic sections with a single
<logic:equals> - Remove old forwards from
struts-config.xml
Example
- For the example above there are three subgroups:
- validity
- status
- access
- We then create the following pattern for the groupings: [pageName].[validity].[status].[admin] Examples of the pattern applied are:
- summaryPage.valid.assigned.admin
- summaryPage.invalid.assigned.admin
- summaryPage.valid.assigned.user
- summaryPage.valid.rejected.user
- We add the new forwards to
struts-config.xml123456789101112131415161718192021222324<action path="/TestInput" ...><!-- original forward --><forwardname="summaryPage"path="summaryPage"/><!-- new forwards --><forwardname="summaryPage.valid.assigned.admin"path="summaryPage.valid.assigned.admin"/><forwardname="summaryPage.invalid.assigned.admin"path="summaryPage.invalid.assigned.admin"/><forwardname="summaryPage.valid.assigned.user"path="summaryPage.valid.assigned.user"/><forwardname="summaryPage.valid.rejected.user"path="summaryPage.valid.rejected.user"/></action> - We add new tiles-config.xml definitions based on the first one:
12345678910111213141516<!-- original --><definition name="summaryPage" path="summary.jsp"></definition><!-- new --><definition name="summaryPage.valid.assigned.admin" extends="summaryPage"></definition><definition name="summaryPage.invalid.assigned.admin" extends="summaryPage"></definition><definition name="summaryPage.valid.assigned.user" extends="summaryPage"></definition><definition name="summaryPage.valid.rejected.user" extends="summaryPage"></definition]
- In our execute method, we replace
1return mapping.findForward("summaryPage");
with
123456789101112131415StringBuilder forward = new StringBuilder("summaryPage.");if (isValid()) {forward.append("valid");} else {forward.append("invalid");}forward.append('.');if (isStatus(ASSIGNED)) {forward.append("assigned");} else if (isStatus(REJECTED)) {forward.append("rejected");}forward.append('.');forward.append(getUserType());return mapping.findForward(forward.toString()); - We add additional attributes to the tiles-config.xml
123456789101112131415<definition name="summaryPage.valid.assigned.admin" extends="summaryPage"><put name="canPermanentlyDelete" value="true" /><put name="canReassign" value="true" /></definition><definition name="summaryPage.invalid.assigned.admin" extends="summaryPage"><put name="canPermanentlyDelete" value="true" /></definition><definition name="summaryPage.valid.assigned.user" extends="summaryPage"><put name="canReassign" value="true" /></definition><definition name="summaryPage.valid.rejected.user" extends="summaryPage"></definition>
- Sub-tiles aren’t used in this situation, however if we are using sub-tiles like the following:
123456<definition name="basePage" path="basepage.jsp"></definition><definition name="summaryPage" extends="basePage"><put name="body" value="summary.jsp" /></definition>
Tiles will not render the following definition correctly or as one would normally expect.
1234<definition name="summaryPage.valid.assigned.admin" extends="summaryPage"><put name="canPermanentlyDelete" value="true" /><put name="canReassign" value="true" /></definition>Since the tiles attributes are not passed across definitions. To get around this we need to create a separate tile for the view.
1234567891011121314<definition name="basePage" path="basepage.jsp"></definition><definition name="summaryPage.view" path="summary.jsp"></definition><definition name="summaryPage.valid.assigned.admin" extends="basePage"><put name="body" value="summaryPage.valid.assigned.admin.view" /></definition><definition name="summaryPage.valid.assigned.admin.view" extends="summaryPage.view"><put name="canPermanentlyDelete" value="true" /><put name="canReassign" value="true" /></definition> - In the beginning of the JSP file we put in the following tags
12<tiles:useAttribute name="canPermanentlyDelete" ignore="true" /><tiles:useAttribute name="canReassign" ignore="true" />
Ignore is set to true so that in case it is not defined in the definition, it will still load the page. It is okay to have it present as well.
- We replace the deeply nested logic:equals such as
1234567<logic:equals value="true" name="valid"><logic:equals value="assigned" name="status"><logic:equals value="admin" name="access"><html:submit value="Reassign" /></logic:equals></logic:equals></logic:equals>
with
123<logic:equals value="true" name="canReassign"><html:submit value="Reassign" /></logic:equals> - The last thing to do is remove the old forward from the
struts-config.xmlsince it is no longer needed.1234<forwardname="summaryPage"path="summaryPage"/>
