Spring Roo Docs(1) Wedding Sample
Chapter2. Beginning With Roo: The Tutorial
2.2 Alternative Tutorial: The Wedding RSVP Application
Creating a Persistent Project
>mkdir wedding
>cd wedding
>roo
roo>project --topLevelPackage com.sillycat.wedding
roo>jpa setup --provider HIBERNATE --database HYPERSONIC_PERSISTENT
The database file is stored in ~/wedding.* by default. Here is the command to show them.
roo>database properties list
roo>database properties set --key database.url --value jdbc:hsqldb:wedding
It is ok to change this file directly with IDE. But it want to rebuild the project with filename.roo. You can use ROO to change the properties value.
Creating an Entity
roo>entity jpa --class com.sillycat.wedding.models.Rsvp
.aj file, in a nutshell, there are AspectJ inter-type declarations(ITDs)
roo>field string --fieldName code --notNull --sizeMin 1 --sizeMax 30
roo>field string --fieldName email --sizeMax 30
roo>field number --fieldName attending --type java.lang.Integer
roo>field string --fieldName specialRequests --sizeMax 100
roo>field date --fieldName confirmed --type java.util.Date
--notNull --sizeMin --sizeMax argument refer to the new Bean Validation standard, which is otherwise known as JSR 303.
And this particular standard offers automatic web and persistence tier validation, including creating the correct DDL for the tables.
Proving It Works: JUnit, Web Tier and Selenium
JUnit Integration test
roo>test integration
This integration test will verify the common JPA operations like persist, remove, find, merge and etc.
Add web tier as well
roo>controller scaffold ~.web.RsvpController
This web tier provided by Roo builds on Spring Framework3's excellent REST support. And we can use selenium test our web tier.
roo>selenium test --controller ~.web.RsvpController
we can run the JUnit test with command
roo>perform tests
quit the roo and start tomcat with maven command
>mvn tomcat:run
>mvn selenium:selenese
Security and Logging
We will fine-tune the Log4J-based logging.
roo>logging setup --package WEB --level DEBUG
At present anyone can access our web site and use the exsting RESTful administrative backend to create, update and delete RSVPs.
According to requirements, we wanted to use invitations codes to ensure only invited guests can RSVP.
>security setup
Manual Controllers, Dynamic Finders and Email Support
Creat a manual controller with command
roo>controller class --class ~.web.PublicRsvpController
Our objective is to retrieve the correct RSVP for a particular invitation code. We will treat each invitation code as a unique login name. Dynamic Finder. JPA QL.
roo>finder list --class ~.models.Rsvp --filter code
Add this finder to our system
roo>finder add --finderName findRsvpsByCodeEquals
prepare the email sender
roo>email sender setup --hostServer smtp.gmail.com --username
[email protected] --password password --port 587 --protocol SMTP
roo>field email template --class ~.web.PublicRsvpController
Final Steps
Change the file applicationContext-security.xml to enable the security check.
<http auto-config="true" use-expressions="true">
<form-login login-processing-url="/resources/j_spring_security_check" login-page="/login" authentication-failure-url="/login?login_error=t" />
<logout logout-url="/resources/j_spring_security_logout" />
<!-- Configure these elements to secure URIs in your application -->
<intercept-url pattern="/rsvps/**" access="hasRole('ROLE_ADMIN')" />
<intercept-url pattern="/login**" access="permitAll" />
<intercept-url pattern="/publicrsvp/**" access="permitAll" />
<intercept-url pattern="/resources/**" access="permitAll" />
<intercept-url pattern="/**" access="isAuthenticated()" />
</http>
<!-- Configure Authentication mechanism -->
<authentication-manager alias="authenticationManager">
<!-- SHA-256 values can be produced using 'echo -n your_desired_password | sha256sum' (using normal *nix environments) -->
<authentication-provider>
<user-service>
<user name="admin" password="ignored" authorities="ROLE_ADMIN" />
<user name="user1" password="ignored" authorities="ROLE_USER" />
<user name="user2" password="ignored" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
Spring Security does't realize we're ignoring passwords, so we need to edit the
src/main/webapp/WEB-INF/views/login.jspx and an <input name="j_password" type="hidden" value="ignored" /> line within the form.
<div>
<input id="j_password" type='hidden' name='j_password' value='ignored' />
</div>
Setting up email codes, and lookup code and create and fetch Rsvp in PublicRsvpController.java
@RequestMapping
public String get(ModelMap modelMap) {
modelMap.put("rsvp", getRsvp());
return "publicrsvp/publicrsvp";
}
@RequestMapping(method = RequestMethod.POST)
public String post(@ModelAttribute("rsvp") Rsvp rsvp, ModelMap modelMap) {
rsvp.setConfirmed(new Date());
if (rsvp.getId() == null) {
rsvp.persist();
} else {
rsvp.merge();
}
if (rsvp.getEmail().length() > 0) {
sendMessage("Carl <
[email protected]>",
"RSVP to our wedding", rsvp.getEmail(),
"Your RSVP has been saved: " + rsvp.toString());
}
modelMap.put("rsvp", rsvp);
return "publicrsvp/thanks";
}
private Rsvp getRsvp() {
Rsvp rsvp = new Rsvp();
try {
String code = SecurityContextHolder.getContext()
.getAuthentication().getName();
rsvp.setCode(code);
rsvp = (Rsvp) Rsvp.findRsvpsByCodeEquals(code).getSingleResult();
} catch (DataAccessException ignored) {
}
return rsvp;
}
Copy and rename the template publicrsvp/index.jspx to thanks.jspx
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<div xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:spring="http://www.springframework.org/tags"
xmlns:util="urn:jsptagdir:/WEB-INF/tags/util" version="2.0">
<jsp:directive.page contentType="text/html;charset=UTF-8" />
<jsp:output omit-xml-declaration="yes" />
<div>"Your RSVP has been confirmed: ${rsvp}".</div>
</div>
Copy and rename the template rsvp/create.jspx to publicrsvp/publicrsvp.jspx
<form:create id="fc_com_sillycat_wedding_models_Rsvp"
modelAttribute="rsvp" path="/publicrsvp" render="${empty dependencies}"
z="ljAD4P5uXRFqRI8AFiu0rOIXndU=">
<field:input field="code" id="c_com_sillycat_wedding_models_Rsvp_code"
max="30" min="1" required="true" z="lVc2JbMBUNmIMqGIuXeedt0RnDY=" />
<field:input field="email"
id="c_com_sillycat_wedding_models_Rsvp_email" max="30"
validationMessageCode="field_invalid_email"
z="xyUIdENd33YA6sFXUYBJInPPQ9c=" />
<field:input field="attending"
id="c_com_sillycat_wedding_models_Rsvp_attending"
validationMessageCode="field_invalid_integer"
z="51w2MRa7wL+mnX12lrVWCFESVxI=" />
<field:textarea field="specialRequests"
id="c_com_sillycat_wedding_models_Rsvp_specialRequests"
z="F1IVYZ4BIBHNm3DpKj8FFeNPTMs=" />
</form:create>
And change the views.xml under publicrsvp
<definition extends="default" name="publicrsvp/thanks">
<put-attribute name="body"
value="/WEB-INF/views/publicrsvp/thanks.jspx" />
</definition>
<definition extends="default" name="publicrsvp/publicrsvp">
<put-attribute name="body"
value="/WEB-INF/views/publicrsvp/publicrsvp.jspx" />
</definition>
The very last step is to edit index.jspx to link our homepage to our publicrsvp
<a href="publicrsvp">Enter the System</a>
references:
http://blog.springsource.com/2009/05/27/roo-part-2/
books:
spring-roo-docs.pdf