Introduction
This application is basically the same as the "stripes-crud" application and lesson found
here. See that lesson for a more complete deomonstration. All the classes
in the source code you can download are groovy classes. Below I'll show the two DAO classes used. This app is really simple and doesn't
do a whole lot, but it will get you feel of some basic CRUD. (In a follow up I'll have this running with iBATIS and some Spring.)
Building and Running
Download the source code using the link above. The source comes with an ant build file.
**Unlike the previous stripes-crud application I'm now using Resin instead of Tomcat. Just modify the server and deploydir lines in the ant build.xml file to point to your appropriate server and deploy path.
Type "ant deploy" from within the directory where you extracted the source code, and it will compile the war and deploy it to your server. Start your server and go to http://localhost:8080/stripes-crud-groovy/ (assuming you're using port 8080 of course.) A war is also built in the dist directory of the project.
(Lastly, I ended up putting the groovy-all jar in the WEB-INF/lib instead of the smaller groovy.jar. The only reason is because I didn't feel like messing around figuring out the classpath issues when running the ant groovy compiler which needs the groovy-all jar and it would get confused if I had the smaller jar in the WEB-INF/lib since that's in my classpath also for the build. I could fix it, I'm just being lazy. Just know that if you go to really deploy a real app you don't need the larger groovy-all jar in your app's lib, just use the smaller groovy.jar.)
**Unlike the previous stripes-crud application I'm now using Resin instead of Tomcat. Just modify the server and deploydir lines in the ant build.xml file to point to your appropriate server and deploy path.
Type "ant deploy" from within the directory where you extracted the source code, and it will compile the war and deploy it to your server. Start your server and go to http://localhost:8080/stripes-crud-groovy/ (assuming you're using port 8080 of course.) A war is also built in the dist directory of the project.
(Lastly, I ended up putting the groovy-all jar in the WEB-INF/lib instead of the smaller groovy.jar. The only reason is because I didn't feel like messing around figuring out the classpath issues when running the ant groovy compiler which needs the groovy-all jar and it would get confused if I had the smaller jar in the WEB-INF/lib since that's in my classpath also for the build. I could fix it, I'm just being lazy. Just know that if you go to really deploy a real app you don't need the larger groovy-all jar in your app's lib, just use the smaller groovy.jar.)
Department.groovy
import org.apache.commons.lang.builder.ToStringBuilder
class Department {
int departmentId
String name
String toString() {
return ToStringBuilder.reflectionToString(this)
}
}
Employee.groovy
import org.apache.commons.lang.builder.ToStringBuilder
class Employee {
int employeeId
int age
String firstName
String lastName
Department department
String toString() {
return ToStringBuilder.reflectionToString(this)
}
}
EmployeeDao.groovy
class EmployeeDao {
static List employees =
[new Employee( employeeId: 4, firstName: "Greg", lastName: "Ward", age: 25, department: DepartmentDao.departmentsMap[100] ),
new Employee( employeeId: 1, firstName: "John", lastName: "Supper", age: 36, department: DepartmentDao.departmentsMap[300] ),
new Employee( employeeId: 3, firstName: "Fred", lastName: "Doofus", age: 39, department: DepartmentDao.departmentsMap[200] ),
new Employee( employeeId: 2, firstName: "Bob", lastName: "Blobber", age: 24, department: DepartmentDao.departmentsMap[100] ) ]
List getAllEmployees() {
return employees.sort{a,b -> a.lastName.equalsIgnoreCase(b.lastName) ? 0: a.lastName.toUpperCase() < b.lastName.toUpperCase() ? -1: 1}
}
def getEmployee(id) {
return employees.find{ it.employeeId == id }
}
def update(emp) {
emp.department = DepartmentDao.departmentsMap[ emp.department.departmentId ]
employees[employees.findIndexOf{ it.employeeId in emp.employeeId }] = emp
}
def insert(emp) {
def mc= [compare:{a,b -> a.employeeId == b.employeeId? 0: a.employeeId < b.employeeId ? -1: 1}] as Comparator
emp.department = DepartmentDao.departmentsMap[ emp.department.departmentId]
emp.employeeId = (employees.max(mc)).employeeId + 1
employees.add(emp)
}
def delete(id) {
employees.remove( employees.findIndexOf{ it.employeeId in id } )
}
}
DepartmentDao.groovy
class DepartmentDao {
static Map departmentsMap = new HashMap()
static List departments = [
new Department( departmentId: 100, name: "Accounting" ),
new Department( departmentId: 200, name: "HR"),
new Department( departmentId: 300, name: "Sales")]
static {
departments.each { dept ->
departmentsMap.put( dept.departmentId, dept )
}
}
List getDepartments() {
return departments
}
Map getDepartmentsMap() {
return departmentsMap
}
}
EmployeeActionBean.groovy
The only thing I can't seem to get working is the nested annotation syntax. The Groovy compiler complains. If anyone knows why, or a work-around
please let me know.
You'll see service method calls here, but all they do is delegate to the dao classes, so I didn't even bother to show them since they were so trivial. (I really could have just left them out, but some people like layers so I left them in.)
You'll see service method calls here, but all they do is delegate to the dao classes, so I didn't even bother to show them since they were so trivial. (I really could have just left them out, but some people like layers so I left them in.)
class EmployeeActionBean extends BaseActionBean {
static String EMPLOYEES_DISPLAY = "/Employee.action?employees="
static String EMPLOYEES = "/WEB-INF/jsp/employees.jsp"
static String EMPLOYEE_FORM = "/WEB-INF/jsp/employeeForm.jsp"
EmployeeService employeeService = new EmployeeService()
DepartmentService departmentService = new DepartmentService()
@ValidateNestedProperties([
@Validate(field="firstName", required=true),
@Validate(field="lastName", required=true),
@Validate(field="age", required=true,converter=IntegerTypeConverter.class)
])
Employee employee
@DontValidate
@DefaultHandler
public Resolution employees() {
return new ForwardResolution(EMPLOYEES)
}
@DontValidate
Resolution preEdit() {
if ( employee?.employeeId ) {
employee = employeeService.getEmployee(employee.employeeId)
}
return new ForwardResolution(EMPLOYEE_FORM)
}
Resolution save() {
if ( employee?.employeeId) {
employeeService.updateEmployee(employee)
} else {
employeeService.insertEmployee(employee)
}
return new RedirectResolution(EMPLOYEES_DISPLAY)
}
@DontValidate
public Resolution delete() {
employeeService.deleteEmployee(employee.employeeId)
return new RedirectResolution(EMPLOYEES_DISPLAY)
}
@DontValidate
public Resolution cancel() {
return new RedirectResolution(EMPLOYEES_DISPLAY)
}
List getAllDepartments() {
return departmentService.getAllDepartments()
}
List getAllEmployees() {
return employeeService.getAllEmployees()
}
}