偶然在查看文档时,看到这个demo,后来认真看了下真是麻雀虽小,很单一的struts2的增删改查,但是却从各方面诠释着struts2这一开源框架的精妙设计和丰富的可定制性。文档上提供是片段式的代码讲解,且是英文的,所以这里记录一下,方面以后查看。
和以前一样,先上效果图:
图一:
图二:
图三:
图四:
虽然从图上看的话,以上功能简单,但是代码里,时刻体现着该框架的设计之优秀,首先,我们新建一个web功能CusManager,并加入struts2的7个必要jar包。
第一步,新建两个实体类Department和Employee作POJO,代码如下:
package com.aurifa.struts2.tutorial.model;
import java.io.Serializable;
public class Department implements Serializable {
Integer departmentId;
String name;
public Department() {
}
public Department(Integer departmentId, String name) {
this.departmentId = departmentId;
this.name = name;
}
public Integer getDepartmentId() {
return departmentId;
}
public void setDepartmentId(Integer departmentId) {
this.departmentId = departmentId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.aurifa.struts2.tutorial.model;
import java.io.Serializable;
public class Employee implements Serializable {
private Integer employeeId;
private Integer age;
private String firstName;
private String lastName;
private Department department;
public Employee() {
}
public Employee(Integer employeeId, String firstName, String lastName,
Integer age, Department department) {
this.employeeId = employeeId;
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.department = department;
}
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
public Integer getEmployeeId() {
return employeeId;
}
public void setEmployeeId(Integer employeeId) {
this.employeeId = employeeId;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
第二步,定义dao层的接口,代码如下:
package com.aurifa.struts2.tutorial.dao;
import java.util.List;
import java.util.Map;
public interface DepartmentDao {
public List getAllDepartments();
public Map getDepartmentsMap();
}
package com.aurifa.struts2.tutorial.dao;
import java.util.List;
import com.aurifa.struts2.tutorial.model.Employee;
public interface EmployeeDao {
public List getAllEmployees();
public Employee getEmployee(Integer id);
public void update(Employee emp);
public void insert(Employee emp);
public void delete(Integer id);
}
第三步,完成上述接口的实现类,代码如下:
package com.aurifa.struts2.tutorial.dao;
import java.util.*;
import com.aurifa.struts2.tutorial.model.Department;
public class DepartmentNoDBdao implements DepartmentDao {
private static List departments;
private static Map departmentsMap;
static {
departments = new ArrayList();
departments.add(new Department( new Integer(100), "Accounting" ));
departments.add(new Department( new Integer(200), "R & D"));
departments.add(new Department( new Integer(300), "Sales" ));
departmentsMap = new HashMap();
Iterator iter = departments.iterator();
while( iter.hasNext() ) {
Department dept = (Department)iter.next();
departmentsMap.put(dept.getDepartmentId(), dept );
}
}
public List getAllDepartments() {
return departments;
}
public Map getDepartmentsMap() {
return departmentsMap;
}
}
package com.aurifa.struts2.tutorial.dao;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.aurifa.struts2.tutorial.model.Department;
import com.aurifa.struts2.tutorial.model.Employee;
public class EmployeeNoDBdao implements EmployeeDao {
private static Map departmentsMap;
private static ArrayList employees;
static {
employees = new ArrayList();
employees.add(new Employee(new Integer(1), "John", "Doe", new Integer(36), new Department(new Integer(100), "Accounting")));
employees.add(new Employee(new Integer(2), "Bob", "Smith", new Integer(25), new Department(new Integer(300), "Sales")));
DepartmentDao deptDao = new DepartmentNoDBdao();
departmentsMap = deptDao.getDepartmentsMap();
}
Log logger = LogFactory.getLog(this.getClass());
public List getAllEmployees() {
return employees;
}
public Employee getEmployee(Integer id) {
Employee emp = null;
Iterator iter = employees.iterator();
while (iter.hasNext()) {
emp = (Employee)iter.next();
if (emp.getEmployeeId().equals(id)) {
break;
}
}
return emp;
}
public void update(Employee emp) {
Integer id = emp.getEmployeeId();
for (int i = 0; i < employees.size(); i++) {
Employee tempEmp = (Employee)employees.get(i);
if (tempEmp.getEmployeeId().equals(id)) {
emp.setDepartment((Department)departmentsMap.get(emp.getDepartment().getDepartmentId()));
employees.set(i, emp);
break;
}
}
}
public void insert(Employee emp) {
int lastId = 0;
Iterator iter = employees.iterator();
while (iter.hasNext()) {
Employee temp = (Employee)iter.next();
if (temp.getEmployeeId().intValue() > lastId) {
lastId = temp.getEmployeeId().intValue();
}
}
emp.setDepartment((Department)departmentsMap.get(emp.getDepartment().getDepartmentId()));
emp.setEmployeeId(new Integer(lastId + 1));
employees.add(emp);
}
public void delete(Integer id) {
for (int i = 0; i < employees.size(); i++) {
Employee tempEmp = (Employee)employees.get(i);
if (tempEmp.getEmployeeId().equals(id)) {
employees.remove(i);
break;
}
}
}
}
第四步,根据dao层,完成service层(因为代码较为简单,未明确分包),代码如下:
package com.aurifa.struts2.tutorial.service;
import java.util.List;
import com.aurifa.struts2.tutorial.dao.DepartmentDao;
import com.aurifa.struts2.tutorial.dao.DepartmentNoDBdao;
public class DepartmentDaoService implements DepartmentService {
private DepartmentDao dao;
public DepartmentDaoService() {
this.dao = new DepartmentNoDBdao();
}
public List getAllDepartments() {
return dao.getAllDepartments();
}
}
package com.aurifa.struts2.tutorial.service;
import java.util.List;
import com.aurifa.struts2.tutorial.dao.EmployeeDao;
import com.aurifa.struts2.tutorial.dao.EmployeeNoDBdao;
import com.aurifa.struts2.tutorial.model.Employee;
public class EmployeeDaoService implements EmployeeService {
private EmployeeDao dao;
public EmployeeDaoService() {
this.dao = new EmployeeNoDBdao();
}
public List getAllEmployees() {
return dao.getAllEmployees();
}
public void updateEmployee(Employee emp) {
dao.update(emp);
}
public void deleteEmployee(Integer id) {
dao.delete(id);
}
public Employee getEmployee(Integer id) {
return dao.getEmployee(id);
}
public void insertEmployee(Employee emp) {
dao.insert(emp);
}
}
第五步,service层的接口,代码如下:
package com.aurifa.struts2.tutorial.service;
import java.util.List;
public interface DepartmentService {
public List getAllDepartments();
}
package com.aurifa.struts2.tutorial.service;
import java.util.List;
import com.aurifa.struts2.tutorial.model.Employee;
public interface EmployeeService {
public List getAllEmployees();
public void updateEmployee(Employee emp);
public void deleteEmployee(Integer id);
public Employee getEmployee(Integer id);
public void insertEmployee(Employee emp);
}
第六步,则是action层,代码如下:
package com.aurifa.struts2.tutorial.action;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.aurifa.struts2.tutorial.model.Employee;
import com.aurifa.struts2.tutorial.service.DepartmentDaoService;
import com.aurifa.struts2.tutorial.service.DepartmentService;
import com.aurifa.struts2.tutorial.service.EmployeeDaoService;
import com.aurifa.struts2.tutorial.service.EmployeeService;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.Preparable;
public class EmployeeAction extends ActionSupport implements Preparable {
/**
*
*/
private static final long serialVersionUID = -6886717038958304064L;
private Log logger = LogFactory.getLog(this.getClass());
private static EmployeeService empService = new EmployeeDaoService();
private static DepartmentService deptService = new DepartmentDaoService();
private Employee employee;
private List employees;
private List departments;
public void prepare() throws Exception {
departments = deptService.getAllDepartments();
if (employee != null && employee.getEmployeeId() != null) {
employee = empService.getEmployee(employee.getEmployeeId());
}
}
public String doSave() {
if (employee.getEmployeeId() == null) {
empService.insertEmployee(employee);
} else {
empService.updateEmployee(employee);
}
return SUCCESS;
}
public String doDelete() {
empService.deleteEmployee(employee.getEmployeeId());
return SUCCESS;
}
public String doList() {
employees = empService.getAllEmployees();
return SUCCESS;
}
public String doInput() {
return INPUT;
}
/**
* @return Returns the employee.
*/
public Employee getEmployee() {
return employee;
}
/**
* @param employee
* The employee to set.
*/
public void setEmployee(Employee employee) {
this.employee = employee;
}
/**
* @return Returns the employees.
*/
public List getEmployees() {
return employees;
}
/**
* @return Returns the departments.
*/
public List getDepartments() {
return departments;
}
}
接着在同级目录下,我们添加该action的同名验证框架,代码如下:
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"> <validators> <field name="employee.firstName"> <field-validator type="requiredstring"> <message key="errors.required.firstname"/> </field-validator> </field> <field name="employee.lastName"> <field-validator type="requiredstring"> <message key="errors.required.lastname"/> </field-validator> </field> <field name="employee.age"> <field-validator type="required" short-circuit="true"> <message key="errors.required.age"/> </field-validator> <field-validator type="int"> <param name="min">18</param> <param name="max">65</param> <message key="errors.required.age.limit"/> </field-validator> </field> </validators>
至此,代码部分大抵完成,下面在src下,新建所需的配置文件:
首先是log4j,代码如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <appender name="stdout" class="org.apache.log4j.ConsoleAppender"> <layout class="org.apache.log4j.TTCCLayout"/> </appender> <!-- log detail configuration --> <logger name="com.opensymphony.xwork"> <level value="error"/> <appender-ref ref="stdout"/> </logger> <logger name="com.opensymphony.webwork"> <level value="error"/> <appender-ref ref="stdout"/> </logger> <logger name="freemarker"> <level value="warn"/> <appender-ref ref="stdout"/> </logger> <logger name="com.mevipro"> <level value="debug"/> <appender-ref ref="stdout"/> </logger> <root> <level value="error"/> <appender-ref ref="stdout"/> </root> </log4j:configuration>
其次是struts.xml,代码如下:
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <!-- Include webwork default (from the Struts JAR). --> <include file="struts-default.xml"/> <!-- Configuration for the default package. --> <package name="default" extends="struts-default"> <!-- Default interceptor stack. --> <default-interceptor-ref name="paramsPrepareParamsStack"/> <action name="index" class="com.aurifa.struts2.tutorial.action.EmployeeAction" method="list"> <result name="success">/jsp/employees.jsp</result> <!-- we don't need the full stack here --> <interceptor-ref name="basicStack"/> </action> <action name="crud" class="com.aurifa.struts2.tutorial.action.EmployeeAction" method="input"> <result name="success" type="redirect-action">index</result> <result name="input">/jsp/employeeForm.jsp</result> <result name="error">/jsp/error.jsp</result> </action> </package> </struts>
然后是struts的国际化文件,struts.properties和guest.properties,代码分别如下:
struts.custom.i18n.resources=guest
#labels application.title=Employee Maintenance Application label.employees=Employees label.delete=Delete label.edit=Edit label.employee.edit=Edit Employee label.employee.add=Add Employee label.firstName=First Name label.lastName=Last Name label.department=Department label.age=Age #button labels button.label.submit=Submit button.label.cancel=Cancel ##-- errors errors.prefix=<span style="color:red;font-weight:bold;"> errors.suffix=</span> errors.general=An Error Has Occcured errors.required.firstname=Name is required. errors.required.lastname=Last name is required. errors.required.age=Please provide an age. errors.required.age.limit=Please provide an age between ${min} and ${max}. errors.required.department=Department is required.
最后贴上运行时的jsp页面,代码不多,下面我分别贴出来,代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="Refresh" content="0;URL=index.action"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> This is my JSP page. <br> </body> </html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="s" uri="/struts-tags" %> <s:if test="employee==null || employee.employeeId == null"> <s:set name="title" value="%{'Add new employee'}"/> </s:if> <s:else> <s:set name="title" value="%{'Update employee'}"/> </s:else> <html> <head> <link href="css/main.css" rel="stylesheet" type="text/css"/> <style>td { white-space:nowrap; }</style> <title><s:property value="#title"/></title> </head> <body> <div class="titleDiv"><s:text name="application.title"/></div> <h1><s:property value="#title"/></h1> <%--<s:actionerror />--%> <%--<s:actionmessage />--%> <s:form action="crud!save.action" method="post"> <s:textfield name="employee.firstName" value="%{employee.firstName}" label="%{getText('label.firstName')}" size="40"/> <s:textfield name="employee.lastName" value="%{employee.lastName}" label="%{getText('label.lastName')}" size="40"/> <s:textfield name="employee.age" value="%{employee.age}" label="%{getText('label.age')}" size="20"/> <s:select name="employee.department.departmentId" value="%{employee.department.departmentId}" list="departments" listKey="departmentId" listValue="name"/> <%-- <s:select name="gender" list="%{#{'male':'Male', 'female':'Female'}}" />--%> <s:hidden name="employee.employeeId" value="%{employee.employeeId}"/> <s:submit value="%{getText('button.label.submit')}"/> <s:submit value="%{getText('button.label.cancel')}" name="redirect-action:index"/> </s:form> </body> </html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <link href="css/main.css" rel="stylesheet" type="text/css"/> <title><s:text name="label.employees"/></title> </head> <body> <div class="titleDiv"><s:text name="application.title"/></div> <h1><s:text name="label.employees"/></h1> <s:url id="url" action="crud!input" /> <a href="<s:property value="#url"/>">Add New Employee</a> <br/><br/> <table class="borderAll"> <tr> <th><s:text name="label.firstName"/></th> <th><s:text name="label.lastName"/></th> <th><s:text name="label.age"/></th> <th><s:text name="label.department"/></th> <th> </th> </tr> <s:iterator value="employees" status="status"> <tr class="<s:if test="#status.even">even</s:if><s:else>odd</s:else>"> <td class="nowrap"><s:property value="firstName"/></td> <td class="nowrap"><s:property value="lastName"/></td> <td class="nowrap"><s:property value="age"/></td> <td class="nowrap"><s:property value="department.name"/></td> <td class="nowrap"> <s:url action="crud!input" id="url"> <s:param name="employee.employeeId" value="employeeId"/> </s:url> <a href="<s:property value="#url"/>">Edit</a> <s:url action="crud!delete" id="url"> <s:param name="employee.employeeId" value="employeeId"/> </s:url> <a href="<s:property value="#url"/>">Delete</a> </td> </tr> </s:iterator> </table> </body> </html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>Error Page</title> <link href="<s:url value='/css/main.css'/>" rel="stylesheet" type="text/css"/> </head> <body> <s:actionerror/> <br/> In order that the development team can address this error, please report what you were doing that caused this error. <br/><br/> The following information can help the development team find where the error happened and what can be done to prevent it from happening in the future. </body> </html>
以上页面引用到的css文件,代码如下:
html, body {
margin-left: 10px;
margin-right: 10px;
margin-bottom: 5px;
color: black;
background-color: white;
font-family: Verdana, Arial, sans-serif;
font-size:12px;
}
.titleDiv {
background-color: #EFFBEF;
font-weight:bold;
font-size:18px;
text-align:left;
padding-left:10px;
padding-top:10px;
padding-bottom:10px;
border:2px solid #8F99EF;
}
h1 { font-weight:bold; color: brown; font-size:15px; text-align:left;}
td { font-size:12px; padding-right:10px; }
th { text-align:left; font-weight:bold; font-size:13px; padding-right:10px; }
.tdLabel { font-weight: bold; white-space:nowrap; vertical-align:top;}
A { color:#4A825A; text-decoration:none;}
A:link { text-decoration:none;}
A:visited { text-decoration:none;}
A:hover { text-decoration:none; color: red;}
.borderAll {
border: 2px solid #8F99EF;
}
.butStnd {
font-family:arial,sans-serif;
font-size:11px;
width:105px;
background-color:#DCDFFA ;color:#4A825A;font-weight:bold;
}
.error {
color: red;
font-weight: bold;
}
.errorSection {
padding-left:18px;
padding-top:2px;
padding-bottom:10px;
padding-right:5px;
}
.even { background-color: #EFFBEF; }
.odd { background-color: white; }
.nowrap { white-space:nowrap; }
到这里,这个例子基本上就完成了,其主要亮点在action层的实现类和验证xml,而jsp页面的tag和struts.xml也比较耐看,将web.xml配置好struts2的监听以后,部署到tomcat之后,浏览器键入:localhost:8080/CusManager,即可得到以上效果图所示。
代码我是全部都贴上了,连css也有,不会有任何地方的缺失,假使大家运行报错,请认真查看错误,并检查自己的web.xml的配置,除此之外不会有任何错误。