偶然在查看文档时,看到这个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的配置,除此之外不会有任何错误。